/* #Specification: routes / gateways identified manually The user is allowed to program some routes to other network using gateways. A default gateways may be identified (default_router) */ #include #include #include #include #include "netconf.h" #include #include "netconf.m" #include #include #include "internal.h" NETCONF_HELP_FILE help_routes ("routes"); static NETCONF_HELP_FILE help_defroute ("default_route"); CONFIG_FILE f_conf_routes (ETC_CONF_ROUTES ,help_routes,CONFIGF_MANAGED|CONFIGF_OPTIONAL ,subsys_netclient); static CONFIG_FILE f_ip_forward (PROC_SYS_IP_FORWARD ,help_routes,CONFIGF_PROBED|CONFIGF_OPTIONAL); static CONFIG_FILE f_snmp (PROC_NET_SNMP ,help_routes,CONFIGF_PROBED|CONFIGF_OPTIONAL); struct GROUTES_INFO { SSTRING defroute; ROUTES routes; }; /* Sort routes by destination */ static int cmp_route_by_dest (const void *p1, const void *p2) { ROUTE *h1 = *(ROUTE**)p1; ROUTE *h2 = *(ROUTE**)p2; return strcmp(h1->getdst(),h2->getdst()); } static int (*fct_load)(ROUTES &rt)=NULL; static int (*fct_save)(SSTRING &defroute, ROUTES &rt)=NULL; void groutes_sethook( int (*_fct_load)(ROUTES &rt), int (*_fct_save)(SSTRING &defroute, ROUTES &rt)) { fct_load = _fct_load; fct_save = _fct_save; } /* Write /etc/conf.routes */ static void groutes_save(GROUTES_INFO &info) { if (fct_save != NULL){ (*fct_save)(info.defroute,info.routes); f_conf_routes.unlink (); }else{ FILE_CFG *fout = f_conf_routes.fopen ("w"); if (fout != NULL){ if (!info.defroute.is_empty()){ fprintf (fout,"-net default gw %s\n",info.defroute.get()); } info.routes.write(fout); fclose (fout); } } } static void groutes_editothers( GROUTES_INFO &info, RTTYPE route_type) { int choice=0; DIALOG_RECORDS dia; static const char *tbhead[]={ MSG_U(H_ROUTENET,"Network\tNetmask\tGateway"), MSG_U(H_ROUTEHOST,"Host\tGateway"), MSG_U(H_ROUTEALT,"Network\tNetmask\tInterface") }; dia.newf_head ("",tbhead[route_type]); dia.addwhat (MSG_U(I_TOADDROUTE,"Select [Add] to add a new route")); while (1){ ROUTE *tb[500]; int nbrt=0; { // Collect the entries which are host route or network route // depending on edit_host_route int nb_total = info.routes.getnb(); for (int i=0; igettype()){ tb[nbrt++] = pt; } } } qsort (tb,nbrt,sizeof(ROUTE *),cmp_route_by_dest); { for (int i=0; igetmask(),rt->getiface()); }else if (route_type==RTTYPE_NETWORK){ snprintf (buf,sizeof(buf)-1,"%s\t%s",rt->getmask(),rt->getgateway()); }else{ strcpy_cut (buf,rt->getgateway(),sizeof(buf)); } dia.set_menuitem (i,tb[i]->getdst(),buf); } } dia.remove_last (nbrt+1); static const char *tbtitle[]={ MSG_U(T_ROUTENET,"Route to other networks"), MSG_U(T_ROUTEHOSTS,"Route to other hosts"), MSG_U(T_ROUTEALT,"Route to alternate local networks"), }; static const char *tbintro[]={ MSG_U(I_ROUTENET ,"If your network has access to other networks\n" "you must tell how to reach those networks\n"), MSG_U(I_ROUTEHOSTS ,"If your network has access to remote hosts\n" "you must tell how to reach those hosts\n"), MSG_U(I_ROUTEALT ,"If there are several IP networks sharing the same\n" "physical network (wire), you must configure the routing\n" "this here") }; MENU_STATUS code = dia.editmenu (tbtitle[route_type] ,tbintro[route_type] ,help_routes ,choice,MENUBUT_ADD); if (code == MENU_QUIT || code == MENU_ESCAPE){ break; }else if (code == MENU_ADD){ ROUTE *route = new ROUTE ("","","" ,route_type == RTTYPE_HOST ? "UGH" : "UG",""); if (route->edit(route_type)==0){ info.routes.add (route); groutes_save (info); }else{ delete route; } }else if (nbrt > 0){ if (code == MENU_OK){ ROUTE *route = tb[choice]; int ok = route->edit(route_type); if (ok != -1){ if (ok == 1){ info.routes.remove_del (route); } groutes_save(info); } } } } } #if 0 /* Check if there is at least one route other than the default Return != 0 if yes. */ static int groutes_isothers( ROUTES &routes, RTTYPE route_type) { int ret = 0; int nb = routes.getnb(); for (int i=0; igettype()){ ret = 1; break; } } return ret; } #endif /* Return != 0 if the kernel has routing enabled currently */ static int groutes_isrouter() { int ret = 0; FILE_CFG * fin = f_ip_forward.fopen ("r"); if (fin != NULL){ char buf[20]; if (fgets(buf,sizeof(buf)-1,fin)!=NULL){ ret = atoi(buf); } fclose (fin); }else{ fin = f_snmp.fopen ("r"); if (fin != NULL){ char buf[1000]; if (fgets(buf,sizeof(buf)-1,fin)!=NULL && fgets(buf,sizeof(buf)-1,fin)!=NULL){ char *pt = str_skipword(buf); pt = str_skip(pt); if (isdigit(*pt)) ret = atoi(pt); } fclose (fin); } } return ret; } static const char K_ROUTING[]="routing"; static const char K_ENABLED[]="ipv4"; void groutes_setrouting () { int isrouter = groutes_isrouter(); int router = linuxconf_getvalnum(K_ROUTING,K_ENABLED,isrouter); net_hint ("IPV4ROUTING",router ? "true" : "false"); if (router != isrouter){ net_prtlog (NETLOG_CMD,router ? MSG_U(I_ROUTERON,"Enabling routing\n") : MSG_U(I_ROUTEROFF,"Disabling routing\n")); if (!simul_ison()){ FILE_CFG *fout = f_ip_forward.fopen ("w"); if (fout != NULL){ fprintf (fout,"%d\n",router); fclose (fout); }else{ xconf_error (MSG_U(E_ROUTINGCTRL ,"Can't controlling routing with this kernel")); } } net_hint ("RECONF_IPV4ROUTING","yes"); } } static void groutes_editdef ( GROUTES_INFO &info) { DIALOG dia; char isrouter = linuxconf_getvalnum (K_ROUTING,K_ENABLED ,groutes_isrouter()); dia.newf_str(MSG_U(F_DEFGTW,"Default gateway") ,info.defroute); dia.newf_chk("",isrouter,MSG_U(I_ISROUTER,"Enable routing")); if (!f_ip_forward.exist()) dia.set_lastreadonly(); if (dia.edit_form (MSG_U(T_DEFAULTS,"Defaults") ,MSG_U(I_DEFGTW ,"Enter the IP number of the main gateway\n" "And indicate if this machine is allowed to\n" "route IP packets") ,help_defroute) == MENU_ACCEPT){ groutes_save(info); if (f_ip_forward.exist()){ linuxconf_setcursys (subsys_netclient); linuxconf_replace (K_ROUTING,K_ENABLED,isrouter); linuxconf_save(); } } } static int groutes_edit( GROUTES_INFO &info) { int ret = 0; int choice=0; static const char *default_route = MSG_U(M_DEFROUTE,"Defaults"); static const char *other_route_net = MSG_U(M_ROUTENET,"other routes to networks"); static const char *other_route_host = MSG_U(M_ROUTEHOSTS,"other routes to hosts"); static const char *other_route_alt = MSG_U(M_ROUTEALT,"routes to alternate local nets"); static const char *routed = MSG_U(M_ROUTED,"the routed daemon"); #if 0 char default_route_str[80]; char other_route_str_net[80]; char other_route_str_host[80]; char other_route_str_alt[80]; #endif static const char *menuopt[]={ MSG_U(M_SET,"Set"), default_route, "", other_route_net, "", other_route_host, "", other_route_alt, MSG_U(M_CONFIG,"Configure"),routed, NULL }; DIALOG_MENU dia; dia.new_menuitems (menuopt); while (1){ MENU_STATUS code = dia.editmenu( MSG_U(T_ROUTES,"Routes to other networks") ,MSG_U(I_ROUTES ,"If your network has access to other networks\n" "you must tell how to reach those networks\n" "For many setup, simply setting the default route\n" "is good enough\n" "\n" "If you only talk to machines on the local network\n" "then all this is not necessary.\n") ,help_routes ,choice,0); if (code == MENU_QUIT || code == MENU_ESCAPE){ ret = -1; break; }else{ const char *key = dia.getmenustr(choice); if (key == default_route){ groutes_editdef (info); }else if (key == other_route_net){ groutes_editothers (info,RTTYPE_NETWORK); }else if (key == other_route_host){ groutes_editothers (info,RTTYPE_HOST); }else if (key == other_route_alt){ groutes_editothers (info,RTTYPE_ALTNET); }else if (key == routed){ routed_edit(); } } } return ret; } /* Read /etc/conf.routes */ PUBLIC void ROUTES::readconf () { if (fct_load != NULL && !f_conf_routes.exist()){ (*fct_load)(*this); }else{ /* #Specification: ETC_CONF_ROUTES / format The format of /etc/conf.routes is simply the end of a route command (everything after the add keyword). So if you want to install a default route (and want to do so by editing /etc/conf.routes manually, then you write -net default gw router You only write routes which are not associated to devices. The primary route to the ethernet network is taken care automaticly by netconf. You just place extra routes here. */ FILE_CFG *fin = f_conf_routes.fopen ("r"); if (fin != NULL){ char buf[300]; int noline=0; while (fgets_strip (buf,sizeof(buf)-1,fin,&noline)!=NULL){ if (buf[0] != '\0'){ ROUTE *pt = new ROUTE (buf,noline); add (pt); } } fclose (fin); } } } static void groutes_read(GROUTES_INFO &info) { info.routes.readconf (); ROUTE *def = info.routes.finddefault(); if (def != NULL){ info.defroute.setfrom (def->getgateway()); info.routes.remove_del (def); } } /* Edite /etc/conf.routes */ void netconf_editroutes() { GROUTES_INFO info; groutes_read(info); groutes_edit(info); } void groutes_setgateway (const char *ip, bool verbose) { GROUTES_INFO info; groutes_read(info); if (info.defroute.cmp(ip)!=0){ if (verbose){ net_prtlog (NETLOG_CMD,MSG_U(I_SETGATEWAY ,"Changing default gateway to %s\n") ,ip); } if (!simul_ison()){ info.defroute.setfrom (ip); groutes_save(info); } } } static void groutes_editdef() { GROUTES_INFO info; groutes_read(info); groutes_editdef(info); } #include static PUBLISH_VARIABLES_MSG groutes_var_list[]={ {"gateway",P_MSG_R(F_DEFGTW)}, {"routingon",P_MSG_R(I_ISROUTER)}, { NULL, NULL } }; static REGISTER_VARIABLES groutes_registry1("routing",groutes_var_list ,NULL,groutes_editdef);