PF from OpenBSD 3.5
This commit is contained in:
parent
eaa9fc4cc3
commit
6adffbf983
|
@ -0,0 +1,229 @@
|
|||
/* $OpenBSD: if_pflog.c,v 1.11 2003/12/31 11:18:25 cedric Exp $ */
|
||||
/*
|
||||
* The authors of this code are John Ioannidis (ji@tla.org),
|
||||
* Angelos D. Keromytis (kermit@csd.uch.gr) and
|
||||
* Niels Provos (provos@physnet.uni-hamburg.de).
|
||||
*
|
||||
* This code was written by John Ioannidis for BSD/OS in Athens, Greece,
|
||||
* in November 1995.
|
||||
*
|
||||
* Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
|
||||
* by Angelos D. Keromytis.
|
||||
*
|
||||
* Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
|
||||
* and Niels Provos.
|
||||
*
|
||||
* Copyright (C) 1995, 1996, 1997, 1998 by John Ioannidis, Angelos D. Keromytis
|
||||
* and Niels Provos.
|
||||
* Copyright (c) 2001, Angelos D. Keromytis, Niels Provos.
|
||||
*
|
||||
* Permission to use, copy, and modify this software with or without fee
|
||||
* is hereby granted, provided that this entire notice is included in
|
||||
* all copies of any software which is or includes a copy or
|
||||
* modification of this software.
|
||||
* You may use this code under the GNU public license if you so wish. Please
|
||||
* contribute changes back to the authors under this freer than GPL license
|
||||
* so that we may further the use of strong encryption without limitations to
|
||||
* all.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
|
||||
* IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
|
||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
|
||||
* MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
|
||||
* PURPOSE.
|
||||
*/
|
||||
|
||||
#include "bpfilter.h"
|
||||
#include "pflog.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/route.h>
|
||||
#include <net/bpf.h>
|
||||
|
||||
#ifdef INET
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_var.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#endif
|
||||
|
||||
#ifdef INET6
|
||||
#ifndef INET
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#include <netinet6/nd6.h>
|
||||
#endif /* INET6 */
|
||||
|
||||
#include <net/pfvar.h>
|
||||
#include <net/if_pflog.h>
|
||||
|
||||
#define PFLOGMTU (32768 + MHLEN + MLEN)
|
||||
|
||||
#ifdef PFLOGDEBUG
|
||||
#define DPRINTF(x) do { if (pflogdebug) printf x ; } while (0)
|
||||
#else
|
||||
#define DPRINTF(x)
|
||||
#endif
|
||||
|
||||
struct pflog_softc pflogif[NPFLOG];
|
||||
|
||||
void pflogattach(int);
|
||||
int pflogoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
|
||||
struct rtentry *);
|
||||
int pflogioctl(struct ifnet *, u_long, caddr_t);
|
||||
void pflogrtrequest(int, struct rtentry *, struct sockaddr *);
|
||||
void pflogstart(struct ifnet *);
|
||||
|
||||
extern int ifqmaxlen;
|
||||
|
||||
void
|
||||
pflogattach(int npflog)
|
||||
{
|
||||
struct ifnet *ifp;
|
||||
int i;
|
||||
|
||||
bzero(pflogif, sizeof(pflogif));
|
||||
|
||||
for (i = 0; i < NPFLOG; i++) {
|
||||
ifp = &pflogif[i].sc_if;
|
||||
snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflog%d", i);
|
||||
ifp->if_softc = &pflogif[i];
|
||||
ifp->if_mtu = PFLOGMTU;
|
||||
ifp->if_ioctl = pflogioctl;
|
||||
ifp->if_output = pflogoutput;
|
||||
ifp->if_start = pflogstart;
|
||||
ifp->if_type = IFT_PFLOG;
|
||||
ifp->if_snd.ifq_maxlen = ifqmaxlen;
|
||||
ifp->if_hdrlen = PFLOG_HDRLEN;
|
||||
if_attach(ifp);
|
||||
if_alloc_sadl(ifp);
|
||||
|
||||
#if NBPFILTER > 0
|
||||
bpfattach(&pflogif[i].sc_if.if_bpf, ifp, DLT_PFLOG,
|
||||
PFLOG_HDRLEN);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Start output on the pflog interface.
|
||||
*/
|
||||
void
|
||||
pflogstart(struct ifnet *ifp)
|
||||
{
|
||||
struct mbuf *m;
|
||||
int s;
|
||||
|
||||
for (;;) {
|
||||
s = splimp();
|
||||
IF_DROP(&ifp->if_snd);
|
||||
IF_DEQUEUE(&ifp->if_snd, m);
|
||||
splx(s);
|
||||
|
||||
if (m == NULL)
|
||||
return;
|
||||
else
|
||||
m_freem(m);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
pflogoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
|
||||
struct rtentry *rt)
|
||||
{
|
||||
m_freem(m);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
void
|
||||
pflogrtrequest(int cmd, struct rtentry *rt, struct sockaddr *sa)
|
||||
{
|
||||
if (rt)
|
||||
rt->rt_rmx.rmx_mtu = PFLOGMTU;
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
int
|
||||
pflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||
{
|
||||
switch (cmd) {
|
||||
case SIOCSIFADDR:
|
||||
case SIOCAIFADDR:
|
||||
case SIOCSIFDSTADDR:
|
||||
case SIOCSIFFLAGS:
|
||||
if (ifp->if_flags & IFF_UP)
|
||||
ifp->if_flags |= IFF_RUNNING;
|
||||
else
|
||||
ifp->if_flags &= ~IFF_RUNNING;
|
||||
break;
|
||||
default:
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir,
|
||||
u_int8_t reason, struct pf_rule *rm, struct pf_rule *am,
|
||||
struct pf_ruleset *ruleset)
|
||||
{
|
||||
#if NBPFILTER > 0
|
||||
struct ifnet *ifn;
|
||||
struct pfloghdr hdr;
|
||||
struct mbuf m1;
|
||||
|
||||
if (kif == NULL || m == NULL || rm == NULL)
|
||||
return (-1);
|
||||
|
||||
bzero(&hdr, sizeof(hdr));
|
||||
hdr.length = PFLOG_REAL_HDRLEN;
|
||||
hdr.af = af;
|
||||
hdr.action = rm->action;
|
||||
hdr.reason = reason;
|
||||
memcpy(hdr.ifname, kif->pfik_name, sizeof(hdr.ifname));
|
||||
|
||||
if (am == NULL) {
|
||||
hdr.rulenr = htonl(rm->nr);
|
||||
hdr.subrulenr = -1;
|
||||
} else {
|
||||
hdr.rulenr = htonl(am->nr);
|
||||
hdr.subrulenr = htonl(rm->nr);
|
||||
if (ruleset != NULL)
|
||||
memcpy(hdr.ruleset, ruleset->name,
|
||||
sizeof(hdr.ruleset));
|
||||
|
||||
|
||||
}
|
||||
hdr.dir = dir;
|
||||
|
||||
#ifdef INET
|
||||
if (af == AF_INET && dir == PF_OUT) {
|
||||
struct ip *ip;
|
||||
|
||||
ip = mtod(m, struct ip *);
|
||||
ip->ip_sum = 0;
|
||||
ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
|
||||
}
|
||||
#endif /* INET */
|
||||
|
||||
m1.m_next = m;
|
||||
m1.m_len = PFLOG_HDRLEN;
|
||||
m1.m_data = (char *) &hdr;
|
||||
|
||||
ifn = &(pflogif[0].sc_if);
|
||||
|
||||
if (ifn->if_bpf)
|
||||
bpf_mtap(ifn->if_bpf, &m1);
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/* $OpenBSD: if_pflog.h,v 1.10 2004/03/19 04:52:04 frantzen Exp $ */
|
||||
/*
|
||||
* Copyright 2001 Niels Provos <provos@citi.umich.edu>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _NET_IF_PFLOG_H_
|
||||
#define _NET_IF_PFLOG_H_
|
||||
|
||||
struct pflog_softc {
|
||||
struct ifnet sc_if; /* the interface */
|
||||
};
|
||||
|
||||
/* XXX keep in sync with pfvar.h */
|
||||
#ifndef PF_RULESET_NAME_SIZE
|
||||
#define PF_RULESET_NAME_SIZE 16
|
||||
#endif
|
||||
|
||||
struct pfloghdr {
|
||||
u_int8_t length;
|
||||
sa_family_t af;
|
||||
u_int8_t action;
|
||||
u_int8_t reason;
|
||||
char ifname[IFNAMSIZ];
|
||||
char ruleset[PF_RULESET_NAME_SIZE];
|
||||
u_int32_t rulenr;
|
||||
u_int32_t subrulenr;
|
||||
u_int8_t dir;
|
||||
u_int8_t pad[3];
|
||||
};
|
||||
|
||||
#define PFLOG_HDRLEN sizeof(struct pfloghdr)
|
||||
/* minus pad, also used as a signature */
|
||||
#define PFLOG_REAL_HDRLEN offsetof(struct pfloghdr, pad)
|
||||
|
||||
/* XXX remove later when old format logs are no longer needed */
|
||||
struct old_pfloghdr {
|
||||
u_int32_t af;
|
||||
char ifname[IFNAMSIZ];
|
||||
short rnr;
|
||||
u_short reason;
|
||||
u_short action;
|
||||
u_short dir;
|
||||
};
|
||||
#define OLD_PFLOG_HDRLEN sizeof(struct old_pfloghdr)
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
#if NPFLOG > 0
|
||||
#define PFLOG_PACKET(i,x,a,b,c,d,e,f,g) pflog_packet(i,a,b,c,d,e,f,g)
|
||||
#else
|
||||
#define PFLOG_PACKET(i,x,a,b,c,d,e,f,g) ((void)0)
|
||||
#endif /* NPFLOG > 0 */
|
||||
#endif /* _KERNEL */
|
||||
#endif /* _NET_IF_PFLOG_H_ */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,280 @@
|
|||
/* $OpenBSD: if_pfsync.h,v 1.13 2004/03/22 04:54:17 mcbride Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001 Michael Shalayeff
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _NET_IF_PFSYNC_H_
|
||||
#define _NET_IF_PFSYNC_H_
|
||||
|
||||
|
||||
#define PFSYNC_ID_LEN sizeof(u_int64_t)
|
||||
|
||||
struct pfsync_state_scrub {
|
||||
u_int16_t pfss_flags;
|
||||
u_int8_t pfss_ttl; /* stashed TTL */
|
||||
u_int8_t scrub_flag;
|
||||
u_int32_t pfss_ts_mod; /* timestamp modulation */
|
||||
} __packed;
|
||||
|
||||
struct pfsync_state_host {
|
||||
struct pf_addr addr;
|
||||
u_int16_t port;
|
||||
u_int16_t pad[3];
|
||||
} __packed;
|
||||
|
||||
struct pfsync_state_peer {
|
||||
struct pfsync_state_scrub scrub; /* state is scrubbed */
|
||||
u_int32_t seqlo; /* Max sequence number sent */
|
||||
u_int32_t seqhi; /* Max the other end ACKd + win */
|
||||
u_int32_t seqdiff; /* Sequence number modulator */
|
||||
u_int16_t max_win; /* largest window (pre scaling) */
|
||||
u_int16_t mss; /* Maximum segment size option */
|
||||
u_int8_t state; /* active state level */
|
||||
u_int8_t wscale; /* window scaling factor */
|
||||
u_int8_t scrub_flag;
|
||||
u_int8_t pad[5];
|
||||
} __packed;
|
||||
|
||||
struct pfsync_state {
|
||||
u_int32_t id[2];
|
||||
char ifname[IFNAMSIZ];
|
||||
struct pfsync_state_host lan;
|
||||
struct pfsync_state_host gwy;
|
||||
struct pfsync_state_host ext;
|
||||
struct pfsync_state_peer src;
|
||||
struct pfsync_state_peer dst;
|
||||
struct pf_addr rt_addr;
|
||||
u_int32_t rule;
|
||||
u_int32_t anchor;
|
||||
u_int32_t nat_rule;
|
||||
u_int32_t creation;
|
||||
u_int32_t expire;
|
||||
u_int32_t packets[2];
|
||||
u_int32_t bytes[2];
|
||||
u_int32_t creatorid;
|
||||
sa_family_t af;
|
||||
u_int8_t proto;
|
||||
u_int8_t direction;
|
||||
u_int8_t log;
|
||||
u_int8_t allow_opts;
|
||||
u_int8_t timeout;
|
||||
u_int8_t sync_flags;
|
||||
u_int8_t updates;
|
||||
} __packed;
|
||||
|
||||
struct pfsync_state_upd {
|
||||
u_int32_t id[2];
|
||||
struct pfsync_state_peer src;
|
||||
struct pfsync_state_peer dst;
|
||||
u_int32_t creatorid;
|
||||
u_int32_t expire;
|
||||
u_int8_t timeout;
|
||||
u_int8_t updates;
|
||||
u_int8_t pad[6];
|
||||
} __packed;
|
||||
|
||||
struct pfsync_state_del {
|
||||
u_int32_t id[2];
|
||||
u_int32_t creatorid;
|
||||
struct {
|
||||
u_int8_t state;
|
||||
} src;
|
||||
struct {
|
||||
u_int8_t state;
|
||||
} dst;
|
||||
u_int8_t pad[2];
|
||||
} __packed;
|
||||
|
||||
struct pfsync_state_upd_req {
|
||||
u_int32_t id[2];
|
||||
u_int32_t creatorid;
|
||||
u_int32_t pad;
|
||||
} __packed;
|
||||
|
||||
struct pfsync_state_clr {
|
||||
char ifname[IFNAMSIZ];
|
||||
u_int32_t creatorid;
|
||||
u_int32_t pad;
|
||||
} __packed;
|
||||
|
||||
struct pfsync_state_bus {
|
||||
u_int32_t creatorid;
|
||||
u_int32_t endtime;
|
||||
u_int8_t status;
|
||||
#define PFSYNC_BUS_START 1
|
||||
#define PFSYNC_BUS_END 2
|
||||
u_int8_t pad[7];
|
||||
} __packed;
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
union sc_statep {
|
||||
struct pfsync_state *s;
|
||||
struct pfsync_state_upd *u;
|
||||
struct pfsync_state_del *d;
|
||||
struct pfsync_state_clr *c;
|
||||
struct pfsync_state_bus *b;
|
||||
struct pfsync_state_upd_req *r;
|
||||
};
|
||||
|
||||
extern int pfsync_sync_ok;
|
||||
|
||||
struct pfsync_softc {
|
||||
struct ifnet sc_if;
|
||||
struct ifnet *sc_sync_ifp;
|
||||
|
||||
struct ip_moptions sc_imo;
|
||||
struct timeout sc_tmo;
|
||||
struct timeout sc_bulk_tmo;
|
||||
struct timeout sc_bulkfail_tmo;
|
||||
struct in_addr sc_sendaddr;
|
||||
struct mbuf *sc_mbuf; /* current cummulative mbuf */
|
||||
struct mbuf *sc_mbuf_net; /* current cummulative mbuf */
|
||||
union sc_statep sc_statep;
|
||||
union sc_statep sc_statep_net;
|
||||
u_int32_t sc_ureq_received;
|
||||
u_int32_t sc_ureq_sent;
|
||||
int sc_bulk_tries;
|
||||
int sc_maxcount; /* number of states in mtu */
|
||||
int sc_maxupdates; /* number of updates/state */
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
struct pfsync_header {
|
||||
u_int8_t version;
|
||||
#define PFSYNC_VERSION 2
|
||||
u_int8_t af;
|
||||
u_int8_t action;
|
||||
#define PFSYNC_ACT_CLR 0 /* clear all states */
|
||||
#define PFSYNC_ACT_INS 1 /* insert state */
|
||||
#define PFSYNC_ACT_UPD 2 /* update state */
|
||||
#define PFSYNC_ACT_DEL 3 /* delete state */
|
||||
#define PFSYNC_ACT_UPD_C 4 /* "compressed" state update */
|
||||
#define PFSYNC_ACT_DEL_C 5 /* "compressed" state delete */
|
||||
#define PFSYNC_ACT_INS_F 6 /* insert fragment */
|
||||
#define PFSYNC_ACT_DEL_F 7 /* delete fragments */
|
||||
#define PFSYNC_ACT_UREQ 8 /* request "uncompressed" state */
|
||||
#define PFSYNC_ACT_BUS 9 /* Bulk Update Status */
|
||||
#define PFSYNC_ACT_MAX 10
|
||||
u_int8_t count;
|
||||
} __packed;
|
||||
|
||||
#define PFSYNC_BULKPACKETS 1 /* # of packets per timeout */
|
||||
#define PFSYNC_MAX_BULKTRIES 12
|
||||
#define PFSYNC_HDRLEN sizeof(struct pfsync_header)
|
||||
#define PFSYNC_ACTIONS \
|
||||
"CLR ST", "INS ST", "UPD ST", "DEL ST", \
|
||||
"UPD ST COMP", "DEL ST COMP", "INS FR", "DEL FR", \
|
||||
"UPD REQ", "BLK UPD STAT"
|
||||
|
||||
#define PFSYNC_DFLTTL 255
|
||||
|
||||
struct pfsyncstats {
|
||||
u_long pfsyncs_ipackets; /* total input packets, IPv4 */
|
||||
u_long pfsyncs_ipackets6; /* total input packets, IPv6 */
|
||||
u_long pfsyncs_badif; /* not the right interface */
|
||||
u_long pfsyncs_badttl; /* TTL is not PFSYNC_DFLTTL */
|
||||
u_long pfsyncs_hdrops; /* packets shorter than header */
|
||||
u_long pfsyncs_badver; /* bad (incl unsupp) version */
|
||||
u_long pfsyncs_badact; /* bad action */
|
||||
u_long pfsyncs_badlen; /* data length does not match */
|
||||
u_long pfsyncs_badauth; /* bad authentication */
|
||||
u_long pfsyncs_badstate; /* insert/lookup failed */
|
||||
|
||||
u_long pfsyncs_opackets; /* total output packets, IPv4 */
|
||||
u_long pfsyncs_opackets6; /* total output packets, IPv6 */
|
||||
u_long pfsyncs_onomem; /* no memory for an mbuf for a send */
|
||||
u_long pfsyncs_oerrors; /* ip output error */
|
||||
};
|
||||
|
||||
/*
|
||||
* Configuration structure for SIOCSETPFSYNC SIOCGETPFSYNC
|
||||
*/
|
||||
struct pfsyncreq {
|
||||
char pfsyncr_syncif[IFNAMSIZ];
|
||||
int pfsyncr_maxupdates;
|
||||
int pfsyncr_authlevel;
|
||||
};
|
||||
#define SIOCSETPFSYNC _IOW('i', 247, struct ifreq)
|
||||
#define SIOCGETPFSYNC _IOWR('i', 248, struct ifreq)
|
||||
|
||||
|
||||
#define pf_state_peer_hton(s,d) do { \
|
||||
(d)->seqlo = htonl((s)->seqlo); \
|
||||
(d)->seqhi = htonl((s)->seqhi); \
|
||||
(d)->seqdiff = htonl((s)->seqdiff); \
|
||||
(d)->max_win = htons((s)->max_win); \
|
||||
(d)->mss = htons((s)->mss); \
|
||||
(d)->state = (s)->state; \
|
||||
(d)->wscale = (s)->wscale; \
|
||||
} while (0)
|
||||
|
||||
#define pf_state_peer_ntoh(s,d) do { \
|
||||
(d)->seqlo = ntohl((s)->seqlo); \
|
||||
(d)->seqhi = ntohl((s)->seqhi); \
|
||||
(d)->seqdiff = ntohl((s)->seqdiff); \
|
||||
(d)->max_win = ntohs((s)->max_win); \
|
||||
(d)->mss = ntohs((s)->mss); \
|
||||
(d)->state = (s)->state; \
|
||||
(d)->wscale = (s)->wscale; \
|
||||
} while (0)
|
||||
|
||||
#define pf_state_host_hton(s,d) do { \
|
||||
bcopy(&(s)->addr, &(d)->addr, sizeof((d)->addr)); \
|
||||
(d)->port = (s)->port; \
|
||||
} while (0)
|
||||
|
||||
#define pf_state_host_ntoh(s,d) do { \
|
||||
bcopy(&(s)->addr, &(d)->addr, sizeof((d)->addr)); \
|
||||
(d)->port = (s)->port; \
|
||||
} while (0)
|
||||
|
||||
#ifdef _KERNEL
|
||||
void pfsync_input(struct mbuf *, ...);
|
||||
int pfsync_clear_states(u_int32_t, char *);
|
||||
int pfsync_pack_state(u_int8_t, struct pf_state *, int);
|
||||
#define pfsync_insert_state(st) do { \
|
||||
if ((st->rule.ptr->rule_flag & PFRULE_NOSYNC) || \
|
||||
(st->proto == IPPROTO_PFSYNC)) \
|
||||
st->sync_flags |= PFSTATE_NOSYNC; \
|
||||
else if (!st->sync_flags) \
|
||||
pfsync_pack_state(PFSYNC_ACT_INS, (st), 1); \
|
||||
st->sync_flags &= ~PFSTATE_FROMSYNC; \
|
||||
} while (0)
|
||||
#define pfsync_update_state(st) do { \
|
||||
if (!st->sync_flags) \
|
||||
pfsync_pack_state(PFSYNC_ACT_UPD, (st), 1); \
|
||||
st->sync_flags &= ~PFSTATE_FROMSYNC; \
|
||||
} while (0)
|
||||
#define pfsync_delete_state(st) do { \
|
||||
if (!st->sync_flags) \
|
||||
pfsync_pack_state(PFSYNC_ACT_DEL, (st), 1); \
|
||||
st->sync_flags &= ~PFSTATE_FROMSYNC; \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#endif /* _NET_IF_PFSYNC_H_ */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,840 @@
|
|||
/* $OpenBSD: pf_if.c,v 1.11 2004/03/15 11:38:23 cedric Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001 Daniel Hartmeier
|
||||
* Copyright (c) 2003 Cedric Berger
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/filio.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/device.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_types.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_var.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_var.h>
|
||||
|
||||
#include <net/pfvar.h>
|
||||
|
||||
#ifdef INET6
|
||||
#include <netinet/ip6.h>
|
||||
#endif /* INET6 */
|
||||
|
||||
#define ACCEPT_FLAGS(oklist) \
|
||||
do { \
|
||||
if ((flags & ~(oklist)) & \
|
||||
PFI_FLAG_ALLMASK) \
|
||||
return (EINVAL); \
|
||||
} while (0)
|
||||
|
||||
#define senderr(e) do { rv = (e); goto _bad; } while (0)
|
||||
|
||||
struct pfi_kif **pfi_index2kif;
|
||||
struct pfi_kif *pfi_self;
|
||||
int pfi_indexlim;
|
||||
struct pfi_ifhead pfi_ifs;
|
||||
struct pfi_statehead pfi_statehead;
|
||||
int pfi_ifcnt;
|
||||
struct pool pfi_addr_pl;
|
||||
long pfi_update = 1;
|
||||
struct pfr_addr *pfi_buffer;
|
||||
int pfi_buffer_cnt;
|
||||
int pfi_buffer_max;
|
||||
char pfi_reserved_anchor[PF_ANCHOR_NAME_SIZE] =
|
||||
PF_RESERVED_ANCHOR;
|
||||
char pfi_interface_ruleset[PF_RULESET_NAME_SIZE] =
|
||||
PF_INTERFACE_RULESET;
|
||||
|
||||
void pfi_dynaddr_update(void *);
|
||||
void pfi_kifaddr_update(void *);
|
||||
void pfi_table_update(struct pfr_ktable *, struct pfi_kif *,
|
||||
int, int);
|
||||
void pfi_instance_add(struct ifnet *, int, int);
|
||||
void pfi_address_add(struct sockaddr *, int, int);
|
||||
int pfi_if_compare(struct pfi_kif *, struct pfi_kif *);
|
||||
struct pfi_kif *pfi_if_create(const char *, struct pfi_kif *, int);
|
||||
void pfi_copy_group(char *, const char *, int);
|
||||
void pfi_dynamic_drivers(void);
|
||||
void pfi_newgroup(const char *, int);
|
||||
int pfi_skip_if(const char *, struct pfi_kif *, int);
|
||||
int pfi_unmask(void *);
|
||||
void pfi_dohooks(struct pfi_kif *);
|
||||
|
||||
RB_PROTOTYPE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare);
|
||||
RB_GENERATE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare);
|
||||
|
||||
#define PFI_DYNAMIC_BUSES { "pcmcia", "cardbus", "uhub" }
|
||||
#define PFI_BUFFER_MAX 0x10000
|
||||
#define PFI_MTYPE M_IFADDR
|
||||
|
||||
void
|
||||
pfi_initialize(void)
|
||||
{
|
||||
if (pfi_self != NULL) /* already initialized */
|
||||
return;
|
||||
|
||||
TAILQ_INIT(&pfi_statehead);
|
||||
pool_init(&pfi_addr_pl, sizeof(struct pfi_dynaddr), 0, 0, 0,
|
||||
"pfiaddrpl", &pool_allocator_nointr);
|
||||
pfi_buffer_max = 64;
|
||||
pfi_buffer = malloc(pfi_buffer_max * sizeof(*pfi_buffer),
|
||||
PFI_MTYPE, M_WAITOK);
|
||||
pfi_self = pfi_if_create("self", NULL, PFI_IFLAG_GROUP);
|
||||
pfi_dynamic_drivers();
|
||||
}
|
||||
|
||||
void
|
||||
pfi_attach_clone(struct if_clone *ifc)
|
||||
{
|
||||
pfi_initialize();
|
||||
pfi_newgroup(ifc->ifc_name, PFI_IFLAG_CLONABLE);
|
||||
}
|
||||
|
||||
void
|
||||
pfi_attach_ifnet(struct ifnet *ifp)
|
||||
{
|
||||
struct pfi_kif *p, *q, key;
|
||||
int s;
|
||||
|
||||
pfi_initialize();
|
||||
s = splsoftnet();
|
||||
pfi_update++;
|
||||
if (ifp->if_index >= pfi_indexlim) {
|
||||
/*
|
||||
* grow pfi_index2kif, similar to ifindex2ifnet code in if.c
|
||||
*/
|
||||
size_t m, n, oldlim;
|
||||
struct pfi_kif **mp, **np;
|
||||
|
||||
oldlim = pfi_indexlim;
|
||||
if (pfi_indexlim == 0)
|
||||
pfi_indexlim = 64;
|
||||
while (ifp->if_index >= pfi_indexlim)
|
||||
pfi_indexlim <<= 1;
|
||||
|
||||
m = oldlim * sizeof(struct pfi_kif *);
|
||||
mp = pfi_index2kif;
|
||||
n = pfi_indexlim * sizeof(struct pfi_kif *);
|
||||
np = malloc(n, PFI_MTYPE, M_DONTWAIT);
|
||||
if (np == NULL)
|
||||
panic("pfi_attach_ifnet: "
|
||||
"cannot allocate translation table");
|
||||
bzero(np, n);
|
||||
if (mp != NULL)
|
||||
bcopy(mp, np, m);
|
||||
pfi_index2kif = np;
|
||||
if (mp != NULL)
|
||||
free(mp, PFI_MTYPE);
|
||||
}
|
||||
|
||||
strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name));
|
||||
p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
|
||||
if (p == NULL) {
|
||||
/* add group */
|
||||
pfi_copy_group(key.pfik_name, ifp->if_xname,
|
||||
sizeof(key.pfik_name));
|
||||
q = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
|
||||
if (q == NULL)
|
||||
q = pfi_if_create(key.pfik_name, pfi_self, PFI_IFLAG_GROUP);
|
||||
if (q == NULL)
|
||||
panic("pfi_attach_ifnet: "
|
||||
"cannot allocate '%s' group", key.pfik_name);
|
||||
|
||||
/* add interface */
|
||||
p = pfi_if_create(ifp->if_xname, q, PFI_IFLAG_INSTANCE);
|
||||
if (p == NULL)
|
||||
panic("pfi_attach_ifnet: "
|
||||
"cannot allocate '%s' interface", ifp->if_xname);
|
||||
} else
|
||||
q = p->pfik_parent;
|
||||
p->pfik_ifp = ifp;
|
||||
p->pfik_flags |= PFI_IFLAG_ATTACHED;
|
||||
p->pfik_ah_cookie =
|
||||
hook_establish(ifp->if_addrhooks, 1, pfi_kifaddr_update, p);
|
||||
pfi_index2kif[ifp->if_index] = p;
|
||||
pfi_dohooks(p);
|
||||
splx(s);
|
||||
}
|
||||
|
||||
void
|
||||
pfi_detach_ifnet(struct ifnet *ifp)
|
||||
{
|
||||
struct pfi_kif *p, *q, key;
|
||||
int s;
|
||||
|
||||
strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name));
|
||||
|
||||
s = splsoftnet();
|
||||
pfi_update++;
|
||||
p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
|
||||
if (p == NULL) {
|
||||
printf("pfi_detach_ifnet: cannot find %s", ifp->if_xname);
|
||||
splx(s);
|
||||
return;
|
||||
}
|
||||
hook_disestablish(p->pfik_ifp->if_addrhooks, p->pfik_ah_cookie);
|
||||
q = p->pfik_parent;
|
||||
p->pfik_ifp = NULL;
|
||||
p->pfik_flags &= ~PFI_IFLAG_ATTACHED;
|
||||
pfi_index2kif[ifp->if_index] = NULL;
|
||||
pfi_dohooks(p);
|
||||
pfi_maybe_destroy(p);
|
||||
splx(s);
|
||||
}
|
||||
|
||||
struct pfi_kif *
|
||||
pfi_lookup_create(const char *name)
|
||||
{
|
||||
struct pfi_kif *p, *q, key;
|
||||
int s;
|
||||
|
||||
s = splsoftnet();
|
||||
p = pfi_lookup_if(name);
|
||||
if (p == NULL) {
|
||||
pfi_copy_group(key.pfik_name, name, sizeof(key.pfik_name));
|
||||
q = pfi_lookup_if(key.pfik_name);
|
||||
if (q != NULL)
|
||||
p = pfi_if_create(name, q, PFI_IFLAG_INSTANCE);
|
||||
}
|
||||
splx(s);
|
||||
return (p);
|
||||
}
|
||||
|
||||
struct pfi_kif *
|
||||
pfi_attach_rule(const char *name)
|
||||
{
|
||||
struct pfi_kif *p;
|
||||
|
||||
p = pfi_lookup_create(name);
|
||||
if (p != NULL)
|
||||
p->pfik_rules++;
|
||||
return (p);
|
||||
}
|
||||
|
||||
void
|
||||
pfi_detach_rule(struct pfi_kif *p)
|
||||
{
|
||||
if (p == NULL)
|
||||
return;
|
||||
if (p->pfik_rules > 0)
|
||||
p->pfik_rules--;
|
||||
else
|
||||
printf("pfi_detach_rule: reference count at 0\n");
|
||||
pfi_maybe_destroy(p);
|
||||
}
|
||||
|
||||
void
|
||||
pfi_attach_state(struct pfi_kif *p)
|
||||
{
|
||||
if (!p->pfik_states++)
|
||||
TAILQ_INSERT_TAIL(&pfi_statehead, p, pfik_w_states);
|
||||
}
|
||||
|
||||
void
|
||||
pfi_detach_state(struct pfi_kif *p)
|
||||
{
|
||||
if (p == NULL)
|
||||
return;
|
||||
if (p->pfik_states <= 0) {
|
||||
printf("pfi_detach_state: reference count <= 0\n");
|
||||
return;
|
||||
}
|
||||
if (!--p->pfik_states)
|
||||
TAILQ_REMOVE(&pfi_statehead, p, pfik_w_states);
|
||||
pfi_maybe_destroy(p);
|
||||
}
|
||||
|
||||
int
|
||||
pfi_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af)
|
||||
{
|
||||
struct pfi_dynaddr *dyn;
|
||||
char tblname[PF_TABLE_NAME_SIZE];
|
||||
struct pf_ruleset *ruleset = NULL;
|
||||
int s, rv = 0;
|
||||
|
||||
if (aw->type != PF_ADDR_DYNIFTL)
|
||||
return (0);
|
||||
dyn = pool_get(&pfi_addr_pl, PR_NOWAIT);
|
||||
if (dyn == NULL)
|
||||
return (1);
|
||||
bzero(dyn, sizeof(*dyn));
|
||||
|
||||
s = splsoftnet();
|
||||
dyn->pfid_kif = pfi_attach_rule(aw->v.ifname);
|
||||
if (dyn->pfid_kif == NULL)
|
||||
senderr(1);
|
||||
|
||||
dyn->pfid_net = pfi_unmask(&aw->v.a.mask);
|
||||
if (af == AF_INET && dyn->pfid_net == 32)
|
||||
dyn->pfid_net = 128;
|
||||
strlcpy(tblname, aw->v.ifname, sizeof(tblname));
|
||||
if (aw->iflags & PFI_AFLAG_NETWORK)
|
||||
strlcat(tblname, ":network", sizeof(tblname));
|
||||
if (aw->iflags & PFI_AFLAG_BROADCAST)
|
||||
strlcat(tblname, ":broadcast", sizeof(tblname));
|
||||
if (aw->iflags & PFI_AFLAG_PEER)
|
||||
strlcat(tblname, ":peer", sizeof(tblname));
|
||||
if (aw->iflags & PFI_AFLAG_NOALIAS)
|
||||
strlcat(tblname, ":0", sizeof(tblname));
|
||||
if (dyn->pfid_net != 128)
|
||||
snprintf(tblname + strlen(tblname),
|
||||
sizeof(tblname) - strlen(tblname), "/%d", dyn->pfid_net);
|
||||
ruleset = pf_find_or_create_ruleset(pfi_reserved_anchor,
|
||||
pfi_interface_ruleset);
|
||||
if (ruleset == NULL)
|
||||
senderr(1);
|
||||
|
||||
dyn->pfid_kt = pfr_attach_table(ruleset, tblname);
|
||||
if (dyn->pfid_kt == NULL)
|
||||
senderr(1);
|
||||
|
||||
dyn->pfid_kt->pfrkt_flags |= PFR_TFLAG_ACTIVE;
|
||||
dyn->pfid_iflags = aw->iflags;
|
||||
dyn->pfid_af = af;
|
||||
dyn->pfid_hook_cookie = hook_establish(dyn->pfid_kif->pfik_ah_head, 1,
|
||||
pfi_dynaddr_update, dyn);
|
||||
if (dyn->pfid_hook_cookie == NULL)
|
||||
senderr(1);
|
||||
|
||||
aw->p.dyn = dyn;
|
||||
pfi_dynaddr_update(aw->p.dyn);
|
||||
splx(s);
|
||||
return (0);
|
||||
|
||||
_bad:
|
||||
if (dyn->pfid_kt != NULL)
|
||||
pfr_detach_table(dyn->pfid_kt);
|
||||
if (ruleset != NULL)
|
||||
pf_remove_if_empty_ruleset(ruleset);
|
||||
if (dyn->pfid_kif != NULL)
|
||||
pfi_detach_rule(dyn->pfid_kif);
|
||||
pool_put(&pfi_addr_pl, dyn);
|
||||
splx(s);
|
||||
return (rv);
|
||||
}
|
||||
|
||||
void
|
||||
pfi_dynaddr_update(void *p)
|
||||
{
|
||||
struct pfi_dynaddr *dyn = (struct pfi_dynaddr *)p;
|
||||
struct pfi_kif *kif = dyn->pfid_kif;
|
||||
struct pfr_ktable *kt = dyn->pfid_kt;
|
||||
|
||||
if (dyn == NULL || kif == NULL || kt == NULL)
|
||||
panic("pfi_dynaddr_update");
|
||||
if (kt->pfrkt_larg != pfi_update) {
|
||||
/* this table needs to be brought up-to-date */
|
||||
pfi_table_update(kt, kif, dyn->pfid_net, dyn->pfid_iflags);
|
||||
kt->pfrkt_larg = pfi_update;
|
||||
}
|
||||
pfr_dynaddr_update(kt, dyn);
|
||||
}
|
||||
|
||||
void
|
||||
pfi_table_update(struct pfr_ktable *kt, struct pfi_kif *kif, int net, int flags)
|
||||
{
|
||||
int e, size2 = 0;
|
||||
struct pfi_kif *p;
|
||||
struct pfr_table t;
|
||||
|
||||
if ((kif->pfik_flags & PFI_IFLAG_INSTANCE) && kif->pfik_ifp == NULL) {
|
||||
pfr_clr_addrs(&kt->pfrkt_t, NULL, 0);
|
||||
return;
|
||||
}
|
||||
pfi_buffer_cnt = 0;
|
||||
if ((kif->pfik_flags & PFI_IFLAG_INSTANCE))
|
||||
pfi_instance_add(kif->pfik_ifp, net, flags);
|
||||
else if (strcmp(kif->pfik_name, "self")) {
|
||||
TAILQ_FOREACH(p, &kif->pfik_grouphead, pfik_instances)
|
||||
pfi_instance_add(p->pfik_ifp, net, flags);
|
||||
} else {
|
||||
RB_FOREACH(p, pfi_ifhead, &pfi_ifs)
|
||||
if (p->pfik_flags & PFI_IFLAG_INSTANCE)
|
||||
pfi_instance_add(p->pfik_ifp, net, flags);
|
||||
}
|
||||
t = kt->pfrkt_t;
|
||||
t.pfrt_flags = 0;
|
||||
if ((e = pfr_set_addrs(&t, pfi_buffer, pfi_buffer_cnt, &size2,
|
||||
NULL, NULL, NULL, 0)))
|
||||
printf("pfi_table_update: cannot set %d new addresses "
|
||||
"into table %s: %d\n", pfi_buffer_cnt, kt->pfrkt_name, e);
|
||||
}
|
||||
|
||||
void
|
||||
pfi_instance_add(struct ifnet *ifp, int net, int flags)
|
||||
{
|
||||
struct ifaddr *ia;
|
||||
int got4 = 0, got6 = 0;
|
||||
int net2, af;
|
||||
|
||||
if (ifp == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH(ia, &ifp->if_addrlist, ifa_list) {
|
||||
if (ia->ifa_addr == NULL)
|
||||
continue;
|
||||
af = ia->ifa_addr->sa_family;
|
||||
if (af != AF_INET && af != AF_INET6)
|
||||
continue;
|
||||
if ((flags & PFI_AFLAG_BROADCAST) && af == AF_INET6)
|
||||
continue;
|
||||
if ((flags & PFI_AFLAG_BROADCAST) &&
|
||||
!(ifp->if_flags & IFF_BROADCAST))
|
||||
continue;
|
||||
if ((flags & PFI_AFLAG_PEER) &&
|
||||
!(ifp->if_flags & IFF_POINTOPOINT))
|
||||
continue;
|
||||
if ((flags & PFI_AFLAG_NETWORK) && af == AF_INET6 &&
|
||||
IN6_IS_ADDR_LINKLOCAL(
|
||||
&((struct sockaddr_in6 *)ia->ifa_addr)->sin6_addr))
|
||||
continue;
|
||||
if (flags & PFI_AFLAG_NOALIAS) {
|
||||
if (af == AF_INET && got4)
|
||||
continue;
|
||||
if (af == AF_INET6 && got6)
|
||||
continue;
|
||||
}
|
||||
if (af == AF_INET)
|
||||
got4 = 1;
|
||||
else
|
||||
got6 = 1;
|
||||
net2 = net;
|
||||
if (net2 == 128 && (flags & PFI_AFLAG_NETWORK)) {
|
||||
if (af == AF_INET) {
|
||||
net2 = pfi_unmask(&((struct sockaddr_in *)
|
||||
ia->ifa_netmask)->sin_addr);
|
||||
} else {
|
||||
net2 = pfi_unmask(&((struct sockaddr_in6 *)
|
||||
ia->ifa_netmask)->sin6_addr);
|
||||
}
|
||||
}
|
||||
if (af == AF_INET && net2 > 32)
|
||||
net2 = 32;
|
||||
if (flags & PFI_AFLAG_BROADCAST)
|
||||
pfi_address_add(ia->ifa_broadaddr, af, net2);
|
||||
else if (flags & PFI_AFLAG_PEER)
|
||||
pfi_address_add(ia->ifa_dstaddr, af, net2);
|
||||
else
|
||||
pfi_address_add(ia->ifa_addr, af, net2);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pfi_address_add(struct sockaddr *sa, int af, int net)
|
||||
{
|
||||
struct pfr_addr *p;
|
||||
int i;
|
||||
|
||||
if (pfi_buffer_cnt >= pfi_buffer_max) {
|
||||
int new_max = pfi_buffer_max * 2;
|
||||
|
||||
if (new_max > PFI_BUFFER_MAX) {
|
||||
printf("pfi_address_add: address buffer full (%d/%d)\n",
|
||||
pfi_buffer_cnt, PFI_BUFFER_MAX);
|
||||
return;
|
||||
}
|
||||
p = malloc(new_max * sizeof(*pfi_buffer), PFI_MTYPE,
|
||||
M_DONTWAIT);
|
||||
if (p == NULL) {
|
||||
printf("pfi_address_add: no memory to grow buffer "
|
||||
"(%d/%d)\n", pfi_buffer_cnt, PFI_BUFFER_MAX);
|
||||
return;
|
||||
}
|
||||
memcpy(pfi_buffer, p, pfi_buffer_cnt * sizeof(*pfi_buffer));
|
||||
/* no need to zero buffer */
|
||||
free(pfi_buffer, PFI_MTYPE);
|
||||
pfi_buffer = p;
|
||||
pfi_buffer_max = new_max;
|
||||
}
|
||||
if (af == AF_INET && net > 32)
|
||||
net = 128;
|
||||
p = pfi_buffer + pfi_buffer_cnt++;
|
||||
bzero(p, sizeof(*p));
|
||||
p->pfra_af = af;
|
||||
p->pfra_net = net;
|
||||
if (af == AF_INET)
|
||||
p->pfra_ip4addr = ((struct sockaddr_in *)sa)->sin_addr;
|
||||
if (af == AF_INET6) {
|
||||
p->pfra_ip6addr = ((struct sockaddr_in6 *)sa)->sin6_addr;
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&p->pfra_ip6addr))
|
||||
p->pfra_ip6addr.s6_addr16[1] = 0;
|
||||
}
|
||||
/* mask network address bits */
|
||||
if (net < 128)
|
||||
((caddr_t)p)[p->pfra_net/8] &= ~(0xFF >> (p->pfra_net%8));
|
||||
for (i = (p->pfra_net+7)/8; i < sizeof(p->pfra_u); i++)
|
||||
((caddr_t)p)[i] = 0;
|
||||
}
|
||||
|
||||
void
|
||||
pfi_dynaddr_remove(struct pf_addr_wrap *aw)
|
||||
{
|
||||
int s;
|
||||
|
||||
if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL ||
|
||||
aw->p.dyn->pfid_kif == NULL || aw->p.dyn->pfid_kt == NULL)
|
||||
return;
|
||||
|
||||
s = splsoftnet();
|
||||
hook_disestablish(aw->p.dyn->pfid_kif->pfik_ah_head,
|
||||
aw->p.dyn->pfid_hook_cookie);
|
||||
pfi_detach_rule(aw->p.dyn->pfid_kif);
|
||||
aw->p.dyn->pfid_kif = NULL;
|
||||
pfr_detach_table(aw->p.dyn->pfid_kt);
|
||||
aw->p.dyn->pfid_kt = NULL;
|
||||
pool_put(&pfi_addr_pl, aw->p.dyn);
|
||||
aw->p.dyn = NULL;
|
||||
splx(s);
|
||||
}
|
||||
|
||||
void
|
||||
pfi_dynaddr_copyout(struct pf_addr_wrap *aw)
|
||||
{
|
||||
if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL ||
|
||||
aw->p.dyn->pfid_kif == NULL)
|
||||
return;
|
||||
aw->p.dyncnt = aw->p.dyn->pfid_acnt4 + aw->p.dyn->pfid_acnt6;
|
||||
}
|
||||
|
||||
void
|
||||
pfi_kifaddr_update(void *v)
|
||||
{
|
||||
int s;
|
||||
|
||||
s = splsoftnet();
|
||||
pfi_update++;
|
||||
pfi_dohooks(v);
|
||||
splx(s);
|
||||
}
|
||||
|
||||
int
|
||||
pfi_if_compare(struct pfi_kif *p, struct pfi_kif *q)
|
||||
{
|
||||
return (strncmp(p->pfik_name, q->pfik_name, IFNAMSIZ));
|
||||
}
|
||||
|
||||
struct pfi_kif *
|
||||
pfi_if_create(const char *name, struct pfi_kif *q, int flags)
|
||||
{
|
||||
struct pfi_kif *p;
|
||||
|
||||
p = malloc(sizeof(*p), PFI_MTYPE, M_DONTWAIT);
|
||||
if (p == NULL)
|
||||
return (NULL);
|
||||
bzero(p, sizeof(*p));
|
||||
p->pfik_ah_head = malloc(sizeof(*p->pfik_ah_head), PFI_MTYPE,
|
||||
M_DONTWAIT);
|
||||
if (p->pfik_ah_head == NULL) {
|
||||
free(p, PFI_MTYPE);
|
||||
return (NULL);
|
||||
}
|
||||
bzero(p->pfik_ah_head, sizeof(*p->pfik_ah_head));
|
||||
TAILQ_INIT(p->pfik_ah_head);
|
||||
TAILQ_INIT(&p->pfik_grouphead);
|
||||
strlcpy(p->pfik_name, name, sizeof(p->pfik_name));
|
||||
RB_INIT(&p->pfik_lan_ext);
|
||||
RB_INIT(&p->pfik_ext_gwy);
|
||||
p->pfik_flags = flags;
|
||||
p->pfik_parent = q;
|
||||
p->pfik_tzero = time.tv_sec;
|
||||
|
||||
RB_INSERT(pfi_ifhead, &pfi_ifs, p);
|
||||
if (q != NULL) {
|
||||
q->pfik_addcnt++;
|
||||
TAILQ_INSERT_TAIL(&q->pfik_grouphead, p, pfik_instances);
|
||||
}
|
||||
pfi_ifcnt++;
|
||||
return (p);
|
||||
}
|
||||
|
||||
int
|
||||
pfi_maybe_destroy(struct pfi_kif *p)
|
||||
{
|
||||
int i, j, k, s;
|
||||
struct pfi_kif *q = p->pfik_parent;
|
||||
|
||||
if ((p->pfik_flags & (PFI_IFLAG_ATTACHED | PFI_IFLAG_GROUP)) ||
|
||||
p->pfik_rules > 0 || p->pfik_states > 0)
|
||||
return (0);
|
||||
|
||||
s = splsoftnet();
|
||||
if (q != NULL) {
|
||||
for (i = 0; i < 2; i++)
|
||||
for (j = 0; j < 2; j++)
|
||||
for (k = 0; k < 2; k++) {
|
||||
q->pfik_bytes[i][j][k] +=
|
||||
p->pfik_bytes[i][j][k];
|
||||
q->pfik_packets[i][j][k] +=
|
||||
p->pfik_packets[i][j][k];
|
||||
}
|
||||
q->pfik_delcnt++;
|
||||
TAILQ_REMOVE(&q->pfik_grouphead, p, pfik_instances);
|
||||
}
|
||||
pfi_ifcnt--;
|
||||
RB_REMOVE(pfi_ifhead, &pfi_ifs, p);
|
||||
splx(s);
|
||||
|
||||
free(p->pfik_ah_head, PFI_MTYPE);
|
||||
free(p, PFI_MTYPE);
|
||||
return (1);
|
||||
}
|
||||
|
||||
void
|
||||
pfi_copy_group(char *p, const char *q, int m)
|
||||
{
|
||||
while (m > 1 && *q && !(*q >= '0' && *q <= '9')) {
|
||||
*p++ = *q++;
|
||||
m--;
|
||||
}
|
||||
if (m > 0)
|
||||
*p++ = '\0';
|
||||
}
|
||||
|
||||
void
|
||||
pfi_dynamic_drivers(void)
|
||||
{
|
||||
char *buses[] = PFI_DYNAMIC_BUSES;
|
||||
int nbuses = sizeof(buses)/sizeof(buses[0]);
|
||||
int enabled[sizeof(buses)/sizeof(buses[0])];
|
||||
struct device *dev;
|
||||
struct cfdata *cf;
|
||||
struct cfdriver *drv;
|
||||
short *p;
|
||||
int i;
|
||||
|
||||
bzero(enabled, sizeof(enabled));
|
||||
TAILQ_FOREACH(dev, &alldevs, dv_list) {
|
||||
if (!(dev->dv_flags & DVF_ACTIVE))
|
||||
continue;
|
||||
for (i = 0; i < nbuses; i++)
|
||||
if (!enabled[i] && !strcmp(buses[i],
|
||||
dev->dv_cfdata->cf_driver->cd_name))
|
||||
enabled[i] = 1;
|
||||
}
|
||||
for (cf = cfdata; cf->cf_driver; cf++) {
|
||||
if (cf->cf_driver->cd_class != DV_IFNET)
|
||||
continue;
|
||||
for (p = cf->cf_parents; p && *p >= 0; p++) {
|
||||
if ((drv = cfdata[*p].cf_driver) == NULL)
|
||||
continue;
|
||||
for (i = 0; i < nbuses; i++)
|
||||
if (enabled[i] &&
|
||||
!strcmp(drv->cd_name, buses[i]))
|
||||
break;
|
||||
if (i < nbuses) {
|
||||
pfi_newgroup(cf->cf_driver->cd_name,
|
||||
PFI_IFLAG_DYNAMIC);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pfi_newgroup(const char *name, int flags)
|
||||
{
|
||||
struct pfi_kif *p;
|
||||
|
||||
p = pfi_lookup_if(name);
|
||||
if (p == NULL)
|
||||
p = pfi_if_create(name, pfi_self, PFI_IFLAG_GROUP);
|
||||
if (p == NULL) {
|
||||
printf("pfi_newgroup: cannot allocate '%s' group", name);
|
||||
return;
|
||||
}
|
||||
p->pfik_flags |= flags;
|
||||
}
|
||||
|
||||
void
|
||||
pfi_fill_oldstatus(struct pf_status *pfs)
|
||||
{
|
||||
struct pfi_kif *p, key;
|
||||
int i, j, k, s;
|
||||
|
||||
strlcpy(key.pfik_name, pfs->ifname, sizeof(key.pfik_name));
|
||||
s = splsoftnet();
|
||||
p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
|
||||
if (p == NULL) {
|
||||
splx(s);
|
||||
return;
|
||||
}
|
||||
bzero(pfs->pcounters, sizeof(pfs->pcounters));
|
||||
bzero(pfs->bcounters, sizeof(pfs->bcounters));
|
||||
for (i = 0; i < 2; i++)
|
||||
for (j = 0; j < 2; j++)
|
||||
for (k = 0; k < 2; k++) {
|
||||
pfs->pcounters[i][j][k] =
|
||||
p->pfik_packets[i][j][k];
|
||||
pfs->bcounters[i][j] +=
|
||||
p->pfik_bytes[i][j][k];
|
||||
}
|
||||
splx(s);
|
||||
}
|
||||
|
||||
int
|
||||
pfi_clr_istats(const char *name, int *nzero, int flags)
|
||||
{
|
||||
struct pfi_kif *p;
|
||||
int n = 0, s;
|
||||
long tzero = time.tv_sec;
|
||||
|
||||
s = splsoftnet();
|
||||
ACCEPT_FLAGS(PFI_FLAG_GROUP|PFI_FLAG_INSTANCE);
|
||||
RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
|
||||
if (pfi_skip_if(name, p, flags))
|
||||
continue;
|
||||
bzero(p->pfik_packets, sizeof(p->pfik_packets));
|
||||
bzero(p->pfik_bytes, sizeof(p->pfik_bytes));
|
||||
p->pfik_tzero = tzero;
|
||||
n++;
|
||||
}
|
||||
splx(s);
|
||||
if (nzero != NULL)
|
||||
*nzero = n;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfi_get_ifaces(const char *name, struct pfi_if *buf, int *size, int flags)
|
||||
{
|
||||
struct pfi_kif *p;
|
||||
int s, n = 0;
|
||||
|
||||
ACCEPT_FLAGS(PFI_FLAG_GROUP|PFI_FLAG_INSTANCE);
|
||||
s = splsoftnet();
|
||||
RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
|
||||
if (pfi_skip_if(name, p, flags))
|
||||
continue;
|
||||
if (*size > n++) {
|
||||
if (!p->pfik_tzero)
|
||||
p->pfik_tzero = boottime.tv_sec;
|
||||
if (copyout(p, buf++, sizeof(*buf))) {
|
||||
splx(s);
|
||||
return (EFAULT);
|
||||
}
|
||||
}
|
||||
}
|
||||
splx(s);
|
||||
*size = n;
|
||||
return (0);
|
||||
}
|
||||
|
||||
struct pfi_kif *
|
||||
pfi_lookup_if(const char *name)
|
||||
{
|
||||
struct pfi_kif *p, key;
|
||||
|
||||
strlcpy(key.pfik_name, name, sizeof(key.pfik_name));
|
||||
p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
|
||||
return (p);
|
||||
}
|
||||
|
||||
int
|
||||
pfi_skip_if(const char *filter, struct pfi_kif *p, int f)
|
||||
{
|
||||
int n;
|
||||
|
||||
if ((p->pfik_flags & PFI_IFLAG_GROUP) && !(f & PFI_FLAG_GROUP))
|
||||
return (1);
|
||||
if ((p->pfik_flags & PFI_IFLAG_INSTANCE) && !(f & PFI_FLAG_INSTANCE))
|
||||
return (1);
|
||||
if (filter == NULL || !*filter)
|
||||
return (0);
|
||||
if (!strcmp(p->pfik_name, filter))
|
||||
return (0); /* exact match */
|
||||
n = strlen(filter);
|
||||
if (n < 1 || n >= IFNAMSIZ)
|
||||
return (1); /* sanity check */
|
||||
if (filter[n-1] >= '0' && filter[n-1] <= '9')
|
||||
return (1); /* only do exact match in that case */
|
||||
if (strncmp(p->pfik_name, filter, n))
|
||||
return (1); /* prefix doesn't match */
|
||||
return (p->pfik_name[n] < '0' || p->pfik_name[n] > '9');
|
||||
}
|
||||
|
||||
/* from pf_print_state.c */
|
||||
int
|
||||
pfi_unmask(void *addr)
|
||||
{
|
||||
struct pf_addr *m = addr;
|
||||
int i = 31, j = 0, b = 0;
|
||||
u_int32_t tmp;
|
||||
|
||||
while (j < 4 && m->addr32[j] == 0xffffffff) {
|
||||
b += 32;
|
||||
j++;
|
||||
}
|
||||
if (j < 4) {
|
||||
tmp = ntohl(m->addr32[j]);
|
||||
for (i = 31; tmp & (1 << i); --i)
|
||||
b++;
|
||||
}
|
||||
return (b);
|
||||
}
|
||||
|
||||
void
|
||||
pfi_dohooks(struct pfi_kif *p)
|
||||
{
|
||||
for (; p != NULL; p = p->pfik_parent)
|
||||
dohooks(p->pfik_ah_head, 0);
|
||||
}
|
||||
|
||||
int
|
||||
pfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af)
|
||||
{
|
||||
if (af == AF_INET) {
|
||||
switch (dyn->pfid_acnt4) {
|
||||
case 0:
|
||||
return (0);
|
||||
case 1:
|
||||
return (PF_MATCHA(0, &dyn->pfid_addr4,
|
||||
&dyn->pfid_mask4, a, AF_INET));
|
||||
default:
|
||||
return (pfr_match_addr(dyn->pfid_kt, a, AF_INET));
|
||||
}
|
||||
} else {
|
||||
switch (dyn->pfid_acnt6) {
|
||||
case 0:
|
||||
return (0);
|
||||
case 1:
|
||||
return (PF_MATCHA(0, &dyn->pfid_addr6,
|
||||
&dyn->pfid_mask6, a, AF_INET6));
|
||||
default:
|
||||
return (pfr_match_addr(dyn->pfid_kt, a, AF_INET6));
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,525 @@
|
|||
/* $OpenBSD: pf_osfp.c,v 1.9 2004/01/04 20:08:42 pvalchev Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2003 Mike Frantzen <frantzen@w4g.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#ifdef _KERNEL
|
||||
# include <sys/systm.h>
|
||||
#endif /* _KERNEL */
|
||||
#include <sys/mbuf.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/pfvar.h>
|
||||
|
||||
#ifdef INET6
|
||||
#include <netinet/ip6.h>
|
||||
#endif /* INET6 */
|
||||
|
||||
|
||||
#ifdef _KERNEL
|
||||
# define DPFPRINTF(format, x...) \
|
||||
if (pf_status.debug >= PF_DEBUG_NOISY) \
|
||||
printf(format , ##x)
|
||||
typedef struct pool pool_t;
|
||||
|
||||
#else
|
||||
/* Userland equivalents so we can lend code to tcpdump et al. */
|
||||
|
||||
# include <arpa/inet.h>
|
||||
# include <errno.h>
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
# define pool_t int
|
||||
# define pool_get(pool, flags) malloc(*(pool))
|
||||
# define pool_put(pool, item) free(item)
|
||||
# define pool_init(pool, size, a, ao, f, m, p) (*(pool)) = (size)
|
||||
|
||||
# ifdef PFDEBUG
|
||||
# include <sys/stdarg.h>
|
||||
# define DPFPRINTF(format, x...) fprintf(stderr, format , ##x)
|
||||
# else
|
||||
# define DPFPRINTF(format, x...) ((void)0)
|
||||
# endif /* PFDEBUG */
|
||||
#endif /* _KERNEL */
|
||||
|
||||
|
||||
SLIST_HEAD(pf_osfp_list, pf_os_fingerprint) pf_osfp_list;
|
||||
pool_t pf_osfp_entry_pl;
|
||||
pool_t pf_osfp_pl;
|
||||
|
||||
struct pf_os_fingerprint *pf_osfp_find(struct pf_osfp_list *,
|
||||
struct pf_os_fingerprint *, u_int8_t);
|
||||
struct pf_os_fingerprint *pf_osfp_find_exact(struct pf_osfp_list *,
|
||||
struct pf_os_fingerprint *);
|
||||
void pf_osfp_insert(struct pf_osfp_list *,
|
||||
struct pf_os_fingerprint *);
|
||||
|
||||
|
||||
#ifdef _KERNEL
|
||||
/*
|
||||
* Passively fingerprint the OS of the host (IPv4 TCP SYN packets only)
|
||||
* Returns the list of possible OSes.
|
||||
*/
|
||||
struct pf_osfp_enlist *
|
||||
pf_osfp_fingerprint(struct pf_pdesc *pd, struct mbuf *m, int off,
|
||||
const struct tcphdr *tcp)
|
||||
{
|
||||
struct ip *ip;
|
||||
char hdr[60];
|
||||
|
||||
/* XXX don't have a fingerprint database for IPv6 :-( */
|
||||
if (pd->af != PF_INET || pd->proto != IPPROTO_TCP || (tcp->th_off << 2)
|
||||
< sizeof(*tcp))
|
||||
return (NULL);
|
||||
|
||||
ip = mtod(m, struct ip *);
|
||||
if (!pf_pull_hdr(m, off, hdr, tcp->th_off << 2, NULL, NULL, pd->af))
|
||||
return (NULL);
|
||||
|
||||
return (pf_osfp_fingerprint_hdr(ip, (struct tcphdr *)hdr));
|
||||
}
|
||||
#endif /* _KERNEL */
|
||||
|
||||
struct pf_osfp_enlist *
|
||||
pf_osfp_fingerprint_hdr(const struct ip *ip, const struct tcphdr *tcp)
|
||||
{
|
||||
struct pf_os_fingerprint fp, *fpresult;
|
||||
int cnt, optlen = 0;
|
||||
const u_int8_t *optp;
|
||||
|
||||
if ((tcp->th_flags & (TH_SYN|TH_ACK)) != TH_SYN || (ip->ip_off &
|
||||
htons(IP_OFFMASK)))
|
||||
return (NULL);
|
||||
|
||||
memset(&fp, 0, sizeof(fp));
|
||||
|
||||
fp.fp_psize = ntohs(ip->ip_len);
|
||||
fp.fp_ttl = ip->ip_ttl;
|
||||
if (ip->ip_off & htons(IP_DF))
|
||||
fp.fp_flags |= PF_OSFP_DF;
|
||||
fp.fp_wsize = ntohs(tcp->th_win);
|
||||
|
||||
|
||||
cnt = (tcp->th_off << 2) - sizeof(*tcp);
|
||||
optp = (const u_int8_t *)((const char *)tcp + sizeof(*tcp));
|
||||
for (; cnt > 0; cnt -= optlen, optp += optlen) {
|
||||
if (*optp == TCPOPT_EOL)
|
||||
break;
|
||||
|
||||
fp.fp_optcnt++;
|
||||
if (*optp == TCPOPT_NOP) {
|
||||
fp.fp_tcpopts = (fp.fp_tcpopts << PF_OSFP_TCPOPT_BITS) |
|
||||
PF_OSFP_TCPOPT_NOP;
|
||||
optlen = 1;
|
||||
} else {
|
||||
if (cnt < 2)
|
||||
return (NULL);
|
||||
optlen = optp[1];
|
||||
if (optlen > cnt || optlen < 2)
|
||||
return (NULL);
|
||||
switch (*optp) {
|
||||
case TCPOPT_MAXSEG:
|
||||
if (optlen >= TCPOLEN_MAXSEG)
|
||||
memcpy(&fp.fp_mss, &optp[2],
|
||||
sizeof(fp.fp_mss));
|
||||
fp.fp_tcpopts = (fp.fp_tcpopts <<
|
||||
PF_OSFP_TCPOPT_BITS) | PF_OSFP_TCPOPT_MSS;
|
||||
NTOHS(fp.fp_mss);
|
||||
break;
|
||||
case TCPOPT_WINDOW:
|
||||
if (optlen >= TCPOLEN_WINDOW)
|
||||
memcpy(&fp.fp_wscale, &optp[2],
|
||||
sizeof(fp.fp_wscale));
|
||||
NTOHS(fp.fp_wscale);
|
||||
fp.fp_tcpopts = (fp.fp_tcpopts <<
|
||||
PF_OSFP_TCPOPT_BITS) |
|
||||
PF_OSFP_TCPOPT_WSCALE;
|
||||
break;
|
||||
case TCPOPT_SACK_PERMITTED:
|
||||
fp.fp_tcpopts = (fp.fp_tcpopts <<
|
||||
PF_OSFP_TCPOPT_BITS) | PF_OSFP_TCPOPT_SACK;
|
||||
break;
|
||||
case TCPOPT_TIMESTAMP:
|
||||
if (optlen >= TCPOLEN_TIMESTAMP) {
|
||||
u_int32_t ts;
|
||||
memcpy(&ts, &optp[2], sizeof(ts));
|
||||
if (ts == 0)
|
||||
fp.fp_flags |= PF_OSFP_TS0;
|
||||
|
||||
}
|
||||
fp.fp_tcpopts = (fp.fp_tcpopts <<
|
||||
PF_OSFP_TCPOPT_BITS) | PF_OSFP_TCPOPT_TS;
|
||||
break;
|
||||
default:
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
optlen = MAX(optlen, 1); /* paranoia */
|
||||
}
|
||||
|
||||
DPFPRINTF("fingerprinted %s:%d %d:%d:%d:%d:%llx (%d) "
|
||||
"(TS=%s,M=%s%d,W=%s%d)\n",
|
||||
inet_ntoa(ip->ip_src), ntohs(tcp->th_sport),
|
||||
fp.fp_wsize, fp.fp_ttl, (fp.fp_flags & PF_OSFP_DF) != 0,
|
||||
fp.fp_psize, (long long int)fp.fp_tcpopts, fp.fp_optcnt,
|
||||
(fp.fp_flags & PF_OSFP_TS0) ? "0" : "",
|
||||
(fp.fp_flags & PF_OSFP_MSS_MOD) ? "%" :
|
||||
(fp.fp_flags & PF_OSFP_MSS_DC) ? "*" : "",
|
||||
fp.fp_mss,
|
||||
(fp.fp_flags & PF_OSFP_WSCALE_MOD) ? "%" :
|
||||
(fp.fp_flags & PF_OSFP_WSCALE_DC) ? "*" : "",
|
||||
fp.fp_wscale);
|
||||
|
||||
if ((fpresult = pf_osfp_find(&pf_osfp_list, &fp,
|
||||
PF_OSFP_MAXTTL_OFFSET)))
|
||||
return (&fpresult->fp_oses);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Match a fingerprint ID against a list of OSes */
|
||||
int
|
||||
pf_osfp_match(struct pf_osfp_enlist *list, pf_osfp_t os)
|
||||
{
|
||||
struct pf_osfp_entry *entry;
|
||||
int os_class, os_version, os_subtype;
|
||||
int en_class, en_version, en_subtype;
|
||||
|
||||
if (os == PF_OSFP_ANY)
|
||||
return (1);
|
||||
if (list == NULL) {
|
||||
DPFPRINTF("osfp no match against %x\n", os);
|
||||
return (os == PF_OSFP_UNKNOWN);
|
||||
}
|
||||
PF_OSFP_UNPACK(os, os_class, os_version, os_subtype);
|
||||
SLIST_FOREACH(entry, list, fp_entry) {
|
||||
PF_OSFP_UNPACK(entry->fp_os, en_class, en_version, en_subtype);
|
||||
if ((os_class == PF_OSFP_ANY || en_class == os_class) &&
|
||||
(os_version == PF_OSFP_ANY || en_version == os_version) &&
|
||||
(os_subtype == PF_OSFP_ANY || en_subtype == os_subtype)) {
|
||||
DPFPRINTF("osfp matched %s %s %s %x==%x\n",
|
||||
entry->fp_class_nm, entry->fp_version_nm,
|
||||
entry->fp_subtype_nm, os, entry->fp_os);
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
DPFPRINTF("fingerprint 0x%x didn't match\n", os);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Initialize the OS fingerprint system */
|
||||
void
|
||||
pf_osfp_initialize(void)
|
||||
{
|
||||
pool_init(&pf_osfp_entry_pl, sizeof(struct pf_osfp_entry), 0, 0, 0,
|
||||
"pfosfpen", NULL);
|
||||
pool_init(&pf_osfp_pl, sizeof(struct pf_os_fingerprint), 0, 0, 0,
|
||||
"pfosfp", NULL);
|
||||
SLIST_INIT(&pf_osfp_list);
|
||||
}
|
||||
|
||||
/* Flush the fingerprint list */
|
||||
void
|
||||
pf_osfp_flush(void)
|
||||
{
|
||||
struct pf_os_fingerprint *fp;
|
||||
struct pf_osfp_entry *entry;
|
||||
|
||||
while ((fp = SLIST_FIRST(&pf_osfp_list))) {
|
||||
SLIST_REMOVE_HEAD(&pf_osfp_list, fp_next);
|
||||
while ((entry = SLIST_FIRST(&fp->fp_oses))) {
|
||||
SLIST_REMOVE_HEAD(&fp->fp_oses, fp_entry);
|
||||
pool_put(&pf_osfp_entry_pl, entry);
|
||||
}
|
||||
pool_put(&pf_osfp_pl, fp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Add a fingerprint */
|
||||
int
|
||||
pf_osfp_add(struct pf_osfp_ioctl *fpioc)
|
||||
{
|
||||
struct pf_os_fingerprint *fp, fpadd;
|
||||
struct pf_osfp_entry *entry;
|
||||
|
||||
memset(&fpadd, 0, sizeof(fpadd));
|
||||
fpadd.fp_tcpopts = fpioc->fp_tcpopts;
|
||||
fpadd.fp_wsize = fpioc->fp_wsize;
|
||||
fpadd.fp_psize = fpioc->fp_psize;
|
||||
fpadd.fp_mss = fpioc->fp_mss;
|
||||
fpadd.fp_flags = fpioc->fp_flags;
|
||||
fpadd.fp_optcnt = fpioc->fp_optcnt;
|
||||
fpadd.fp_wscale = fpioc->fp_wscale;
|
||||
fpadd.fp_ttl = fpioc->fp_ttl;
|
||||
|
||||
DPFPRINTF("adding osfp %s %s %s = %s%d:%d:%d:%s%d:0x%llx %d "
|
||||
"(TS=%s,M=%s%d,W=%s%d) %x\n",
|
||||
fpioc->fp_os.fp_class_nm, fpioc->fp_os.fp_version_nm,
|
||||
fpioc->fp_os.fp_subtype_nm,
|
||||
(fpadd.fp_flags & PF_OSFP_WSIZE_MOD) ? "%" :
|
||||
(fpadd.fp_flags & PF_OSFP_WSIZE_MSS) ? "S" :
|
||||
(fpadd.fp_flags & PF_OSFP_WSIZE_MTU) ? "T" :
|
||||
(fpadd.fp_flags & PF_OSFP_WSIZE_DC) ? "*" : "",
|
||||
fpadd.fp_wsize,
|
||||
fpadd.fp_ttl,
|
||||
(fpadd.fp_flags & PF_OSFP_DF) ? 1 : 0,
|
||||
(fpadd.fp_flags & PF_OSFP_PSIZE_MOD) ? "%" :
|
||||
(fpadd.fp_flags & PF_OSFP_PSIZE_DC) ? "*" : "",
|
||||
fpadd.fp_psize,
|
||||
(long long int)fpadd.fp_tcpopts, fpadd.fp_optcnt,
|
||||
(fpadd.fp_flags & PF_OSFP_TS0) ? "0" : "",
|
||||
(fpadd.fp_flags & PF_OSFP_MSS_MOD) ? "%" :
|
||||
(fpadd.fp_flags & PF_OSFP_MSS_DC) ? "*" : "",
|
||||
fpadd.fp_mss,
|
||||
(fpadd.fp_flags & PF_OSFP_WSCALE_MOD) ? "%" :
|
||||
(fpadd.fp_flags & PF_OSFP_WSCALE_DC) ? "*" : "",
|
||||
fpadd.fp_wscale,
|
||||
fpioc->fp_os.fp_os);
|
||||
|
||||
|
||||
if ((fp = pf_osfp_find_exact(&pf_osfp_list, &fpadd))) {
|
||||
SLIST_FOREACH(entry, &fp->fp_oses, fp_entry) {
|
||||
if (PF_OSFP_ENTRY_EQ(entry, &fpioc->fp_os))
|
||||
return (EEXIST);
|
||||
}
|
||||
if ((entry = pool_get(&pf_osfp_entry_pl, PR_NOWAIT)) == NULL)
|
||||
return (ENOMEM);
|
||||
} else {
|
||||
if ((fp = pool_get(&pf_osfp_pl, PR_NOWAIT)) == NULL)
|
||||
return (ENOMEM);
|
||||
memset(fp, 0, sizeof(*fp));
|
||||
fp->fp_tcpopts = fpioc->fp_tcpopts;
|
||||
fp->fp_wsize = fpioc->fp_wsize;
|
||||
fp->fp_psize = fpioc->fp_psize;
|
||||
fp->fp_mss = fpioc->fp_mss;
|
||||
fp->fp_flags = fpioc->fp_flags;
|
||||
fp->fp_optcnt = fpioc->fp_optcnt;
|
||||
fp->fp_wscale = fpioc->fp_wscale;
|
||||
fp->fp_ttl = fpioc->fp_ttl;
|
||||
SLIST_INIT(&fp->fp_oses);
|
||||
if ((entry = pool_get(&pf_osfp_entry_pl, PR_NOWAIT)) == NULL) {
|
||||
pool_put(&pf_osfp_pl, fp);
|
||||
return (ENOMEM);
|
||||
}
|
||||
pf_osfp_insert(&pf_osfp_list, fp);
|
||||
}
|
||||
memcpy(entry, &fpioc->fp_os, sizeof(*entry));
|
||||
|
||||
/* Make sure the strings are NUL terminated */
|
||||
entry->fp_class_nm[sizeof(entry->fp_class_nm)-1] = '\0';
|
||||
entry->fp_version_nm[sizeof(entry->fp_version_nm)-1] = '\0';
|
||||
entry->fp_subtype_nm[sizeof(entry->fp_subtype_nm)-1] = '\0';
|
||||
|
||||
SLIST_INSERT_HEAD(&fp->fp_oses, entry, fp_entry);
|
||||
|
||||
#ifdef PFDEBUG
|
||||
if ((fp = pf_osfp_validate()))
|
||||
printf("Invalid fingerprint list\n");
|
||||
#endif /* PFDEBUG */
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* Find a fingerprint in the list */
|
||||
struct pf_os_fingerprint *
|
||||
pf_osfp_find(struct pf_osfp_list *list, struct pf_os_fingerprint *find,
|
||||
u_int8_t ttldiff)
|
||||
{
|
||||
struct pf_os_fingerprint *f;
|
||||
|
||||
#define MATCH_INT(_MOD, _DC, _field) \
|
||||
if ((f->fp_flags & _DC) == 0) { \
|
||||
if ((f->fp_flags & _MOD) == 0) { \
|
||||
if (f->_field != find->_field) \
|
||||
continue; \
|
||||
} else { \
|
||||
if (f->_field == 0 || find->_field % f->_field) \
|
||||
continue; \
|
||||
} \
|
||||
}
|
||||
|
||||
SLIST_FOREACH(f, list, fp_next) {
|
||||
if (f->fp_tcpopts != find->fp_tcpopts ||
|
||||
f->fp_optcnt != find->fp_optcnt ||
|
||||
f->fp_ttl < find->fp_ttl ||
|
||||
f->fp_ttl - find->fp_ttl > ttldiff ||
|
||||
(f->fp_flags & (PF_OSFP_DF|PF_OSFP_TS0)) !=
|
||||
(find->fp_flags & (PF_OSFP_DF|PF_OSFP_TS0)))
|
||||
continue;
|
||||
|
||||
MATCH_INT(PF_OSFP_PSIZE_MOD, PF_OSFP_PSIZE_DC, fp_psize)
|
||||
MATCH_INT(PF_OSFP_MSS_MOD, PF_OSFP_MSS_DC, fp_mss)
|
||||
MATCH_INT(PF_OSFP_WSCALE_MOD, PF_OSFP_WSCALE_DC, fp_wscale)
|
||||
if ((f->fp_flags & PF_OSFP_WSIZE_DC) == 0) {
|
||||
if (f->fp_flags & PF_OSFP_WSIZE_MSS) {
|
||||
if (find->fp_mss == 0)
|
||||
continue;
|
||||
|
||||
/* Some "smart" NAT devices and DSL routers will tweak the MSS size and
|
||||
* will set it to whatever is suitable for the link type.
|
||||
*/
|
||||
#define SMART_MSS 1460
|
||||
if ((find->fp_wsize % find->fp_mss ||
|
||||
find->fp_wsize / find->fp_mss !=
|
||||
f->fp_wsize) &&
|
||||
(find->fp_wsize % SMART_MSS ||
|
||||
find->fp_wsize / SMART_MSS !=
|
||||
f->fp_wsize))
|
||||
continue;
|
||||
} else if (f->fp_flags & PF_OSFP_WSIZE_MTU) {
|
||||
if (find->fp_mss == 0)
|
||||
continue;
|
||||
|
||||
#define MTUOFF (sizeof(struct ip) + sizeof(struct tcphdr))
|
||||
#define SMART_MTU (SMART_MSS + MTUOFF)
|
||||
if ((find->fp_wsize % (find->fp_mss + MTUOFF) ||
|
||||
find->fp_wsize / (find->fp_mss + MTUOFF) !=
|
||||
f->fp_wsize) &&
|
||||
(find->fp_wsize % SMART_MTU ||
|
||||
find->fp_wsize / SMART_MTU !=
|
||||
f->fp_wsize))
|
||||
continue;
|
||||
} else if (f->fp_flags & PF_OSFP_WSIZE_MOD) {
|
||||
if (f->fp_wsize == 0 || find->fp_wsize %
|
||||
f->fp_wsize)
|
||||
continue;
|
||||
} else {
|
||||
if (f->fp_wsize != find->fp_wsize)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return (f);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Find an exact fingerprint in the list */
|
||||
struct pf_os_fingerprint *
|
||||
pf_osfp_find_exact(struct pf_osfp_list *list, struct pf_os_fingerprint *find)
|
||||
{
|
||||
struct pf_os_fingerprint *f;
|
||||
|
||||
SLIST_FOREACH(f, list, fp_next) {
|
||||
if (f->fp_tcpopts == find->fp_tcpopts &&
|
||||
f->fp_wsize == find->fp_wsize &&
|
||||
f->fp_psize == find->fp_psize &&
|
||||
f->fp_mss == find->fp_mss &&
|
||||
f->fp_flags == find->fp_flags &&
|
||||
f->fp_optcnt == find->fp_optcnt &&
|
||||
f->fp_wscale == find->fp_wscale &&
|
||||
f->fp_ttl == find->fp_ttl)
|
||||
return (f);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Insert a fingerprint into the list */
|
||||
void
|
||||
pf_osfp_insert(struct pf_osfp_list *list, struct pf_os_fingerprint *ins)
|
||||
{
|
||||
struct pf_os_fingerprint *f, *prev = NULL;
|
||||
|
||||
/* XXX need to go semi tree based. can key on tcp options */
|
||||
|
||||
SLIST_FOREACH(f, list, fp_next)
|
||||
prev = f;
|
||||
if (prev)
|
||||
SLIST_INSERT_AFTER(prev, ins, fp_next);
|
||||
else
|
||||
SLIST_INSERT_HEAD(list, ins, fp_next);
|
||||
}
|
||||
|
||||
/* Fill a fingerprint by its number (from an ioctl) */
|
||||
int
|
||||
pf_osfp_get(struct pf_osfp_ioctl *fpioc)
|
||||
{
|
||||
struct pf_os_fingerprint *fp;
|
||||
struct pf_osfp_entry *entry;
|
||||
int num = fpioc->fp_getnum;
|
||||
int i = 0;
|
||||
|
||||
|
||||
memset(fpioc, 0, sizeof(*fpioc));
|
||||
SLIST_FOREACH(fp, &pf_osfp_list, fp_next) {
|
||||
SLIST_FOREACH(entry, &fp->fp_oses, fp_entry) {
|
||||
if (i++ == num) {
|
||||
fpioc->fp_mss = fp->fp_mss;
|
||||
fpioc->fp_wsize = fp->fp_wsize;
|
||||
fpioc->fp_flags = fp->fp_flags;
|
||||
fpioc->fp_psize = fp->fp_psize;
|
||||
fpioc->fp_ttl = fp->fp_ttl;
|
||||
fpioc->fp_wscale = fp->fp_wscale;
|
||||
fpioc->fp_getnum = num;
|
||||
memcpy(&fpioc->fp_os, entry,
|
||||
sizeof(fpioc->fp_os));
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (EBUSY);
|
||||
}
|
||||
|
||||
|
||||
/* Validate that each signature is reachable */
|
||||
struct pf_os_fingerprint *
|
||||
pf_osfp_validate(void)
|
||||
{
|
||||
struct pf_os_fingerprint *f, *f2, find;
|
||||
|
||||
SLIST_FOREACH(f, &pf_osfp_list, fp_next) {
|
||||
memcpy(&find, f, sizeof(find));
|
||||
|
||||
/* We do a few MSS/th_win percolations to make things unique */
|
||||
if (find.fp_mss == 0)
|
||||
find.fp_mss = 128;
|
||||
if (f->fp_flags & PF_OSFP_WSIZE_MSS)
|
||||
find.fp_wsize *= find.fp_mss, 1;
|
||||
else if (f->fp_flags & PF_OSFP_WSIZE_MTU)
|
||||
find.fp_wsize *= (find.fp_mss + 40);
|
||||
else if (f->fp_flags & PF_OSFP_WSIZE_MOD)
|
||||
find.fp_wsize *= 2;
|
||||
if (f != (f2 = pf_osfp_find(&pf_osfp_list, &find, 0))) {
|
||||
if (f2)
|
||||
printf("Found \"%s %s %s\" instead of "
|
||||
"\"%s %s %s\"\n",
|
||||
SLIST_FIRST(&f2->fp_oses)->fp_class_nm,
|
||||
SLIST_FIRST(&f2->fp_oses)->fp_version_nm,
|
||||
SLIST_FIRST(&f2->fp_oses)->fp_subtype_nm,
|
||||
SLIST_FIRST(&f->fp_oses)->fp_class_nm,
|
||||
SLIST_FIRST(&f->fp_oses)->fp_version_nm,
|
||||
SLIST_FIRST(&f->fp_oses)->fp_subtype_nm);
|
||||
else
|
||||
printf("Couldn't find \"%s %s %s\"\n",
|
||||
SLIST_FIRST(&f->fp_oses)->fp_class_nm,
|
||||
SLIST_FIRST(&f->fp_oses)->fp_version_nm,
|
||||
SLIST_FIRST(&f->fp_oses)->fp_subtype_nm);
|
||||
return (f);
|
||||
}
|
||||
}
|
||||
return (NULL);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue