--- linux/net/inet/ip_fw.c Wed Feb 15 14:21:53 1995 +++ linux-old/net/inet/ip_fw.c Sun Feb 12 17:31:30 1995 @@ -4,9 +4,18 @@ * and the licenses thus do not conflict. While this port is subject * to the GPL I also place my modifications under the original * license in recognition of the original copyright. + * -- Alan Cox. * * Ported from BSD to Linux, * Alan Cox 22/Nov/1994. + * Zeroing /proc and other additions + * Jos Vos 4/Feb/1995. + * Merged and included the FreeBSD-Current changes at Urgen's request + * (but hey its a lot cleaner now). Urgen would prefer in some ways + * we waited for his final product but since Linux 1.2.0 is about to + * appear its not practical - Read: It works, its not clean but please + * don't consider it to be his standard of finished work. + * Alan Cox 12/Feb/1995 * * All the real work was done by ..... */ @@ -25,6 +34,7 @@ * This software is provided ``AS IS'' without any warranties of any kind. */ +#include #include #include #include @@ -39,6 +49,8 @@ #include #include #include +#include +#include #include "ip.h" #include "protocol.h" #include "route.h" @@ -52,11 +64,34 @@ * Implement IP packet firewall */ +#ifdef CONFIG_IPFIREWALL_DEBUG +#define dprintf1(a) printk(a) +#define dprintf2(a1,a2) printk(a1,a2) +#define dprintf3(a1,a2,a3) printk(a1,a2,a3) +#define dprintf4(a1,a2,a3,a4) printk(a1,a2,a3,a4) +#else +#define dprintf1(a) +#define dprintf2(a1,a2) +#define dprintf3(a1,a2,a3) +#define dprintf4(a1,a2,a3,a4) +#endif + +#define print_ip(a) printf("%d.%d.%d.%d",(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 + #ifdef CONFIG_IP_FIREWALL struct ip_fw *ip_fw_fwd_chain; struct ip_fw *ip_fw_blk_chain; -int ip_fw_blk_policy=1; -int ip_fw_fwd_policy=1; +int ip_fw_blk_policy=IP_FW_F_ACCEPT; +int ip_fw_fwd_policy=IP_FW_F_ACCEPT; #endif #ifdef CONFIG_IP_ACCT struct ip_fw *ip_acct_chain; @@ -67,16 +102,6 @@ #define IP_INFO_ACCT 2 -extern inline void print_ip(unsigned long xaddr) -{ - unsigned long addr = ntohl(xaddr); - printk("%ld.%ld.%ld.%ld",(addr>>24) & 0xff, - (addr>>16)&0xff, - (addr>>8)&0xff, - addr&0xFF); -} - - /* * Returns 1 if the port is matched by the vector, 0 otherwise */ @@ -104,336 +129,230 @@ return(0); } +#if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL) + /* - * Returns 0 if packet should be dropped, 1 or more if it should be accepted + * Returns 0 if packet should be dropped, 1 or more if it should be accepted. + * Also does accounting so you can feed it the accounting chain. */ -#ifdef CONFIG_IP_FIREWALL -int ip_fw_chk(struct iphdr *ip, struct ip_fw *chain, int policy) +int ip_fw_chk(struct iphdr *ip, struct device *rif, struct ip_fw *chain, int policy) { - unsigned long src, dst; - char got_proto=0; - int frwl_proto, proto=0; struct ip_fw *f; - unsigned short src_port=0, dst_port=0; - unsigned short *portptr=(unsigned short *)&(((u_int *)ip)[ip->ihl]); - - if (!chain) - return(policy); /* If no chain, use your policy. */ - - src = ip->saddr; - dst = ip->daddr; - -#ifdef DEBUG_CONFIG_IP_FIREWALL - { - printk("packet "); - switch(ip->protocol) - { - case IPPROTO_TCP: - printf("TCP "); - break; - case IPPROTO_UDP: - printf("UDP "); - break; - case IPPROTO_ICMP: - printf("ICMP:%d ",((char *)portptr)[0]&0xff); - break; - default: - printf("p=%d ",ip->protocol); - break; - } - print_ip(ip->saddr); - if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP) - { - printf(":%d ",ntohs(portptr[0])); - } - print_ip(ip->daddr); - if ( ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP) - { - printf(":%d ",ntohs(portptr[1])); - } - printf("\n"); - } -#endif + struct tcphdr *tcp=(struct tcphdr *)((unsigned long *)ip+ip->ihl); + struct udphdr *udp=(struct udphdr *)((unsigned long *)ip+ip->ihl); + __u32 src, dst; + __u16 src_port=0, dst_port=0; + unsigned short f_prt=0, prt; + char notcpsyn=1; + unsigned short f_flag; - for (f=chain;f;f=f->next) - { - if ((src&f->src_mask.s_addr)==f->src.s_addr - && (dst&f->dst_mask.s_addr)==f->dst.s_addr) - { - frwl_proto=f->flags&IP_FW_F_KIND; - if (frwl_proto==IP_FW_F_ALL) - { - /* Universal frwl - we've got a match! */ - -#ifdef DEBUG_CONFIG_IP_FIREWALL - printf("universal frwl match\n"); -#endif - f->p_cnt++; - f->b_cnt+=ntohs(ip->tot_len); -#ifdef CONFIG_IP_FIREWALL_VERBOSE - if (!(f->flags & IP_FW_F_ACCEPT)) - goto bad_packet; - return 1; -#else - return( f->flags & IP_FW_F_ACCEPT ); -#endif - } - else - { - /* - * Specific firewall - packet's protocol must match firewall's - */ - if (!got_proto) - { - /* - * We still had not determined the protocol - * of this packet,now the time to do so. - */ - switch(ip->protocol) - { - case IPPROTO_TCP: - /* - * First two shorts in TCP are src/dst ports - */ - proto=IP_FW_F_TCP; - src_port=ntohs(portptr[0]); - dst_port=ntohs(portptr[1]); - break; - case IPPROTO_UDP: - /* - * First two shorts in UDP are src/dst ports - */ - proto = IP_FW_F_UDP; - src_port = ntohs(portptr[0]); - dst_port = ntohs(portptr[1]); - break; - case IPPROTO_ICMP: - proto=IP_FW_F_ICMP; - break; - default: - proto=IP_FW_F_ALL; -#ifdef DEBUG_CONFIG_IP_FIREWALL - printf("non TCP/UDP packet\n"); -#endif - } - got_proto=1; - } - /* - * At this moment we surely know the protocol of this - * packet and we'll check if it matches,then proceed further.. - */ - if (proto==frwl_proto) - { - - if (proto==IP_FW_F_ICMP || (port_match(&f->ports[0],f->n_src_p,src_port, - f->flags&IP_FW_F_SRNG) && - port_match(&f->ports[f->n_src_p],f->n_dst_p,dst_port, - f->flags&IP_FW_F_DRNG))) - { - /* We've got a match! */ - f->p_cnt++; - f->b_cnt+=ntohs(ip->tot_len); -#ifdef CONFIG_IP_FIREWALL_VERBOSE - if (!(f->flags & IP_FW_F_ACCEPT)) - goto bad_packet; - return 1; -#else - return( f->flags & IP_FW_F_ACCEPT); -#endif - } /* Ports match */ - } /* Proto matches */ - } /* ALL/Specific */ - } /* IP addr/mask matches */ - } /* Loop */ - /* - * 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 the chain is empty follow policy. The BSD one + * accepts anything giving you a time window while + * flushing and rebuilding the tables. */ - -#ifdef CONFIG_IP_FIREWALL_VERBOSE - if (!(policy)) - goto bad_packet; - return 1; -#else - return(policy); -#endif + + src = ip->saddr; + dst = ip->daddr; -#ifdef CONFIG_IP_FIREWALL_VERBOSE -bad_packet: - /* - * VERY ugly piece of code which actually - * makes kernel printf for denied packets... + /* + * 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. + * + * Note that this theoretically allows partial packet + * spoofing. Not very dangerous but paranoid people may + * wish to play with this. It also allows the so called + * "fragment bomb" denial of service attack on some types + * of system. */ - if (f->flags&IP_FW_F_PRN) - { - printf("ip_fw_chk says no to "); - switch(ip->protocol) - { - case IPPROTO_TCP: - printf("TCP "); - break; - case IPPROTO_UDP: - printf("UDP "); - break; - case IPPROTO_ICMP: - printf("ICMP:%d ",((char *)portptr)[0]&0xff); - break; - default: - printf("p=%d ",ip->protocol); - break; - } - print_ip(ip->saddr); - if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP) - { - printf(":%d ",ntohs(portptr[0])); - } - else - { - printf("\n"); - } - print_ip(ip->daddr); - if ( ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP ) - { - printf(":%d ",ntohs(portptr[1])); - } - printf("\n"); - } - return(0); -#endif -} -#endif /* CONFIG_IP_FIREWALL */ - - - - -#ifdef CONFIG_IP_ACCT -void ip_acct_cnt(struct iphdr *ip,struct ip_fw *chain) -{ - unsigned long src, dst; - char got_proto=0,rev=0; - int frwl_proto, proto=0; - struct ip_fw *f; - unsigned short src_port=0, dst_port=0; - unsigned short *portptr=(unsigned short *)&(((u_int *)ip)[ip->ihl]); - if (!chain) - return; + if (ip->frag_off&IP_OFFSET) + return(1); src = ip->saddr; dst = ip->daddr; - for (f=chain;f;f=f->next) - { - if ((src&f->src_mask.s_addr)==f->src.s_addr - && (dst&f->dst_mask.s_addr)==f->dst.s_addr) - { - rev=0; - goto addr_match; - } - if ((f->flags&IP_FW_F_BIDIR) && - ((src&f->src_mask.s_addr)==f->dst.s_addr - && (dst&f->dst_mask.s_addr)==f->src.s_addr)) - { - rev=1; - goto addr_match; - } - continue; -addr_match: - frwl_proto=f->flags&IP_FW_F_KIND; - if (frwl_proto==IP_FW_F_ALL) + /* + * If we got interface from which packet came + * we can use the address directly. This is unlike + * 4.4BSD derived systems that have an address chain + * per device. We have a device per address with dummy + * devices instead. + */ + + dprintf1("Packet "); + switch(ip->protocol) + { + case IPPROTO_TCP: + dprintf1("TCP "); + src_port=ntohs(tcp->source); + dst_port=ntohs(tcp->dest); + if(tcp->syn) + notcpsyn=0; /* We *DO* have SYN, value FALSE */ + prt=IP_FW_F_TCP; + break; + case IPPROTO_UDP: + dprintf1("UDP "); + src_port=ntohs(udp->source); + dst_port=ntohs(udp->dest); + prt=IP_FW_F_UDP; + break; + case IPPROTO_ICMP: + dprintf2("ICMP:%d ",((char *)portptr)[0]&0xff); + prt=IP_FW_F_ICMP; + break; + default: + dprintf2("p=%d ",ip->protocol); + prt=IP_FW_F_ALL; + break; + } + dprint_ip(ip->saddr); + + if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP) + dprintf2(":%d ", src_port); + dprint_ip(ip->daddr); + if ( ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP) + dprintf2(":%d ",dst_port); + dprintf1("\n"); + + for (f=chain;f;f=f->fw_next) + { + /* + * This is a bit simpler as we don't have to walk + * an interface chain as you do in BSD - same logic + * however. + */ + if ((src&f->fw_smsk.s_addr)==f->fw_src.s_addr + && (dst&f->fw_dmsk.s_addr)==f->fw_dst.s_addr) { - /* Universal frwl - we've got a match! */ - f->p_cnt++; /* Rise packet count */ - /* - * Rise byte count, convert from host to network byte order. - */ - - f->b_cnt+=ntohs(ip->tot_len); + * Look for a VIA match + */ + if(f->fw_via.s_addr && rif) + { + if(rif->pa_addr!=f->fw_via.s_addr) + continue; /* Mismatch */ + } + /* + * Drop through - this is a match + */ } else + continue; + + /* + * Ok the chain addresses match. + */ + + f_prt=f->fw_flg&IP_FW_F_KIND; + if (f_prt!=IP_FW_F_ALL) { /* - * Specific firewall - packet's protocol must match firewall's + * 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 (!got_proto) - { - /* - * We still had not determined the protocol - * of this packet,now the time to do so. - */ - switch(ip->protocol) - { - case IPPROTO_TCP: - /* - * First two shorts in TCP are src/dst ports - */ - proto=IP_FW_F_TCP; - src_port=ntohs(portptr[0]); - dst_port=ntohs(portptr[1]); - break; - case IPPROTO_UDP: - /* - * First two shorts in UDP are src/dst ports - */ - proto = IP_FW_F_UDP; - src_port = ntohs(portptr[0]); - dst_port = ntohs(portptr[1]); - break; - case IPPROTO_ICMP: - proto=IP_FW_F_ICMP; - break; - default: - proto=IP_FW_F_ALL; - } - got_proto=1; - } + if((f->fw_flg&IP_FW_F_TCPSYN) && notcpsyn) + continue; /* - * At this moment we surely know the protocol of this - * packet and we'll check if it matches,then proceed further.. + * Specific firewall - packet's protocol + * must match firewall's. */ - if (proto==frwl_proto) + + if(prt!=f_prt) + continue; + + 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_SRNG)))) { + continue; + } + } +#ifdef CONFIG_IP_FIREWALL_VERBOSE + /* + * VERY ugly piece of code which actually + * makes kernel printf for denied packets... + */ - if ((proto==IP_FW_F_ICMP || - (port_match(&f->ports[0],f->n_src_p,src_port, - f->flags&IP_FW_F_SRNG) && - port_match(&f->ports[f->n_src_p],f->n_dst_p,dst_port, - f->flags&IP_FW_F_DRNG))) - || ((rev) - && (port_match(&f->ports[0],f->n_src_p,dst_port, - f->flags&IP_FW_F_SRNG) - && port_match(&f->ports[f->n_src_p],f->n_dst_p,src_port, - f->flags&IP_FW_F_DRNG)))) - { - f->p_cnt++; /* Rise packet count */ - /* - * Rise byte count, convert from host to network byte order. - */ - f->b_cnt+=ntohs(ip->tot_len); - } /* Ports match */ - } /* Proto matches */ - } /* ALL/Specific */ - } /* IP addr/mask matches */ -} /* End of whole function */ -#endif /* CONFIG_IP_ACCT */ + if (f->fw_flg & IP_FW_F_PRN) + { + if(f->fw_flg&IP_FW_F_ACCEPT) + printk("Accept "); + else + printk("Deny "); + switch(ip->protocol) + { + case IPPROTO_TCP: + printk("TCP "); + break; + case IPPROTO_UDP: + printk("UDP "); + case IPPROTO_ICMP: + printk("ICMP "); + break; + default: + printk("p=%d ",ip->protocol); + break; + } + print_ip(ip->saddr); + if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP) + printk(":%d", src_port); + printk(" "); + print_ip(ip->daddr); + if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP) + printk(":%d",dst_port); + printk("\n"); + } +#endif + if(f->fw_flg&IP_FW_F_ACCEPT) + { + f->fw_bcnt+=ntohs(ip->tot_len); + f->fw_pcnt++; + return 1; + } + break; + } /* Loop */ + + /* + * If we get here then none of the firewalls matched or one matched + * but was a no. So now we rely on policy defined in the rejecting + * entry or if none was found in the policy variable + */ -#if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL) + if(f!=NULL) /* A deny match */ + f_flag=f->fw_flg; + else + f_flag=policy; + if(f_flag&IP_FW_F_ACCEPT) + return 1; + if(f_flag&IP_FW_F_ICMPRPL) + return -1; + return 0; +} + + + + static void zero_fw_chain(struct ip_fw *chainptr) { struct ip_fw *ctmp=chainptr; while(ctmp) { - ctmp->p_cnt=0l; - ctmp->b_cnt=0l; - ctmp=ctmp->next; + ctmp->fw_pcnt=0L; + ctmp->fw_bcnt=0L; + ctmp=ctmp->fw_next; } } @@ -446,7 +365,7 @@ { struct ip_fw *ftmp; ftmp = *chainptr; - *chainptr = ftmp->next; + *chainptr = ftmp->fw_next; kfree_s(ftmp,sizeof(*ftmp)); } restore_flags(flags); @@ -475,15 +394,15 @@ #ifdef DEBUG_CONFIG_IP_FIREWALL printf("ip_fw_ctl: malloc said no\n"); #endif - return( ENOSPC ); + return( ENOMEM ); } memcpy(ftmp, frwl, sizeof( struct ip_fw ) ); - ftmp->p_cnt=0L; - ftmp->b_cnt=0L; + ftmp->fw_pcnt=0L; + ftmp->fw_bcnt=0L; - ftmp->next = NULL; + ftmp->fw_next = NULL; cli(); @@ -494,11 +413,11 @@ else { chtmp_prev=NULL; - for (chtmp=*chainptr;chtmp!=NULL;chtmp=chtmp->next) + for (chtmp=*chainptr;chtmp!=NULL;chtmp=chtmp->fw_next) { addb4=0; - newkind=ftmp->flags & IP_FW_F_KIND; - oldkind=chtmp->flags & IP_FW_F_KIND; + 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 @@ -513,15 +432,15 @@ * Sorry,but i had to do this.... */ - n_sa=ntohl(ftmp->src.s_addr); - n_da=ntohl(ftmp->dst.s_addr); - n_sm=ntohl(ftmp->src_mask.s_addr); - n_dm=ntohl(ftmp->dst_mask.s_addr); - - o_sa=ntohl(chtmp->src.s_addr); - o_da=ntohl(chtmp->dst.s_addr); - o_sm=ntohl(chtmp->src_mask.s_addr); - o_dm=ntohl(chtmp->dst_mask.s_addr); + 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; @@ -563,23 +482,24 @@ * of ports. */ - if (ftmp->flags & IP_FW_F_SRNG) - n_sr=ftmp->ports[1]-ftmp->ports[0]; + if (ftmp->fw_flg & IP_FW_F_SRNG) + n_sr=ftmp->fw_pts[1]-ftmp->fw_pts[0]; else - n_sr=(ftmp->n_src_p)?ftmp->n_src_p : 0xFFFF; + n_sr=(ftmp->fw_nsp)? + ftmp->fw_nsp : 0xFFFF; - if (chtmp->flags & IP_FW_F_SRNG) - o_sr=chtmp->ports[1]-chtmp->ports[0]; + if (chtmp->fw_flg & IP_FW_F_SRNG) + o_sr=chtmp->fw_pts[1]-chtmp->fw_pts[0]; else - o_sr=(chtmp->n_src_p)?chtmp->n_src_p : 0xFFFF; + o_sr=(chtmp->fw_nsp)?chtmp->fw_nsp : 0xFFFF; if (n_sro_sr) addb4--; - n_n=ftmp->n_src_p; - n_o=chtmp->n_src_p; + n_n=ftmp->fw_nsp; + n_o=chtmp->fw_nsp; /* * Actually this cannot happen as the frwl control @@ -591,15 +511,15 @@ (n_o>(IP_FW_MAX_PORTS-2))) goto skip_check; - if (ftmp->flags & IP_FW_F_DRNG) - n_dr=ftmp->ports[n_n+1]-ftmp->ports[n_n]; + 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->n_dst_p)? ftmp->n_dst_p : 0xFFFF; + n_dr=(ftmp->fw_ndp)? ftmp->fw_ndp : 0xFFFF; - if (chtmp->flags & IP_FW_F_DRNG) - o_dr=chtmp->ports[n_o+1]-chtmp->ports[n_o]; + 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->n_dst_p)? chtmp->n_dst_p : 0xFFFF; + o_dr=(chtmp->fw_ndp)? chtmp->fw_ndp : 0xFFFF; if (n_dro_dr) @@ -611,13 +531,13 @@ { if (chtmp_prev) { - chtmp_prev->next=ftmp; - ftmp->next=chtmp; + chtmp_prev->fw_next=ftmp; + ftmp->fw_next=chtmp; } else { *chainptr=ftmp; - ftmp->next=chtmp; + ftmp->fw_next=chtmp; } restore_flags(flags); return 0; @@ -627,7 +547,7 @@ } if (chtmp_prev) - chtmp_prev->next=ftmp; + chtmp_prev->fw_next=ftmp; else *chainptr=ftmp; restore_flags(flags); @@ -649,7 +569,7 @@ if ( ftmp == NULL ) { #ifdef DEBUG_CONFIG_IP_FIREWALL - printf("ip_fw_ctl: chain is empty\n"); + printk("ip_fw_ctl: chain is empty\n"); #endif restore_flags(flags); return( EINVAL ); @@ -661,21 +581,22 @@ while( ftmp != NULL ) { matches=1; - if ((memcmp(&ftmp->src,&frwl->src,sizeof(struct in_addr))) - || (memcmp(&ftmp->src_mask,&frwl->src_mask,sizeof(struct in_addr))) - || (memcmp(&ftmp->dst,&frwl->dst,sizeof(struct in_addr))) - || (memcmp(&ftmp->dst_mask,&frwl->dst_mask,sizeof(struct in_addr))) - || (ftmp->flags!=frwl->flags)) + 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.s_addr!=frwl->fw_via.s_addr + || ftmp->fw_flg!=frwl->fw_flg) matches=0; - tport1=ftmp->n_src_p+ftmp->n_dst_p; - tport2=frwl->n_src_p+frwl->n_dst_p; + 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->ports[tmpnum]!=frwl->ports[tmpnum]) + if (ftmp->fw_pts[tmpnum]!=frwl->fw_pts[tmpnum]) matches=0; } if(matches) @@ -683,13 +604,13 @@ was_found=1; if (ltmp) { - ltmp->next=ftmp->next; + ltmp->fw_next=ftmp->fw_next; kfree_s(ftmp,sizeof(*ftmp)); - ftmp=ltmp->next; + ftmp=ltmp->fw_next; } else { - *chainptr=ftmp->next; + *chainptr=ftmp->fw_next; kfree_s(ftmp,sizeof(*ftmp)); ftmp=*chainptr; } @@ -697,7 +618,7 @@ else { ltmp = ftmp; - ftmp = ftmp->next; + ftmp = ftmp->fw_next; } } restore_flags(flags); @@ -715,44 +636,44 @@ if ( len != sizeof(struct ip_fw) ) { #ifdef DEBUG_CONFIG_IP_FIREWALL - printf("ip_fw_ctl: len=%d, want %d\n",m->m_len, + printk("ip_fw_ctl: len=%d, want %d\n",m->m_len, sizeof(struct ip_fw)); #endif return(NULL); } - if ( (frwl->flags & ~IP_FW_F_MASK) != 0 ) + if ( (frwl->fw_flg & ~IP_FW_F_MASK) != 0 ) { #ifdef DEBUG_CONFIG_IP_FIREWALL - printf("ip_fw_ctl: undefined flag bits set (flags=%x)\n", - frwl->flags); + printk("ip_fw_ctl: undefined flag bits set (flags=%x)\n", + frwl->fw_flg); #endif return(NULL); } - if ( (frwl->flags & IP_FW_F_SRNG) && frwl->n_src_p < 2 ) + if ( (frwl->fw_flg & IP_FW_F_SRNG) && frwl->fw_nsp < 2 ) { #ifdef DEBUG_CONFIG_IP_FIREWALL - printf("ip_fw_ctl: src range set but n_src_p=%d\n", - frwl->n_src_p); + printk("ip_fw_ctl: src range set but n_src_p=%d\n", + frwl->fw_nsp); #endif return(NULL); } - if ( (frwl->flags & IP_FW_F_DRNG) && frwl->n_dst_p < 2 ) + if ( (frwl->fw_flg & IP_FW_F_DRNG) && frwl->fw_ndp < 2 ) { #ifdef DEBUG_CONFIG_IP_FIREWALL - printf("ip_fw_ctl: dst range set but n_dst_p=%d\n", - frwl->n_dst_p); + printk("ip_fw_ctl: dst range set but n_dst_p=%d\n", + frwl->fw_ndp); #endif return(NULL); } - if ( frwl->n_src_p + frwl->n_dst_p > IP_FW_MAX_PORTS ) + if ( frwl->fw_nsp + frwl->fw_ndp > IP_FW_MAX_PORTS ) { #ifdef DEBUG_CONFIG_IP_FIREWALL - printf("ip_fw_ctl: too many ports (%d+%d)\n", - frwl->n_src_p,frwl->n_dst_p); + printk("ip_fw_ctl: too many ports (%d+%d)\n", + frwl->fw_nsp,frwl->fw_ndp); #endif return(NULL); } @@ -764,6 +685,12 @@ #ifdef CONFIG_IP_ACCT + +int ip_acct_cnt(struct iphdr *iph, struct device *dev, struct ip_fw *f) +{ + return ip_fw_chk(iph, dev, f, 0); +} + int ip_acct_ctl(int stage, void *m, int len) { if ( stage == IP_ACCT_FLUSH ) @@ -839,8 +766,6 @@ { int *tmp_policy_ptr; tmp_policy_ptr=(int *)m; - if ((*tmp_policy_ptr)!=1 && (*tmp_policy_ptr)!=0) - return (EINVAL); if ( stage == IP_FW_POLICY_BLK ) ip_fw_blk_policy=*tmp_policy_ptr; else @@ -872,7 +797,7 @@ return(EINVAL); } - if ( ip_fw_chk(ip, + if ( ip_fw_chk(ip, NULL, stage == IP_FW_CHK_BLK ? ip_fw_blk_chain : ip_fw_fwd_chain, stage == IP_FW_CHK_BLK ? @@ -912,7 +837,7 @@ * Should be panic but... (Why are BSD people panic obsessed ??) */ #ifdef DEBUG_CONFIG_IP_FIREWALL - printf("ip_fw_ctl: unknown request %d\n",stage); + printk("ip_fw_ctl: unknown request %d\n",stage); #endif return(EINVAL); } @@ -968,16 +893,16 @@ while(i!=NULL) { - len+=sprintf(buffer+len,"%08lX/%08lX->%08lX/%08lX %X ", - ntohl(i->src.s_addr),ntohl(i->src_mask.s_addr), - ntohl(i->dst.s_addr),ntohl(i->dst_mask.s_addr), - i->flags); + len+=sprintf(buffer+len,"%08lX/%08lX->%08lX/%08lX %08lX %X ", + ntohl(i->fw_src.s_addr),ntohl(i->fw_smsk.s_addr), + ntohl(i->fw_dst.s_addr),ntohl(i->fw_dmsk.s_addr), + ntohl(i->fw_via.s_addr),i->fw_flg); len+=sprintf(buffer+len,"%u %u %lu %lu ", - i->n_src_p,i->n_dst_p, i->p_cnt,i->b_cnt); + i->fw_nsp,i->fw_ndp, i->fw_pcnt,i->fw_bcnt); len+=sprintf(buffer+len,"%u %u %u %u %u %u %u %u %u %u\n", - i->ports[0],i->ports[1],i->ports[2],i->ports[3], - i->ports[4],i->ports[5],i->ports[6],i->ports[7], - i->ports[8],i->ports[9]); + i->fw_pts[0],i->fw_pts[1],i->fw_pts[2],i->fw_pts[3], + i->fw_pts[4],i->fw_pts[5],i->fw_pts[6],i->fw_pts[7], + i->fw_pts[8],i->fw_pts[9]); pos=begin+len; if(posp_cnt=0L; - i->b_cnt=0L; + i->fw_pcnt=0L; + i->fw_bcnt=0L; } if(pos>offset+length) break; - i=i->next; + i=i->fw_next; } restore_flags(flags); *start=buffer+(offset-begin); @@ -1005,23 +930,38 @@ #ifdef CONFIG_IP_ACCT -int ip_acct_procinfo(char *buffer, char **start, off_t offset, int length, int reset) +int ip_acct_procinfo(char *buffer, char **start, off_t offset, int length) { - return ip_chain_procinfo(IP_INFO_ACCT,buffer,start,offset,length,reset); + return ip_chain_procinfo(IP_INFO_ACCT, buffer,start,offset,length,0); } +int ip_acct0_procinfo(char *buffer, char **start, off_t offset, int length) +{ + return ip_chain_procinfo(IP_INFO_ACCT, buffer,start,offset,length,1); +} + #endif #ifdef CONFIG_IP_FIREWALL -int ip_fw_blk_procinfo(char *buffer, char **start, off_t offset, int length, int reset) +int ip_fw_blk_procinfo(char *buffer, char **start, off_t offset, int length) +{ + return ip_chain_procinfo(IP_INFO_BLK, buffer,start,offset,length,0); +} + +int ip_fw_blk0_procinfo(char *buffer, char **start, off_t offset, int length) +{ + return ip_chain_procinfo(IP_INFO_BLK, buffer,start,offset,length,1); +} + +int ip_fw_fwd_procinfo(char *buffer, char **start, off_t offset, int length) { - return ip_chain_procinfo(IP_INFO_BLK,buffer,start,offset,length,reset); + return ip_chain_procinfo(IP_INFO_FWD, buffer,start,offset,length,0); } -int ip_fw_fwd_procinfo(char *buffer, char **start, off_t offset, int length, int reset) +int ip_fw_fwd0_procinfo(char *buffer, char **start, off_t offset, int length) { - return ip_chain_procinfo(IP_INFO_FWD,buffer,start,offset,length,reset); + return ip_chain_procinfo(IP_INFO_FWD, buffer,start,offset,length,1); } #endif --- linux/include/linux/ip_fw.h Sun Feb 5 12:44:40 1995 +++ linux-old/include/linux/ip_fw.h Sat Feb 11 20:43:58 1995 @@ -7,6 +7,12 @@ * * Ported from BSD to Linux, * Alan Cox 22/Nov/1994. + * Merged and included the FreeBSD-Current changes at Urgen's request + * (but hey its a lot cleaner now). Urgen would prefer in some ways + * we waited for his final product but since Linux 1.2.0 is about to + * appear its not practical - Read: It works, its not clean but please + * don't consider it to be his standard of finished work. + * Alan. * * All the real work was done by ..... */ @@ -38,43 +44,46 @@ struct ip_fw { - struct ip_fw *next; /* Next firewall on chain */ - struct in_addr src, dst; /* Source and destination IP addr */ - struct in_addr src_mask, dst_mask; /* Mask for src and dest IP addr */ - unsigned short flags; /* Flags word */ - unsigned short n_src_p, n_dst_p; /* # of src ports and # of dst ports */ + struct ip_fw *fw_next; /* Next firewall on chain */ + struct in_addr fw_src, fw_dst; /* Source and destination IP addr */ + struct in_addr fw_smsk, fw_dmsk; /* Mask for src and dest IP addr */ + struct in_addr fw_via; /* IP address of interface "via" */ + unsigned short fw_flg; /* Flags word */ + unsigned short fw_nsp, fw_ndp; /* N'of src ports and # of dst ports */ /* in ports array (dst ports follow */ /* src ports; max of 10 ports in all; */ /* count of 0 means match all ports) */ #define IP_FW_MAX_PORTS 10 /* A reasonable maximum */ - unsigned short ports[IP_FW_MAX_PORTS]; /* Array of port numbers to match */ - unsigned long p_cnt,b_cnt; /* Packet and byte counters */ + unsigned short fw_pts[IP_FW_MAX_PORTS]; /* Array of port numbers to match */ + unsigned long fw_pcnt,fw_bcnt; /* Packet and byte counters */ }; /* * Values for "flags" field . */ -#define IP_FW_F_ALL 0x00 /* This is a universal packet firewall*/ -#define IP_FW_F_TCP 0x01 /* This is a TCP packet firewall */ -#define IP_FW_F_UDP 0x02 /* This is a UDP packet firewall */ -#define IP_FW_F_ICMP 0x03 /* This is a ICMP packet firewall */ -#define IP_FW_F_KIND 0x03 /* Mask to isolate firewall kind */ -#define IP_FW_F_ACCEPT 0x04 /* This is an accept firewall (as * +#define IP_FW_F_ALL 0x000 /* This is a universal packet firewall*/ +#define IP_FW_F_TCP 0x001 /* This is a TCP packet firewall */ +#define IP_FW_F_UDP 0x002 /* This is a UDP packet firewall */ +#define IP_FW_F_ICMP 0x003 /* This is a ICMP packet firewall */ +#define IP_FW_F_KIND 0x003 /* Mask to isolate firewall kind */ +#define IP_FW_F_ACCEPT 0x004 /* This is an accept firewall (as * * opposed to a deny firewall)* * */ -#define IP_FW_F_SRNG 0x08 /* The first two src ports are a min * +#define IP_FW_F_SRNG 0x008 /* The first two src ports are a min * * and max range (stored in host byte * * order). * * */ -#define IP_FW_F_DRNG 0x10 /* The first two dst ports are a min * +#define IP_FW_F_DRNG 0x010 /* The first two dst ports are a min * * and max range (stored in host byte * * order). * * (ports[0] <= port <= ports[1]) * * */ -#define IP_FW_F_PRN 0x20 /* In verbose mode print this firewall*/ -#define IP_FW_F_BIDIR 0x40 /* For accounting-count two way */ -#define IP_FW_F_MASK 0x7F /* All possible flag bits mask */ +#define IP_FW_F_PRN 0x020 /* In verbose mode print this firewall*/ +#define IP_FW_F_BIDIR 0x040 /* For accounting-count two way */ +#define IP_FW_F_TCPSYN 0x080 /* For tcp packets-check SYN only */ +#define IP_FW_F_ICMPRPL 0x100 /* Send back icmp unreachable packet */ +#define IP_FW_F_MASK 0x1FF /* All possible flag bits mask */ /* * New IP firewall options for [gs]etsockopt at the RAW IP level. @@ -116,14 +125,14 @@ extern struct ip_fw *ip_fw_fwd_chain; extern int ip_fw_blk_policy; extern int ip_fw_fwd_policy; -extern int ip_fw_chk(struct iphdr *, struct ip_fw *, int); extern int ip_fw_ctl(int, void *, int); #endif #ifdef CONFIG_IP_ACCT extern struct ip_fw *ip_acct_chain; -extern void ip_acct_cnt(struct iphdr *, struct ip_fw *); +extern int ip_acct_cnt(struct iphdr *, struct device *, struct ip_fw *); extern int ip_acct_ctl(int, void *, int); #endif +extern int ip_fw_chk(struct iphdr *, struct device *rif,struct ip_fw *, int); #endif /* KERNEL */ #endif /* _IP_FW_H */ --- linux/net/inet/ip.c Sun Feb 5 12:44:40 1995 +++ linux-old/net/inet/ip.c Sun Feb 12 21:01:50 1995 @@ -1262,14 +1219,18 @@ struct rtable *rt; /* Route we use */ unsigned char *ptr; /* Data pointer */ unsigned long raddr; /* Router IP address */ - + /* * See if we are allowed to forward this. */ #ifdef CONFIG_IP_FIREWALL - if(!ip_fw_chk(skb->h.iph, ip_fw_fwd_chain, ip_fw_fwd_policy)) + int err; + + if((err=ip_fw_chk(skb->h.iph, dev, ip_fw_fwd_chain, ip_fw_fwd_policy))!=1) { + if(err==-1) + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, dev); return; } #endif @@ -1425,7 +1386,7 @@ * Count mapping we shortcut */ - ip_acct_cnt(iph,ip_acct_chain); + ip_acct_cnt(iph,dev,ip_acct_chain); #endif /* @@ -1462,6 +1423,9 @@ take up stack space. */ int brd=IS_MYADDR; int is_frag=0; +#ifdef CONFIG_IP_FIREWALL + int err; +#endif ip_statistics.IpInReceives++; @@ -1493,9 +1457,11 @@ #ifdef CONFIG_IP_FIREWALL - if(!LOOPBACK(iph->daddr) && !ip_fw_chk(iph,ip_fw_blk_chain, - ip_fw_blk_policy)) + if( + (err=ip_fw_chk(iph,dev,ip_fw_blk_chain,ip_fw_blk_policy))!=1) { + if(err==-1) + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0, dev); kfree_skb(skb, FREE_WRITE); return 0; } @@ -1609,7 +1575,7 @@ */ #ifdef CONFIG_IP_ACCT - ip_acct_cnt(iph,ip_acct_chain); + ip_acct_cnt(iph,dev, ip_acct_chain); #endif /* @@ -1906,7 +1872,7 @@ ip_statistics.IpOutRequests++; #ifdef CONFIG_IP_ACCT - ip_acct_cnt(iph,ip_acct_chain); + ip_acct_cnt(iph,dev, ip_acct_chain); #endif #ifdef CONFIG_IP_MULTICAST