freebsd-nq/sys/netinet/ip_fw.c
David Greenman c6e8c3576e Fixed panic that occurs on certain firewall rejected packets that was
caused by dtom() being used on an mbuf cluster. The fix involves passing
around the mbuf pointer.

Submitted by:	Bill Fenner
1995-07-09 14:29:46 +00:00

931 lines
21 KiB
C

/*
* Copyright (c) 1993 Daniel Boulet
* Copyright (c) 1994 Ugen J.S.Antsilevich
*
* Redistribution and use in source forms, with and without modification,
* are permitted provided that this entire comment appears intact.
*
* Redistribution in binary form may occur without any restrictions.
* Obviously, it would be nice if you gave credit where credit is due
* but requiring it would be too onerous.
*
* This software is provided ``AS IS'' without any warranties of any kind.
*/
/*
* Implement IP packet firewall
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/domain.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/errno.h>
#include <sys/time.h>
#include <sys/kernel.h>
#include <net/if.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <netinet/ip_icmp.h>
#include <netinet/ip_fw.h>
#ifdef IPFIREWALL_DEBUG
#define dprintf1(a) printf(a)
#define dprintf2(a1,a2) printf(a1,a2)
#define dprintf3(a1,a2,a3) printf(a1,a2,a3)
#define dprintf4(a1,a2,a3,a4) printf(a1,a2,a3,a4)
#else
#define dprintf1(a)
#define dprintf2(a1,a2)
#define dprintf3(a1,a2,a3)
#define dprintf4(a1,a2,a3,a4)
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#define print_ip(a) printf("%ld.%ld.%ld.%ld",(ntohl(a.s_addr)>>24)&0xFF,\
(ntohl(a.s_addr)>>16)&0xFF,\
(ntohl(a.s_addr)>>8)&0xFF,\
(ntohl(a.s_addr))&0xFF);
#ifdef IPFIREWALL_DEBUG
#define dprint_ip(a) print_ip(a)
#else
#define dprint_ip(a)
#endif
/*
* Returns TRUE if the port is matched by the vector, FALSE otherwise
*/
inline int
port_match(portptr, nports, port, range_flag)
u_short *portptr;
int nports;
u_short port;
int range_flag;
{
if (!nports)
return TRUE;
if (range_flag) {
if (portptr[0] <= port && port <= portptr[1]) {
return TRUE;
}
nports -= 2;
portptr += 2;
}
while (nports-- > 0) {
if (*portptr++ == port) {
return TRUE;
}
}
return FALSE;
}
/*
* Returns TRUE if it should be accepted, FALSE otherwise.
*/
#ifdef IPFIREWALL
int
ip_fw_chk(m, ip, rif, chain)
struct mbuf *m;
struct ip *ip;
struct ifnet *rif;
struct ip_fw *chain;
{
register struct ip_fw *f;
struct tcphdr *tcp = (struct tcphdr *) ((u_long *) ip + ip->ip_hl);
struct udphdr *udp = (struct udphdr *) ((u_long *) ip + ip->ip_hl);
struct icmp *icmp = (struct icmp *) ((u_long *) ip + ip->ip_hl);
struct ifaddr *ia = NULL, *ia_p;
struct in_addr src, dst, ia_i;
u_short src_port = 0, dst_port = 0;
u_short f_prt = 0, prt;
char notcpsyn = 1;
/*
* If the chain is empty allow any packet-this is equal to disabling
* firewall.
*/
if (chain == NULL)
return TRUE;
/*
* This way we handle fragmented packets. we ignore all fragments but
* the first one so the whole packet can't be reassembled. This way we
* relay on the full info which stored only in first packet.
*/
if (ip->ip_off & IP_OFFMASK)
return TRUE;
src = ip->ip_src;
dst = ip->ip_dst;
/*
* If we got interface from which packet came-store pointer to it's
* first adress
*/
if (rif != NULL)
ia = rif->if_addrlist;
dprintf1("Packet ");
switch (ip->ip_p) {
case IPPROTO_TCP:
dprintf1("TCP ");
src_port = ntohs(tcp->th_sport);
dst_port = ntohs(tcp->th_dport);
if (tcp->th_flags & TH_SYN)
notcpsyn = 0; /* We *DO* have SYN ,value FALSE */
prt = IP_FW_F_TCP;
break;
case IPPROTO_UDP:
dprintf1("UDP ");
src_port = ntohs(udp->uh_sport);
dst_port = ntohs(udp->uh_dport);
prt = IP_FW_F_UDP;
break;
case IPPROTO_ICMP:
dprintf2("ICMP:%u ", icmp->icmp_type);
prt = IP_FW_F_ICMP;
break;
default:
dprintf2("p=%d ", ip->ip_p);
prt = IP_FW_F_ALL;
break;
}
dprint_ip(ip->ip_src);
if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) {
dprintf2(":%d ", src_port);
}
dprint_ip(ip->ip_dst);
if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) {
dprintf2(":%d ", dst_port);
}
dprintf1("\n");
for (f = chain; f != NULL; f = f->fw_next)
if ((src.s_addr & f->fw_smsk.s_addr) == f->fw_src.s_addr &&
(dst.s_addr & f->fw_dmsk.s_addr) == f->fw_dst.s_addr) {
if (rif == NULL)
goto via_match;
if (f->fw_flg & IP_FW_F_IFNAME) {
/*
* No name/unit set so
* match any.
*/
if (!f->fw_via_name[0])
goto via_match;
if (rif->if_unit == f->fw_via_unit &&
!strncmp(rif->if_name, f->fw_via_name, FW_IFNLEN))
goto via_match;
} else {
/*
* No via ip set so match
* any.
*/
if (!f->fw_via_ip.s_addr)
goto via_match;
for (ia_p = ia; ia_p != NULL; ia_p = ia_p->ifa_next) {
if ((ia_p->ifa_addr == NULL) ||
(ia_p->ifa_addr->sa_family != AF_INET))
continue;
ia_i.s_addr =
((struct sockaddr_in *)(ia_p->ifa_addr))->sin_addr.s_addr;
if (ia_i.s_addr == f->fw_via_ip.s_addr)
goto via_match;
}
}
/*
* If we got here,no "via"'s matched,so we should
* continue to the next firewall entry.
*/
continue;
via_match:
f_prt = f->fw_flg & IP_FW_F_KIND;
if (f_prt == IP_FW_F_ALL) {
/* Universal frwl - we've got a match! */
goto got_match;
} else {
/*
* This is actually buggy as if you set SYN
* flag on UDp or ICMP firewall it will never
* work,but actually it is a concern of
* software which sets firewall entries.
*/
if (f->fw_flg & IP_FW_F_TCPSYN && notcpsyn)
continue;
/*
* Specific firewall - packet's protocol must
* match firewall's
*/
if (prt == f_prt) {
if (prt == IP_FW_F_ICMP ||
(port_match(&f->fw_pts[0], f->fw_nsp, src_port,
f->fw_flg & IP_FW_F_SRNG) &&
port_match(&f->fw_pts[f->fw_nsp], f->fw_ndp, dst_port,
f->fw_flg & IP_FW_F_DRNG))) {
goto got_match;
} /* Ports match */
} /* Proto matches */
} /* ALL/Specific */
} /* IP addr/mask matches */
/*
* If we get here then none of the firewalls matched. So now we relay
* on policy defined by user-unmatched packet can be ever accepted or
* rejected...
*/
if (ip_fw_policy & IP_FW_P_DENY) {
f = (struct ip_fw *) NULL;
goto bad_packet;
}
return TRUE;
got_match:
#ifdef IPFIREWALL_VERBOSE
/*
* VERY ugly piece of code which actually makes kernel printf for
* denied packets...
*/
if (f->fw_flg & IP_FW_F_PRN) {
if (f->fw_flg & IP_FW_F_ACCEPT)
printf("Accept ");
else
printf("Deny ");
switch (ip->ip_p) {
case IPPROTO_TCP:
printf("TCP ");
break;
case IPPROTO_UDP:
printf("UDP ");
break;
case IPPROTO_ICMP:
printf("ICMP:%u ", icmp->icmp_type);
break;
default:
printf("p=%d ", ip->ip_p);
break;
}
print_ip(ip->ip_src);
if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP)
printf(":%d", src_port);
printf(" ");
print_ip(ip->ip_dst);
if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP)
printf(":%d", dst_port);
printf("\n");
}
#endif
if (f->fw_flg & IP_FW_F_ACCEPT)
return TRUE;
bad_packet:
if (f != NULL) {
/*
* Do not ICMP reply to icmp packets....:) or to packets
* rejected by entry without the special ICMP reply flag.
*/
if ((f_prt == IP_FW_F_ICMP) ||
!(f->fw_flg & IP_FW_F_ICMPRPL)) {
m_freem(m);
return FALSE;
}
if (f_prt == IP_FW_F_ALL)
icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0L, 0);
else
icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0L, 0);
return FALSE;
}
m_freem(m);
return FALSE;
}
#endif /* IPFIREWALL */
#ifdef IPACCT
void
ip_acct_cnt(ip, rif, chain, nh_conv)
struct ip *ip;
struct ifnet *rif;
struct ip_fw *chain;
int nh_conv;
{
register struct ip_fw *f;
struct tcphdr *tcp = (struct tcphdr *) ((u_long *) ip + ip->ip_hl);
struct udphdr *udp = (struct udphdr *) ((u_long *) ip + ip->ip_hl);
struct ifaddr *ia = NULL, *ia_p;
struct in_addr src, dst, ia_i;
u_short src_port = 0, dst_port = 0;
u_short f_prt, prt = 0;
char rev = 0;
if (chain == NULL)
return;
if (ip->ip_off & IP_OFFMASK)
return;
src = ip->ip_src;
dst = ip->ip_dst;
if (rif != NULL)
ia = rif->if_addrlist;
switch (ip->ip_p) {
case IPPROTO_TCP:
src_port = ntohs(tcp->th_sport);
dst_port = ntohs(tcp->th_dport);
prt = IP_FW_F_TCP;
break;
case IPPROTO_UDP:
src_port = ntohs(udp->uh_sport);
dst_port = ntohs(udp->uh_dport);
prt = IP_FW_F_UDP;
break;
case IPPROTO_ICMP:
prt = IP_FW_F_ICMP;
break;
default:
prt = IP_FW_F_ALL;
break;
}
for (f = chain; f != NULL; f = f->fw_next) {
if ((src.s_addr & f->fw_smsk.s_addr) == f->fw_src.s_addr
&& (dst.s_addr & f->fw_dmsk.s_addr) == f->fw_dst.s_addr) {
rev = 0;
goto addr_match;
}
if ((f->fw_flg & IP_FW_F_BIDIR) &&
((src.s_addr & f->fw_smsk.s_addr) == f->fw_dst.s_addr
&& (dst.s_addr & f->fw_dmsk.s_addr) == f->fw_src.s_addr)) {
rev = 1;
goto addr_match;
}
continue;
addr_match:
/*
* We use here same code for "via" matching as in
* firewall.This is wrong and does not do much use,because in
* most cases instead of interface passed NULL pointer.Need to
* be completely rewritten.
*/
if (rif == NULL)
goto via_match;
if (f->fw_flg & IP_FW_F_IFNAME) {
if (!f->fw_via_name[0])
goto via_match; /* No name/unit set,match any */
if (rif->if_unit == f->fw_via_unit &&
!strncmp(rif->if_name, f->fw_via_name, FW_IFNLEN))
goto via_match;
} else {
/*
* No via ip set so
* match any?
*/
if (!f->fw_via_ip.s_addr)
goto via_match;
for (ia_p = ia; ia_p != NULL; ia_p = ia_p->ifa_next) {
if (!ia_p->ifa_addr || ia_p->ifa_addr->sa_family != AF_INET)
continue;
ia_i.s_addr =
((struct sockaddr_in *) (ia_p->ifa_addr))->sin_addr.s_addr;
if (ia_i.s_addr == f->fw_via_ip.s_addr)
goto via_match;
}
}
/*
* If we got here,no "via"'s matched,so we should continue to
* the next firewall entry.
*/
continue;
via_match:
f_prt = f->fw_flg & IP_FW_F_KIND;
if (f_prt == IP_FW_F_ALL) {
/* Universal frwl - we've got a match! */
f->fw_pcnt++; /* Rise packet count */
/*
* Rise byte count, if need to convert from host to
* network byte order,do it.
*/
if (nh_conv)
f->fw_bcnt += ntohs(ip->ip_len);
else
f->fw_bcnt += ip->ip_len;
} else {
/*
* Specific firewall - packet's protocol must match
* firewall's
*/
if (prt == f_prt) {
if ((prt == IP_FW_F_ICMP ||
(port_match(&f->fw_pts[0], f->fw_nsp, src_port,
f->fw_flg & IP_FW_F_SRNG) &&
port_match(&f->fw_pts[f->fw_nsp], f->fw_ndp, dst_port,
f->fw_flg & IP_FW_F_DRNG))) ||
((rev) && (port_match(&f->fw_pts[0], f->fw_nsp, dst_port,
f->fw_flg & IP_FW_F_SRNG) &&
port_match(&f->fw_pts[f->fw_nsp], f->fw_ndp, src_port,
f->fw_flg & IP_FW_F_DRNG)))) {
f->fw_pcnt++; /* Rise packet count */
/*
* Rise byte count, if need to convert
* from host to network byte order,do
* it.
*/
if (nh_conv)
f->fw_bcnt += ntohs(ip->ip_len);
else
f->fw_bcnt += ip->ip_len;
} /* Ports match */
} /* Proto matches */
} /* ALL/Specific */
} /* IP addr/mask matches */
}
#endif /* IPACCT */
static void
zero_fw_chain(chainptr)
struct ip_fw *chainptr;
{
struct ip_fw *ctmp = chainptr;
while (ctmp != NULL) {
ctmp->fw_pcnt = 0l;
ctmp->fw_bcnt = 0l;
ctmp = ctmp->fw_next;
}
}
static void
free_fw_chain(chainptr)
struct ip_fw **chainptr;
{
int s;
s = splnet();
while (*chainptr != NULL) {
struct ip_fw *ftmp;
ftmp = *chainptr;
*chainptr = ftmp->fw_next;
free(ftmp, M_IPFW);
}
splx(s);
}
static int
add_entry(chainptr, frwl)
struct ip_fw **chainptr;
struct ip_fw *frwl;
{
struct ip_fw *ftmp;
struct ip_fw *chtmp = NULL;
struct ip_fw *chtmp_prev = NULL;
u_long m_src_mask, m_dst_mask;
u_long n_sa, n_da, o_sa, o_da, o_sm, o_dm, n_sm, n_dm;
u_short n_sr, n_dr, o_sr, o_dr;
u_short oldkind, newkind;
int addb4 = 0;
int n_o, n_n;
int s;
s = splnet();
ftmp = malloc(sizeof(struct ip_fw), M_IPFW, M_DONTWAIT);
if (ftmp == NULL) {
dprintf1("ip_fw_ctl: malloc said no\n");
splx(s);
return (ENOSPC);
}
bcopy(frwl, ftmp, sizeof(struct ip_fw));
ftmp->fw_pcnt = 0L;
ftmp->fw_bcnt = 0L;
ftmp->fw_next = NULL;
if (*chainptr == NULL) {
*chainptr = ftmp;
} else {
chtmp_prev = NULL;
for (chtmp = *chainptr; chtmp != NULL; chtmp = chtmp->fw_next) {
addb4 = 0;
newkind = ftmp->fw_flg & IP_FW_F_KIND;
oldkind = chtmp->fw_flg & IP_FW_F_KIND;
if (newkind != IP_FW_F_ALL &&
oldkind != IP_FW_F_ALL &&
oldkind != newkind) {
chtmp_prev = chtmp;
continue;
}
/*
* Very very *UGLY* code... Sorry,but i had to do
* this....
*/
n_sa = ntohl(ftmp->fw_src.s_addr);
n_da = ntohl(ftmp->fw_dst.s_addr);
n_sm = ntohl(ftmp->fw_smsk.s_addr);
n_dm = ntohl(ftmp->fw_dmsk.s_addr);
o_sa = ntohl(chtmp->fw_src.s_addr);
o_da = ntohl(chtmp->fw_dst.s_addr);
o_sm = ntohl(chtmp->fw_smsk.s_addr);
o_dm = ntohl(chtmp->fw_dmsk.s_addr);
m_src_mask = o_sm & n_sm;
m_dst_mask = o_dm & n_dm;
if ((o_sa & m_src_mask) == (n_sa & m_src_mask)) {
if (n_sm > o_sm)
addb4++;
if (n_sm < o_sm)
addb4--;
}
if ((o_da & m_dst_mask) == (n_da & m_dst_mask)) {
if (n_dm > o_dm)
addb4++;
if (n_dm < o_dm)
addb4--;
}
if (((o_da & o_dm) == (n_da & n_dm))
&& ((o_sa & o_sm) == (n_sa & n_sm))) {
if (newkind != IP_FW_F_ALL &&
oldkind == IP_FW_F_ALL)
addb4++;
if (newkind == oldkind && (oldkind == IP_FW_F_TCP ||
oldkind == IP_FW_F_UDP)) {
/*
* Here the main idea is to check the
* size of port range which the frwl
* covers We actually don't check
* their values but just the wideness
* of range they have so that less
* wide ranges or single ports go
* first and wide ranges go later. No
* ports at all treated as a range of
* maximum number of ports.
*/
if (ftmp->fw_flg & IP_FW_F_SRNG)
n_sr = ftmp->fw_pts[1] - ftmp->fw_pts[0];
else
n_sr = (ftmp->fw_nsp) ?
ftmp->fw_nsp : USHRT_MAX;
if (chtmp->fw_flg & IP_FW_F_SRNG)
o_sr = chtmp->fw_pts[1] - chtmp->fw_pts[0];
else
o_sr = (chtmp->fw_nsp) ?
chtmp->fw_nsp : USHRT_MAX;
if (n_sr < o_sr)
addb4++;
if (n_sr > o_sr)
addb4--;
n_n = ftmp->fw_nsp;
n_o = chtmp->fw_nsp;
/*
* Actually this cannot happen as the
* frwl control procedure checks for
* number of ports in source and
* destination range but we will try
* to be more safe.
*/
if ((n_n > (IP_FW_MAX_PORTS - 2)) ||
(n_o > (IP_FW_MAX_PORTS - 2)))
goto skip_check;
if (ftmp->fw_flg & IP_FW_F_DRNG)
n_dr = ftmp->fw_pts[n_n + 1] - ftmp->fw_pts[n_n];
else
n_dr = (ftmp->fw_ndp) ?
ftmp->fw_ndp : USHRT_MAX;
if (chtmp->fw_flg & IP_FW_F_DRNG)
o_dr = chtmp->fw_pts[n_o + 1] - chtmp->fw_pts[n_o];
else
o_dr = (chtmp->fw_ndp) ?
chtmp->fw_ndp : USHRT_MAX;
if (n_dr < o_dr)
addb4++;
if (n_dr > o_dr)
addb4--;
skip_check:
}
}
if (addb4 > 0) {
if (chtmp_prev != NULL) {
chtmp_prev->fw_next = ftmp;
ftmp->fw_next = chtmp;
} else {
*chainptr = ftmp;
ftmp->fw_next = chtmp;
}
splx(s);
return 0;
}
chtmp_prev = chtmp;
}
if (chtmp_prev != NULL)
chtmp_prev->fw_next = ftmp;
else
#ifdef DIAGNOSTIC
panic("Can't happen");
#else
*chainptr = ftmp;
#endif
}
splx(s);
return (0);
}
static int
del_entry(chainptr, frwl)
struct ip_fw **chainptr;
struct ip_fw *frwl;
{
struct ip_fw *ftmp, *ltmp;
u_short tport1, tport2, tmpnum;
char matches, was_found;
int s;
s = splnet();
ftmp = *chainptr;
if (ftmp == NULL) {
dprintf1("ip_fw_ctl: chain is empty\n");
splx(s);
return (EINVAL);
}
ltmp = NULL;
was_found = 0;
while (ftmp != NULL) {
matches = 1;
if (ftmp->fw_src.s_addr != frwl->fw_src.s_addr ||
ftmp->fw_dst.s_addr != frwl->fw_dst.s_addr ||
ftmp->fw_smsk.s_addr != frwl->fw_smsk.s_addr ||
ftmp->fw_dmsk.s_addr != frwl->fw_dmsk.s_addr ||
ftmp->fw_via_ip.s_addr != frwl->fw_via_ip.s_addr ||
ftmp->fw_flg != frwl->fw_flg)
matches = 0;
tport1 = ftmp->fw_nsp + ftmp->fw_ndp;
tport2 = frwl->fw_nsp + frwl->fw_ndp;
if (tport1 != tport2)
matches = 0;
else if (tport1 != 0) {
for (tmpnum = 0; tmpnum < tport1 && tmpnum < IP_FW_MAX_PORTS; tmpnum++)
if (ftmp->fw_pts[tmpnum] != frwl->fw_pts[tmpnum])
matches = 0;
}
if (matches) {
was_found = 1;
if (ltmp != NULL) {
ltmp->fw_next = ftmp->fw_next;
free(ftmp, M_IPFW);
ftmp = ltmp->fw_next;
} else {
*chainptr = ftmp->fw_next;
free(ftmp, M_IPFW);
ftmp = *chainptr;
}
} else {
ltmp = ftmp;
ftmp = ftmp->fw_next;
}
}
splx(s);
if (was_found)
return 0;
else
return (EINVAL);
}
static int
clr_entry(chainptr, frwl)
struct ip_fw **chainptr;
struct ip_fw *frwl;
{
struct ip_fw *ftmp, *ltmp;
u_short tport1, tport2, tmpnum;
char matches, was_found;
ftmp = *chainptr;
if (ftmp == NULL) {
dprintf1("ip_fw_ctl: chain is empty\n");
return (EINVAL);
}
was_found = 0;
while (ftmp != NULL) {
matches = 1;
if (ftmp->fw_src.s_addr != frwl->fw_src.s_addr ||
ftmp->fw_dst.s_addr != frwl->fw_dst.s_addr ||
ftmp->fw_smsk.s_addr != frwl->fw_smsk.s_addr ||
ftmp->fw_dmsk.s_addr != frwl->fw_dmsk.s_addr ||
ftmp->fw_via_ip.s_addr != frwl->fw_via_ip.s_addr ||
ftmp->fw_flg != frwl->fw_flg)
matches = 0;
tport1 = ftmp->fw_nsp + ftmp->fw_ndp;
tport2 = frwl->fw_nsp + frwl->fw_ndp;
if (tport1 != tport2)
matches = 0;
else if (tport1 != 0) {
for (tmpnum = 0; tmpnum < tport1 && tmpnum < IP_FW_MAX_PORTS; tmpnum++)
if (ftmp->fw_pts[tmpnum] != frwl->fw_pts[tmpnum])
matches = 0;
}
if (matches) {
was_found = 1;
ftmp->fw_pcnt = 0L;
ftmp->fw_bcnt = 0L;
}
ftmp = ftmp->fw_next;
}
if (was_found)
return 0;
else
return (EINVAL);
}
struct ip_fw *
check_ipfw_struct(m)
struct mbuf *m;
{
struct ip_fw *frwl;
if (m->m_len != sizeof(struct ip_fw)) {
dprintf3("ip_fw_ctl: len=%d, want %d\n", m->m_len,
sizeof(struct ip_fw));
return (NULL);
}
frwl = mtod(m, struct ip_fw *);
if ((frwl->fw_flg & ~IP_FW_F_MASK) != 0) {
dprintf2("ip_fw_ctl: undefined flag bits set (flags=%x)\n",
frwl->fw_flg);
return (NULL);
}
if ((frwl->fw_flg & IP_FW_F_SRNG) && frwl->fw_nsp < 2) {
dprintf2("ip_fw_ctl: src range set but n_src_p=%d\n",
frwl->fw_nsp);
return (NULL);
}
if ((frwl->fw_flg & IP_FW_F_DRNG) && frwl->fw_ndp < 2) {
dprintf2("ip_fw_ctl: dst range set but n_dst_p=%d\n",
frwl->fw_ndp);
return (NULL);
}
if (frwl->fw_nsp + frwl->fw_ndp > IP_FW_MAX_PORTS) {
dprintf3("ip_fw_ctl: too many ports (%d+%d)\n",
frwl->fw_nsp, frwl->fw_ndp);
return (NULL);
}
#if 0
if ((frwl->fw_flg & IP_FW_F_KIND) == IP_FW_F_ICMP) {
dprintf1("ip_fw_ctl: request for unsupported ICMP frwling\n");
return (NULL);
}
#endif
return frwl;
}
#ifdef IPACCT
int
ip_acct_ctl(stage, m)
int stage;
struct mbuf *m;
{
if (stage == IP_ACCT_FLUSH) {
free_fw_chain(&ip_acct_chain);
return (0);
}
if (stage == IP_ACCT_ZERO) {
zero_fw_chain(ip_acct_chain);
return (0);
}
if (stage == IP_ACCT_ADD ||
stage == IP_ACCT_DEL ||
stage == IP_ACCT_CLR) {
struct ip_fw *frwl;
if ((frwl = check_ipfw_struct(m)) == NULL)
return (EINVAL);
switch (stage) {
case IP_ACCT_ADD:
return (add_entry(&ip_acct_chain, frwl));
case IP_ACCT_DEL:
return (del_entry(&ip_acct_chain, frwl));
case IP_ACCT_CLR:
return (clr_entry(&ip_acct_chain, frwl));
default:
#ifdef DIAGNOSTIC
panic("Can't happen");
#else
dprintf2("ip_acct_ctl: unknown request %d\n", stage);
return (EINVAL);
#endif
}
}
dprintf2("ip_acct_ctl: unknown request %d\n", stage);
return (EINVAL);
}
#endif
#ifdef IPFIREWALL
int
ip_fw_ctl(stage, m)
int stage;
struct mbuf *m;
{
if (stage == IP_FW_FLUSH) {
free_fw_chain(&ip_fw_chain);
return (0);
}
if (m == NULL) {
printf("ip_fw_ctl: NULL mbuf ptr\n");
return (EINVAL);
}
if (stage == IP_FW_POLICY) {
u_short *tmp_policy_ptr;
tmp_policy_ptr = mtod(m, u_short *);
if ((*tmp_policy_ptr) & ~IP_FW_P_MASK)
return (EINVAL);
ip_fw_policy = *tmp_policy_ptr;
return 0;
}
/*
* Here we really working hard-adding new elements
* to firewall chain or deleting'em
*/
if (stage == IP_FW_ADD ||
stage == IP_FW_DEL) {
struct ip_fw *frwl;
if ((frwl = check_ipfw_struct(m)) == NULL)
return (EINVAL);
switch (stage) {
case IP_FW_ADD:
return (add_entry(&ip_fw_chain, frwl));
case IP_FW_DEL:
return (del_entry(&ip_fw_chain, frwl));
default:
#ifdef DIAGNOSTIC
panic("Can't happen");
#else
dprintf2("ip_fw_ctl: unknown request %d\n", stage);
return (EINVAL);
#endif
}
}
dprintf2("ip_fw_ctl: unknown request %d\n", stage);
return (EINVAL);
}
#endif /* IPFIREWALL */