freebsd-skq/sbin/ipfw/ipfw.c
Ugen J.S. Antsilevich 5a9bab798e Support IP Option smatching in grammar and listing.
TcpSyn option removed and will be shortly repoaced by support of all
TCP Flags including syn and ack...
1995-10-01 21:54:05 +00:00

1247 lines
23 KiB
C

/*
* Copyright (c) 1994 Ugen J.S.Antsilevich
* Idea and grammar partially left from:
* Copyright (c) 1993 Daniel Boulet
*
* 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.
*
* NEW command line interface for IP firewall facility
*
* $Id: ipfw.c,v 1.16 1995/08/22 00:38:02 gpalmer Exp $
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include <netdb.h>
#include <kvm.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#define IPFIREWALL
#define IPACCT
#include <netinet/ip_fw.h>
#define MAXSTR 25
char progname[MAXSTR]; /* Program name for errors */
char proto_name[MAXSTR]=""; /* Current line protocol */
int s; /* main RAW socket */
int do_resolv=1; /* Would try to resolv all */
int do_short=0; /* Compact output */
int do_acct=0; /* Show packet/byte count */
int ports_ok=0; /* flag allowing ports */
u_short flags=0; /* New entry flags */
#define FW 0x001 /* Firewall action */
#define AC 0x002 /* Accounting action */
#define S_ANY "any"
#define IS_TO(x) (!strcmp(x,"to"))
#define IS_FROM(x) (!strcmp(x,"from"))
#define IS_VIA(x) (!strcmp(x,"via") || !strcmp(x,"on"))
#define IS_IPOPT(x) (!strncmp(x,"ipop",4) || !strncmp(x,"opt",3))
#define IS_TCPFLG(x) (!strncmp(x,"tcpf",4) || !strncmp(x,"fla",3))
#define IS_TOKEN(x) (IS_TO(x) || IS_FROM(x) || IS_VIA(x) ||\
IS_IPOPT(x) || IS_TCPFLG(x))
#define IPO_LSRR "ls"
#define IPO_SSRR "ss"
#define IPO_RR "rr"
#define IPO_TS "ts"
#define P_AC "a" /* of "accept" for policy action */
#define P_DE "d" /* of "deny" for policy action */
#define CH_FW "f" /* of "firewall" for chains in zero/flush */
#define CH_AC "a" /* of "accounting" for chain in zero/flush/list */
char action_tab[][MAXSTR]={
"addf",
#define A_ADDF 0
"delf",
#define A_DELF 1
"chkf",
#define A_CHKF 2
"adda",
#define A_ADDA 3
"dela",
#define A_DELA 4
"clr",
#define A_CLRA 5
"f",
#define A_FLUSH 6
"z",
#define A_ZERO 7
"l",
#define A_LIST 8
"po",
#define A_POLICY 9
"",
#define A_NONE 10
};
char type_tab[][MAXSTR]={
"acc",
#define T_ACCEPT 0
"pas",
#define T_PASS 1
"log",
#define T_LOG 2
"rej",
#define T_REJECT 3
"lrej",
#define T_LREJECT 4
"den",
#define T_DENY 5
"lden",
#define T_LDENY 6
"sin",
#define T_SINGLE 7
"bid",
#define T_BIDIR 8
"",
#define T_NONE 9
};
char proto_tab[][MAXSTR]={
"all",
#define P_ALL 0
"icmp",
#define P_ICMP 1
"tcp",
#define P_TCP 2
"udp",
#define P_UDP 3
""
#define P_NONE 4
};
struct nlist nlf[]={
#define N_FCHAIN 0
{ "_ip_fw_chain" },
#define N_POLICY 1
{ "_ip_fw_policy" },
"" ,
};
struct nlist nla[]={
#define N_ACHAIN 0
{ "_ip_acct_chain" },
"" ,
};
int mask_bits(m_ad)
struct in_addr m_ad;
{
int h_fnd=0,h_num=0,i;
u_long mask;
mask=ntohl(m_ad.s_addr);
for (i=0;i<sizeof(u_long)*CHAR_BIT;i++) {
if (mask & 1L) {
h_fnd=1;
h_num++;
} else {
if (h_fnd)
return -1;
}
mask=mask>>1;
}
return h_num;
}
void
show_ipfw(chain,c_t)
struct ip_fw *chain;
int c_t;
{
char *comma;
u_long adrt;
struct hostent *he;
int i,mb;
if (do_short && do_acct) {
printf("%8d:%8d ",chain->fw_bcnt,chain->fw_pcnt);
}
if (do_short)
if (c_t==FW) {
if (chain->fw_flg & IP_FW_F_ACCEPT)
if (chain->fw_flg & IP_FW_F_PRN)
printf(" l");
else
printf(" a");
else
if (chain->fw_flg & IP_FW_F_PRN)
if (chain->fw_flg & IP_FW_F_ICMPRPL)
printf("lr");
else
printf("ld");
else
if (chain->fw_flg & IP_FW_F_ICMPRPL)
printf(" r");
else
printf(" d");
} else {
if (chain->fw_flg & IP_FW_F_BIDIR)
printf(" b");
else
printf(" s");
}
else
if (c_t==FW) {
if (chain->fw_flg & IP_FW_F_ACCEPT)
if (chain->fw_flg & IP_FW_F_PRN)
printf("log ");
else
printf("accept ");
else
if (chain->fw_flg & IP_FW_F_PRN)
if (chain->fw_flg & IP_FW_F_ICMPRPL)
printf("lreject ");
else
printf("ldeny ");
else
if (chain->fw_flg & IP_FW_F_ICMPRPL)
printf("reject ");
else
printf("deny ");
} else {
if (chain->fw_flg & IP_FW_F_BIDIR)
printf("bidir ");
else
printf("single ");
}
if (do_short)
switch (chain->fw_flg & IP_FW_F_KIND) {
case IP_FW_F_ICMP:
printf("I ");
break;
case IP_FW_F_TCP:
printf("T ");
break;
case IP_FW_F_UDP:
printf("U ");
break;
case IP_FW_F_ALL:
printf("A ");
break;
default:
break;
}
else
switch (chain->fw_flg & IP_FW_F_KIND) {
case IP_FW_F_ICMP:
printf("icmp ");
break;
case IP_FW_F_TCP:
printf("tcp ");
break;
case IP_FW_F_UDP:
printf("udp ");
break;
case IP_FW_F_ALL:
printf("all ");
break;
default:
break;
}
if (do_short)
printf("[");
else
printf("from ");
adrt=ntohl(chain->fw_smsk.s_addr);
if (adrt==ULONG_MAX && do_resolv) {
adrt=(chain->fw_src.s_addr);
he=gethostbyaddr((char *)&adrt,sizeof(u_long),AF_INET);
if (he==NULL) {
printf(inet_ntoa(chain->fw_src));
printf(":");
printf(inet_ntoa(chain->fw_smsk));
} else
printf("%s",he->h_name);
} else {
printf(inet_ntoa(chain->fw_src));
if (adrt!=ULONG_MAX)
if ((mb=mask_bits(chain->fw_smsk))>=0)
printf("/%d",mb);
else {
printf(":");
printf(inet_ntoa(chain->fw_smsk));
}
}
comma = " ";
for (i=0;i<chain->fw_nsp; i++ ) {
printf("%s%d",comma,chain->fw_pts[i]);
if (i==0 && (chain->fw_flg & IP_FW_F_SRNG))
comma = ":";
else
comma = ",";
}
if (do_short)
printf("][");
else
printf(" to ");
adrt=ntohl(chain->fw_dmsk.s_addr);
if (adrt==ULONG_MAX && do_resolv) {
adrt=(chain->fw_dst.s_addr);
he=gethostbyaddr((char *)&adrt,sizeof(u_long),AF_INET);
if (he==NULL) {
printf(inet_ntoa(chain->fw_dst));
printf(":");
printf(inet_ntoa(chain->fw_dmsk));
} else
printf("%s",he->h_name);
} else {
printf(inet_ntoa(chain->fw_dst));
if (adrt!=ULONG_MAX)
if ((mb=mask_bits(chain->fw_dmsk))>=0)
printf("/%d",mb);
else {
printf(":");
printf(inet_ntoa(chain->fw_dmsk));
}
}
comma = " ";
for (i=0;i<chain->fw_ndp;i++) {
printf("%s%d",comma,chain->fw_pts[chain->fw_nsp+i]);
if (i==chain->fw_nsp && (chain->fw_flg & IP_FW_F_DRNG))
comma = ":";
else
comma = ",";
}
if (chain->fw_flg&IP_FW_F_IFNAME && chain->fw_via_name[0]) {
char ifnb[FW_IFNLEN+1];
if (do_short)
printf("][");
else
printf(" via ");
strncpy(ifnb,chain->fw_via_name,FW_IFNLEN);
ifnb[FW_IFNLEN]='\0';
printf("%s%d",ifnb,chain->fw_via_unit);
} else
if (chain->fw_via_ip.s_addr) {
if (do_short)
printf("][");
else
printf(" via ");
printf(inet_ntoa(chain->fw_via_ip));
}
if (do_short)
printf("]");
if (chain->fw_ipopt && chain->fw_ipnopt) {
if (do_short) {
printf("[");
if (chain->fw_ipopt & IP_FW_IPOPT_SSRR)
printf("S");
if (chain->fw_ipnopt & IP_FW_IPOPT_SSRR)
printf("s");
if (chain->fw_ipopt & IP_FW_IPOPT_LSRR)
printf("L");
if (chain->fw_ipnopt & IP_FW_IPOPT_LSRR)
printf("l");
if (chain->fw_ipopt & IP_FW_IPOPT_RR)
printf("R");
if (chain->fw_ipnopt & IP_FW_IPOPT_RR)
printf("r");
if (chain->fw_ipopt & IP_FW_IPOPT_TS)
printf("T");
if (chain->fw_ipnopt & IP_FW_IPOPT_TS)
printf("t");
printf("]");
} else {
int _opt_printed = 0;
#define PRINTOPT(x) {if (_opt_printed) printf(",");\
printf(x); _opt_printed = 1;}
printf("ipopt ");
if (chain->fw_ipopt & IP_FW_IPOPT_SSRR)
PRINTOPT("ssrr");
if (chain->fw_ipnopt & IP_FW_IPOPT_SSRR)
PRINTOPT("!ssrr");
if (chain->fw_ipopt & IP_FW_IPOPT_LSRR)
PRINTOPT("lsrr");
if (chain->fw_ipnopt & IP_FW_IPOPT_LSRR)
PRINTOPT("!lsrr");
if (chain->fw_ipopt & IP_FW_IPOPT_RR)
PRINTOPT("rr");
if (chain->fw_ipnopt & IP_FW_IPOPT_RR)
PRINTOPT("!rr");
if (chain->fw_ipopt & IP_FW_IPOPT_TS)
PRINTOPT("ts");
if (chain->fw_ipnopt & IP_FW_IPOPT_TS)
PRINTOPT("!ts");
}
}
printf("\n");
}
list(av)
char **av;
{
kvm_t *kd;
static char errb[_POSIX2_LINE_MAX];
struct ip_fw b,*btmp;
if (!(kd=kvm_openfiles(NULL,NULL,NULL,O_RDONLY,errb))) {
fprintf(stderr,"%s: kvm_openfiles: %s\n",
progname,kvm_geterr(kd));
exit(1);
}
if (*av==NULL || !strncmp(*av,CH_FW,strlen(CH_FW))) {
if (kvm_nlist(kd,nlf)<0 || nlf[0].n_type==0) {
fprintf(stderr,"%s: kvm_nlist: no namelist in %s\n",
progname,getbootfile());
exit(1);
}
}
if (*av==NULL || !strncmp(*av,CH_FW,strlen(CH_FW))) {
kvm_read(kd,(u_long)nlf[N_FCHAIN].n_value,&b,sizeof(struct ip_fw));
printf("FireWall chain entries:\n");
while(b.fw_next!=NULL) {
btmp=b.fw_next;
kvm_read(kd,(u_long)btmp,&b,sizeof(struct ip_fw));
show_ipfw(&b,FW);
}
}
if (*av==NULL || !strncmp(*av,CH_AC,strlen(CH_AC))) {
if (kvm_nlist(kd,nla)<0 || nla[0].n_type==0) {
fprintf(stderr,"%s: kvm_nlist: no namelist in %s\n",
progname,getbootfile());
exit(1);
}
}
if (*av==NULL || !strncmp(*av,CH_AC,strlen(CH_AC))) {
kvm_read(kd,(u_long)nla[N_ACHAIN].n_value,&b,sizeof(struct ip_fw));
printf("Accounting chain entries:\n");
while(b.fw_next!=NULL) {
btmp=b.fw_next;
kvm_read(kd,(u_long)btmp,&b,sizeof(struct ip_fw));
show_ipfw(&b,AC);
}
}
}
int get_num(str,tab)
char *str;
char tab[][MAXSTR];
{
int i=0;
while(tab[i][0]!='\0') {
if (strlen(str)>=strlen(tab[i]))
if (!strncmp(str,tab[i],strlen(tab[i])))
return i;
i++;
}
return i;
}
void show_usage(str)
char *str;
{
if (str)
fprintf(stderr,"%s: ERROR - %s\n",progname,str);
else
fprintf(stderr,"%s: ERROR - bad arguments\n",progname);
fprintf(stderr,"See man %s(8) for proper usage.\n",progname);
}
u_short get_port(str)
char *str;
{
struct servent *sptr;
char *end;
int port,slen = strlen(str);
if ((slen>0) && (strspn(str,"0123456789")==slen)) {
port = strtol(str,&end,10);
if (*end!='\0') {
fprintf(stderr,"%s: illegal port number :%s\n"
,progname,str);
exit(1);
}
if ((port<=0) || (port>USHRT_MAX)) {
fprintf(stderr,"%s: port number out of range :%d\n"
,progname,port);
exit(1);
}
return((u_short)port);
} else {
sptr = getservbyname(str,proto_name);
if (!sptr) {
fprintf(stderr,"%s: unknown service :%s\n"
,progname,str);
exit(1);
}
return((u_short)ntohs(sptr->s_port));
}
}
char *findchar(str,c)
char *str;
char c;
{
int i,len=strlen(str);
for (i=0;i<len;i++) {
if (str[i]==c)
return(char*)(&str[i]);
}
return NULL;
}
int set_entry_ports(str,ports,a_max,is_range)
char *str;
u_short *ports;
int a_max;
int *is_range;
{
char *s_pr2,*s_h,*s_t,*cp;
u_short p1,p2;
int i=0;
(void)strtok(str,":");
s_pr2=strtok(NULL,"");
if (s_pr2) {
p1 = get_port(str);
p2 = get_port(s_pr2);
if (a_max<2) {
fprintf(stderr,"%s: too many ports.\n",progname);
exit(1);
}
ports[0]=p1;
ports[1]=p2;
*is_range=1;
return 2;
}
s_h=str;
while ((cp=findchar(s_h,','))!=NULL) {
if (i>a_max) {
fprintf(stderr,"%s: too many ports.\n",progname);
exit(1);
}
*cp='\0';
if ((s_t=(++cp))=='\0') {
fprintf(stderr,"%s: bad port list.\n",progname);
exit(1);
}
ports[i++]=get_port(s_h);
s_h=s_t;
}
if (i>a_max) {
fprintf(stderr,"%s: too many ports.\n",progname);
exit(1);
}
ports[i]=get_port(s_h);
*is_range=0;
return (i+1);
}
void set_entry_ip(str,addr,mask)
char *str;
struct in_addr *addr,*mask;
{
char *sm_bit,*sm_oct,*end;
int n_bit;
struct hostent *hptr;
if (!strncmp(str,S_ANY,strlen(S_ANY))) {
addr->s_addr=0L;
mask->s_addr=0L;
return;
}
if (mask) {
(void)strtok(str,"/");
sm_bit=strtok(NULL,"");
(void)strtok(str,":");
sm_oct=strtok(NULL,"");
}
if (!inet_aton(str,addr)) {
if (do_resolv) {
if (!(hptr=gethostbyname(str))) {
fprintf(stderr,"%s: Unknown host name : %s\n",
progname,str);
exit(1);
} else {
addr->s_addr=*((u_long *)hptr->h_addr);
}
} else {
fprintf(stderr,"%s: Bad IP : %s\n",progname,str);
exit(1);
}
}
/*
* This is in case mask we
* want to set IP only
*/
if (!mask)
return;
mask->s_addr=htonl(ULONG_MAX);
if (sm_bit) {
n_bit = strtol(sm_bit,&end,10);
if (*end!='\0') {
show_usage(NULL);
exit(1);
}
if (n_bit<0 || n_bit>sizeof(u_long)*CHAR_BIT) {
show_usage(NULL);
exit(1);
}
if (n_bit>0)
mask->s_addr=
htonl(ULONG_MAX<<(sizeof(u_long)*CHAR_BIT-n_bit));
else
mask->s_addr=0L;
}
if (sm_oct) {
if (!inet_aton(sm_oct,mask)) {
show_usage(NULL);
exit(1);
}
}
/*
* Ugh..better of corse do it in kernel so no error possible
* but faster here so this way it goes...
*/
addr->s_addr=mask->s_addr & addr->s_addr;
}
int set_entry_ifname(str,frwl)
char *str;
struct ip_fw * frwl;
{
char name[IFNAMSIZ],buf[IFNAMSIZ],*sptr;
short unit;
int i;
i=0; sptr=str;
while(isalpha(*sptr++)) {
i++;
}
*sptr--;
if (i==0)
return 1;
strncpy(name,str,i);
name[i]='\0';
unit=(short)atoi(sptr);
sprintf(buf,"%s%d",name,unit);
if (strcmp(str,buf))
return 1;
strncpy(frwl->fw_via_name,name,FW_IFNLEN);
frwl->fw_via_unit=unit;
return 0;
}
void set_entry_ipopts(str, frwl)
char *str;
struct ip_fw *frwl;
{
char *t_str,*p_str;
u_char *optr;
p_str = str;
while ((t_str = strtok(p_str,",")) != NULL) {
p_str = NULL;
printf("tstr = %s\n", t_str);
if (t_str[0] == '!') {
optr = &(frwl->fw_ipnopt);
t_str ++;
} else
optr = &(frwl->fw_ipopt);
if (!strncmp(t_str, IPO_LSRR, strlen(IPO_LSRR)))
*(optr) |= IP_FW_IPOPT_LSRR;
else
if (!strncmp(t_str, IPO_SSRR, strlen(IPO_SSRR)))
*(optr) |= IP_FW_IPOPT_SSRR;
else
if (!strncmp(t_str, IPO_RR, strlen(IPO_RR)))
*(optr) |= IP_FW_IPOPT_RR;
else
if (!strncmp(t_str, IPO_TS, strlen(IPO_TS)))
*(optr) |= IP_FW_IPOPT_TS;
else {
fprintf(stderr,"%s: bad ipoption.\n", progname);
exit(1);
}
}
}
void set_entry(av,frwl)
char **av;
struct ip_fw * frwl;
{
int ir;
int got_from=0, got_to=0, got_via=0, got_ipopt=0, got_tcpflg=0;
#define T_FROM 1
#define T_TO 2
#define T_VIA 3
#define T_IPOPT 4
#define T_TCPFLG 5
int token;
/*
* This section actually creates
* generic entry which matches everything
* in this sorry world...
*/
frwl->fw_nsp=0;
frwl->fw_ndp=0;
frwl->fw_ipopt = 0;
frwl->fw_ipnopt = 0;
frwl->fw_via_ip.s_addr=0L;
frwl->fw_src.s_addr=0L;
frwl->fw_dst.s_addr=0L;
frwl->fw_smsk.s_addr=0L;
frwl->fw_dmsk.s_addr=0L;
get_next:
token = 0;
if (IS_FROM(*av)) {
token = T_FROM;
if (got_from) {
show_usage("Redefined 'from'.");
exit(1);
}
if (*(++av)==NULL) {
show_usage("Missing 'from' specification.");
exit(1);
}
set_entry_ip(*av,&(frwl->fw_src),&(frwl->fw_smsk));
got_from=1;
}
if (IS_TO(*av)) {
token = T_TO;
if (got_to) {
show_usage("Redefined 'to'.");
exit(1);
}
if (*(++av)==NULL) {
show_usage("Missing 'to' specification.");
exit(1);
}
set_entry_ip(*av,&(frwl->fw_dst),&(frwl->fw_dmsk));
got_to = 1;
}
if (IS_VIA(*av)) {
token = T_VIA;
if (got_via) {
show_usage("Redefined 'via'.");
exit(1);
}
if (*(++av)==NULL) {
show_usage("Missing 'via' specification.");
exit(1);
}
/*
* Try first to set interface name
* from arguments.set_entry_ip() will exit on
* wrong argument.
*/
if (set_entry_ifname(*av,frwl))
set_entry_ip(*av,&(frwl->fw_via_ip),NULL);
else
flags |= IP_FW_F_IFNAME;
got_via = 1;
}
if (IS_IPOPT(*av)) {
token = T_IPOPT;
if (got_ipopt) {
show_usage("Redefined 'ipoptions'.");
exit(1);
}
if (*(++av)==NULL) {
show_usage("Missing 'ipoptions' specification.");
exit(1);
}
set_entry_ipopts(*av, frwl);
got_ipopt = 1;
}
if (*(++av)==NULL) {
return;
}
if (IS_TOKEN(*av))
goto get_next;
if (ports_ok && token == T_FROM) {
ir = 0;
frwl->fw_nsp=
set_entry_ports(*av,frwl->fw_pts,IP_FW_MAX_PORTS,&ir);
if (ir)
flags|=IP_FW_F_SRNG;
if (*(++av)==NULL) {
return;
}
}
if (ports_ok && token == T_TO) {
ir = 0;
frwl->fw_ndp=
set_entry_ports(*av,&(frwl->fw_pts[frwl->fw_nsp]),
(IP_FW_MAX_PORTS-frwl->fw_nsp),&ir);
if (ir)
flags|=IP_FW_F_DRNG;
if (*(++av)==NULL) {
return;
}
}
if (token == 0) {
show_usage("Unknown token.");
exit(1);
}
goto get_next;
}
flush(av)
char **av;
{
if (*av==NULL) {
if (setsockopt(s,IPPROTO_IP,IP_FW_FLUSH,NULL,0)<0) {
fprintf(stderr,"%s: setsockopt failed.\n",progname);
exit(1);
} else {
printf("All firewall entries flushed.\n");
}
if (setsockopt(s,IPPROTO_IP,IP_ACCT_FLUSH,NULL,0)<0) {
fprintf(stderr,"%s: setsockopt failed.\n",progname);
exit(1);
} else {
printf("All accounting entries flushed.\n");
}
exit(0);
}
if (!strncmp(*av,CH_FW,strlen(CH_FW))) {
if (setsockopt(s,IPPROTO_IP,IP_FW_FLUSH,NULL,0)<0) {
fprintf(stderr,"%s: setsockopt failed.\n",progname);
exit(1);
} else {
printf("All firewall entries flushed.\n");
exit(0);
}
}
if (!strncmp(*av,CH_AC,strlen(CH_AC))) {
if (setsockopt(s,IPPROTO_IP,IP_ACCT_FLUSH,NULL,0)<0) {
fprintf(stderr,"%s: setsockopt failed.\n",progname);
exit(1);
} else {
printf("All accounting entries flushed.\n");
exit(0);
}
}
}
void policy(av)
char **av;
{
u_short p=0,b;
kvm_t *kd;
static char errb[_POSIX2_LINE_MAX];
if (*av==NULL || strlen(*av)<=0) {
if ( (kd=kvm_openfiles(NULL,NULL,NULL,O_RDONLY,errb)) == NULL) {
fprintf(stderr,"%s: kvm_openfiles: %s\n",progname,kvm_geterr(kd));
exit(1);
}
if (kvm_nlist(kd,nlf) < 0 || nlf[0].n_type == 0) {
fprintf(stderr,"%s: kvm_nlist: no namelist in %s\n",
progname,getbootfile());
exit(1);
}
kvm_read(kd,(u_long)nlf[N_POLICY].n_value,&b,sizeof(int));
if (b&IP_FW_P_DENY)
printf("Default policy: DENY\n");
else
printf("Default policy: ACCEPT\n");
exit(1);
}
if (!strncmp(*av,P_DE,strlen(P_DE)))
p|=IP_FW_P_DENY;
else
if (!strncmp(*av,P_AC,strlen(P_AC)))
p&=~IP_FW_P_DENY;
else {
fprintf(stderr,"%s: bad policy value.\n",progname);
exit(1);
}
if (setsockopt(s,IPPROTO_IP,IP_FW_POLICY,&p,sizeof(p))<0) {
fprintf(stderr,"%s: setsockopt failed.\n",progname);
exit(1);
} else {
if (p&IP_FW_P_DENY)
printf("Policy set to DENY.\n");
else
printf("Policy set to ACCEPT.\n");
exit(0);
}
}
zero()
{
if (setsockopt(s,IPPROTO_IP,IP_ACCT_ZERO,NULL,0)<0) {
fprintf(stderr,"%s: setsockopt failed.\n",progname);
exit(1);
} else {
printf("Accounting cleared.\n");
exit(0);
}
}
main(ac,av)
int ac;
char **av;
{
char ch;
extern int optind;
int ctl,int_t,is_check=0,int_notdef=0;
struct ip_fw frwl;
strcpy(progname,*av);
s = socket( AF_INET, SOCK_RAW, IPPROTO_RAW );
if ( s < 0 ) {
fprintf(stderr,"%s: Can't open raw socket.Must be root to use this programm. \n",progname);
exit(1);
}
if ( ac == 1 ) {
show_usage(NULL);
exit(1);
}
while ((ch = getopt(ac, av ,"ans")) != EOF)
switch(ch) {
case 'a':
do_acct=1;
break;
case 'n':
do_resolv=0;
break;
case 's':
do_short=1;
break;
case '?':
default:
show_usage(NULL);
exit(1);
}
if (*(av+=optind)==NULL) {
show_usage(NULL);
exit(1);
}
switch(get_num(*av,action_tab)) {
case A_ADDF:
ctl=IP_FW_ADD;
int_t=FW;
break;
case A_DELF:
ctl=IP_FW_DEL;
int_t=FW;
break;
case A_CHKF:
int_t=FW;
is_check=1;
break;
case A_ADDA:
ctl=IP_ACCT_ADD;
int_t=AC;
break;
case A_DELA:
ctl=IP_ACCT_DEL;
int_t=AC;
break;
case A_CLRA:
ctl=IP_ACCT_CLR;
int_t=AC;
break;
case A_FLUSH:
flush(++av);
exit(0); /* successful exit */
case A_LIST:
list(++av);
exit(0); /* successful exit */
case A_ZERO:
zero();
exit(0); /* successful exit */
case A_POLICY:
policy(++av);
exit(0); /* we never get here */
default:
int_t=(AC|FW);
int_notdef=1;
} /* main action switch */
if (is_check)
goto proto_switch;
if (!int_notdef)
if (*(++av)==NULL) {
show_usage(NULL);
exit(1);
}
switch(get_num(*av,type_tab)) {
case T_LREJECT:
flags|=IP_FW_F_PRN;
case T_REJECT:
flags|=IP_FW_F_ICMPRPL;
if (!int_t&FW) {
show_usage(NULL);
exit(1);
}
int_t=FW;
break;
case T_LDENY:
flags|=IP_FW_F_PRN;
case T_DENY:
flags|=0; /* just to show it related to flags */
if (!int_t&FW) {
show_usage(NULL);
exit(1);
}
int_t=FW;
break;
case T_LOG:
flags|=IP_FW_F_PRN;
case T_ACCEPT:
case T_PASS:
flags|=IP_FW_F_ACCEPT;
if (!int_t&FW) {
show_usage(NULL);
exit(1);
}
int_t=FW;
break;
case T_SINGLE:
flags|=0; /* just to show it related to flags */
if (!int_t&AC) {
show_usage(NULL);
exit(1);
}
int_t=AC;
break;
case T_BIDIR:
flags|=IP_FW_F_BIDIR;
if (!int_t&AC) {
show_usage(NULL);
exit(1);
}
int_t=AC;
break;
default:
show_usage(NULL);
exit(1);
} /* type of switch */
if (int_notdef) {
if (int_t==FW)
ctl=IP_FW_ADD;
if (int_t==AC)
ctl=IP_ACCT_ADD;
}
proto_switch:
if (*(++av)==NULL) {
show_usage(NULL);
exit(1);
}
switch(get_num(*av,proto_tab)) {
case P_ALL:
flags|=IP_FW_F_ALL;
break;
case P_ICMP:
flags|=IP_FW_F_ICMP;
break;
case P_TCP:
flags|=IP_FW_F_TCP;
ports_ok=1;
strcpy(proto_name,"tcp");
break;
case P_UDP:
flags|=IP_FW_F_UDP;
ports_ok=1;
strcpy(proto_name,"udp");
break;
default:
show_usage(NULL);
exit(1);
}
if (*(++av)==NULL) {
show_usage(NULL);
exit(1);
}
set_entry(av,&frwl);
frwl.fw_flg=flags;
if (is_check) {
#ifndef disabled
fprintf(stderr,"%s: checking disabled.\n",progname);
#else
struct ip *pkt;
struct tcphdr *th;
int p_len=sizeof(struct ip)+sizeof(struct tcphdr);
pkt=(struct ip*)malloc(p_len);
pkt->ip_v = IPVERSION;
pkt->ip_hl = sizeof(struct ip)/sizeof(int);
th=(struct tcphdr *)(pkt+1);
switch(get_num(proto_name,proto_tab)) {
case P_TCP:
pkt->ip_p = IPPROTO_TCP;
break;
case P_UDP:
pkt->ip_p = IPPROTO_UDP;
break;
default:
fprintf(stderr,"%s: can check TCP/UDP packets\
only.\n",progname);
exit(1);
}
if (frwl.fw_nsp!=1 || frwl.fw_ndp!=1) {
fprintf(stderr,"%s: check needs one src/dst port.\n",
progname);
exit(1);
}
if (ntohl(frwl.fw_smsk.s_addr)!=ULONG_MAX ||
ntohl(frwl.fw_dmsk.s_addr)!=ULONG_MAX) {
fprintf(stderr,"%s: can't check masked IP.\n",progname);
exit(1);
}
pkt->ip_src.s_addr=frwl.fw_src.s_addr;
pkt->ip_dst.s_addr=frwl.fw_dst.s_addr;
th->th_sport=htons(frwl.fw_pts[0]);
th->th_dport=htons(frwl.fw_pts[frwl.fw_nsp]);
if (setsockopt(s,IPPROTO_IP,ctl,pkt,p_len))
printf("Packet DENYED.\n");
else
printf("Packet ACCEPTED.\n");
exit(0);
#endif
} else {
if (setsockopt(s,IPPROTO_IP,ctl,&frwl,sizeof(frwl))<0) {
fprintf(stderr,"%s: setsockopt failed.\n",progname);
exit(1);
}
}
close(s);
}