#include #include #include #include #include #include "../module_apis/dnsconf_apidef.h" #include "dhcpd.h" #include "dhcpd.m" #include #include extern CONFIG_FILE f_lease; PUBLIC LEASE::LEASE( const char *_host, const char *_ip, const char *_mac, const char *_starts, const char *_ends, const int _parserank) { strcpy (ip,_ip); host.setfrom(_host); starts.setfrom (_starts); ends.setfrom (_ends); mac.setfrom (_mac); parserank = _parserank; ipa.copyword(ip); } PUBLIC LEASE *LEASES::getitem (int no) const { return (LEASE*)ARRAY::getitem(no); } /* hubert@id-pro.de: Compare by ip and position in the leasefile */ static int cmp_by_ip (const ARRAY_OBJ *o1, const ARRAY_OBJ *o2) { LEASE *l1 = (LEASE*)o1; LEASE *l2 = (LEASE*)o2; int ret = l1->ipa.cmp(&l2->ipa); if (ret == 0){ // We put the last update first, because dups are skipped // (see markdup) #if 0 ret = l1->parserank - l2->parserank; #else ret = l1->ends.cmp(l2->ends); #endif } return ret; } /* Compare by name and position in the leasefile */ static int cmp_by_name (const ARRAY_OBJ *o1, const ARRAY_OBJ *o2) { LEASE *l1 = (LEASE*)o1; LEASE *l2 = (LEASE*)o2; int ret = l1->host.cmp(l2->host); if (ret == 0){ ret = l1->ends.cmp(l2->ends); } return ret; } /* Mark items which are duplicated. Items are sorted by named and lease end time. The last orccurence of an item is not marked as duplicate. */ PUBLIC void LEASES::markdup() { int nb = getnb(); for (int i=0; iisdup = false; sort (cmp_by_ip); for (int i=0; iipa.cmp(&l->ipa) ==0) l->isdup = true; } sort (cmp_by_name); for (int i=0; ihost.cmp(l->host) ==0) l->isdup = true; } } PRIVATE void LEASES::init (FILE_CFG *fin) { if (fin != NULL){ char buf[1000]; SSTRING starts,ends,ip,mac,host; int parsenr = 0; while (fgets(buf,sizeof(buf)-1,fin)!=NULL){ char keyw[100]; char *pt = strchr (buf,';'); if (pt != NULL) *pt = '\0'; pt = str_copyword (keyw,buf,sizeof(keyw)); if (strcmp(keyw,"lease")==0){ ip.copyword (pt); }else if (strcmp(keyw,"starts")==0){ pt = str_skip(pt); pt = str_skipword(pt); starts.copyword (pt); }else if (strcmp(keyw,"ends")==0){ pt = str_skip(pt); pt = str_skipword(pt); // We keep the whole date, because we use this to compare // lease. We could do the same for start, for completness // but in general, we just want to know the day a lease // started. ends.setfrom (pt); }else if (strcmp(keyw,"hardware")==0){ pt = str_copyword(keyw,pt,sizeof(keyw)); if (strcmp(keyw,"ethernet")==0){ mac.copyword (pt); } }else if (strcmp(keyw,"client-hostname")==0){ str_extract (pt,host); }else if (strcmp(keyw,"}")==0){ add (new LEASE(host.get(),ip.get(),mac.get(),starts.get() ,ends.get(), parsenr)); host.setfrom (""); ip.setfrom (""); mac.setfrom (""); starts.setfrom (""); ends.setfrom (""); parsenr++; } } fclose (fin); } } PUBLIC LEASES::LEASES() { init (f_lease.fopen ("r")); } PUBLIC LEASES::LEASES(const char *fname) { init (f_lease.fopen (fname,"r")); } /* Update the DNS from the dhcp server Return 0 if the DNS was updated, != 0 if the DNS was left unchanged */ int leases_updatedns ( DNSCONF_API *api, bool command_line, bool verbose, UWE_RANGES* ranges, const char *fname, const char *defdom) { int ret = -1; bool validname = dhcp_getvalidname(); if (defdom == NULL || defdom[0] == '\0'){ if (command_line){ fprintf (stderr,MSG_U(E_DNSDOM ,"You must specify in which DNS domain\n" "DHCP host must be inserted")); }else{ xconf_error (MSG_R(E_DNSDOM)); } }else{ LEASES leases(fname); leases.markdup (); bool must_write = false; int nb = leases.getnb(); for (int i=0; ihost.get(); if (!l->isdup && host[0] != '\0' && strlen(host)<999){ // We remove the . if there (should not) and then add // the default domain char fqdn[1000],orig[1000]; if (strchr(host,'.')!=NULL){ strncpy (fqdn,host,sizeof(fqdn)-1); fqdn[sizeof(fqdn)-1] = '\0'; char *pt = strchr(fqdn,'.'); pt++; strcpy (pt,defdom); }else{ snprintf (fqdn,sizeof(fqdn)-1,"%s.%s",host,defdom); } strcpy (orig,fqdn); /* #Specification: dhcp to dns / name conversion We turn spaces and _ into - as this is not legal for DNS. (or not recommended). Well, quite a few other special character seems valid (or windows does not check much) for netbios, so we have to map character above 127 and most special character. */ { char *pt = fqdn; while (*pt != '\0'){ if (!(isalpha(*pt) || isdigit(*pt) || *pt == '-' || *pt == '.')){ // Replace all invalid characters *pt = '-'; } // Make sure the last character is not special if (pt[1] == '\0'){ if (*pt == '-' || *pt == '.'){ *pt = '0'; } } pt++; } } if (strcmp(fqdn,"-")!=0 && (strcmp(fqdn,orig)==0 || !validname)){ const char *ip = l->ip; IP_ADDRS ips; int nbip = api->geta (fqdn,ips); if (nbip == 0){ if (api->setfromip (fqdn,ip) != 0) must_write = true; }else if (!ranges->inrange(ips)){ //hubert@id-pro.de: check if the ip is in the range of the server // The DNS already have a name with an IP outside of // the reach of the DHCP server. This is probably // an IP entered manually (a server probably), so // we are not allowed to override it. // We produce an error so the admin can fix the // offending workstation syslog (LOG_ERR,"dhcp2dns: station %s with IP %s clashes with a manual entry in the DNS" ,fqdn,ip); }else if (nbip != 1 || ips.getitem(0)->cmp(ip)!=0){ // If there were more than one IP in the DNS for that // name, those A records will be changed (since DHCP // has a single IP for that NAME. // Or if the IP is different, then we must change it. if (api->setfromip (fqdn,ip) != 0) must_write = true; } } } } if (must_write){ api->write(); if (command_line){ if (verbose) printf (MSG_U(N_UPDATED,"DNS was updated")); }else{ xconf_notice (MSG_R(N_UPDATED)); } ret = 0; }else{ if (command_line){ if (verbose) printf (MSG_U(N_UPTODATE,"DNS was already up to date")); }else{ xconf_notice (MSG_R(N_UPTODATE)); } } } return ret; } /* Present the list of host currently served by the dhcpd server */ void leases_showalloc() { LEASES leases; leases.showalloc(); }