#include #include #include #include #include "rarp.h" #include "netconf.h" #include #include #include "rarp.m" #include "../../paths.h" static HELP_FILE help_rarp ("rarp","rarp"); static CONFIG_FILE f_net_rarp (PROC_NET_RARP ,help_rarp ,CONFIGF_OPTIONAL|CONFIGF_PROBED); class RARP_ENTRY: public ARRAY_OBJ{ public: char seen; // Used to tell if one entry has been // processed char active; // This record has to be activated in the kernel SSTRING ip; // IP number of host name SSTRING hw; // Hardware address SSTRING comment; /*~PROTOBEG~ RARP_ENTRY */ public: RARP_ENTRY (const char *_ip, const char *_hw, int _active, const char *_comment); RARP_ENTRY (const char *str, int noline); RARP_ENTRY (void); int cmp (const char *ipstr); int edit (void); int is_valid (int talk); private: int normalise (void); public: int set (void); int unset (void); /*~PROTOEND~ RARP_ENTRY */ }; /* Constructor used to read /proc/net/rarp */ PUBLIC RARP_ENTRY::RARP_ENTRY(const char *str, int noline) { active = 1; seen = 0; char ipstr[100]; char mbps[100]; char ethernet[100]; char hwstr[100]; /* #Specification: rarp / proc/net/rarp / format We assume this file has the following format and are simply looking for 4 words. # ip_number 10Mbps Ethernet hw_address # We are validating the second and third word to make sure */ if (sscanf (str,"%s %s %s %s",ipstr,mbps,ethernet,hwstr)==4){ if (strcmp(mbps,"10Mbps")!=0 || strcmp(ethernet,"Ethernet")!=0){ xconf_error (MSG_U(E_IVLDRARPFORM ,"Invalid format in file %s, line %d") ,f_net_rarp.getpath(),noline); }else{ ip.setfrom (ipstr); hw.setfrom (hwstr); } } } /* Constructor used to read configuration. */ PUBLIC RARP_ENTRY::RARP_ENTRY( const char *_ip, const char *_hw, int _active, const char *_comment) { seen = 0; ip.setfrom (_ip); hw.setfrom (_hw); active = (char)_active; comment.setfrom (_comment); normalise(); } /* Create an empty entry */ PUBLIC RARP_ENTRY::RARP_ENTRY() { seen = 0; active = 1; } /* Add this entry to the rarp table */ PUBLIC int RARP_ENTRY::set() { char buf[200]; sprintf (buf,"-s %s %s",ip.get(),hw.get()); return netconf_system_if ("rarp",buf); } /* Compare one IP number with this entry Return 0 if equal, != 0 if different. */ PUBLIC int RARP_ENTRY::cmp(const char *ipstr) { int ret = ip.cmp(ipstr); if (ret != 0){ /* #Specification: rarp / entry / ip or host name We can specify a host either by its IP number or its host name. */ struct hostent *ent = gethostbyname(ip.get()); if (ent != NULL){ char str[20]; ipnum_ip2a (ent,str); ret = strcmp(ipstr,str); } } return ret; } /* delete this entry from the rarp table */ PUBLIC int RARP_ENTRY::unset () { char buf[200]; sprintf (buf,"-d %s",ip.get()); return netconf_system_if ("rarp",buf); } class RARP_ENTRIES: public ARRAY{ /*~PROTOBEG~ RARP_ENTRIES */ public: RARP_ENTRIES (CONFIG_FILE&f); RARP_ENTRIES (void); int edit (void); RARP_ENTRY *getitem (int no); int isoneactive (void); RARP_ENTRY *locate (const char *ipstr); void update (RARP_ENTRIES¤t); int write (void); /*~PROTOEND~ RARP_ENTRIES */ }; PUBLIC RARP_ENTRY *RARP_ENTRIES::getitem (int no) { return (RARP_ENTRY*)ARRAY::getitem(no); } /* Locate an entry using its IP number or name. Only active entries are checked. */ PUBLIC RARP_ENTRY *RARP_ENTRIES::locate (const char *ipstr) { RARP_ENTRY *ret = NULL; for (int i=0; iactive && a->cmp(ipstr)==0){ ret = a; break; } } return ret; } static char RARP[]="rarp"; static char ENTRY[]="entry"; /* Load from /etc/conf.linuxconf */ PUBLIC RARP_ENTRIES::RARP_ENTRIES() { SSTRINGS strs; linuxconf_getall (RARP,ENTRY,strs,0); int nb = strs.getnb(); for (int i=0; iget(); pt = str_copyword (ipstr,pt,sizeof(ipstr)); pt = str_copyword (hwstr,pt,sizeof(hwstr)); pt = str_copyword (acstr,pt,sizeof(acstr)); // The active field has been added. It defaults to "active" int active = acstr[0] == '\0' ? 1 : atoi(acstr) != 0; pt = str_skip(pt); sscanf (s->get(),"%s %s",ipstr,hwstr); add (new RARP_ENTRY (ipstr,hwstr,active,pt)); } rstmodified(); } /* Update /etc/conf.linuxconf */ PUBLIC int RARP_ENTRIES::write() { int n = getnb(); linuxconf_removeall (RARP,ENTRY); for (int i=0; iip.get(),e->hw.get(),e->active ,e->comment.get()); linuxconf_add (RARP,ENTRY,buf); } rstmodified(); return linuxconf_save(); } /* Load the running config. */ PUBLIC RARP_ENTRIES::RARP_ENTRIES(CONFIG_FILE &f) { FILE_CFG *fin = f.fopen ("r"); if (fin != NULL){ int noline = 1; char buf[300]; // Skip the first line fgets (buf,sizeof(buf)-1,fin); while (fgets (buf,sizeof(buf)-1,fin) != NULL){ noline++; add (new RARP_ENTRY(buf,noline)); } fclose (fin); } } PUBLIC void RARP_ENTRIES::update (RARP_ENTRIES ¤t) { int n = current.getnb(); int i; for (i=0; iip.get()); if (a == NULL){ cur_a->unset(); }else{ a->seen = 1; if (a->hw.cmp(cur_a->hw)!=0){ cur_a->unset(); a->set(); } } } n = getnb(); for (i=0; iseen && a->active) a->set(); } } /* Validate and normalise the format of the hardware address. Make sure there is 2 digits per byte. This helps when comparing with the current setup as read from /proc/net/rarp. */ PRIVATE int RARP_ENTRY::normalise() { int digits[6]; memset (digits,0,sizeof(digits)); const char *pt = hw.get(); int err = 0; int nbhex = 0; int nbpt = 0; while (*pt != '\0'){ char carac = *pt++; if (carac == ':'){ if (nbhex == 0 || nbhex > 2) err = 1; nbhex = 0; nbpt++; }else if (nbpt == 6){ err = 1; }else if (isxdigit(carac)){ digits[nbpt] *= 16; if (isalpha(carac)){ carac = toupper(carac) - 'A' + 10; }else{ carac -= '0'; } digits[nbpt] += carac; nbhex++; }else{ err = 1; } } if (nbpt != 5 || nbhex == 0){ err = 1; }else{ char formstr[6*2+5+0]; sprintf (formstr,"%02x:%02x:%02x:%02x:%02x:%02x" ,digits[0],digits[1],digits[2],digits[3],digits[4],digits[5]); hw.setfrom (formstr); } return err ? -1 : 0; } /* Return != 0 the entry is valid. May operate silently or show errors */ PUBLIC int RARP_ENTRY::is_valid(int talk) { int ret = 0; if (ip.is_empty() || hw.is_empty()){ if (talk) xconf_error (MSG_U(E_ALLFIELD,"All field must be filled")); }else{ if (normalise()==-1){ if (talk){ xconf_error (MSG_U(E_HARDETH ,"Invalid hardware ethernet address\n" "%s\n" "Expect xx:xx:xx:xx:xx:xx format") ,hw.get()); } }else{ ret = 1; } } return ret; } /* Edit one entry Return -1 if the user cancel Return 0 if the user accept the changes Return 1 if the user wish to delete this record */ PUBLIC int RARP_ENTRY::edit() { int ret = -1; DIALOG dia; dia.newf_chk ("",active,MSG_U(F_RARPACTIVE,"This record is active")); dia.newf_str (MSG_U(F_HOSTNAME,"host name or IP number"),ip); dia.newf_str (MSG_U(F_ETHADR,"Ethernet address"),hw); dia.newf_str (MSG_U(F_COMMENT,"Comment"),comment); int nof = 0; while (1){ MENU_STATUS code = dia.edit(MSG_U(T_ETH2IP,"Ethernet to IP translation") ,MSG_U(I_ETH2IP ,"Enter an IP number or a host name\n" "and its ethernet 6 hexadecimal digit\n" "address") ,help_rarp ,nof ,MENUBUT_CANCEL|MENUBUT_ACCEPT|MENUBUT_DEL); if (code == MENU_CANCEL || code == MENU_ESCAPE){ break; }else if (code == MENU_DEL){ ret = 1; break; }else if (is_valid(1)){ ret = 0; break; } } if (ret != 0) dia.restore(); return ret; } static int cmp_by_ip (const ARRAY_OBJ *o1, const ARRAY_OBJ *o2) { RARP_ENTRY *e1 = (RARP_ENTRY*)o1; RARP_ENTRY *e2 = (RARP_ENTRY*)o2; return e1->ip.cmp(e2->ip); } PUBLIC int RARP_ENTRIES::edit() { int choice = 0; while (1){ DIALOG_LISTE dia; dia.newf_head ("",MSG_U(H_RARPLIST,"Host or IP\tMAC address\tActive\tComment")); sort (cmp_by_ip); for (int i=0; ihw.get() ,e->active ? 'X' : ' ' ,e->comment.get()); dia.new_menuitem (e->ip.get(),buf); } dia.addwhat (MSG_U(I_ANEWENTRY,"Select [Add] to add a new entry")); MENU_STATUS code = dia.editmenu( MSG_U(T_RARPCONF,"RARP configuration") ,MSG_U(I_RARPCONF,"You are allowed to edit/add\n" "RARP (Reverse Address Resolution)\n" "which will allow other computer to get\n" "their IP number from this server\n") ,help_rarp ,choice ,0); if (code == MENU_ESCAPE || code == MENU_QUIT){ break; }else if (perm_rootaccess(MSG_U(P_EDITRARP ,"to edit RARP configuration"))){ if (code == MENU_ADD){ RARP_ENTRY *e = new RARP_ENTRY; manage_edit (e,e->edit()); }else{ editone (choice); } } } return 0; } /* Return != 0 if there is at least one record active */ PUBLIC int RARP_ENTRIES::isoneactive() { int ret = 0; int n = getnb(); for (int i=0; iactive){ ret = 1; break; } } return ret; } /* Edit the RARP table used to program the kernel RARP table */ void rarp_edit() { RARP_ENTRIES rarps; rarps.edit(); } /* Install, update the rarp table */ void rarp_activate () { if (perm_rootaccess(MSG_U(P_UPDRARP,"to install RARP entry"))){ RARP_ENTRIES conf; if (f_net_rarp.exist()){ RARP_ENTRIES cur (f_net_rarp); conf.update (cur); }else if (conf.isoneactive()){ /* #Specification: rarp / module If /proc/net/rarp is not available, the command "modprobe rarp" is executed to load the module. The presence of /proc/net/rarp is checked again to see if it has succeeded. An error message is generated. This is done only if some rarp entries are configured. */ netconf_system_if ("modprobe","rarp"); if (f_net_rarp.exist()){ RARP_ENTRIES cur (f_net_rarp); conf.update (cur); }else{ xconf_error (MSG_U(E_NORARP ,"This kernel does not support RARP\n" "I can't load the RARP table\n" "Some machines may fail to boot because of that")); } } } }