From 4b628fa86de9e1f3e478283a0118b2209ccc5885 Mon Sep 17 00:00:00 2001 From: luigi Date: Mon, 14 Dec 1998 18:09:13 +0000 Subject: Last bits (i think) of dummynet for -current. --- sys/netinet/if_ether.c | 12 ++- sys/netinet/in.h | 7 +- sys/netinet/ip_dummynet.c | 115 +++++++++++--------- sys/netinet/ip_dummynet.h | 10 ++ sys/netinet/ip_fw.c | 270 +++++++++++++++++++++++++++++++++------------- sys/netinet/ip_fw.h | 11 +- sys/netinet/ip_input.c | 129 ++++++++++++++++------ sys/netinet/ip_output.c | 107 ++++++++++++++---- sys/netinet/raw_ip.c | 24 ++++- 9 files changed, 503 insertions(+), 182 deletions(-) (limited to 'sys/netinet') diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c index ac8d86d..2dbc38c 100644 --- a/sys/netinet/if_ether.c +++ b/sys/netinet/if_ether.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)if_ether.c 8.1 (Berkeley) 6/10/93 - * $Id: if_ether.c,v 1.47 1998/06/12 03:48:14 julian Exp $ + * $Id: if_ether.c,v 1.48 1998/09/17 00:04:21 fenner Exp $ */ /* @@ -41,6 +41,7 @@ */ #include "opt_inet.h" +#include "opt_bdg.h" #include #include @@ -461,7 +462,16 @@ in_arpinput(m) (void)memcpy(&isaddr, ea->arp_spa, sizeof (isaddr)); (void)memcpy(&itaddr, ea->arp_tpa, sizeof (itaddr)); for (ia = in_ifaddrhead.tqh_first; ia; ia = ia->ia_link.tqe_next) +#ifdef BRIDGE + /* + * For a bridge, we want to check the address irrespective + * of the receive interface. (This will change slightly + * when we have clusters of interfaces). + */ + { +#else if (ia->ia_ifp == &ac->ac_if) { +#endif maybe_ia = ia; if ((itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) || (isaddr.s_addr == ia->ia_addr.sin_addr.s_addr)) diff --git a/sys/netinet/in.h b/sys/netinet/in.h index 67e5851..1188bde 100644 --- a/sys/netinet/in.h +++ b/sys/netinet/in.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)in.h 8.3 (Berkeley) 1/3/94 - * $Id: in.h,v 1.36 1998/07/06 03:20:12 julian Exp $ + * $Id: in.h,v 1.37 1998/08/23 03:07:14 wollman Exp $ */ #ifndef _NETINET_IN_H_ @@ -323,6 +323,11 @@ struct ip_opts { #define IP_FW_GET 54 /* get entire firewall rule chain */ #define IP_NAT 55 /* set/get NAT opts */ +#define IP_DUMMYNET_CONFIGURE 60 /* add/configure a dummynet pipe */ +#define IP_DUMMYNET_DEL 61 /* delete a dummynet pipe from chain */ +#define IP_DUMMYNET_FLUSH 62 /* flush dummynet */ +#define IP_DUMMYNET_GET 64 /* get entire dummynet pipes */ + /* * Defaults and limits for options */ diff --git a/sys/netinet/ip_dummynet.c b/sys/netinet/ip_dummynet.c index 31b4249..9743a0a 100644 --- a/sys/netinet/ip_dummynet.c +++ b/sys/netinet/ip_dummynet.c @@ -10,7 +10,7 @@ * * This software is provided ``AS IS'' without any warranties of any kind. * - * $Id: ip_dummynet.c 1.2 1998/08/21 15:01:13 luigi Exp $ + * $Id: ip_dummynet.c,v 1.1 1998/09/12 22:03:20 luigi Exp $ */ /* @@ -40,6 +40,7 @@ #include /* XXX */ #include #include +#include #include #include #include @@ -68,7 +69,7 @@ SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, calls, CTLFLAG_RD, &dn_calls, 0, "") SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, idle, CTLFLAG_RD, &dn_idle, 0, ""); #endif -static int ip_dn_ctl(int optname, struct mbuf **mm); +static int ip_dn_ctl(struct sockopt *sopt); static void dummynet(void); static void dn_restart(void); @@ -116,7 +117,7 @@ dn_move(struct dn_pipe *pipe, int immediate) */ if ( pipe->p.head == NULL && pipe->ticks_from_last_insert != pipe->delay) { - printf("Warning, empty pipe and delay %d (should be %a)d\n", + printf("Warning, empty pipe and delay %d (should be %d)\n", pipe->ticks_from_last_insert, pipe->delay); pipe->ticks_from_last_insert = pipe->delay; } @@ -402,68 +403,77 @@ dn_rule_delete(void *r) { struct dn_pipe *q, *p = all_pipes ; - + int matches = 0 ; for ( p= all_pipes ; p ; p = p->next ) { struct dn_pkt *x ; for (x = p->r.head ; x ; x = (struct dn_pkt *)x->dn_next ) - if (x->hdr.mh_data == r) + if (x->hdr.mh_data == r) { + matches++ ; x->hdr.mh_data = (void *)ip_fw_default_rule ; + } for (x = p->p.head ; x ; x = (struct dn_pkt *)x->dn_next ) - if (x->hdr.mh_data == r) + if (x->hdr.mh_data == r) { + matches++ ; x->hdr.mh_data = (void *)ip_fw_default_rule ; } } + printf("dn_rule_delete, r 0x%x, default 0x%x%s, %d matches\n", + r, ip_fw_default_rule, + r == ip_fw_default_rule ? " AARGH!":"", matches); +} /* * handler for the various dummynet socket options * (get, flush, config, del) */ static int -ip_dn_ctl(int optname, struct mbuf **mm) +ip_dn_ctl(struct sockopt *sopt) { - struct mbuf *m ; - if (optname == IP_DUMMYNET_GET) { - struct dn_pipe *p = all_pipes ; - *mm = m = m_get(M_WAIT, MT_SOOPTS); - m->m_len = 0 ; - m->m_next = NULL ; - for (; p ; p = p->next ) { - struct dn_pipe *q = mtod(m,struct dn_pipe *) ; - memcpy( m->m_data, p, sizeof(*p) ); + int error = 0 ; + size_t size ; + char *buf, *bp ; + struct dn_pipe *p, *q, tmp_pipe ; + + struct dn_pipe *x, *a, *b ; + + /* Disallow sets in really-really secure mode. */ + if (sopt->sopt_dir == SOPT_SET && securelevel >= 3) + return (EPERM); + + switch (sopt->sopt_name) { + default : + panic("ip_dn_ctl -- unknown option"); + + case IP_DUMMYNET_GET : + for (p = all_pipes, size = 0 ; p ; p = p->next ) + size += sizeof( *p ) ; + buf = malloc(size, M_TEMP, M_WAITOK); + if (buf == 0) { + error = ENOBUFS ; + break ; + } + for (p = all_pipes, bp = buf ; p ; p = p->next ) { + struct dn_pipe *q = (struct dn_pipe *)bp ; + + bcopy(p, bp, sizeof( *p ) ); /* * return bw and delay in bits/s and ms, respectively */ q->bandwidth *= (8*hz) ; q->delay = (q->delay * 1000) / hz ; - - m->m_len = sizeof(*p) ; - m->m_next = m_get(M_WAIT, MT_SOOPTS); - m = m->m_next ; - m->m_len = 0 ; - } - return 0 ; + bp += sizeof( *p ) ; } - if (securelevel > 2) { /* like in the firewall code... */ - if (m) (void)m_free(m); - return (EPERM) ; - } - m = *mm ; - if (optname == IP_DUMMYNET_FLUSH) { + error = sooptcopyout(sopt, buf, size); + FREE(buf, M_TEMP); + break ; + case IP_DUMMYNET_FLUSH : dummynet_flush() ; - if (m) (void)m_free(m); - return 0 ; - } - if (!m) /* need an argument for the following */ - return (EINVAL); - if (optname == IP_DUMMYNET_CONFIGURE) { - struct dn_pipe *p = mtod(m,struct dn_pipe *) ; - struct dn_pipe *x, *a, *b ; - if (m->m_len != sizeof (*p) ) { - printf("dn_pipe Invalid length, %d instead of %d\n", - m->m_len, sizeof(*p) ); - (void)m_free(m); - return (EINVAL); - } + break ; + case IP_DUMMYNET_CONFIGURE : + p = &tmp_pipe ; + error = sooptcopyin(sopt, p, sizeof *p, sizeof *p); + if (error) + break ; /* * The config program passes parameters as follows: * bandwidth = bits/second (0 = no limits); @@ -509,7 +519,8 @@ ip_dn_ctl(int optname, struct mbuf **mm) x = malloc(sizeof(struct dn_pipe), M_IPFW, M_DONTWAIT) ; if (x == NULL) { printf("ip_dummynet.c: sorry no memory\n"); - return (ENOSPC) ; + error = ENOSPC ; + break ; } bzero(x, sizeof(*x) ); x->bandwidth = p->bandwidth ; @@ -528,12 +539,13 @@ ip_dn_ctl(int optname, struct mbuf **mm) a->next = x ; splx(s); } - (void)m_free(m); - return 0 ; - } - if (optname == IP_DUMMYNET_DEL) { - struct dn_pipe *p = mtod(m,struct dn_pipe *) ; - struct dn_pipe *x, *a, *b ; + break ; + + case IP_DUMMYNET_DEL : + p = &tmp_pipe ; + error = sooptcopyin(sopt, p, sizeof *p, sizeof *p); + if (error) + break ; for (a = NULL , b = all_pipes ; b && b->pipe_nr < p->pipe_nr ; a = b , b = b->next) ; @@ -557,8 +569,9 @@ ip_dn_ctl(int optname, struct mbuf **mm) purge_pipe(b); /* remove pkts from here */ free(b, M_IPFW); } + break ; } - return 0 ; + return error ; } void diff --git a/sys/netinet/ip_dummynet.h b/sys/netinet/ip_dummynet.h index 33833fc..f01406f 100644 --- a/sys/netinet/ip_dummynet.h +++ b/sys/netinet/ip_dummynet.h @@ -16,6 +16,8 @@ #ifndef _IP_DUMMYNET_H #define _IP_DUMMYNET_H +typedef int ip_dn_ctl_t __P((struct sockopt *)) ; +extern ip_dn_ctl_t *ip_dn_ctl_ptr; /* * Definition of dummynet data structures. * Dummynet handles a list of pipes, each one identified by a unique @@ -85,12 +87,20 @@ struct dn_pipe { /* a pipe */ }; /* + * The following is used to define a new mbuf type that is + * prepended to the packet when it comes out of a pipe. The definition + * ought to go in /sys/sys/mbuf.h but here it is less intrusive. + */ + +#define MT_DUMMYNET MT_CONTROL +/* * what to do of a packet when it comes out of a pipe */ #define DN_TO_IP_OUT 1 #define DN_TO_IP_IN 2 #define DN_TO_BDG_FWD 3 #ifdef KERNEL +MALLOC_DECLARE(M_IPFW); void ip_dn_init(void); /* called in ip_input.c */ void dn_rule_delete(void *r); /* used in ip_fw.c */ int dummynet_io(int pipe, int dir, diff --git a/sys/netinet/ip_fw.c b/sys/netinet/ip_fw.c index 8e818dc..d9069dc 100644 --- a/sys/netinet/ip_fw.c +++ b/sys/netinet/ip_fw.c @@ -12,15 +12,16 @@ * * This software is provided ``AS IS'' without any warranties of any kind. * - * $Id: ip_fw.c,v 1.98 1998/11/15 15:33:52 bde Exp $ + * $Id: ip_fw.c,v 1.96 1998/08/23 03:07:14 wollman Exp $ */ /* * Implement IP packet firewall */ -#if !defined(KLD_MODULE) && !defined(IPFIREWALL_MODULE) +#ifndef IPFIREWALL_MODULE #include "opt_ipfw.h" +#include "opt_ipdn.h" #include "opt_ipdivert.h" #include "opt_inet.h" #ifndef INET @@ -43,18 +44,25 @@ #include #include #include +#ifdef DUMMYNET +#include +#include +#endif #include #include #include #include #include +#include /* XXX ethertype_ip */ + static int fw_debug = 1; #ifdef IPFIREWALL_VERBOSE static int fw_verbose = 1; #else static int fw_verbose = 0; #endif +static int fw_one_pass = 0; /* XXX */ #ifdef IPFIREWALL_VERBOSE_LIMIT static int fw_verbose_limit = IPFIREWALL_VERBOSE_LIMIT; #else @@ -63,13 +71,14 @@ static int fw_verbose_limit = 0; #define IPFW_DEFAULT_RULE ((u_int)(u_short)~0) -static LIST_HEAD (ip_fw_head, ip_fw_chain) ip_fw_chain; +LIST_HEAD (ip_fw_head, ip_fw_chain) ip_fw_chain; -static MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's"); +MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's"); #ifdef SYSCTL_NODE SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall"); SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, debug, CTLFLAG_RW, &fw_debug, 0, ""); +SYSCTL_INT(_net_inet_ip_fw, OID_AUTO,one_pass,CTLFLAG_RW, &fw_one_pass, 0, ""); SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose, CTLFLAG_RW, &fw_verbose, 0, ""); SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, &fw_verbose_limit, 0, ""); #endif @@ -100,8 +109,16 @@ static int icmptype_match __P((struct icmp * icmp, struct ip_fw * f)); static void ipfw_report __P((struct ip_fw *f, struct ip *ip, struct ifnet *rif, struct ifnet *oif)); +static void flush_rule_ptrs(void); + +#ifdef IPFIREWALL_MODULE +static ip_fw_chk_t *old_chk_ptr; +static ip_fw_ctl_t *old_ctl_ptr; +#endif + static int ip_fw_chk __P((struct ip **pip, int hlen, struct ifnet *oif, u_int16_t *cookie, struct mbuf **m, + struct ip_fw_chain **flow_id, struct sockaddr_in **next_hop)); static int ip_fw_ctl __P((struct sockopt *sopt)); @@ -279,6 +296,7 @@ static void ipfw_report(struct ip_fw *f, struct ip *ip, struct ifnet *rif, struct ifnet *oif) { + if (ip) { static u_int64_t counter; struct tcphdr *const tcp = (struct tcphdr *) ((u_int32_t *) ip+ ip->ip_hl); struct udphdr *const udp = (struct udphdr *) ((u_int32_t *) ip+ ip->ip_hl); @@ -319,6 +337,11 @@ ipfw_report(struct ip_fw *f, struct ip *ip, case IP_FW_F_SKIPTO: printf("SkipTo %d", f->fw_skipto_rule); break; +#ifdef DUMMYNET + case IP_FW_F_PIPE: + printf("Pipe %d", f->fw_skipto_rule); + break; +#endif #ifdef IPFIREWALL_FORWARD case IP_FW_F_FWD: printf("Forward to "); @@ -383,15 +406,45 @@ ipfw_report(struct ip_fw *f, struct ip *ip, printf("ipfw: limit reached on rule #%d\n", f ? f->fw_number : -1); } +} + +/* + * given an ip_fw_chain *, lookup_next_rule will return a pointer + * of the same type to the next one. This can be either the jump + * target (for skipto instructions) or the next one in the chain (in + * all other cases including a missing jump target). + * Backward jumps are not allowed, so start looking from the next + * rule... + */ +static struct ip_fw_chain * lookup_next_rule(struct ip_fw_chain *me); + +static struct ip_fw_chain * +lookup_next_rule(struct ip_fw_chain *me) +{ + struct ip_fw_chain *chain ; + int rule = me->rule->fw_skipto_rule ; /* guess... */ + + if ( (me->rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_SKIPTO ) + for (chain = me->chain.le_next; chain ; chain = chain->chain.le_next ) + if (chain->rule->fw_number >= rule) + return chain ; + return me->chain.le_next ; /* failure or not a skipto */ +} /* * Parameters: * - * ip Pointer to packet header (struct ip *) + * pip Pointer to packet header (struct ip **) + * XXX future extension: pip = NULL means a complete ethernet packet + * including ethernet header in the mbuf. Other fields + * are ignored/invalid. + * * hlen Packet header length * oif Outgoing interface, or NULL if packet is incoming * *cookie Skip up to the first rule past this rule number; * *m The packet; we set to NULL when/if we nuke it. + * *flow_id pointer to the last matching rule (in/out) + * *next_hop socket we are forwarding to (in/out). * * Return value: * @@ -404,17 +457,58 @@ ipfw_report(struct ip_fw *f, struct ip *ip, static int ip_fw_chk(struct ip **pip, int hlen, struct ifnet *oif, u_int16_t *cookie, struct mbuf **m, + struct ip_fw_chain **flow_id, struct sockaddr_in **next_hop) { struct ip_fw_chain *chain; struct ip_fw *rule = NULL; - struct ip *ip = *pip; + struct ip *ip = NULL ; struct ifnet *const rif = (*m)->m_pkthdr.rcvif; - u_short offset = (ip->ip_off & IP_OFFMASK); + u_short offset ; u_short src_port, dst_port; u_int16_t skipto = *cookie; - *cookie = 0; + if (pip) { /* normal ip packet */ + ip = *pip; + offset = (ip->ip_off & IP_OFFMASK); + } else { /* bridged or non-ip packet */ + struct ether_header *eh = mtod(*m, struct ether_header *); + switch (ntohs(eh->ether_type)) { + case ETHERTYPE_IP : + if ((*m)->m_lenip_v != IPVERSION) + goto non_ip ; + hlen = ip->ip_hl << 2; + if (hlen < sizeof(struct ip)) /* minimum header length */ + goto non_ip ; + if ((*m)->m_len < 14 + hlen + 14) { + printf("-- m_len %d, need more...\n", (*m)->m_len); + goto non_ip ; + } + offset = (ip->ip_off & IP_OFFMASK); + break ; + default : +non_ip: ip = NULL ; + break ; + } + } + + if (*flow_id) { + if (fw_one_pass) + return 0 ; /* accept if passed first test */ + /* + * pkt has already been tagged. Look for the next rule + * to restart processing + */ + chain = LIST_NEXT( *flow_id, chain); + + if ( (chain = (*flow_id)->rule->next_rule_ptr) == NULL ) + chain = (*flow_id)->rule->next_rule_ptr = + lookup_next_rule(*flow_id) ; + if (! chain) goto dropit; + } else { /* * Go down the chain, looking for enlightment * If we've been asked to start at a given rule immediatly, do so. @@ -428,8 +522,12 @@ ip_fw_chk(struct ip **pip, int hlen, } if (! chain) goto dropit; } + } + *cookie = 0; for (; chain; chain = LIST_NEXT(chain, chain)) { - register struct ip_fw *const f = chain->rule; + register struct ip_fw * f ; +again: + f = chain->rule; if (oif) { /* Check direction outbound */ @@ -440,6 +538,40 @@ ip_fw_chk(struct ip **pip, int hlen, if (!(f->fw_flg & IP_FW_F_IN)) continue; } + if (ip == NULL ) { + /* + * do relevant checks for non-ip packets: + * after this, only goto got_match or continue + */ + struct ether_header *eh = mtod(*m, struct ether_header *); + + /* + * make default rule always match or we have a panic + */ + if (f->fw_number == IPFW_DEFAULT_RULE) + goto got_match ; + /* + * temporary hack: + * udp from 0.0.0.0 means this rule applies. + * 1 src port is match ether type + * 2 src ports (interval) is match ether type + * 3 src ports is match ether address + */ + if ( f->fw_src.s_addr != 0 || f->fw_prot != IPPROTO_UDP) + continue; + switch (IP_FW_GETNSRCP(f)) { + case 1: /* match one type */ + if ( /* ( (f->fw_flg & IP_FW_F_INVSRC) != 0) ^ */ + ( f->fw_uar.fw_pts[0] == ntohs(eh->ether_type) ) ) { + printf("match!\n"); + goto got_match ; + } + break ; + default: + break ; + } + continue ; + } /* Fragments */ if ((f->fw_flg & IP_FW_F_FRAG) && !(ip->ip_off & IP_OFFMASK)) @@ -489,12 +621,12 @@ ip_fw_chk(struct ip **pip, int hlen, continue; #define PULLUP_TO(len) do { \ - if ((*m)->m_len < (len) \ - && (*m = m_pullup(*m, (len))) == 0) { \ + if ((*m)->m_len < (len) ) { \ + if ( (*m = m_pullup(*m, (len))) == 0) \ goto bogusfrag; \ - } \ *pip = ip = mtod(*m, struct ip *); \ offset = (ip->ip_off & IP_OFFMASK); \ + } \ } while (0) /* Protocol specific checks */ @@ -578,9 +710,19 @@ bogusfrag: } got_match: + *flow_id = chain ; /* XXX set flow id */ /* Update statistics */ f->fw_pcnt += 1; + /* + * note -- bridged-ip packets still have some fields + * in network order, including ip_len + */ + if (ip) { + if (pip) f->fw_bcnt += ip->ip_len; + else + f->fw_bcnt += ntohs(ip->ip_len); + } f->timestamp = time_second; /* Log to console if desired */ @@ -593,9 +735,11 @@ got_match: return(0); case IP_FW_F_COUNT: continue; +#ifdef IPDIVERT case IP_FW_F_DIVERT: *cookie = f->fw_number; return(f->fw_divert_port); +#endif case IP_FW_F_TEE: /* * XXX someday tee packet here, but beware that you @@ -606,17 +750,17 @@ got_match: * to write custom routine. */ continue; - case IP_FW_F_SKIPTO: -#ifdef DIAGNOSTIC - while (LIST_NEXT(chain, chain) - && LIST_NEXT(chain, chain)->rule->fw_number - < f->fw_skipto_rule) -#else - while (LIST_NEXT(chain, chain)->rule->fw_number - < f->fw_skipto_rule) + case IP_FW_F_SKIPTO: /* XXX check */ + if ( f->next_rule_ptr ) + chain = f->next_rule_ptr ; + else + chain = lookup_next_rule(chain) ; + if (! chain) goto dropit; + goto again ; +#ifdef DUMMYNET + case IP_FW_F_PIPE: + return(f->fw_pipe_nr | 0x10000 ); #endif - chain = LIST_NEXT(chain, chain); - continue; #ifdef IPFIREWALL_FORWARD case IP_FW_F_FWD: /* Change the next-hop address for this packet. @@ -656,6 +800,7 @@ got_match: * - The packet is not a multicast or broadcast packet */ if ((rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_REJECT + && ip && (ip->ip_p != IPPROTO_ICMP || is_icmp_query(ip)) && !((*m)->m_flags & (M_BCAST|M_MCAST)) && !IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { @@ -698,7 +843,7 @@ dropit: /* * Finally, drop the packet. */ - *cookie = 0; + /* *cookie = 0; */ /* XXX is this necessary ? */ if (*m) { m_freem(*m); *m = NULL; @@ -706,6 +851,22 @@ dropit: return(0); } +/* + * when a rule is added/deleted, zero the direct pointers within + * all firewall rules. These will be reconstructed on the fly + * as packets are matched. + * Must be called at splnet(). + */ +static void +flush_rule_ptrs() +{ + struct ip_fw_chain *fcp ; + + for (fcp = ip_fw_chain.lh_first; fcp; fcp = fcp->chain.le_next) { + fcp->rule->next_rule_ptr = NULL ; + } +} + static int add_entry(struct ip_fw_head *chainptr, struct ip_fw *frwl) { @@ -727,6 +888,8 @@ add_entry(struct ip_fw_head *chainptr, struct ip_fw *frwl) ftmp->fw_in_if.fu_via_if.name[FW_IFNLEN - 1] = '\0'; ftmp->fw_pcnt = 0L; ftmp->fw_bcnt = 0L; + ftmp->next_rule_ptr = NULL ; + ftmp->pipe_ptr = NULL ; fwc->rule = ftmp; s = splnet(); @@ -763,6 +926,7 @@ add_entry(struct ip_fw_head *chainptr, struct ip_fw *frwl) fcpl = fcp; } } + flush_rule_ptrs(); splx(s); return (0); @@ -786,6 +950,10 @@ del_entry(struct ip_fw_head *chainptr, u_short number) next = LIST_NEXT(fcp, chain); LIST_REMOVE(fcp, chain); +#ifdef DUMMYNET + dn_rule_delete(fcp) ; +#endif + flush_rule_ptrs(); free(fcp->rule, M_IPFW); free(fcp, M_IPFW); fcp = next; @@ -941,6 +1109,7 @@ check_ipfw_struct(struct ip_fw *frwl) } break; case IP_FW_F_DIVERT: /* Diverting to port zero is invalid */ + case IP_FW_F_PIPE: /* piping through 0 is invalid */ case IP_FW_F_TEE: if (frwl->fw_divert_port == 0) { dprintf(("%s can't divert to port 0\n", err_prefix)); @@ -1049,12 +1218,15 @@ ip_fw_ctl(struct sockopt *sopt) break; default: - panic("ip_fw_ctl"); + printf("ip_fw_ctl invalid option %d\n", sopt->sopt_name); + error = EINVAL ; } return (error); } +struct ip_fw_chain *ip_fw_default_rule ; + void ip_fw_init(void) { @@ -1077,6 +1249,7 @@ ip_fw_init(void) add_entry(&ip_fw_chain, &default_rule)) panic("ip_fw_init"); + ip_fw_default_rule = ip_fw_chain.lh_first ; printf("IP packet filtering initialized, " #ifdef IPDIVERT "divert enabled, "); @@ -1102,10 +1275,7 @@ ip_fw_init(void) #endif } -static ip_fw_chk_t *old_chk_ptr; -static ip_fw_ctl_t *old_ctl_ptr; - -#if defined(IPFIREWALL_MODULE) && !defined(KLD_MODULE) +#ifdef IPFIREWALL_MODULE #include #include @@ -1152,48 +1322,4 @@ ipfw_mod(struct lkm_table *lkmtp, int cmd, int ver) MOD_DISPATCH(ipfw, lkmtp, cmd, ver, ipfw_load, ipfw_unload, lkm_nullcmd); } -#else -static int -ipfw_modevent(module_t mod, int type, void *unused) -{ - int s; - - switch (type) { - case MOD_LOAD: - s = splnet(); - - old_chk_ptr = ip_fw_chk_ptr; - old_ctl_ptr = ip_fw_ctl_ptr; - - ip_fw_init(); - splx(s); - return 0; - case MOD_UNLOAD: - s = splnet(); - - ip_fw_chk_ptr = old_chk_ptr; - ip_fw_ctl_ptr = old_ctl_ptr; - - while (LIST_FIRST(&ip_fw_chain) != NULL) { - struct ip_fw_chain *fcp = LIST_FIRST(&ip_fw_chain); - LIST_REMOVE(LIST_FIRST(&ip_fw_chain), chain); - free(fcp->rule, M_IPFW); - free(fcp, M_IPFW); - } - - splx(s); - printf("IP firewall unloaded\n"); - return 0; - default: - break; - } - return 0; -} - -static moduledata_t ipfwmod = { - "ipfw", - ipfw_modevent, - 0 -}; -DECLARE_MODULE(ipfw, ipfwmod, SI_SUB_PSEUDO, SI_ORDER_ANY); #endif diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h index 31e8366..a4cee76 100644 --- a/sys/netinet/ip_fw.h +++ b/sys/netinet/ip_fw.h @@ -11,7 +11,7 @@ * * This software is provided ``AS IS'' without any warranties of any kind. * - * $Id: ip_fw.h,v 1.34 1998/08/23 03:07:14 wollman Exp $ + * $Id: ip_fw.h,v 1.35 1998/09/02 19:14:01 phk Exp $ */ #ifndef _IP_FW_H @@ -35,7 +35,7 @@ union ip_fw_if { struct in_addr fu_via_ip; /* Specified by IP address */ struct { /* Specified by interface name */ -#define FW_IFNLEN IFNAMSIZ +#define FW_IFNLEN 10 /* need room ! was IFNAMSIZ */ char name[FW_IFNLEN]; short unit; /* -1 means match any unit */ } fu_via_if; @@ -69,6 +69,7 @@ struct ip_fw { union ip_fw_if fw_in_if, fw_out_if; /* Incoming and outgoing interfaces */ union { u_short fu_divert_port; /* Divert/tee port (options IPDIVERT) */ + u_short fu_pipe_nr; /* pipe number (option DUMMYNET) */ u_short fu_skipto_rule; /* SKIPTO command rule number */ u_short fu_reject_code; /* REJECT response code */ struct sockaddr_in fu_fwd_ip; @@ -78,6 +79,8 @@ struct ip_fw { /* in ports array (dst ports follow */ /* src ports; max of 10 ports in all; */ /* count of 0 means match all ports) */ + void *pipe_ptr; /* Pipe ptr in case of dummynet pipe */ + void *next_rule_ptr ; /* next rule in case of match */ }; #define IP_FW_GETNSRCP(rule) ((rule)->fw_nports & 0x0f) @@ -94,6 +97,7 @@ struct ip_fw { #define fw_divert_port fw_un.fu_divert_port #define fw_skipto_rule fw_un.fu_skipto_rule #define fw_reject_code fw_un.fu_reject_code +#define fw_pipe_nr fw_un.fu_pipe_nr #define fw_fwd_ip fw_un.fu_fwd_ip struct ip_fw_chain { @@ -113,6 +117,7 @@ struct ip_fw_chain { #define IP_FW_F_TEE 0x00000005 /* This is a tee rule */ #define IP_FW_F_SKIPTO 0x00000006 /* This is a skipto rule */ #define IP_FW_F_FWD 0x00000007 /* This is a "change forwarding address" rule */ +#define IP_FW_F_PIPE 0x00000008 /* This is a dummynet rule */ #define IP_FW_F_IN 0x00000100 /* Check inbound packets */ #define IP_FW_F_OUT 0x00000200 /* Check outbound packets */ @@ -188,7 +193,7 @@ void ip_fw_init __P((void)); struct ip; struct sockopt; typedef int ip_fw_chk_t __P((struct ip **, int, struct ifnet *, u_int16_t *, - struct mbuf **, struct sockaddr_in **)); + struct mbuf **, struct ip_fw_chain **, struct sockaddr_in **)); typedef int ip_fw_ctl_t __P((struct sockopt *)); extern ip_fw_chk_t *ip_fw_chk_ptr; extern ip_fw_ctl_t *ip_fw_ctl_ptr; diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index 8661bf8..839c5b7 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 - * $Id: ip_input.c,v 1.107 1998/11/16 08:27:36 dfr Exp $ + * $Id: ip_input.c,v 1.101 1998/09/10 08:56:40 dfr Exp $ * $ANA: ip_input.c,v 1.5 1996/09/18 14:34:59 wollman Exp $ */ @@ -39,6 +39,7 @@ #include "opt_bootp.h" #include "opt_ipfw.h" +#include "opt_ipdn.h" #include "opt_ipdivert.h" #include "opt_ipfilter.h" @@ -47,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -76,6 +78,10 @@ #include #endif +#ifdef DUMMYNET +#include +#endif + int rsvp_on = 0; static int ip_rsvp_on; struct socket *ip_rsvpd; @@ -149,6 +155,10 @@ SYSCTL_INT(_net_inet_ip, IPCTL_DEFMTU, mtu, CTLFLAG_RW, ip_fw_chk_t *ip_fw_chk_ptr; ip_fw_ctl_t *ip_fw_ctl_ptr; +#ifdef DUMMYNET +ip_dn_ctl_t *ip_dn_ctl_ptr; +#endif + /* IP Network Address Translation (NAT) hooks */ ip_nat_t *ip_nat_ptr; ip_nat_ctl_t *ip_nat_ctl_ptr; @@ -224,6 +234,12 @@ ip_init() ip_id = time_second & 0xffff; ipintrq.ifq_maxlen = ipqmaxlen; +#ifdef IPFIREWALL + ip_fw_init(); +#endif +#ifdef DUMMYNET + ip_dn_init(); +#endif #ifdef IPNAT ip_nat_init(); #endif @@ -245,9 +261,34 @@ ip_input(struct mbuf *m) { struct ip *ip; struct ipq *fp; + struct ipqent *ipqe; struct in_ifaddr *ia; int i, hlen, mff; u_short sum; +#ifndef IPDIVERT /* dummy variable for the firewall code to play with */ + u_short ip_divert_cookie = 0 ; +#endif +#ifdef COMPAT_IPFW + struct ip_fw_chain *rule = NULL ; +#endif + +#if defined(IPFIREWALL) && defined(DUMMYNET) + /* + * dummynet packet are prepended a vestigial mbuf with + * m_type = MT_DUMMYNET and m_data pointing to the matching + * rule. + */ + if (m->m_type == MT_DUMMYNET) { + struct mbuf *m0 = m ; + rule = (struct ip_fw_chain *)(m->m_data) ; + m = m->m_next ; + free(m0, M_IPFW); + ip = mtod(m, struct ip *); + hlen = IP_VHL_HL(ip->ip_vhl) << 2; + goto iphack ; + } else + rule = NULL ; +#endif #ifdef DIAGNOSTIC if (m == NULL || (m->m_flags & M_PKTHDR) == 0) @@ -336,9 +377,12 @@ tooshort: * deals with it. * - Firewall: deny/allow/divert * - Xlate: translate packet's addr/port (NAT). + * - Pipe: pass pkt through dummynet. * - Wrap: fake packet's addr/port * - Encapsulate: put it in another IP and send out. */ + +iphack: #if defined(IPFILTER) || defined(IPFILTER_LKM) /* * Check if we want to allow this packet to be processed. @@ -354,8 +398,6 @@ tooshort: #endif #ifdef COMPAT_IPFW if (ip_fw_chk_ptr) { - u_int16_t port; - #ifdef IPFIREWALL_FORWARD /* * If we've been forwarded from the output side, then @@ -364,29 +406,41 @@ tooshort: if (ip_fw_fwd_addr) goto ours; #endif /* IPFIREWALL_FORWARD */ + i = (*ip_fw_chk_ptr)(&ip, hlen, NULL, &ip_divert_cookie, + &m, &rule, &ip_fw_fwd_addr); + /* + * see the comment in ip_output for the return values + * produced by the firewall. + */ + if (!m) /* packet discarded by firewall */ + return ; + if (i == 0 && ip_fw_fwd_addr == NULL) /* common case */ + goto pass ; +#ifdef DUMMYNET + if (i & 0x10000) { + /* send packet to the appropriate pipe */ + dummynet_io(i&0xffff,DN_TO_IP_IN,m,NULL,NULL,0, rule); + return ; + } +#endif #ifdef IPDIVERT - port = (*ip_fw_chk_ptr)(&ip, hlen, NULL, &ip_divert_cookie, - &m, &ip_fw_fwd_addr); - if (port) { + if (i > 0 && i < 0x10000) { /* Divert packet */ - frag_divert_port = port; + frag_divert_port = i & 0xffff ; goto ours; } -#else /* !DIVERT */ +#endif +#ifdef IPFIREWALL_FORWARD + if (i == 0 && ip_fw_fwd_addr != NULL) + goto pass ; +#endif /* - * If ipfw says divert, we have to just drop packet - * Use port as a dummy argument. + * if we get here, the packet must be dropped */ - port = 0; - if ((*ip_fw_chk_ptr)(&ip, hlen, NULL, &port, - &m, &ip_fw_fwd_addr)) { m_freem(m); - m = NULL; - } -#endif /* !DIVERT */ - if (!m) return; } +pass: if (ip_nat_ptr && !(*ip_nat_ptr)(&ip, &m, m->m_pkthdr.rcvif, IP_NAT_IN)) return; @@ -512,7 +566,7 @@ ours: */ if (ip->ip_off & (IP_MF | IP_OFFMASK | IP_RF)) { if (m->m_flags & M_EXT) { /* XXX */ - if ((m = m_pullup(m, hlen)) == 0) { + if ((m = m_pullup(m, sizeof (struct ip))) == 0) { ipstat.ips_toosmall++; #ifdef IPDIVERT frag_divert_port = 0; @@ -710,13 +764,13 @@ ip_reass(m, fp, where) fp->ipq_id = ip->ip_id; fp->ipq_src = ip->ip_src; fp->ipq_dst = ip->ip_dst; - fp->ipq_frags = m; - m->m_nextpkt = NULL; + fp->ipq_frags = 0; #ifdef IPDIVERT fp->ipq_divert = 0; fp->ipq_div_cookie = 0; #endif - goto inserted; + q = 0; + goto insert; } #define GETIP(m) ((struct ip*)((m)->m_pkthdr.header)) @@ -731,8 +785,7 @@ ip_reass(m, fp, where) /* * If there is a preceding segment, it may provide some of * our data already. If so, drop the data from the incoming - * segment. If it provides all of our data, drop us, otherwise - * stick new segment in the proper place. + * segment. If it provides all of our data, drop us. */ if (p) { i = GETIP(p)->ip_off + GETIP(p)->ip_len - ip->ip_off; @@ -743,11 +796,6 @@ ip_reass(m, fp, where) ip->ip_off += i; ip->ip_len -= i; } - m->m_nextpkt = p->m_nextpkt; - p->m_nextpkt = m; - } else { - m->m_nextpkt = fp->ipq_frags; - fp->ipq_frags = m; } /* @@ -755,7 +803,7 @@ ip_reass(m, fp, where) * if they are completely covered, dequeue them. */ for (; q != NULL && ip->ip_off + ip->ip_len > GETIP(q)->ip_off; - q = nq) { + p = q, q = nq) { i = (ip->ip_off + ip->ip_len) - GETIP(q)->ip_off; if (i < GETIP(q)->ip_len) { @@ -765,11 +813,14 @@ ip_reass(m, fp, where) break; } nq = q->m_nextpkt; - m->m_nextpkt = nq; + if (p) + p->m_nextpkt = nq; + else + fp->ipq_frags = nq; m_freem(q); } -inserted: +insert: #ifdef IPDIVERT /* @@ -784,8 +835,16 @@ inserted: #endif /* - * Check for complete reassembly. + * Stick new segment in its place; + * check for complete reassembly. */ + if (p == NULL) { + m->m_nextpkt = fp->ipq_frags; + fp->ipq_frags = m; + } else { + m->m_nextpkt = p->m_nextpkt; + p->m_nextpkt = m; + } next = 0; for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) { if (GETIP(q)->ip_off != next) @@ -1241,7 +1300,7 @@ ip_srcroute() *(mtod(m, struct in_addr *)) = *p--; #ifdef DIAGNOSTIC if (ipprintfs) - printf(" hops %lx", (u_long)ntohl(mtod(m, struct in_addr *)->s_addr)); + printf(" hops %lx", ntohl(mtod(m, struct in_addr *)->s_addr)); #endif /* @@ -1261,7 +1320,7 @@ ip_srcroute() while (p >= ip_srcrt.route) { #ifdef DIAGNOSTIC if (ipprintfs) - printf(" %lx", (u_long)ntohl(q->s_addr)); + printf(" %lx", ntohl(q->s_addr)); #endif *q++ = *p--; } @@ -1271,7 +1330,7 @@ ip_srcroute() *q = ip_srcrt.dst; #ifdef DIAGNOSTIC if (ipprintfs) - printf(" %lx\n", (u_long)ntohl(q->s_addr)); + printf(" %lx\n", ntohl(q->s_addr)); #endif return (m); } diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index c9acdf3..32e3545 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -37,12 +37,12 @@ #define _IP_VHL #include "opt_ipfw.h" +#include "opt_ipdn.h" #include "opt_ipdivert.h" #include "opt_ipfilter.h" #include #include -#include #include #include #include @@ -77,6 +77,10 @@ static MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "internet multicast options"); #include #endif +#ifdef DUMMYNET +#include +#endif + #ifdef IPFIREWALL_FORWARD_DEBUG #define print_ip(a) printf("%ld.%ld.%ld.%ld",(ntohl(a.s_addr)>>24)&0xFF,\ (ntohl(a.s_addr)>>16)&0xFF,\ @@ -131,6 +135,41 @@ ip_output(m0, opt, ro, flags, imo) int fwd_rewrite_src = 0; #endif +#ifndef IPDIVERT /* dummy variable for the firewall code to play with */ + u_short ip_divert_cookie = 0 ; +#endif +#ifdef COMPAT_IPFW + struct ip_fw_chain *rule = NULL ; +#endif + +#if defined(IPFIREWALL) && defined(DUMMYNET) + /* + * dummynet packet are prepended a vestigial mbuf with + * m_type = MT_DUMMYNET and m_data pointing to the matching + * rule. + */ + if (m->m_type == MT_DUMMYNET) { + struct mbuf *tmp_m = m ; + /* + * the packet was already tagged, so part of the + * processing was already done, and we need to go down. + * opt, flags and imo have already been used, and now + * they are used to hold ifp and hlen and NULL, respectively. + */ + rule = (struct ip_fw_chain *)(m->m_data) ; + m = m->m_next ; + free(tmp_m, M_IPFW); + ip = mtod(m, struct ip *); + dst = (struct sockaddr_in *)&ro->ro_dst; + ifp = (struct ifnet *)opt; + hlen = IP_VHL_HL(ip->ip_vhl) << 2 ; + opt = NULL ; + flags = 0 ; /* XXX is this correct ? */ + goto sendit; + } else + rule = NULL ; +#endif + #ifdef DIAGNOSTIC if ((m->m_flags & M_PKTHDR) == 0) panic("ip_output no HDR"); @@ -394,28 +433,52 @@ sendit: * Check with the firewall... */ if (ip_fw_chk_ptr) { -#ifdef IPFIREWALL_FORWARD struct sockaddr_in *old = dst; -#endif -#ifdef IPDIVERT - ip_divert_port = (*ip_fw_chk_ptr)(&ip, - hlen, ifp, &ip_divert_cookie, &m, &dst); - if (ip_divert_port) { /* Divert packet */ - (*inetsw[ip_protox[IPPROTO_DIVERT]].pr_input)(m, 0); + + off = (*ip_fw_chk_ptr)(&ip, + hlen, ifp, &ip_divert_cookie, &m, &rule, &dst); + /* + * On return we must do the following: + * m == NULL -> drop the pkt + * 1<=off<= 0xffff -> DIVERT + * (off & 0x10000) -> send to a DUMMYNET pipe + * dst != old -> IPFIREWALL_FORWARD + * off==0, dst==old -> accept + * If some of the above modules is not compiled in, then + * we should't have to check the corresponding condition + * (because the ipfw control socket should not accept + * unsupported rules), but better play safe and drop + * packets in case of doubt. + */ + if (!m) { /* firewall said to reject */ + error = EACCES; goto done; } -#else /* !IPDIVERT */ - u_int16_t dummy = 0; - /* If ipfw says divert, we have to just drop packet */ - if ((*ip_fw_chk_ptr)(&ip, hlen, ifp, &dummy, &m, &dst)) { - m_freem(m); + if (off == 0 && dst == old) /* common case */ + goto pass ; +#ifdef DUMMYNET + if (off & 0x10000) { + /* + * pass the pkt to dummynet. Need to include + * pipe number, m, ifp, ro, hlen because these are + * not recomputed in the next pass. + * All other parameters have been already used and + * so they are not needed anymore. + * XXX note: if the ifp or ro entry are deleted + * while a pkt is in dummynet, we are in trouble! + */ + dummynet_io(off & 0xffff, DN_TO_IP_OUT, m,ifp,ro,hlen,rule); goto done; } -#endif /* !IPDIVERT */ - if (!m) { - error = EACCES; +#endif +#ifdef IPDIVERT + if (off > 0 && off < 0x10000) { /* Divert packet */ + ip_divert_port = off & 0xffff ; + (*inetsw[ip_protox[IPPROTO_DIVERT]].pr_input)(m, 0); goto done; } +#endif + #ifdef IPFIREWALL_FORWARD /* Here we check dst to make sure it's directly reachable on the * interface we previously thought it was. @@ -426,7 +489,7 @@ sendit: * such control is nigh impossible. So we do it here. * And I'm babbling. */ - if (old != dst) { + if (off == 0 && old != dst) { struct in_ifaddr *ia; /* It's changed... */ @@ -515,12 +578,20 @@ sendit: */ if (fwd_rewrite_src) ip->ip_src = IA_SIN(ia)->sin_addr; + goto pass ; } #endif /* IPFIREWALL_FORWARD */ + /* + * if we get here, none of the above matches, and + * we have to drop the pkt + */ + m_freem(m); + error = EACCES; /* not sure this is the right error msg */ + goto done; } #endif /* COMPAT_IPFW */ - +pass: /* * If small enough for interface, can just send directly. */ diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index ee05690..1dd3618 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)raw_ip.c 8.7 (Berkeley) 5/15/95 - * $Id: raw_ip.c,v 1.54 1998/05/15 20:11:34 wollman Exp $ + * $Id: raw_ip.c,v 1.55 1998/08/23 03:07:14 wollman Exp $ */ #include @@ -61,6 +61,10 @@ #include +#include "opt_ipdn.h" +#ifdef DUMMYNET +#include +#endif #if !defined(COMPAT_IPFW) || COMPAT_IPFW == 1 #undef COMPAT_IPFW #define COMPAT_IPFW 1 @@ -259,6 +263,14 @@ rip_ctloutput(so, sopt) else error = ip_nat_ctl_ptr(sopt); break; +#ifdef DUMMYNET + case IP_DUMMYNET_GET: + if (ip_dn_ctl_ptr == NULL) + error = ENOPROTOOPT ; + else + error = ip_dn_ctl_ptr(sopt); + break ; +#endif /* DUMMYNET */ #endif /* COMPAT_IPFW */ case MRT_INIT: @@ -308,6 +320,16 @@ rip_ctloutput(so, sopt) else error = ip_nat_ctl_ptr(sopt); break; +#ifdef DUMMYNET + case IP_DUMMYNET_CONFIGURE: + case IP_DUMMYNET_DEL: + case IP_DUMMYNET_FLUSH: + if (ip_dn_ctl_ptr == NULL) + error = ENOPROTOOPT ; + else + error = ip_dn_ctl_ptr(sopt); + break ; +#endif #endif /* COMPAT_IPFW */ case IP_RSVP_ON: -- cgit v1.1