//test dispatch si port vide #include #include #include #include #include #include #ifdef __GLIBC__ #include #include #include #include #include "k2.0/ip_fw.h" #else #include #include #include #include #include #include #include #include "k2.0/ip_fw.h" #endif #include #include #include "firewall.h" #include "netconf.h" #include #include #include #include #include "../../paths.h" #include "firewall.m" #include #include #ifndef IP_FW_POLICY_IN /* These are just here so it compiles */ #define IP_FW_F_MASQ 0 #define IP_FW_APPEND_OUT 1 #define IP_FW_APPEND_IN 2 #define IP_FW_APPEND_FWD 3 #define IP_ACCT_APPEND 4 #define FIREWAALL_NONE #endif HELP_FILE help_ipfw ("firewall","firewall"); PUBLIC IPFW_SOLVED_TRIPLET::IPFW_SOLVED_TRIPLET( const char *_ip, const char *_mask, const char *_interface, bool _not_flag) { strcpy (ip,_ip); strcpy (mask,_mask); strcpy (interface,_interface); not_flag = _not_flag; } PUBLIC IPFW_SOLVED_TRIPLET *IPFW_SOLVED_TRIPLETS::getitem (int no) const { return (IPFW_SOLVED_TRIPLET*)ARRAY::getitem(no); } PUBLIC IPFW_SOLVED_TRIPLET *IPFW_SOLVED_TRIPLETS::add ( const char *_ip, const char *_mask, const char *_interface, bool not_flag) { IPFW_SOLVED_TRIPLET *ret = new IPFW_SOLVED_TRIPLET(_ip,_mask,_interface ,not_flag); ARRAY::add (ret); return ret; } PUBLIC IPFW_SOLVED::IPFW_SOLVED() { nbbit_msk = 0; } PROTECTED IPFW_RULE::IPFW_RULE() { from.interface.setfrom ("Any"); to.interface.setfrom ("Any"); protocol.setfrom ("all"); /* #Specification: netconf / firewalling / active rule One rule may be defined and desactivated without erasing it. This give some flexibility to the administrator to define complex rules and "comment out" some. */ active = 1; bidir = 1; from.allow_syn = 1; to.allow_syn = 1; weight = 50; solved_valid = false; logging = 0; } PUBLIC int IPFW_RULE::getweight() { return weight; } /* Return true if this is a bidirectional rule */ PUBLIC bool IPFW_RULE::is_bidir() { return bidir; } PROTECTED IPFW_RULEP::IPFW_RULEP() { policy = FW_ACCEPT; } /* Extract a number from a buffer. The number may be enclosed in double quote. */ static const char *firewall_extract ( const char *buf, char &val, int defval) // Default value if the string is empty { SSTRING s; buf = str_extract (buf,s); if (s.is_empty()){ val = defval; }else{ val = s.getval(); } return buf; } static const char *firewall_extract ( const char *buf, int &val, int defval) // Default value if the string is empty { SSTRING s; buf = str_extract (buf,s); if (s.is_empty()){ val = defval; }else{ val = s.getval(); } return buf; } static const char *firewall_extract (const char *buf, IPFW_SRC &s) { buf = str_extract (buf,s.host); buf = str_extract (buf,s.netmask); buf = str_extract (buf,s.portrange); buf = str_extract (buf,s.ports); buf = str_extract (buf,s.interface); return buf; } PROTECTED IPFW_RULE::IPFW_RULE(const char * &buf) { buf = firewall_extract (buf,active,1); buf = str_extract (buf,protocol); buf = firewall_extract (buf,from); buf = firewall_extract (buf,to); bidir = 1; from.allow_syn = 1; to.allow_syn = 1; weight = 50; logging = 0; } /* Extract values from the config line.\ Those features appeared later in the firewall module, so were added to the end of the line. */ PROTECTED const char *IPFW_RULEP::extract_newf(const char *buf) { buf = firewall_extract (buf,policy,FW_ACCEPT); buf = firewall_extract (buf,bidir,1); buf = firewall_extract (buf,from.allow_syn,1); buf = firewall_extract (buf,to.allow_syn,1); buf = firewall_extract (buf,weight,50); buf = str_extract (buf,comment); buf = firewall_extract (buf,logging,0); return buf; } PROTECTED const char *IPFW_RULEP::extract_chain(const char *buf) { buf = str_extract (buf,from.dispatch); buf = str_extract (buf,to.dispatch); return buf; } PROTECTED IPFW_RULEP::IPFW_RULEP(const char * &buf) : IPFW_RULE (buf) { // To keep compatibility with old installation, the policy is read // from the buffer by the IPFW_RULE_ child classes } PUBLIC IPFW_RULE_FORWARD::IPFW_RULE_FORWARD(const char *buf) : IPFW_RULEP (buf) { buf = firewall_extract (buf,masquerade,0); buf = extract_newf (buf); buf = extract_chain (buf); } PUBLIC IPFW_RULE_FORWARD::IPFW_RULE_FORWARD() { masquerade = 0; } PUBLIC IPFW_RULE_OUTPUT::IPFW_RULE_OUTPUT(const char *buf) : IPFW_RULEP (buf) { buf = extract_newf (buf); buf = extract_chain (buf); } PUBLIC IPFW_RULE_OUTPUT::IPFW_RULE_OUTPUT() { } PUBLIC IPFW_RULE_INPUT::IPFW_RULE_INPUT(const char *buf) : IPFW_RULEP (buf) { buf = firewall_extract (buf,doredir,0); buf = str_extract (buf,redirport); buf = extract_newf(buf); buf = str_extract (buf,redirhost); buf = extract_chain (buf); } PUBLIC IPFW_RULE_INPUT::IPFW_RULE_INPUT() { doredir = 0; } PUBLIC IPFW_RULE_ACCT::IPFW_RULE_ACCT(const char *buf) : IPFW_RULE (buf) { buf = firewall_extract (buf,weight,50); buf = str_extract (buf,comment); } PUBLIC IPFW_RULE_ACCT::IPFW_RULE_ACCT() { } static void firewall_append (char *buf, SSTRING &s) { strcat (buf," \""); strcat (buf,s.get()); strcat (buf,"\""); } static void firewall_append (char *buf, int val) { char valstr[20]; sprintf (valstr,"%d",val); strcat (buf," \""); strcat (buf,valstr); strcat (buf,"\""); } static void firewall_append (char *buf, IPFW_SRC &s) { firewall_append (buf,s.host); firewall_append (buf,s.netmask); firewall_append (buf,s.portrange); firewall_append (buf,s.ports); firewall_append (buf,s.interface); } PROTECTED void IPFW_RULEP::append_newf (char *buf) { firewall_append (buf,policy); firewall_append (buf,bidir); firewall_append (buf,from.allow_syn); firewall_append (buf,to.allow_syn); firewall_append (buf,weight); firewall_append (buf,comment); firewall_append (buf,logging); } PROTECTED void IPFW_RULEP::append_chain (char *buf) { firewall_append (buf,from.dispatch); firewall_append (buf,to.dispatch); } const char K_FIREWALL[] = "firewall"; const char K_FORWARD[] = "forward"; const char K_BLOCK[] = "block"; const char K_OUTPUT[] = "output"; const char K_ACCT[] = "acct"; /* Save one forward line in /etc/conf.linuxconf */ PROTECTED void IPFW_RULE::savek(char *buf) { buf[0] = '\0'; firewall_append (buf,active); firewall_append (buf,protocol); firewall_append (buf,from); firewall_append (buf,to); } /* Save one forward line in /etc/conf.linuxconf */ PUBLIC void IPFW_RULE_FORWARD::save(CONFDB *db) { char buf[2000]; IPFW_RULE::savek(buf); firewall_append (buf,masquerade); append_newf(buf); append_chain (buf); db->add (K_FIREWALL,K_FORWARD,buf); } /* Save one forward line in /etc/conf.linuxconf */ PUBLIC void IPFW_RULE_INPUT::save(CONFDB *db) { char buf[2000]; IPFW_RULE::savek(buf); firewall_append (buf,doredir); firewall_append (buf,redirport); append_newf(buf); firewall_append (buf,redirhost); append_chain (buf); db->add (K_FIREWALL,K_BLOCK,buf); } /* Save one output line in /etc/conf.linuxconf */ PUBLIC void IPFW_RULE_OUTPUT::save(CONFDB *db) { char buf[2000]; IPFW_RULE::savek(buf); append_newf(buf); append_chain (buf); db->add (K_FIREWALL,K_OUTPUT,buf); } /* Save one output line in /etc/conf.linuxconf */ PUBLIC void IPFW_RULE_ACCT::save(CONFDB *db) { char buf[2000]; IPFW_RULE::savek(buf); firewall_append (buf,weight); firewall_append (buf,comment); db->add (K_FIREWALL,K_ACCT,buf); } /* Format the minimum information about the rule so it will be presentable in a menu. */ PUBLIC VIRTUAL void IPFW_RULE::present ( char *buf1, int size1, char *buf2, int size2) { snprintf (buf1,size1-1,"[%c]",active ? 'X' : ' '); snprintf (buf2,size2-1,"%s\t%s\t%s\t%s\t\t%s\t%s\t%d\t\t%s" ,"" // No policy for general rules ,protocol.get() ,from.interface.get() ,from.host.get() ,to.interface.get() ,to.host.get() ,weight ,comment.get()); } /* Format the minimum information about the rule so it will be presentable in a menu. */ PUBLIC void IPFW_RULE_INPUT::present ( char *buf1, int size1, char *buf2, int size2) { snprintf (buf1,size1-1,"[%c]",active ? 'X' : ' '); static const char *tbpolicy[]={ MSG_R(F_FW_ACCEPT), MSG_R(F_FW_REJECT), MSG_R(F_FW_DENY) }; snprintf (buf2,size2-1,"%s\t%s\t%s\t%s\t\t%s\t%s\t%d\t%s\t%s" ,tbpolicy[policy] ,protocol.get() ,from.interface.get() ,from.host.get() ,to.interface.get() ,to.host.get() ,weight ,doredir ? "X" : "" ,comment.get()); } /* try to convert something into an IP number Return -1 if it can't. */ static int ipfwrule_convertone ( const char *str, // An IP number, a host name or an interface // name (eth0) IPFW_SOLVED_TRIPLETS &triplets, // Corresponding (computed) netmask // or extracted from the device SSTRING *errmsg, FWINFO_API *tbapi[], int nbapi, bool not_flag) { int ret = -1; if (strchr(str,'/')!=NULL){ // This is a logical host for (int i=0; igethostinfo(str,str_ip)!=-1){ int n = str_ip.getnb(); for (int j=0; jget(); const char *pt = strchr (ip,'/'); if (pt != NULL){ // Ok, the netmask was not included, trying to figure out char tmp[strlen(ip)+1]; strcpy (tmp,ip); char *msk = tmp + (pt-ip); *msk++ = '\0'; triplets.add (tmp,msk,"",not_flag); }else{ char msk[LEN_IP_ASC]; netconf_computemsk (ip,msk); triplets.add (ip,msk,"",not_flag); } } ret = 0; break; } } }else{ char ip[LEN_IP_ASC],msk[LEN_IP_ASC]; ret = netconf_convert (str,ip,msk); if (ret == -1){ if (errmsg != NULL){ char buf[300]; sprintf (buf,MSG_U(E_IVLDIP,"Invalid IP number or host name or interface: %s\n") ,str); errmsg->append (buf); } }else{ triplets.add (ip,msk,"",not_flag); } } return ret; } /* try to convert something into one or many IP numbers Return -1 if it can't. */ static int ipfwrule_convert ( const char *str, // An IP number, a host name or an interface // name (eth0) // May contains several entries splitted using commas IPFW_SOLVED_TRIPLETS &triplets, // Corresponding (computed) netmask // or extracted from the device SSTRING *errmsg, FWINFO_API *tbapi[], int nbapi) { int ret = 0; char tmp[strlen(str)+1]; strcpy (tmp,str); char *pt = tmp; while (*pt != '\0'){ pt = str_skip(pt); char *start = pt; while (*pt != ',' && *pt != '\0') pt++; if (*pt == ',') *pt++ = '\0'; strip_end (start); if (start[0] != '\0'){ bool not_flag = false; if (start[0] == '!'){ not_flag = true; start = str_skip(start+1); } ret |= ipfwrule_convertone (start,triplets,errmsg,tbapi,nbapi,not_flag); } } return triplets.getnb()==0 ? -1 : ret; } static int ipfwrule_checkhn (const char *str) { int ret = -1; str = str_skip(str); if (str[0] == '!') str++; if (strchr(str,'/')!=NULL){ // logical host FWINFO_API *tbapi[MAX_API_PROVIDERS]; int nbapi = fwinfo_apis_init ("ipfwrule_checkhn",tbapi); bool found = false; for (int i=0; ihostexist (str)){ found = true; break; } } fwinfo_apis_end(tbapi,nbapi); if (!found){ // We simply issue a notice. The logical host will be // created later probably. xconf_notice (MSG_U(E_LOGICALHOST ,"Logical host %s does not exist"),str); } ret = 0; }else{ IPFW_SOLVED_TRIPLETS triplets; SSTRING error; ret = ipfwrule_convert (str,triplets,&error,NULL,0); if (ret == -1) xconf_error (error.get()); } return ret; } static bool ipfwrule_isdevice (const char *prefix, int len, const char *name) { bool ret = false; if (strncmp(name,prefix,len)==0){ const char *pt = name + len; // The rest must be digits optionally followed by a dot and digits // for vlans devices if (isdigit(*pt)){ pt = str_skipdig(pt); if (pt[0] == '.' && isdigit(pt[1])) pt = str_skipdig(pt+1); ret = *pt == '\0'; } } return ret; } const char *ipfwrule_getsect (FIREWALL_SECTION section) { static const char *tbsect[]={ MSG_U(I_SECTINPUT,"Input firewalling"), MSG_U(I_SECTFORWARD,"Forward firewalling"), MSG_U(I_SECTOUTPUT,"Output firewalling"), MSG_U(I_SECTACCT,"Packet accounting"), MSG_U(I_SECTINTERNAL,"Linuxconf internal"), }; return tbsect[section]; } /* Lookup the value of the various fields Return -1 if any error. */ PUBLIC int IPFW_RULE::solve ( IPFW_SRC &f, FWINFO_API *tbapi[], int nbapi) { IPFW_SOLVED &solved = f.solved; solved.triplets.remove_all(); int ret = -1; if (ipfwrule_convert(f.host.get(),solved.triplets,NULL,tbapi,nbapi)!=-1){ // Lookup the interface const char *inter = f.interface.get(); const char *not_inter = ""; if (inter[0] == '!'){ not_inter = "!"; inter = str_skip(inter+1); } if (strchr(inter,'/')!=NULL){ for (int i=0; igetdevinfo(inter,strs)!=-1){ int n=strs.getnb(); for (int j=0; jget(); IPFW_SOLVED_TRIPLET *trip = solved.triplets.getitem(j); if (trip != NULL){ // Should match triplets sprintf (trip->interface,"%s%s",not_inter,sinter); } } break; } } }else{ char solved_interface[LEN_IP_ASC]; char *pt_solved = stpcpy (solved_interface,not_inter); if (f.interface.is_empty() || f.interface.icmp("Any")==0){ strcpy (solved_interface,"0.0.0.0"); }else{ /* #Specification: firewall / iface argument We accept a host name, an IP number or a network device name (eth0). */ if (strcmp(inter,"lo")==0 || ipfwrule_isdevice ("eth",3,inter) || ipfwrule_isdevice ("ppp",3,inter) || ipfwrule_isdevice ("tr",2,inter) || ipfwrule_isdevice ("sl",2,inter) || ipfwrule_isdevice ("vlan",4,inter)){ strcpy (pt_solved,inter); }else{ IPFW_SOLVED_TRIPLETS trips; if (ipfwrule_convert (inter,trips,NULL,tbapi,nbapi)!=-1){ IPFW_SOLVED_TRIPLET *trip = trips.getitem(0); if(!kernel_newer(2,2,0) || netconf_finddevfromhost(trip->ip,pt_solved)==-1){ strcpy (pt_solved,trip->ip); } }else{ xconf_error (MSG_U(E_IVLDINTER ,"Section %s, Rule %d\nInvalid interface %s for firewalling rule") ,ipfwrule_getsect(sectnum),rulenum,inter); } } } for (int i=0; iinterface[0] == '\0') strcpy (trip->interface,solved_interface); } } // Now fill the missing netmask if missing for (int i=0; imask); }else{ f.netmask.copy (solved_mask); } // Compute the number of significant bits in the netmask int num4[4]; ipnum_aip24 (msk,num4); unsigned long nmsk = (num4[0] << 24) | (num4[1] << 16) | (num4[2] << 8) | num4[3]; unsigned long cmp = 0x80000000l; int i; for (i=0; i<32 && (nmsk & cmp) != 0; i++, cmp >>= 1); solved.nbbit_msk = i; strcpy (trip->mask,solved_mask); ret = 0; } if (ret == 0){ // Make sure the interface is defined for everyone for (int i=0; iinterface[0] == '\0') ret = -1; } } } return ret; } /* Return the number of significative bits in the netmask (1's) This is taken in the from. */ PUBLIC int IPFW_RULE::nbbitmask_from() { return from.solved.nbbit_msk; } /* Return the number of significative bits in the netmask (1's) This is taken in the "to". */ PUBLIC int IPFW_RULE::nbbitmask_to() { return to.solved.nbbit_msk; } static int cmp_gen( int netmask1, // Number of bits == 1in the netmask int netmask2, const IPFW_SOLVED_TRIPLET *trip1, const IPFW_SOLVED_TRIPLET *trip2, int masq1, // Is it a masquerading rule int masq2, int redir1, // Is it a redirection rule int redir2) { /* #Specification: firewall / sorting of rules Linuxconf knows automaticly how to sort rules so it makes sens Here are the rules it uses to sort redirection rules are always first masquerading rules are always last The most specific netmask is first (the one with the larger number of 1s). If all equals, the rules with the interface Any is last when compared to a rule with a specific interface */ const char *iface1 = trip1 != NULL ? trip1->interface : ""; const char *iface2 = trip2 != NULL ? trip2->interface : ""; int ret = redir2 - redir1; if (ret == 0){ ret = masq1 - masq2; if (ret == 0){ ret = netmask1 - netmask2; if (ret == 0){ ret = strcmp(iface1,iface2); if (ret != 0){ ret = stricmp(iface1,"any"); if (ret == 0){ ret = 1; }else{ ret = stricmp (iface2,"any"); if (ret == 0){ ret = -1; }else{ ret = 0; } } } } } } return ret; } PUBLIC int IPFW_RULE::cmp_gen_to( IPFW_RULE *r, int masq1, // Is it a masquerading rule int masq2, int redir1, // Is it a redirection rule int redir2) { // We compare only the first triplets, assuming all // elements of a logical interface are alike IPFW_SOLVED_TRIPLET *tripto = to.solved.triplets.getitem(0); IPFW_SOLVED_TRIPLET *triprto = r->to.solved.triplets.getitem(0); return cmp_gen ( nbbitmask_to(),r->nbbitmask_to(), tripto,triprto, masq1,masq2, redir1,redir2); } PUBLIC int IPFW_RULE::cmp_gen_from( IPFW_RULE *r, int masq1, // Is it a masquerading rule int masq2, int redir1, // Is it a redirection rule int redir2) { IPFW_SOLVED_TRIPLET *tripfrom = from.solved.triplets.getitem(0); IPFW_SOLVED_TRIPLET *triprfrom = r->from.solved.triplets.getitem(0); return cmp_gen ( nbbitmask_from(),r->nbbitmask_from(), tripfrom,triprfrom, masq1,masq2, redir1,redir2); } PUBLIC int IPFW_RULEP::cmp_policy_to( IPFW_RULEP *r, int masq1, // Is it a masquerading rule int masq2, int redir1, // Is it a redirection rule int redir2) { int ret = r->policy - policy; if (ret == 0) ret = IPFW_RULE::cmp_gen_to(r,masq1,masq2,redir1,redir2); return ret; } PUBLIC int IPFW_RULEP::cmp_policy_from( IPFW_RULEP *r, int masq1, // Is it a masquerading rule int masq2, int redir1, // Is it a redirection rule int redir2) { int ret = r->policy - policy; if (ret == 0) ret = IPFW_RULE::cmp_gen_from(r,masq1,masq2,redir1,redir2); return ret; } PUBLIC int IPFW_RULE_INPUT::cmp_from(IPFW_RULE *r) { IPFW_RULE_INPUT *f = (IPFW_RULE_INPUT*)r; return cmp_policy_from (f,0,0,doredir,f->doredir); } PUBLIC int IPFW_RULE_INPUT::cmp_to(IPFW_RULE *r) { IPFW_RULE_INPUT *f = (IPFW_RULE_INPUT*)r; return cmp_policy_to (f,0,0,doredir,f->doredir); } PUBLIC int IPFW_RULE_OUTPUT::cmp_from(IPFW_RULE *r) { return cmp_policy_from ((IPFW_RULE_OUTPUT*)r,0,0,0,0); } PUBLIC int IPFW_RULE_OUTPUT::cmp_to(IPFW_RULE *r) { return cmp_policy_to ((IPFW_RULE_OUTPUT*)r,0,0,0,0); } PUBLIC int IPFW_RULE_FORWARD::cmp_from(IPFW_RULE *r) { IPFW_RULE_FORWARD *f = (IPFW_RULE_FORWARD*)r; return cmp_policy_from (f,masquerade,f->masquerade,0,0); } PUBLIC int IPFW_RULE_FORWARD::cmp_to(IPFW_RULE *r) { IPFW_RULE_FORWARD *f = (IPFW_RULE_FORWARD*)r; return cmp_policy_to (f,masquerade,f->masquerade,0,0); } PUBLIC int IPFW_RULE_ACCT::cmp_from(IPFW_RULE *r) { return cmp_gen_from (r,0,0,0,0); } PUBLIC int IPFW_RULE_ACCT::cmp_to(IPFW_RULE *r) { return cmp_gen_to (r,0,0,0,0); } /* Check one section of the dialog Return -1 if any error. */ PRIVATE int IPFW_RULE::diacheck (IPFW_SRC &s, int &nof) { int ret = -1; bool allow_port = protocol.cmp("udp")==0 || protocol.cmp("tcp")==0; if (s.host.is_empty()){ nof = 0; xconf_error (MSG_U(E_MISSINGHN,"Missing host or network")); }else if (ipfwrule_checkhn(s.host.get())==-1){ nof = 0; }else if (!s.netmask.is_empty() && !ipnum_validip(s.netmask.get(),false)){ xconf_error (MSG_U(E_IVLDMASK,"Invalid netmask"),s.netmask.get()); nof = 1; }else if (!allow_port && !s.portrange.is_empty()){ xconf_error (MSG_U(E_ALLOWPORTRANGE ,"Port range only allowed for TCP and UDP protocol")); nof = 2; }else if (ipfw_checkrange(s.portrange)==-1){ xconf_error (MSG_U(E_IVLDPRANGE ,"Invalid port range\n" "Expecting xxxx:yyyy where yyyy >= xxxx\n" "xxxx and yyyy are decimal numbers")); nof = 2; }else if (!allow_port && !s.ports.is_empty()){ xconf_error (MSG_U(E_ALLOWPORTLIST ,"Ports list only allowed for TCP and UDP protocol")); nof = 3; }else if (ipfw_checkports(s.ports,protocol)==-1){ xconf_error (MSG_U(E_IVLDPORTS,"Invalid ports list")); nof = 3; }else{ ret = 0; } return ret; } /* Some information to locate some field index in the dialog */ struct DIALOG_CONTEXT { int f_protocol; int f_from_section; int f_to_section; }; PROTECTED void IPFW_RULE::setup_top( DIALOG &dia, DIALOG_CONTEXT &ctx) { dia.newf_chk ("",active,MSG_U(F_RULEACTIVE,"This rule is active")); dia.newf_str (MSG_U(F_COMMENT,"Comment"),comment,60); ctx.f_protocol = dia.getnb(); FIELD_COMBO *comb = dia.newf_combo (MSG_U(F_PROTOCOL,"Protocol") ,protocol); // We make sure those standard protocol are in front comb->addopt ("All"); comb->addopt ("icmp"); comb->addopt ("tcp"); comb->addopt ("udp"); SSTRINGS tb; struct protoent *p; endprotoent(); while ((p=getprotoent())!=NULL){ if (strcasecmp(p->p_name,"tcp")!=0 &&strcasecmp(p->p_name,"udp")!=0 && strcasecmp(p->p_name,"icmp")!=0){ tb.add (new SSTRING(p->p_name)); } } tb.sort(); for (int i=0; iaddopt (tb.getitem(i)->get()); } } PROTECTED void IPFW_RULE::setup_interface( DIALOG &dia, const char *devtitle, SSTRING &interface) { FIELD_COMBO *comb = dia.newf_combo (devtitle,interface); comb->addopt ("Any",MSG_U(F_PACKFROMANY,"Packet come from anywhere")); devlist_setcombo (comb); FWINFO_API *tbapi[MAX_API_PROVIDERS]; int nb = fwinfo_apis_init ("ipfwrule",tbapi); SSTRINGS devs,descs; for (int i=0; igetdevlist (devs,descs); } for (int i=0; iaddopt (devs.getitem(i)->get(),descs.getitem(i)->get()); } fwinfo_apis_end (tbapi,nb); } PROTECTED void IPFW_RULE::setup_host( DIALOG &dia, SSTRING &host) { FIELD_COMBO *comb = dia.newf_combo (MSG_U(F_HOSTORNET,"Host(s) or Network(s)") ,host); comb->addopt ("0.0.0.0",MSG_U(I_ALL,"All")); FWINFO_API *tbapi[MAX_API_PROVIDERS]; int nb = fwinfo_apis_init ("ipfwrule",tbapi); SSTRINGS hosts,descs; for (int i=0; igethostlist (hosts,descs); } for (int i=0; iaddopt (hosts.getitem(i)->get(),descs.getitem(i)->get()); } fwinfo_apis_end (tbapi,nb); } PROTECTED void IPFW_RULE::setup_from( DIALOG &dia, DIALOG_CONTEXT &ctx, const char *devtitle) // Title for the interface { dia.newf_title (MSG_U(F_FROM,"From"),1,"",MSG_R(F_FROM)); ctx.f_from_section = dia.getnb(); setup_host (dia,from.host); FIELD_COMBO *comb = dia.newf_combo (MSG_U(F_HNETMASK,"Netmask"),from.netmask); host_setmasklist(comb); comb = dia.newf_combo (MSG_U(F_PORTRANGE,"Port range"),from.portrange); comb->addopt ("",MSG_U(I_NORANGE,"None")); comb->addopt ("1024:65535",MSG_U(I_CLIENTPORTS,"Client ports")); dia.newf_str (MSG_U(F_OTHERPORTS,"Other ports"),from.ports); dia.newf_chk (MSG_U(F_ACCEPTSYN,"Accept"),from.allow_syn ,MSG_U(I_ACCEPTSYN,"TCP Syn packet")); setup_interface (dia,devtitle,from.interface); } PROTECTED void IPFW_RULE::setup_to( DIALOG &dia, DIALOG_CONTEXT &ctx, const char *devtitle) // Title for the interface { dia.newf_title (MSG_U(F_TO,"To"),1,"",MSG_R(F_TO)); ctx.f_to_section = dia.getnb(); setup_host (dia,to.host); FIELD_COMBO *comb = dia.newf_combo (MSG_R(F_HNETMASK),to.netmask); host_setmasklist (comb); dia.newf_str (MSG_R(F_PORTRANGE),to.portrange); dia.newf_str (MSG_R(F_OTHERPORTS),to.ports); dia.newf_chk (MSG_R(F_ACCEPTSYN),to.allow_syn,MSG_R(I_ACCEPTSYN)); setup_interface(dia,devtitle,to.interface); } PROTECTED void IPFW_RULE::setup_features( DIALOG &dia, DIALOG_CONTEXT &) { dia.newf_title (MSG_U(F_FEATURES,"Features"),1,"",MSG_R(F_FEATURES)); dia.newf_chk (MSG_U(F_THISRULE,"This rule"),bidir ,MSG_U(I_THISRULE,"is bidirectional")); dia.newf_num (MSG_U(F_ORDER,"Ordering factor"),weight); dia.newf_chk (MSG_U(F_LOGGING,"Logging"),logging,MSG_U(I_LOGGING ,"is enabled")); FIELD_COMBO *comb = dia.newf_combo (MSG_U(F_DISPATCHFROM ,"Chain dispatch (from -> to)") ,from.dispatch); comb->addopt ("iface,proto,toport,from/255.255.255.192,to"); comb = dia.newf_combo (MSG_U(F_DISPATCHTO,"Chain dispatch (to -> from)") ,to.dispatch); comb->addopt ("iface,proto,fromport,to/255.255.255.192,from"); } /* Return -1 if abort Return 0 if accept Return 1 if delete required */ PUBLIC int IPFW_RULE::editk( DIALOG &dia, const char *title, DIALOG_CONTEXT &ctx) { int ret = -1; int nof = 0; while (1){ MENU_STATUS code = dia.edit (title ,"" ,help_ipfw ,nof ,MENUBUT_CANCEL|MENUBUT_ACCEPT|MENUBUT_DEL); if (code == MENU_ESCAPE || code == MENU_CANCEL){ break; }else if (code == MENU_DEL){ ret = 1; break; }else if (diacheck(from,nof)==-1){ nof += ctx.f_from_section; }else if (diacheck(to,nof)==-1){ nof += ctx.f_to_section; }else{ if (ipfw_checkproto(protocol.get())==-1){ xconf_error (MSG_U(E_IVLDPROTO,"Invalid protocol")); nof = ctx.f_protocol; }else if (chains_validdispatch (from.dispatch.get(),protocol.get() ,from.interface.get())!=-1 && chains_validdispatch (to.dispatch.get(),protocol.get() ,to.interface.get())!=-1){ ret = 0; break; } } } if (ret != 0) dia.restore(); return ret; } PROTECTED void IPFW_RULEP::setpolicy(DIALOG &dia) { static const char *tbpolicy[]={ MSG_U(F_FW_ACCEPT,"Accept"), MSG_U(F_FW_REJECT,"Reject"), MSG_U(F_FW_DENY,"Deny"), NULL }; dia.newf_chkm (MSG_U(F_RULEPOLICY,"Rule's policy"),policy,tbpolicy); } /* Return -1 if abort */ PUBLIC int IPFW_RULE_FORWARD::edit() { DIALOG dia; DIALOG_CONTEXT ctx; setup_top (dia,ctx); dia.newf_chk ("",masquerade,MSG_U(F_DOMASQUERADE,"Do masquerading")); setpolicy (dia); setup_from (dia,ctx,MSG_U(F_OUTPUTINTER,"Output interface")); setup_to (dia,ctx,MSG_R(F_OUTPUTINTER)); setup_features (dia,ctx); return IPFW_RULE::editk (dia,MSG_U(T_FORWARDING,"Firewall forwarding rule") ,ctx); } /* Return -1 if abort */ PUBLIC int IPFW_RULE_OUTPUT::edit() { DIALOG dia; DIALOG_CONTEXT ctx; setup_top (dia,ctx); setpolicy (dia); setup_from (dia,ctx,MSG_R(F_OUTPUTINTER)); setup_to (dia,ctx,MSG_R(F_OUTPUTINTER)); setup_features (dia,ctx); return IPFW_RULE::editk (dia,MSG_U(T_OUTPUT,"Firewall Outputing rule") ,ctx); } /* Return -1 if abort */ PUBLIC int IPFW_RULE_INPUT::edit() { DIALOG dia; DIALOG_CONTEXT ctx; setup_top (dia,ctx); setpolicy (dia); setup_from (dia,ctx,MSG_U(F_INPUTINTER,"Input interface")); setup_to (dia,ctx,MSG_R(F_INPUTINTER)); setup_features (dia,ctx); dia.newf_title (MSG_U(F_REDIR,"Redirections"),1,"",MSG_R(F_REDIR)); dia.newf_chk ("",doredir,MSG_U(F_DOREDIR,"Redirect to local port/host")); dia.newf_str (MSG_U(F_REDIRPORT,"Redirect to port"),redirport); if (kernel_newer(2,2,0)){ dia.newf_str (MSG_U(F_REDIRHOST,"Redir. to host"),redirhost); } return IPFW_RULE::editk (dia,MSG_U(T_INPUTING,"Firewall inputing rule") ,ctx); } /* Return -1 if abort */ PUBLIC int IPFW_RULE_ACCT::edit() { DIALOG dia; DIALOG_CONTEXT ctx; setup_top (dia,ctx); setup_from (dia,ctx,MSG_R(F_INPUTINTER)); setup_to (dia,ctx,MSG_R(F_INPUTINTER)); return IPFW_RULE::editk (dia,MSG_U(T_ACCT,"IP Accouting rule"),ctx); } PRIVATE int IPFW_RULE::setupone ( int policy, const IPFW_SRC &f, const IPFW_SRC &t, FWTYPE type, const char *redirport, const char *redirhost, bool syn_packets, // This rule applies only to SYN packets bool doit, // Exec the command ? SSTRING *collect, // Will contain a copy of the // command generated SSTRING &errmsg) // Error message are appended to this SSTRING { int ret = 0; for (int i=0; iinterface,protocol.get() ,ftrip->ip,ftrip->mask ,f.portrange.get(),f.ports.get() ,ttrip->ip,ttrip->mask ,t.portrange.get(),t.ports.get() ,type == FWTYPE_REDIR ? redirport : (const char *)NULL ,logging != 0 ,syn_packets ,bf)!=-1){ bf.not_src = ftrip->not_flag; bf.not_dst = ttrip->not_flag; int command = 0; if (type == FWTYPE_MASQ){ command = IP_FW_APPEND_FWD; bf.fw_flg |= IP_FW_F_MASQ; }else if (type == FWTYPE_FORWARD){ command = IP_FW_APPEND_FWD; }else if (type == FWTYPE_OUTPUT){ command = IP_FW_APPEND_OUT; }else if (type == FWTYPE_INPUT){ command = IP_FW_APPEND_IN; }else if (type == FWTYPE_REDIR){ command = IP_FW_APPEND_IN; }else if (type == FWTYPE_ACCT){ command = IP_ACCT_APPEND; } ret |= ipfw_append (sectnum,rulenum,doit,collect,command,bf,redirhost ,f.dispatch.get()); }else{ xconf_error (MSG_U(E_INTERNAL ,"Internal error in section %s, rule %d\n" "From interface %s protocol %s ip %s mask %s\n" "From portrange %s ports %s\n" "To interface %s protocol %s ip %s mask %s\n" "To portrange %s ports %s\n" "redirport %s loggin %d syn_packets %d\n") ,ipfwrule_getsect(sectnum),rulenum ,ftrip->interface,protocol.get() ,ftrip->ip,ftrip->mask ,f.portrange.get(),f.ports.get() ,ttrip->ip,ttrip->mask ,t.portrange.get(),t.ports.get() ,type == FWTYPE_REDIR ? redirport : "" ,logging != 0 ,syn_packets); ret = -1; } } } return ret; } PUBLIC int IPFW_RULE::setup( int policy, const IPFW_SRC &f, const IPFW_SRC &t, FWTYPE type, const char *redirport, const char *redirhost, bool doit, // Exec the command ? SSTRING *collect, // Will contain a copy of the // command generated SSTRING &errmsg) // Error message are appended to this SSTRING { int ret = 0; if (active){ if (protocol.cmp("tcp")==0 && f.allow_syn == 0 && policy == FW_ACCEPT){ // We must block SYN packet first with a specific // rule ret = setupone (FW_DENY,f,t,type,redirport,redirhost ,true,doit,collect,errmsg); } ret |= setupone (policy,f,t,type,redirport,redirhost ,false,doit,collect,errmsg); } return ret; } PROTECTED int IPFW_RULEP::setup( IPFW_SRC &f, IPFW_SRC &t, FWTYPE type, const char *redirport, const char *redirhost, bool doit, // Exec the command ? SSTRING *collect, // Will contain a copy of the // command generated SSTRING &errmsg) // Error message are appended to this SSTRING { return IPFW_RULE::setup (policy,f,t,type,redirport,redirhost,doit,collect,errmsg); } /* Setup one side of the forwarding rule (from -> to) */ PUBLIC int IPFW_RULE_FORWARD::setup_left(bool doit, SSTRING *collect, SSTRING &errmsg) { int ret = -1; if (masquerade){ ret = setup (from,to,FWTYPE_MASQ,NULL,NULL,doit,collect,errmsg); }else{ ret = setup (from,to,FWTYPE_FORWARD,NULL,NULL,doit,collect,errmsg); } return ret; } /* Setup one side of the forwarding rule (to -> from) */ PUBLIC int IPFW_RULE_FORWARD::setup_right(bool doit, SSTRING *collect, SSTRING &errmsg) { int ret = 0; if (!masquerade){ ret = setup (to,from,FWTYPE_FORWARD,NULL,NULL,doit,collect,errmsg); } return ret; } /* Setup one side of the forwarding rule (from -> to) */ PUBLIC int IPFW_RULE_OUTPUT::setup_left(bool doit, SSTRING *collect, SSTRING &errmsg) { return setup (from,to,FWTYPE_OUTPUT,NULL,NULL,doit,collect,errmsg); } /* Setup one side of the forwarding rule (to -> from) */ PUBLIC int IPFW_RULE_OUTPUT::setup_right(bool doit, SSTRING *collect, SSTRING &errmsg) { return setup (to,from,FWTYPE_OUTPUT,NULL,NULL,doit,collect,errmsg); } /* Setup one side of the blocking rule (from -> to) */ PUBLIC int IPFW_RULE_INPUT::setup_left(bool doit, SSTRING *collect, SSTRING &errmsg) { int ret = -1; if (doredir){ const char *port = redirport.get(); if (redirport.is_empty()) port = "0"; const char *rdrhost = redirhost.get(); if (rdrhost[0] == '\0') rdrhost = NULL; ret = setup (from,to,FWTYPE_REDIR,port,rdrhost,doit,collect,errmsg); }else{ ret = setup (from,to,FWTYPE_INPUT,NULL,NULL,doit,collect,errmsg); } return ret; } /* Setup one side of the blocking rule (to -> from) */ PUBLIC int IPFW_RULE_INPUT::setup_right(bool doit, SSTRING *collect, SSTRING &errmsg) { int ret = 0; if (!doredir){ ret = setup (to,from,FWTYPE_INPUT,NULL,NULL,doit,collect,errmsg); } return ret; } /* Setup one side of the accounting rule (from -> to) */ PUBLIC int IPFW_RULE_ACCT::setup_left(bool doit, SSTRING *collect, SSTRING &errmsg) { return setup (FW_ACCEPT,from,to,FWTYPE_ACCT,NULL,NULL,doit,collect,errmsg); } /* Setup one side of the accounting rule (to -> from) */ PUBLIC int IPFW_RULE_ACCT::setup_right(bool doit, SSTRING *collect, SSTRING &errmsg) { return setup (FW_ACCEPT,to,from,FWTYPE_ACCT,NULL,NULL,doit,collect,errmsg); }