diff --git a/sbin/ipfw/ipfw.c b/sbin/ipfw/ipfw.c index 68cb7ef39ba0..a74d62ea6aaf 100644 --- a/sbin/ipfw/ipfw.c +++ b/sbin/ipfw/ipfw.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 1996 Alex Nash * Copyright (c) 1996 Poul-Henning Kamp * Copyright (c) 1994 Ugen J.S.Antsilevich * Idea and grammar partially left from: @@ -15,7 +16,7 @@ * * NEW command line interface for IP firewall facility * - * $Id: ipfw.c,v 1.23 1996/04/03 13:49:10 phk Exp $ + * $Id: ipfw.c,v 1.24 1996/05/11 20:31:55 phk Exp $ * */ @@ -27,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +42,7 @@ char progname[BUFSIZ]; /* Program name for errors */ int s; /* main RAW socket */ int do_resolv=0; /* Would try to resolv all */ int do_acct=0; /* Show packet/byte count */ +int do_time=0; /* Show time stamps */ int mask_bits(m_ad) @@ -62,6 +65,40 @@ mask_bits(m_ad) return h_num; } +void +print_port(port, comma, flg) + u_short port,flg; + const char *comma; +{ + int printed = 0; + + if (do_resolv) { + struct servent *se; + const char *protocol; + + switch (flg & IP_FW_F_KIND) { + case IP_FW_F_TCP: + protocol = "tcp"; + break; + case IP_FW_F_UDP: + protocol = "udp"; + break; + default: + protocol = NULL; + break; + } + + se = getservbyport(htons(port), protocol); + + if (se) { + printf("%s%s", comma, se->s_name); + printed = 1; + } + } + if (!printed) + printf("%s%d",comma,port); +} + void show_ipfw(chain) struct ip_fw *chain; @@ -71,12 +108,28 @@ show_ipfw(chain) struct hostent *he; int i,mb; + if (do_resolv) + setservent(1/*stayopen*/); printf("%05u ", chain->fw_number); if (do_acct) printf("%10lu %10lu ",chain->fw_pcnt,chain->fw_bcnt); + if (do_time) + { + if (chain->timestamp) + { + char timestr[30]; + + strcpy(timestr, ctime((time_t *)&chain->timestamp)); + *strchr(timestr, '\n') = '\0'; + printf("%s ", timestr); + } + else + printf(" "); + } + if (chain->fw_flg & IP_FW_F_ACCEPT) printf("allow"); else if (chain->fw_flg & IP_FW_F_ICMPRPL) @@ -136,7 +189,7 @@ show_ipfw(chain) comma = " "; for (i=0;ifw_nsp; i++ ) { - printf("%s%d",comma,chain->fw_pts[i]); + print_port(chain->fw_pts[i], comma, chain->fw_flg); if (i==0 && (chain->fw_flg & IP_FW_F_SRNG)) comma = "-"; else @@ -174,7 +227,7 @@ show_ipfw(chain) comma = " "; for (i=0;ifw_ndp;i++) { - printf("%s%d",comma,chain->fw_pts[chain->fw_nsp+i]); + print_port(chain->fw_pts[chain->fw_nsp+i], comma, chain->fw_flg); if (i==0 && (chain->fw_flg & IP_FW_F_DRNG)) comma = "-"; else @@ -193,7 +246,10 @@ show_ipfw(chain) printf(" via "); strncpy(ifnb,chain->fw_via_name,FW_IFNLEN); ifnb[FW_IFNLEN]='\0'; - printf("%s%d",ifnb,chain->fw_via_unit); + if (chain->fw_flg & IP_FW_F_IFUWILD) + printf("%s*",ifnb); + else + printf("%s%d",ifnb,chain->fw_via_unit); } else if (chain->fw_via_ip.s_addr) { printf(" via "); printf(inet_ntoa(chain->fw_via_ip)); @@ -242,7 +298,22 @@ show_ipfw(chain) if (chain->fw_tcpf & IP_FW_TCPF_URG) PRINTFLG("urg"); if (chain->fw_tcpnf & IP_FW_TCPF_URG) PRINTFLG("!urg"); } + if (chain->fw_flg & IP_FW_F_ICMPBIT) { + int type_index; + int first = 1; + + printf(" icmptype"); + + for (type_index = 0; type_index < 256; ++type_index) + if (chain->fw_icmptypes[type_index / (sizeof(unsigned) * 8)] & + (1U << (type_index % (sizeof(unsigned) * 8)))) { + printf("%c%d", first == 1 ? ' ' : ',', type_index); + first = 0; + } + } printf("\n"); + if (do_resolv) + endservent(); } void @@ -281,15 +352,16 @@ show_usage(str) "\trule:\taction proto src dst extras...\n" "\t\taction: {allow|deny|reject|count} [log]\n" "\t\tproto: {ip|tcp|udp|icmp}}\n" -"\t\tsrc: from {any|ip[{/bits|:mask}]} [{port|port-port},...]\n" -"\t\tdst: to {any|ip[{/bits|:mask}]} [{port|port-port},...]\n" +"\t\tsrc: from {any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n" +"\t\tdst: to {any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n" "\textras:\n" "\t\tfragment\n" "\t\t{in|out|inout}\n" "\t\tvia {ifname|ip}\n" "\t\t{established|setup}\n" -"\t\ttcpflags [!]{syn|fin|rst|ack|psh},...\n" +"\t\ttcpflags [!]{syn|fin|rst|ack|psh|urg},...\n" "\t\tipoptions [!]{ssrr|lsrr|rr|ts},...\n" +"\t\ticmptypes {type},...\n" , progname ); @@ -298,6 +370,21 @@ show_usage(str) exit (1); } +int +lookup_host (host, ipaddr) + char *host; + struct in_addr *ipaddr; +{ + struct hostent *he = gethostbyname(host); + + if (!he) + return(-1); + + *ipaddr = *(struct in_addr *)he->h_addr_list[0]; + + return(0); +} + void fill_ip(ipno, mask, acp, avp) struct in_addr *ipno, *mask; @@ -319,7 +406,7 @@ fill_ip(ipno, mask, acp, avp) *p++ = '\0'; } - if (!inet_aton(*av,ipno)) + if (lookup_host(*av,ipno) != 0) show_usage("ip number\n"); if (md == ':' && !inet_aton(p,mask)) show_usage("ip number\n"); @@ -349,7 +436,7 @@ fill_port(cnt, ptr, off, arg) u_short *cnt, *ptr, off; char *arg; { - char *s, *comma; + char *s; int initial_range = 0; s = strchr(arg,'-'); @@ -385,6 +472,19 @@ fill_tcpflag(set, reset, vp) u_char *d; while (p && *p) { + struct tpcflags { + char * name; + u_char value; + } flags[] = { + { "syn", IP_FW_TCPF_SYN }, + { "fin", IP_FW_TCPF_FIN }, + { "ack", IP_FW_TCPF_ACK }, + { "psh", IP_FW_TCPF_PSH }, + { "rst", IP_FW_TCPF_RST }, + { "urg", IP_FW_TCPF_URG } + }; + int i; + if (*p == '!') { p++; d = reset; @@ -394,11 +494,13 @@ fill_tcpflag(set, reset, vp) q = strchr(p, ','); if (q) *q++ = '\0'; - if (!strncmp(p,"syn",strlen(p))) *d |= IP_FW_TCPF_SYN; - if (!strncmp(p,"fin",strlen(p))) *d |= IP_FW_TCPF_FIN; - if (!strncmp(p,"ack",strlen(p))) *d |= IP_FW_TCPF_ACK; - if (!strncmp(p,"psh",strlen(p))) *d |= IP_FW_TCPF_PSH; - if (!strncmp(p,"rst",strlen(p))) *d |= IP_FW_TCPF_RST; + for (i = 0; i < sizeof(flags) / sizeof(flags[0]); ++i) + if (!strncmp(p, flags[i].name, strlen(p))) { + *d |= flags[i].value; + break; + } + if (i == sizeof(flags) / sizeof(flags[0])) + show_usage("invalid tcp flag\n"); p = q; } } @@ -429,6 +531,35 @@ fill_ipopt(set, reset, vp) } } +void +fill_icmptypes(types, vp, fw_flg) + u_long *types; + char **vp; + u_short *fw_flg; +{ + char *c = *vp; + + while (*c) + { + unsigned long icmptype; + + if ( *c == ',' ) + ++c; + + icmptype = strtoul(c, &c, 0); + + if ( *c != ',' && *c != '\0' ) + show_usage("invalid ICMP type"); + + if (icmptype > 255) + show_usage("ICMP types are between 0 and 255 inclusive"); + + types[icmptype / (sizeof(unsigned) * 8)] |= + 1 << (icmptype % (sizeof(unsigned) * 8)); + *fw_flg |= IP_FW_F_ICMPBIT; + } +} + void delete(ac,av) int ac; @@ -537,9 +668,12 @@ add(ac,av) char *q; strcpy(rule.fw_via_name, *av); - for (q = rule.fw_via_name; *q && !isdigit(*q); q++) + for (q = rule.fw_via_name; *q && !isdigit(*q) && *q != '*'; q++) continue; - rule.fw_via_unit = atoi(q); + if (*q == '*') + rule.fw_flg = IP_FW_F_IFUWILD; + else + rule.fw_via_unit = atoi(q); *q = '\0'; rule.fw_flg |= IP_FW_F_IFNAME; } else if (inet_aton(*av,&rule.fw_via_ip) == INADDR_NONE) { @@ -579,6 +713,13 @@ add(ac,av) av++; ac--; continue; } } + if ((rule.fw_flg & IP_FW_F_KIND) == IP_FW_F_ICMP) { + if (ac > 1 && !strncmp(*av,"icmptypes",strlen(*av))) { + av++; ac--; + fill_icmptypes(rule.fw_icmptypes, av, &rule.fw_flg); + av++; ac--; continue; + } + } printf("%d %s\n",ac,*av); show_usage("Unknown argument\n"); } @@ -589,6 +730,40 @@ add(ac,av) err(1,"setsockopt(IP_FW_ADD)"); } +void +zero (ac, av) + int ac; + char **av; +{ + av++; ac--; + + if (!ac) { + /* clear all entries */ + if (setsockopt(s,IPPROTO_IP,IP_FW_ZERO,NULL,0)<0) { + fprintf(stderr,"%s: setsockopt failed.\n",progname); + exit(1); + } + printf("Accounting cleared.\n"); + } else { + /* clear a specific entry */ + struct ip_fw rule; + + memset(&rule, 0, sizeof rule); + + /* Rule number */ + if (isdigit(**av)) { + rule.fw_number = atoi(*av); av++; ac--; + + if (setsockopt(s, IPPROTO_IP, IP_FW_ZERO, &rule, sizeof rule)) + err(1, "setsockopt(Zero)"); + printf("Entry %d cleared\n", rule.fw_number); + } + else { + show_usage("expected number"); + } + } +} + int ipfw_main(ac,av) int ac; @@ -603,11 +778,14 @@ ipfw_main(ac,av) show_usage(NULL); } - while ((ch = getopt(ac, av ,"aN")) != EOF) + while ((ch = getopt(ac, av ,"atN")) != EOF) switch(ch) { case 'a': do_acct=1; break; + case 't': + do_time=1; + break; case 'N': do_resolv=1; break; @@ -632,11 +810,7 @@ ipfw_main(ac,av) } printf("Flushed all rules.\n"); } else if (!strncmp(*av, "zero", strlen(*av))) { - if (setsockopt(s,IPPROTO_IP,IP_FW_ZERO,NULL,0)<0) { - fprintf(stderr,"%s: setsockopt failed.\n",progname); - exit(1); - } - printf("Accounting cleared.\n"); + zero(ac,av); } else if (!strncmp(*av, "print", strlen(*av))) { list(--ac,++av); } else if (!strncmp(*av, "list", strlen(*av))) { @@ -662,7 +836,7 @@ main(ac, av) s = socket( AF_INET, SOCK_RAW, IPPROTO_RAW ); if ( s < 0 ) { fprintf(stderr,"%s: Can't open raw socket.\n" - "Must be root to use this programm. \n",progname); + "Must be root to use this program.\n",progname); exit(1); }