diff --git a/sbin/ipfw/ipfw.c b/sbin/ipfw/ipfw.c index 6178dc3971f4..d4e3f1c047d8 100644 --- a/sbin/ipfw/ipfw.c +++ b/sbin/ipfw/ipfw.c @@ -53,10 +53,11 @@ typedef enum { } ipf_kind; int do_resolv=1; +int do_verbose=0; show_usage() { -fprintf(stderr,"ipfw: [-n] \n"); +fprintf(stderr,"ipfw: [-nv] \n"); } @@ -744,6 +745,8 @@ add(ipf_kind kind, int socket_fd, char **argv) if ( *argv == NULL ) { firewall.flags = protocol | accept_firewall | src_range | dst_range; + if (do_verbose) + firewall.flags=firewall.flags | IP_FIREWALL_PRINT; (void)do_setsockopt( socket_fd, IPPROTO_IP, kind == IPF_BLOCKING ? IP_FW_ADD_BLK : IP_FW_ADD_FWD, @@ -896,11 +899,11 @@ if (b!=0 && b!=1) exit(1); } - if (strncmp(argv[0],"deny",strlen(argv[0]))) - p=1; - else - if (strncmp(argv[0],"accept",strlen(argv[0]))) + if (!strncmp(argv[0],"deny",strlen(argv[0]))) p=0; + else + if (!strncmp(argv[0],"accept",strlen(argv[0]))) + p=1; else { fprintf(stderr,"usage: ipfw policy [deny|accept]\n"); @@ -924,6 +927,9 @@ char **argv; int socket_fd; struct ip_firewall *data,*fdata; char **str; + extern char *optarg; + extern int optind; + int ch; socket_fd = socket( AF_INET, SOCK_RAW, IPPROTO_RAW ); @@ -937,13 +943,20 @@ char **argv; exit(1); } - if (!strcmp(argv[1],"-n")) - { - str=&argv[2]; - do_resolv=0; - } - else - str=&argv[1]; + while ((ch = getopt(argc, argv, "vn")) != EOF) + switch(ch) { + case 'n': + do_resolv=0; + break; + case 'v': + do_verbose=1; + break; + case '?': + default: + show_usage(); + } + + str=argv+optind; if (str[0]==NULL) { @@ -959,6 +972,7 @@ char **argv; (void)do_setsockopt( socket_fd, IPPROTO_IP, IP_FW_FLUSH, NULL, 0, 0 ); + printf("All entries flushed.\n"); } else if ( strlen(str[0]) >= strlen("checkb") && strncmp(str[0],"checkblocking",strlen(str[0])) == 0 ) { diff --git a/sys/netinet/ip_fw.c b/sys/netinet/ip_fw.c index a1f9355b1c53..2f4b5e5be8d5 100644 --- a/sys/netinet/ip_fw.c +++ b/sys/netinet/ip_fw.c @@ -89,12 +89,14 @@ int range_flag; * Returns 0 if packet should be dropped, 1 if it should be accepted */ +#ifdef old int ip_firewall_check_print(ip,chain) struct ip *ip; struct ip_firewall *chain; { - if ( !ip_firewall_check_noprint(ip,chain) ) { +struct ip_firewall *fwtmp; + if ( !ip_firewall_check_noprint(ip,chain,&fwtmp) ) { u_short *portptr = (u_short *)&(((u_int *)ip)[ip->ip_hl]); @@ -121,7 +123,9 @@ struct ip_firewall *chain; return(1); } -int ip_firewall_check_noprint(ip,chain) +#endif + +int ip_firewall_check(ip,chain) struct ip *ip; struct ip_firewall *chain; { @@ -130,6 +134,9 @@ struct ip_firewall *chain; int firewall_proto, proto = 0; register struct ip_firewall *fptr; u_short src_port = 0, dst_port = 0; +#ifdef IPFIREWALL_VERBOSE + u_short *portptr = (u_short *)&(((u_int *)ip)[ip->ip_hl]); +#endif if ( chain == NULL ) { /* Is there a firewall chain? */ return(1); @@ -172,12 +179,31 @@ struct ip_firewall *chain; #ifdef DEBUG_IPFIREWALL printf("universal firewall match\n"); #endif -#ifdef olf - return( (fptr->flags & IP_FIREWALL_ACCEPT) == IP_FIREWALL_ACCEPT ); -#else - return( fptr->flags & IP_FIREWALL_ACCEPT ); +#ifdef IPFIREWALL_VERBOSE + if ( !(fptr->flags & IP_FIREWALL_ACCEPT) && + (fptr->flags & IP_FIREWALL_PRINT)) { + printf("ip_firewall_check says no to "); + switch(ip->ip_p) { + 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->ip_p); break; + } + print_ip(ip->ip_src); + if ( ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP ) { + printf(":%d ",ntohs(portptr[0])); + } else { + printf("\n"); + } + print_ip(ip->ip_dst); + if ( ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP ) { + printf(":%d ",ntohs(portptr[1])); + } + printf("\n"); + return(0); + } #endif - + return( fptr->flags & IP_FIREWALL_ACCEPT ); } else { /* Specific firewall - packet's protocol must match firewall's */ @@ -234,12 +260,31 @@ struct ip_firewall *chain; ) ) { -#ifdef old - return( (fptr->flags & IP_FIREWALL_ACCEPT) == IP_FIREWALL_ACCEPT ); - -#else - return( fptr->flags & IP_FIREWALL_ACCEPT); +#ifdef IPFIREWALL_VERBOSE + if ( !(fptr->flags & IP_FIREWALL_ACCEPT) && + (fptr->flags & IP_FIREWALL_PRINT)) { + printf("ip_firewall_check says no to "); + switch(ip->ip_p) { + 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->ip_p); break; + } + print_ip(ip->ip_src); + if ( ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP ) { + printf(":%d ",ntohs(portptr[0])); + } else { + printf("\n"); + } + print_ip(ip->ip_dst); + if ( ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP ) { + printf(":%d ",ntohs(portptr[1])); + } + printf("\n"); + return(0); + } #endif + return( fptr->flags & IP_FIREWALL_ACCEPT); } } @@ -261,11 +306,31 @@ struct ip_firewall *chain; * handles this case). */ -#ifdef old - return( ((chain->flags) & IP_FIREWALL_ACCEPT) != IP_FIREWALL_ACCEPT ); -#else - return(ip_fw_policy); +#ifdef IPFIREWALL_VERBOSE + if ( !(ip_fw_policy) && + (fptr->flags & IP_FIREWALL_PRINT)) { + printf("ip_firewall_check says no to "); + switch(ip->ip_p) { + 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->ip_p); break; + } + print_ip(ip->ip_src); + if ( ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP ) { + printf(":%d ",ntohs(portptr[0])); + } else { + printf("\n"); + } + print_ip(ip->ip_dst); + if ( ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP ) { + printf(":%d ",ntohs(portptr[1])); + } + printf("\n"); + return(0); + } #endif + return(ip_fw_policy); } @@ -291,6 +356,12 @@ struct ip_firewall *firewall; { struct ip_firewall *ftmp; struct ip_firewall *chaintmp=NULL; + struct ip_firewall *chaintmp_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 oldkind,newkind; + int addb4=0; + int n_o,n_n; ftmp = malloc( sizeof(struct ip_firewall), M_SOOPTS, M_DONTWAIT ); if ( ftmp == NULL ) { @@ -307,26 +378,108 @@ struct ip_firewall *firewall; } else { - /* - * This made so to get firewall behavior more *human* oriented- - * as to speed up the packet check the first firewall matching - * the packet used to determine ALLOW/DENY condition,and one - * tends to set up more specific firewall later then more general - * this change allows adding firewalls to the head of chain so - * that the first matching is last added in line of matching - * firewalls.This change is not real turn in behavior but helps - * to use firewall efficiently. - */ -#ifdef old - chaintmp=*chainptr; - while(chaintmp->next!=NULL) - chaintmp=chaintmp->next; - chaintmp->next=ftmp; + chaintmp_prev=NULL; + for (chaintmp=*chainptr;chaintmp!=NULL;chaintmp=chaintmp->next) { + + addb4=0; + + newkind=ftmp->flags & IP_FIREWALL_KIND; + oldkind=chaintmp->flags & IP_FIREWALL_KIND; + + if (newkind!=IP_FIREWALL_UNIVERSAL + && oldkind!=IP_FIREWALL_UNIVERSAL + && oldkind!=newkind) + continue; + /* + * Very very *UGLY* code... + * 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(chaintmp->src.s_addr); + o_da=ntohl(chaintmp->dst.s_addr); + o_sm=ntohl(chaintmp->src_mask.s_addr); + o_dm=ntohl(chaintmp->dst_mask.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_FIREWALL_UNIVERSAL && + oldkind==IP_FIREWALL_UNIVERSAL) + addb4++; + if (newkind==oldkind && (oldkind==IP_FIREWALL_TCP + || oldkind==IP_FIREWALL_UDP)) { + if ( (!(ftmp->flags & IP_FIREWALL_SRC_RANGE) + && ftmp->num_src_ports>0) + || (!(ftmp->flags & IP_FIREWALL_DST_RANGE) + && ftmp->num_dst_ports>0)) + addb4++; + if ((ftmp->flags & IP_FIREWALL_SRC_RANGE) && + (chaintmp->flags & IP_FIREWALL_SRC_RANGE)) + if ((ftmp->ports[1]-ftmp->ports[0])< + (chaintmp->ports[1]-chaintmp->ports[0])) + addb4++; + n_n=ftmp->num_src_ports; + n_o=chaintmp->num_src_ports; + if ((n_n>(IP_FIREWALL_MAX_PORTS-2)) || + (n_o>(IP_FIREWALL_MAX_PORTS-2))) + goto skip_1_check; + /* + * Actually this cannot happen as the firewall control + * procedure checks for number of ports in source and + * destination range but we will try to be more safe. + */ + if ((ftmp->flags & IP_FIREWALL_DST_RANGE) && + (chaintmp->flags & IP_FIREWALL_DST_RANGE)) + if ((ftmp->ports[n_n+1]-ftmp->ports[n_n])< + (chaintmp->ports[n_o+1]-chaintmp->ports[n_o])) + addb4++; + +skip_1_check: + } + } + if (addb4>0) { + if (chaintmp_prev) { + chaintmp_prev->next=ftmp; + ftmp->next=chaintmp; + } else { + *chainptr=ftmp; + ftmp->next=chaintmp; + } + return 0; + } + chaintmp_prev=chaintmp; + } + if (chaintmp_prev) + chaintmp_prev->next=ftmp; + else +#define wrong +#ifdef wrong + *chainptr=ftmp; #else - chaintmp=*chainptr; - *chainptr=ftmp; - ftmp->next=chaintmp; + panic("Can't happen"); #endif +#undef wrong } return(0); } @@ -422,6 +575,8 @@ if ( stage == IP_FW_FLUSH ) if ( stage == IP_FW_POLICY ) { tmp_policy_ptr=mtod(m,int *); + if ((*tmp_policy_ptr)!=1 && (*tmp_policy_ptr)!=0) + return ( EINVAL ); ip_fw_policy=*tmp_policy_ptr; return 0; } diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h index f1ecfc717509..fa2c36b04a49 100644 --- a/sys/netinet/ip_fw.h +++ b/sys/netinet/ip_fw.h @@ -19,6 +19,8 @@ * flags and num_*_ports are stored in host byte order (of course). * Port numbers are stored in HOST byte order. */ +#ifndef _IP_FW_H +#define _IP_FW_H struct ip_firewall { struct ip_firewall *next; /* Next firewall on chain */ @@ -41,7 +43,8 @@ struct ip_firewall { * order). * (ports[0] <= port <= ports[1]) */ -#define IP_FIREWALL_FLAG_BITS 0x1f /* All possible flag bits */ +#define IP_FIREWALL_PRINT 32 /* In verbos mode print this firewall */ +#define IP_FIREWALL_FLAG_BITS 0x2f /* All possible flag bits */ u_short num_src_ports, num_dst_ports;/* # of src ports and # of dst ports */ /* in ports array (dst ports follow */ /* src ports; max of 10 ports in all; */ @@ -69,9 +72,4 @@ extern struct ip_firewall *ip_fw_blk_chain; extern struct ip_firewall *ip_fw_fwd_chain; extern int ip_fw_policy; -#ifdef IPFIREWALL_VERBOSE -#define ip_firewall_check ip_firewall_check_print -#else -#define ip_firewall_check ip_firewall_check_noprint #endif -