diff options
Diffstat (limited to 'sys/netinet/ip_fw.c')
-rw-r--r-- | sys/netinet/ip_fw.c | 180 |
1 files changed, 118 insertions, 62 deletions
diff --git a/sys/netinet/ip_fw.c b/sys/netinet/ip_fw.c index 155a49e..c93ed56 100644 --- a/sys/netinet/ip_fw.c +++ b/sys/netinet/ip_fw.c @@ -124,26 +124,51 @@ int range_flag; */ #ifdef IPFIREWALL -int ip_fw_chk(ip,chain) -struct ip *ip; -struct ip_fw *chain; +int ip_fw_chk(ip,rif,chain) +struct ip *ip; +struct ifnet *rif; +struct ip_fw *chain; { - struct in_addr src, dst; - char notcpsyn=1; - int frwl_proto=0, proto; - struct mbuf *m; register struct ip_fw *f; - u_short src_port=0, dst_port=0; 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; + struct mbuf *m; + 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) - return(1); /* If no chain , always say Ok to packet */ + return(1); + + /* + * 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(1); 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) + ia=rif->if_addrlist; + dprintf1("Packet "); switch(ip->ip_p) { case IPPROTO_TCP: @@ -152,21 +177,21 @@ struct ip_fw *chain; dst_port=ntohs(tcp->th_dport); if (tcp->th_flags&TH_SYN) notcpsyn=0; /* We *DO* have SYN ,value FALSE */ - proto=IP_FW_F_TCP; + prt=IP_FW_F_TCP; break; case IPPROTO_UDP: dprintf1("UDP "); src_port=ntohs(udp->uh_sport); dst_port=ntohs(udp->uh_dport); - proto=IP_FW_F_UDP; + prt=IP_FW_F_UDP; break; case IPPROTO_ICMP: dprintf2("ICMP:%u ",icmp->icmp_type); - proto=IP_FW_F_ICMP; + prt=IP_FW_F_ICMP; break; default: dprintf2("p=%d ",ip->ip_p); - proto=IP_FW_F_ALL; + prt=IP_FW_F_ALL; break; } dprint_ip(ip->ip_src); @@ -183,8 +208,43 @@ struct ip_fw *chain; for (f=chain;f;f=f->next) if ((src.s_addr&f->src_mask.s_addr)==f->src.s_addr && (dst.s_addr&f->dst_mask.s_addr)==f->dst.s_addr) { - frwl_proto=f->flags&IP_FW_F_KIND; - if (frwl_proto==IP_FW_F_ALL) { + if (f->via.s_addr && rif) { + for (ia_p=ia;ia_p;ia_p=ia_p->ifa_next) { + if (!ia_p->ifa_addr || + ia_p->ifa_addr->sa_family!=AF_INET) + /* + * Next interface adress. + * This is continue for + * local "for" + */ + continue; + ia_i.s_addr=(((struct sockaddr_in *)\ + (ia_p->ifa_addr))->sin_addr.s_addr); + if (ia_i.s_addr==f->via.s_addr) + goto via_match; + } + /* + * Next interface adress. + * This is continue for + * local "for" + */ + continue; + } else { + /* + * No special "via" adress set + * or interface from which packet + * came unknown so match anyway + */ + goto via_match; + } + /* + * Skip to next firewall entry - via + * address did not matched. + */ + continue; +via_match: + f_prt=f->flags&IP_FW_F_KIND; + if (f_prt==IP_FW_F_ALL) { /* Universal frwl - we've got a match! */ goto got_match; } else { @@ -201,9 +261,9 @@ struct ip_fw *chain; * Specific firewall - packet's * protocol must match firewall's */ - if (proto==frwl_proto) { + if (prt==f_prt) { - if (proto==IP_FW_F_ICMP || + if (prt==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, @@ -273,7 +333,7 @@ bad_packet: * Do not ICMP reply to icmp * packets....:) */ - if (frwl_proto==IP_FW_F_ICMP) + if (f_prt==IP_FW_F_ICMP) return 0; /* * Reply to packets rejected @@ -292,7 +352,7 @@ bad_packet: return 0; m->m_len = sizeof(struct ip)+64; bcopy((caddr_t)ip,mtod(m, caddr_t),(unsigned)m->m_len); - if (frwl_proto=IP_FW_F_ALL) + 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); @@ -313,41 +373,49 @@ good_packet: #ifdef IPACCT -void ip_acct_cnt(ip,chain,nh_conv) -struct ip *ip; -struct ip_fw *chain; +void ip_acct_cnt(ip,rif,chain,nh_conv) +struct ip *ip; +struct ifnet *rif; +struct ip_fw *chain; int nh_conv; { - struct in_addr src, dst; - char rev=0; - int frwl_proto, proto=0; register struct ip_fw *f; - u_short src_port=0, dst_port=0; 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) return; + if (ip->ip_off&IP_OFFMASK) + return; + src = ip->ip_src; dst = ip->ip_dst; + if (rif) + ia=rif->if_addrlist; + switch(ip->ip_p) { case IPPROTO_TCP: src_port=ntohs(tcp->th_sport); dst_port=ntohs(tcp->th_dport); - proto=IP_FW_F_TCP; + prt=IP_FW_F_TCP; break; case IPPROTO_UDP: src_port=ntohs(udp->uh_sport); dst_port=ntohs(udp->uh_dport); - proto=IP_FW_F_UDP; + prt=IP_FW_F_UDP; break; case IPPROTO_ICMP: - proto=IP_FW_F_ICMP; + prt=IP_FW_F_ICMP; break; default: - proto=IP_FW_F_ALL; + prt=IP_FW_F_ALL; break; } @@ -365,8 +433,24 @@ int nh_conv; } continue; addr_match: - frwl_proto=f->flags&IP_FW_F_KIND; - if (frwl_proto==IP_FW_F_ALL) { + if (f->via.s_addr && rif) { + for (ia_p=ia;ia_p;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->via.s_addr) + goto via_match; + } + continue; + } else { + goto via_match; + } + continue; +via_match: + f_prt=f->flags&IP_FW_F_KIND; + if (f_prt==IP_FW_F_ALL) { /* Universal frwl - we've got a match! */ f->p_cnt++; /* Rise packet count */ @@ -386,9 +470,9 @@ addr_match: * Specific firewall - packet's * protocol must match firewall's */ - if (proto==frwl_proto) { + if (prt==f_prt) { - if ((proto==IP_FW_F_ICMP || + if ((prt==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, @@ -813,34 +897,6 @@ if ( stage == IP_FW_POLICY ) return 0; } -if ( stage == IP_FW_CHK_BLK - || stage == IP_FW_CHK_FWD ) { - - struct ip *ip; - - if ( m->m_len < sizeof(struct ip) + 2 * sizeof(u_short) ) { - dprintf3("ip_fw_ctl: mbuf len=%d, want at least %d\n", - m->m_len,sizeof(struct ip) + 2 * sizeof(u_short)); - return( EINVAL ); - } - - ip = mtod(m,struct ip *); - - if ( ip->ip_hl != sizeof(struct ip) / sizeof(int) ) { - dprintf3("ip_fw_ctl: ip->ip_hl=%d, want %d\n",ip->ip_hl, - sizeof(struct ip)/sizeof(int)); - return(EINVAL); - } - - if ( ip_fw_chk(ip, - stage == IP_FW_CHK_BLK ? - ip_fw_blk_chain : ip_fw_fwd_chain ) - ) - return(0); - else - return(EACCES); - } - /* * Here we really working hard-adding new elements * to blocking/forwarding chains or deleting'em |