From: Roy Marples Date: Thu, 11 Oct 2007 13:26:16 +0000 (+0000) Subject: Reduce stack usage by using malloc more. X-Git-Tag: v3.2.3~189 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b3f5301936ef265fc53a4e02c62edd809b25d3a1;p=thirdparty%2Fdhcpcd.git Reduce stack usage by using malloc more. --- diff --git a/ChangeLog b/ChangeLog index 2857757c..94df85f6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ +Reduce stack usage by using malloc more. If we're on a different subnet from the one we get DHCP for, don't use our current address in messages. Thanks to Wilson Callan. Skip over bogus EINTR error on select when arp checking for a diff --git a/configure.c b/configure.c index 7ecf6fc8..66ff70af 100644 --- a/configure.c +++ b/configure.c @@ -113,14 +113,15 @@ static int make_resolv (const char *ifname, const dhcp_t *dhcp) { FILE *f; struct stat buf; - char resolvconf[PATH_MAX] = {0}; + char *resolvconf = NULL; address_t *address; #ifdef RESOLVCONF if (stat (RESOLVCONF, &buf) == 0) { logger (LOG_DEBUG, "sending DNS information to resolvconf"); - snprintf (resolvconf, PATH_MAX, RESOLVCONF" -a %s", ifname); + asprintf (&resolvconf, RESOLVCONF" -a %s", ifname); f = popen (resolvconf, "w"); + free (resolvconf); if (! f) logger (LOG_ERR, "popen: %s", strerror (errno)); @@ -145,7 +146,7 @@ static int make_resolv (const char *ifname, const dhcp_t *dhcp) for (address = dhcp->dnsservers; address; address = address->next) fprintf (f, "nameserver %s\n", inet_ntoa (address->address)); - if (*resolvconf) + if (resolvconf) pclose (f); else fclose (f); @@ -155,7 +156,7 @@ static int make_resolv (const char *ifname, const dhcp_t *dhcp) return (0); } -static void restore_resolv(const char *ifname) +static void restore_resolv (const char *ifname) { #ifdef RESOLVCONF struct stat buf; @@ -169,12 +170,13 @@ static void restore_resolv(const char *ifname) } #ifdef ENABLE_NTP +#define BUFFERSIZE 1024 static int _make_ntp (const char *file, const char *ifname, const dhcp_t *dhcp) { FILE *f; address_t *address; char *a; - char buffer[1024]; + char *buffer; int tomatch = 0; char *token; bool ntp = false; @@ -190,8 +192,9 @@ static int _make_ntp (const char *file, const char *ifname, const dhcp_t *dhcp) return -1; } } else { - memset (buffer, 0, sizeof (buffer)); - while (fgets (buffer, sizeof (buffer), f)) { + buffer = xmalloc (sizeof (char *) * BUFFERSIZE); + memset (buffer, 0, BUFFERSIZE); + while (fgets (buffer, BUFFERSIZE, f)) { a = buffer; token = strsep (&a, " "); if (! token || strcmp (token, "server") != 0) @@ -209,6 +212,7 @@ static int _make_ntp (const char *file, const char *ifname, const dhcp_t *dhcp) if (tomatch == 0) break; } + free (buffer); fclose (f); /* File has the same name servers that we do, so no need to restart ntp */ @@ -288,11 +292,12 @@ static int make_ntp (const char *ifname, const dhcp_t *dhcp) #endif #ifdef ENABLE_NIS +#define PREFIXSIZE 256 static int make_nis (const char *ifname, const dhcp_t *dhcp) { FILE *f; address_t *address; - char prefix[256] = {0}; + char *prefix; logger (LOG_DEBUG, "writing "NISFILE); if (! (f = fopen(NISFILE, "w"))) { @@ -300,21 +305,25 @@ static int make_nis (const char *ifname, const dhcp_t *dhcp) return -1; } + prefix = xmalloc (sizeof (char *) * PREFIXSIZE); + *prefix = '\0'; fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname); + if (dhcp->nisdomain) { setdomainname (dhcp->nisdomain, strlen (dhcp->nisdomain)); if (dhcp->nisservers) - snprintf (prefix, sizeof (prefix), "domain %s server", dhcp->nisdomain); + snprintf (prefix, PREFIXSIZE, "domain %s server", dhcp->nisdomain); else fprintf (f, "domain %s broadcast\n", dhcp->nisdomain); } else - snprintf (prefix, sizeof (prefix), "%s", "ypserver"); + snprintf (prefix, PREFIXSIZE, "%s", "ypserver"); for (address = dhcp->nisservers; address; address = address->next) fprintf (f, "%s %s\n", prefix, inet_ntoa (address->address)); + free (prefix); fclose (f); exec_cmd (NISSERVICE, NISRESTARTARGS, (char *) NULL); @@ -328,8 +337,8 @@ int configure (const options_t *options, interface_t *iface, route_t *route = NULL; route_t *new_route = NULL; route_t *old_route = NULL; - char newhostname[MAXHOSTNAMELEN] = {0}; - char curhostname[MAXHOSTNAMELEN] = {0}; + char *newhostname = NULL; + char *curhostname = NULL; if (! options || ! iface || ! dhcp) return (-1); @@ -522,6 +531,11 @@ int configure (const options_t *options, interface_t *iface, make_nis(iface->name, dhcp); #endif + curhostname = xmalloc (sizeof (char *) * MAXHOSTNAMELEN); + *curhostname = '\0'; + newhostname = xmalloc (sizeof (char *) * MAXHOSTNAMELEN); + *newhostname = '\0'; + /* Now we have made a resolv.conf we can obtain a hostname if we need it */ if (options->dohostname && (! dhcp->hostname || options->dohostname > 3)) { union { @@ -529,17 +543,18 @@ int configure (const options_t *options, interface_t *iface, struct sockaddr_in sin; } su; socklen_t salen; - char addr[NI_MAXHOST]; + char *addr; struct addrinfo hints, *res; int result; + addr = xmalloc (sizeof (char *) * NI_MAXHOST); salen = sizeof (struct sockaddr); memset (&su.sa, 0, salen); su.sin.sin_family = AF_INET; memcpy (&su.sin.sin_addr, &dhcp->address, sizeof (struct in_addr)); logger (LOG_DEBUG, "Looking up hostname via DNS"); - if ((result = getnameinfo (&su.sa, salen, addr, sizeof (addr), + if ((result = getnameinfo (&su.sa, salen, addr, NI_MAXHOST, NULL, 0, NI_NAMEREQD)) != 0) logger (LOG_ERR, "Failed to lookup hostname via DNS: %s", gai_strerror (result)); else { @@ -587,12 +602,13 @@ int configure (const options_t *options, interface_t *iface, break; } } - strlcpy (newhostname, addr, sizeof (newhostname)); + strlcpy (newhostname, addr, MAXHOSTNAMELEN); } } + free (addr); } - gethostname (curhostname, sizeof (curhostname)); + gethostname (curhostname, MAXHOSTNAMELEN); if (options->dohostname || strlen (curhostname) == 0 @@ -600,13 +616,16 @@ int configure (const options_t *options, interface_t *iface, || strcmp (curhostname, "localhost") == 0) { if (dhcp->hostname) - strlcpy (newhostname, dhcp->hostname, sizeof (newhostname)); + strlcpy (newhostname, dhcp->hostname, MAXHOSTNAMELEN); if (*newhostname) { logger (LOG_INFO, "setting hostname to `%s'", newhostname); sethostname (newhostname, strlen (newhostname)); } } + + free (curhostname); + free (newhostname); #ifdef ENABLE_INFO if (! dhcp->frominfo) diff --git a/dhcp.c b/dhcp.c index 2328c836..94e5510f 100644 --- a/dhcp.c +++ b/dhcp.c @@ -59,10 +59,10 @@ size_t send_message (const interface_t *iface, const dhcp_t *dhcp, unsigned long xid, char type, const options_t *options) { - dhcpmessage_t message; - struct udp_dhcp_packet packet; - unsigned char *m = (unsigned char *) &message; - unsigned char *p = (unsigned char *) &message.options; + struct udp_dhcp_packet *packet; + dhcpmessage_t *message; + unsigned char *m; + unsigned char *p; unsigned char *n_params = NULL; unsigned long l; struct in_addr from; @@ -71,6 +71,7 @@ size_t send_message (const interface_t *iface, const dhcp_t *dhcp, uint32_t ul; uint16_t sz; unsigned int message_length; + size_t retval; if (!iface || !options || !dhcp) return -1; @@ -81,49 +82,52 @@ size_t send_message (const interface_t *iface, const dhcp_t *dhcp, if (type == DHCP_RELEASE) to.s_addr = dhcp->serveraddress.s_addr; - memset (&message, 0, sizeof (dhcpmessage_t)); + message = xmalloc (sizeof (dhcpmessage_t)); + memset (message, 0, sizeof (dhcpmessage_t)); + m = (unsigned char *) message; + p = (unsigned char *) &message->options; if (type == DHCP_INFORM || type == DHCP_RELEASE || type == DHCP_REQUEST) { - message.ciaddr = iface->previous_address.s_addr; + message->ciaddr = iface->previous_address.s_addr; from.s_addr = iface->previous_address.s_addr; /* Just incase we haven't actually configured the address yet */ if (type == DHCP_INFORM && iface->previous_address.s_addr == 0) - message.ciaddr = dhcp->address.s_addr; - + message->ciaddr = dhcp->address.s_addr; + /* Zero the address if we're currently on a different subnet */ if (type == DHCP_REQUEST && iface->previous_netmask.s_addr != dhcp->netmask.s_addr) message->ciaddr = from.s_addr = 0; } - message.op = DHCP_BOOTREQUEST; - message.hwtype = iface->family; + message->op = DHCP_BOOTREQUEST; + message->hwtype = iface->family; switch (iface->family) { case ARPHRD_ETHER: case ARPHRD_IEEE802: - message.hwlen = ETHER_ADDR_LEN; - memcpy (&message.chaddr, &iface->hwaddr, ETHER_ADDR_LEN); + message->hwlen = ETHER_ADDR_LEN; + memcpy (&message->chaddr, &iface->hwaddr, ETHER_ADDR_LEN); break; case ARPHRD_IEEE1394: case ARPHRD_INFINIBAND: - if (message.ciaddr == 0) - message.flags = (int16_t) htons (BROADCAST_FLAG); - message.hwlen = 0; + if (message->ciaddr == 0) + message->flags = (int16_t) htons (BROADCAST_FLAG); + message->hwlen = 0; break; default: logger (LOG_ERR, "dhcp: unknown hardware type %d", iface->family); } if (up < 0 || up > UINT16_MAX) - message.secs = htons ((short) UINT16_MAX); + message->secs = htons ((short) UINT16_MAX); else - message.secs = htons (up); - message.xid = xid; - message.cookie = htonl (MAGIC_COOKIE); + message->secs = htons (up); + message->xid = xid; + message->cookie = htonl (MAGIC_COOKIE); *p++ = DHCP_MESSAGETYPE; *p++ = 1; @@ -144,19 +148,19 @@ size_t send_message (const interface_t *iface, const dhcp_t *dhcp, if (type != DHCP_INFORM) { #define PUTADDR(_type, _val) \ - { \ - *p++ = _type; \ - *p++ = 4; \ - memcpy (p, &_val.s_addr, 4); \ - p += 4; \ - } - if (dhcp->address.s_addr != 0 && iface->previous_address.s_addr == 0 - && type != DHCP_RELEASE) - PUTADDR (DHCP_ADDRESS, dhcp->address); + { \ + *p++ = _type; \ + *p++ = 4; \ + memcpy (p, &_val.s_addr, 4); \ + p += 4; \ + } + if (dhcp->address.s_addr != iface->previous_address.s_addr && + type != DHCP_RELEASE) + PUTADDR (DHCP_ADDRESS, dhcp->address); - if (dhcp->serveraddress.s_addr != 0 && dhcp->address.s_addr !=0 && - (iface->previous_address.s_addr == 0 || type == DHCP_RELEASE)) - PUTADDR (DHCP_SERVERIDENTIFIER, dhcp->serveraddress); + if (dhcp->serveraddress.s_addr != 0 && dhcp->address.s_addr !=0 && + (iface->previous_address.s_addr == 0 || type == DHCP_RELEASE)) + PUTADDR (DHCP_SERVERIDENTIFIER, dhcp->serveraddress); #undef PUTADDR } @@ -290,14 +294,19 @@ size_t send_message (const interface_t *iface, const dhcp_t *dhcp, message_length = p - m; - memset (&packet, 0, sizeof (struct udp_dhcp_packet)); - make_dhcp_packet (&packet, (unsigned char *) &message, message_length, + packet = xmalloc (sizeof (struct udp_dhcp_packet)); + memset (packet, 0, sizeof (struct udp_dhcp_packet)); + make_dhcp_packet (packet, (unsigned char *) message, message_length, from, to); - - logger (LOG_DEBUG, "sending %s with xid 0x%lx", dhcp_message[(int) type], xid); - return send_packet (iface, ETHERTYPE_IP, (unsigned char *) &packet, - message_length + sizeof (struct ip) + - sizeof (struct udphdr)); + free (message); + + logger (LOG_DEBUG, "sending %s with xid 0x%lx", + dhcp_message[(int) type], xid); + retval = send_packet (iface, ETHERTYPE_IP, (unsigned char *) packet, + message_length + sizeof (struct ip) + + sizeof (struct udphdr)); + free (packet); + return (retval); } /* Decode an RFC3397 DNS search order option into a space diff --git a/dhcpcd.c b/dhcpcd.c index f9870520..25519da6 100644 --- a/dhcpcd.c +++ b/dhcpcd.c @@ -48,6 +48,46 @@ #include "logger.h" #include "version.h" +static int doversion = 0; +static int dohelp = 0; +#define EXTRA_OPTS +static const struct option longopts[] = { + {"arp", no_argument, NULL, 'a'}, + {"script", required_argument, NULL, 'c'}, + {"debug", no_argument, NULL, 'd'}, + {"hostname", optional_argument, NULL, 'h'}, + {"classid", optional_argument, NULL, 'i'}, + {"release", no_argument, NULL, 'k'}, + {"leasetime", required_argument, NULL, 'l'}, + {"metric", required_argument, NULL, 'm'}, + {"renew", no_argument, NULL, 'n'}, + {"persistent", no_argument, NULL, 'p'}, + {"inform", optional_argument, NULL, 's'}, + {"request", optional_argument, NULL, 'r'}, + {"timeout", required_argument, NULL, 't'}, + {"userclass", required_argument, NULL, 'u'}, + {"exit", no_argument, NULL, 'x'}, + {"lastlease", no_argument, NULL, 'E'}, + {"fqdn", required_argument, NULL, 'F'}, + {"nogateway", no_argument, NULL, 'G'}, + {"sethostname", no_argument, NULL, 'H'}, + {"clientid", optional_argument, NULL, 'I'}, + {"noipv4ll", no_argument, NULL, 'L'}, + {"nomtu", no_argument, NULL, 'M'}, + {"nontp", no_argument, NULL, 'N'}, + {"nodns", no_argument, NULL, 'R'}, + {"test", no_argument, NULL, 'T'}, + {"nonis", no_argument, NULL, 'Y'}, + {"help", no_argument, &dohelp, 1}, + {"version", no_argument, &doversion, 1}, +#ifdef THERE_IS_NO_FORK + {"daemonised", no_argument, NULL, 'f'}, + {"skiproutes", required_argument, NULL, 'g'}, +#endif + {NULL, 0, NULL, 0} +}; + + #define STRINGINT(_string, _int) { \ char *_tmp; \ long _number = strtol (_string, &_tmp, 0); \ @@ -67,6 +107,8 @@ char dhcpcd[PATH_MAX]; char **dhcpcd_argv = NULL; int dhcpcd_argc = 0; char *dhcpcd_skiproutes = NULL; +#undef EXTRA_OPTS +#define EXTRA_OPTS "fg:" #endif static pid_t read_pid (const char *pidfile) @@ -94,85 +136,49 @@ static void usage () int main(int argc, char **argv) { - options_t options; - int doversion = 0; - int dohelp = 0; + options_t *options; int userclasses = 0; int opt; int option_index = 0; - char prefix[IF_NAMESIZE + 3]; + char *prefix; pid_t pid; int debug = 0; int i; int pidfd = -1; int sig = 0; - const struct option longopts[] = { - {"arp", no_argument, NULL, 'a'}, - {"script", required_argument, NULL, 'c'}, - {"debug", no_argument, NULL, 'd'}, - {"hostname", optional_argument, NULL, 'h'}, - {"classid", optional_argument, NULL, 'i'}, - {"release", no_argument, NULL, 'k'}, - {"leasetime", required_argument, NULL, 'l'}, - {"metric", required_argument, NULL, 'm'}, - {"renew", no_argument, NULL, 'n'}, - {"persistent", no_argument, NULL, 'p'}, - {"inform", optional_argument, NULL, 's'}, - {"request", optional_argument, NULL, 'r'}, - {"timeout", required_argument, NULL, 't'}, - {"userclass", required_argument, NULL, 'u'}, - {"exit", no_argument, NULL, 'x'}, - {"lastlease", no_argument, NULL, 'E'}, - {"fqdn", required_argument, NULL, 'F'}, - {"nogateway", no_argument, NULL, 'G'}, - {"sethostname", no_argument, NULL, 'H'}, - {"clientid", optional_argument, NULL, 'I'}, - {"noipv4ll", no_argument, NULL, 'L'}, - {"nomtu", no_argument, NULL, 'M'}, - {"nontp", no_argument, NULL, 'N'}, - {"nodns", no_argument, NULL, 'R'}, - {"test", no_argument, NULL, 'T'}, - {"nonis", no_argument, NULL, 'Y'}, - {"help", no_argument, &dohelp, 1}, - {"version", no_argument, &doversion, 1}, -#ifdef THERE_IS_NO_FORK - {"daemonised", no_argument, NULL, 'f'}, - {"skiproutes", required_argument, NULL, 'g'}, -#endif - {NULL, 0, NULL, 0} - }; - /* Close any un-needed fd's */ for (i = getdtablesize() - 1; i >= 3; --i) close (i); openlog (PACKAGE, LOG_PID, LOG_LOCAL0); - memset (&options, 0, sizeof (options_t)); - options.script = (char *) DEFAULT_SCRIPT; - snprintf (options.classid, CLASS_ID_MAX_LEN, "%s %s", PACKAGE, VERSION); - options.classid_len = strlen (options.classid); - - options.doarp = true; - options.dodns = true; - options.domtu = true; - options.donis = true; - options.dontp = true; - options.dogateway = true; - options.daemonise = true; - options.doinform = false; - options.doipv4ll = true; - options.timeout = DEFAULT_TIMEOUT; - - gethostname (options.hostname, sizeof (options.hostname)); - if (strcmp (options.hostname, "(none)") == 0 || - strcmp (options.hostname, "localhost") == 0) - memset (options.hostname, 0, sizeof (options.hostname)); + options = xmalloc (sizeof (options_t)); + memset (options, 0, sizeof (options_t)); + options->script = (char *) DEFAULT_SCRIPT; + snprintf (options->classid, CLASS_ID_MAX_LEN, "%s %s", PACKAGE, VERSION); + options->classid_len = strlen (options->classid); + + options->doarp = true; + options->dodns = true; + options->domtu = true; + options->donis = true; + options->dontp = true; + options->dogateway = true; + options->daemonise = true; + options->doinform = false; + options->doipv4ll = true; + options->timeout = DEFAULT_TIMEOUT; + + gethostname (options->hostname, sizeof (options->hostname)); + if (strcmp (options->hostname, "(none)") == 0 || + strcmp (options->hostname, "localhost") == 0) + memset (options->hostname, 0, sizeof (options->hostname)); /* Don't set any optional arguments here so we retain POSIX * compatibility with getopt */ - while ((opt = getopt_long(argc, argv, "c:dh:i:kl:m:npr:s:t:u:xAEF:GHI:LMNRTY", + while ((opt = getopt_long(argc, argv, EXTRA_OPTS + "c:dh:i:kl:m:npr:s:t:u:xAEF:GHI:LMNRTY", longopts, &option_index)) != -1) { switch (opt) { @@ -184,7 +190,7 @@ int main(int argc, char **argv) exit (EXIT_FAILURE); break; case 'c': - options.script = optarg; + options->script = optarg; break; case 'd': debug++; @@ -193,13 +199,13 @@ int main(int argc, char **argv) setloglevel (LOG_DEBUG); break; case 2: - options.daemonise = false; + options->daemonise = false; break; } break; #ifdef THERE_IS_NO_FORK case 'f': - options.daemonised = true; + options->daemonised = true; close_fds (); break; case 'g': @@ -208,50 +214,50 @@ int main(int argc, char **argv) #endif case 'h': if (! optarg) - memset (options.hostname, 0, sizeof (options.hostname)); + memset (options->hostname, 0, sizeof (options->hostname)); else if (strlen (optarg) > MAXHOSTNAMELEN) { logger (LOG_ERR, "`%s' too long for HostName string, max is %d", optarg, MAXHOSTNAMELEN); exit (EXIT_FAILURE); } else - strlcpy (options.hostname, optarg, sizeof (options.hostname)); + strlcpy (options->hostname, optarg, sizeof (options->hostname)); break; case 'i': if (! optarg) { - memset (options.classid, 0, sizeof (options.classid)); - options.classid_len = 0; + memset (options->classid, 0, sizeof (options->classid)); + options->classid_len = 0; } else if (strlen (optarg) > CLASS_ID_MAX_LEN) { logger (LOG_ERR, "`%s' too long for ClassID string, max is %d", optarg, CLASS_ID_MAX_LEN); exit (EXIT_FAILURE); } else - options.classid_len = strlcpy (options.classid, optarg, - sizeof (options.classid)); + options->classid_len = strlcpy (options->classid, optarg, + sizeof (options->classid)); break; case 'k': sig = SIGHUP; break; case 'l': - STRINGINT (optarg, options.leasetime); - if (options.leasetime <= 0) { + STRINGINT (optarg, options->leasetime); + if (options->leasetime <= 0) { logger (LOG_ERR, "leasetime must be a positive value"); exit (EXIT_FAILURE); } break; case 'm': - STRINGINT (optarg, options.metric); + STRINGINT (optarg, options->metric); break; case 'n': sig = SIGALRM; break; case 'p': - options.persistent = true; + options->persistent = true; break; case 's': - options.doinform = true; - options.doarp = false; + options->doinform = true; + options->doarp = false; if (! optarg || strlen (optarg) == 0) { - options.request_address.s_addr = 0; + options->request_address.s_addr = 0; break; } else { char *slash = strchr (optarg, '/'); @@ -261,7 +267,7 @@ int main(int argc, char **argv) * address */ *slash++ = '\0'; if (sscanf (slash, "%d", &cidr) != 1 || - inet_cidrtoaddr (cidr, &options.request_netmask) != 0) { + inet_cidrtoaddr (cidr, &options->request_netmask) != 0) { logger (LOG_ERR, "`%s' is not a valid CIDR", slash); exit (EXIT_FAILURE); } @@ -269,18 +275,18 @@ int main(int argc, char **argv) /* fall through */ } case 'r': - if (! options.doinform) - options.dorequest = true; + if (! options->doinform) + options->dorequest = true; if (strlen (optarg) > 0 && - ! inet_aton (optarg, &options.request_address)) + ! inet_aton (optarg, &options->request_address)) { logger (LOG_ERR, "`%s' is not a valid IP address", optarg); exit (EXIT_FAILURE); } break; case 't': - STRINGINT (optarg, options.timeout); - if (options.timeout < 0) { + STRINGINT (optarg, options->timeout); + if (options->timeout < 0) { logger (LOG_ERR, "timeout must be a positive value"); exit (EXIT_FAILURE); } @@ -289,16 +295,16 @@ int main(int argc, char **argv) { int offset = 0; for (i = 0; i < userclasses; i++) - offset += (int) options.userclass[offset] + 1; + offset += (int) options->userclass[offset] + 1; if (offset + 1 + strlen (optarg) > USERCLASS_MAX_LEN) { logger (LOG_ERR, "userclass overrun, max is %d", USERCLASS_MAX_LEN); exit (EXIT_FAILURE); } userclasses++; - memcpy (options.userclass + offset + 1 , optarg, strlen (optarg)); - options.userclass[offset] = strlen (optarg); - options.userclass_len += (strlen (optarg)) + 1; + memcpy (options->userclass + offset + 1 , optarg, strlen (optarg)); + options->userclass[offset] = strlen (optarg); + options->userclass_len += (strlen (optarg)) + 1; } break; case 'x': @@ -309,32 +315,32 @@ int main(int argc, char **argv) logger (LOG_ERR, "arp support not compiled into dhcpcd"); exit (EXIT_FAILURE); #endif - options.doarp = false; + options->doarp = false; break; case 'E': #ifndef ENABLE_INFO logger (LOG_ERR, "info support not compiled into dhcpcd"); exit (EXIT_FAILURE); #endif - options.dolastlease = true; + options->dolastlease = true; break; case 'F': if (strncmp (optarg, "none", strlen (optarg)) == 0) - options.fqdn = FQDN_NONE; + options->fqdn = FQDN_NONE; else if (strncmp (optarg, "ptr", strlen (optarg)) == 0) - options.fqdn = FQDN_PTR; + options->fqdn = FQDN_PTR; else if (strncmp (optarg, "both", strlen (optarg)) == 0) - options.fqdn = FQDN_BOTH; + options->fqdn = FQDN_BOTH; else { logger (LOG_ERR, "invalid value `%s' for FQDN", optarg); exit (EXIT_FAILURE); } break; case 'G': - options.dogateway = false; + options->dogateway = false; break; case 'H': - options.dohostname++; + options->dohostname++; break; case 'I': if (optarg) { @@ -343,38 +349,38 @@ int main(int argc, char **argv) optarg, CLIENT_ID_MAX_LEN); exit (EXIT_FAILURE); } - options.clientid_len = strlcpy (options.clientid, optarg, - sizeof (options.clientid)); + options->clientid_len = strlcpy (options->clientid, optarg, + sizeof (options->clientid)); /* empty string disabled duid */ - if (options.clientid_len == 0) - options.clientid_len = -1; + if (options->clientid_len == 0) + options->clientid_len = -1; } else { - memset (options.clientid, 0, sizeof (options.clientid)); - options.clientid_len = -1; + memset (options->clientid, 0, sizeof (options->clientid)); + options->clientid_len = -1; } break; case 'L': - options.doipv4ll = false; + options->doipv4ll = false; break; case 'M': - options.domtu = false; + options->domtu = false; break; case 'N': - options.dontp = false; + options->dontp = false; break; case 'R': - options.dodns = false; + options->dodns = false; break; case 'T': #ifndef ENABLE_INFO logger (LOG_ERR, "info support not compiled into dhcpcd"); exit (EXIT_FAILURE); #endif - options.test = true; - options.persistent = true; + options->test = true; + options->persistent = true; break; case 'Y': - options.donis = false; + options->donis = false; break; case '?': usage (); @@ -414,8 +420,8 @@ int main(int argc, char **argv) argv[optind], IF_NAMESIZE); exit (EXIT_FAILURE); } - strlcpy (options.interface, argv[optind], - sizeof (options.interface)); + strlcpy (options->interface, argv[optind], + sizeof (options->interface)); } else { /* If only version was requested then exit now */ if (doversion || dohelp) @@ -425,15 +431,15 @@ int main(int argc, char **argv) exit (EXIT_FAILURE); } - if (strchr (options.hostname, '.')) { - if (options.fqdn == FQDN_DISABLE) - options.fqdn = FQDN_BOTH; + if (strchr (options->hostname, '.')) { + if (options->fqdn == FQDN_DISABLE) + options->fqdn = FQDN_BOTH; } else - options.fqdn = FQDN_DISABLE; + options->fqdn = FQDN_DISABLE; - if (options.request_address.s_addr == 0 && options.doinform) { - if ((options.request_address.s_addr = get_address (options.interface)) != 0) - options.keep_address = true; + if (options->request_address.s_addr == 0 && options->doinform) { + if ((options->request_address.s_addr = get_address (options->interface)) != 0) + options->keep_address = true; } if (geteuid ()) { @@ -441,10 +447,12 @@ int main(int argc, char **argv) exit (EXIT_FAILURE); } - snprintf (prefix, IF_NAMESIZE, "%s: ", options.interface); + prefix = xmalloc (sizeof (char *) * IF_NAMESIZE + 3); + snprintf (prefix, IF_NAMESIZE, "%s: ", options->interface); setlogprefix (prefix); - snprintf (options.pidfile, sizeof (options.pidfile), PIDFILE, - options.interface); + snprintf (options->pidfile, sizeof (options->pidfile), PIDFILE, + options->interface); + free (prefix); chdir ("/"); umask (022); @@ -463,13 +471,13 @@ int main(int argc, char **argv) exit (EXIT_FAILURE); } - if (options.test) { - if (options.dorequest || options.doinform) { + if (options->test) { + if (options->dorequest || options->doinform) { logger (LOG_ERR, "cannot test with --inform or --request"); exit (EXIT_FAILURE); } - if (options.dolastlease) { + if (options->dolastlease) { logger (LOG_ERR, "cannot test with --lastlease"); exit (EXIT_FAILURE); } @@ -482,7 +490,7 @@ int main(int argc, char **argv) if (sig != 0) { int killed = -1; - pid = read_pid (options.pidfile); + pid = read_pid (options->pidfile); if (pid != 0) logger (LOG_INFO, "sending signal %d to pid %d", sig, pid); @@ -490,7 +498,7 @@ int main(int argc, char **argv) logger (sig == SIGALRM ? LOG_INFO : LOG_ERR, ""PACKAGE" not running"); if (pid != 0 && (sig != SIGALRM || killed != 0)) - unlink (options.pidfile); + unlink (options->pidfile); if (killed == 0) exit (EXIT_SUCCESS); @@ -499,22 +507,22 @@ int main(int argc, char **argv) exit (EXIT_FAILURE); } - if (! options.test && ! options.daemonised) { - if ((pid = read_pid (options.pidfile)) > 0 && kill (pid, 0) == 0) { + if (! options->test && ! options->daemonised) { + if ((pid = read_pid (options->pidfile)) > 0 && kill (pid, 0) == 0) { logger (LOG_ERR, ""PACKAGE" already running on pid %d (%s)", - pid, options.pidfile); + pid, options->pidfile); exit (EXIT_FAILURE); } - pidfd = open (options.pidfile, O_WRONLY | O_CREAT | O_NONBLOCK, 0660); + pidfd = open (options->pidfile, O_WRONLY | O_CREAT | O_NONBLOCK, 0660); if (pidfd == -1) { - logger (LOG_ERR, "open `%s': %s", options.pidfile, strerror (errno)); + logger (LOG_ERR, "open `%s': %s", options->pidfile, strerror (errno)); exit (EXIT_FAILURE); } /* Lock the file so that only one instance of dhcpcd runs on an interface */ if (flock (pidfd, LOCK_EX | LOCK_NB) == -1) { - logger (LOG_ERR, "flock `%s': %s", options.pidfile, strerror (errno)); + logger (LOG_ERR, "flock `%s': %s", options->pidfile, strerror (errno)); exit (EXIT_FAILURE); } @@ -530,9 +538,11 @@ int main(int argc, char **argv) srandomdev (); i = EXIT_FAILURE; - if (dhcp_run (&options, &pidfd) == 0) + if (dhcp_run (options, &pidfd) == 0) i = EXIT_SUCCESS; + free (options); + #ifdef THERE_IS_NO_FORK /* There may have been an error before the dhcp_run function * clears this, so just do it here to be safe */ diff --git a/info.c b/info.c index 316a1362..b3277178 100644 --- a/info.c +++ b/info.c @@ -37,11 +37,13 @@ #include "info.h" #ifdef ENABLE_INFO +#define BUFFERSIZE 1024 + static char *cleanmetas (const char *cstr) { /* The largest single element we can have is 256 bytes according to the RFC, so this buffer size should be safe even if it's all ' */ - static char buffer[1024]; + static char buffer[BUFFERSIZE]; char *b = buffer; memset (buffer, 0, sizeof (buffer)); @@ -193,10 +195,11 @@ bool write_info(const interface_t *iface, const dhcp_t *dhcp, fprintf (f, "CLIENTID='00:%s'\n", cleanmetas (options->clientid)); #ifdef ENABLE_DUID else if (iface->duid_length > 0 && options->clientid_len != -1) { - unsigned char duid[256]; - unsigned char *p = duid; + unsigned char *duid; + unsigned char *p; uint32_t ul; + p = duid = xmalloc (iface->duid_length + 6); *p++ = 255; /* IAID is 4 bytes, so if the interface name is 4 bytes then use it */ @@ -213,6 +216,7 @@ bool write_info(const interface_t *iface, const dhcp_t *dhcp, p += iface->duid_length; fprintf (f, "CLIENTID='%s'\n", hwaddr_ntoa (duid, p - duid)); + free (duid); } #endif else @@ -317,7 +321,7 @@ static bool parse_addresses (address_t **address, char *value, const char *var) bool read_info (const interface_t *iface, dhcp_t *dhcp) { FILE *fp; - char buffer[1024]; + char *buffer; char *var; char *value; char *p; @@ -336,8 +340,9 @@ bool read_info (const interface_t *iface, dhcp_t *dhcp) dhcp->frominfo = true; - memset (buffer, 0, sizeof (buffer)); - while ((fgets (buffer, sizeof (buffer), fp))) { + buffer = xmalloc (sizeof (char *) * BUFFERSIZE); + memset (buffer, 0, BUFFERSIZE); + while ((fgets (buffer, BUFFERSIZE, fp))) { var = buffer; /* Strip leading spaces/tabs */ @@ -474,6 +479,7 @@ bool read_info (const interface_t *iface, dhcp_t *dhcp) } fclose (fp); + free (buffer); return (true); } diff --git a/interface.c b/interface.c index 9a87687b..9964ad36 100644 --- a/interface.c +++ b/interface.c @@ -259,8 +259,8 @@ interface_t *read_interface (const char *ifname, int metric) { int s; struct ifreq ifr; - interface_t *iface; - unsigned char hwaddr[20]; + interface_t *iface = NULL; + unsigned char *hwaddr = NULL; int hwlen = 0; sa_family_t family = 0; unsigned short mtu; @@ -286,8 +286,7 @@ interface_t *read_interface (const char *ifname, int metric) strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); if (ioctl (s, SIOCGIFHWADDR, &ifr) == -1) { logger (LOG_ERR, "ioctl SIOCGIFHWADDR: %s", strerror (errno)); - close (s); - return NULL; + goto exit; } switch (ifr.ifr_hwaddr.sa_family) { @@ -302,10 +301,10 @@ interface_t *read_interface (const char *ifname, int metric) break; default: logger (LOG_ERR, "interface is not Ethernet, FireWire, InfiniBand or Token Ring"); - close (s); - return NULL; + goto exit; } + hwaddr = xmalloc (sizeof (unsigned char *) * HWADDR_LEN); memcpy (hwaddr, ifr.ifr_hwaddr.sa_data, hwlen); family = ifr.ifr_hwaddr.sa_family; #else @@ -313,14 +312,13 @@ interface_t *read_interface (const char *ifname, int metric) strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); if (ioctl (s, SIOCSIFMETRIC, &ifr) == -1) { logger (LOG_ERR, "ioctl SIOCSIFMETRIC: %s", strerror (errno)); - close (s); - return NULL; + goto exit; } - + + hwaddr = xmalloc (sizeof (unsigned char *) * HWADDR_LEN); if (_do_interface (ifname, hwaddr, &hwlen, NULL, false, false) != 1) { logger (LOG_ERR, "could not find interface %s", ifname); - close (s); - return NULL; + goto exit; } family = ARPHRD_ETHER; @@ -329,8 +327,7 @@ interface_t *read_interface (const char *ifname, int metric) strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); if (ioctl (s, SIOCGIFMTU, &ifr) == -1) { logger (LOG_ERR, "ioctl SIOCGIFMTU: %s", strerror (errno)); - close (s); - return NULL; + goto exit; } if (ifr.ifr_mtu < MTU_MIN) { @@ -339,8 +336,7 @@ interface_t *read_interface (const char *ifname, int metric) strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); if (ioctl (s, SIOCSIFMTU, &ifr) == -1) { logger (LOG_ERR, "ioctl SIOCSIFMTU,: %s", strerror (errno)); - close (s); - return NULL; + goto exit; } } mtu = ifr.ifr_mtu; @@ -353,21 +349,17 @@ interface_t *read_interface (const char *ifname, int metric) #endif if (ioctl (s, SIOCGIFFLAGS, &ifr) == -1) { logger (LOG_ERR, "ioctl SIOCGIFFLAGS: %s", strerror (errno)); - close (s); - return NULL; + goto exit; } if (! (ifr.ifr_flags & IFF_UP) || ! (ifr.ifr_flags & IFF_RUNNING)) { ifr.ifr_flags |= IFF_UP | IFF_RUNNING; if (ioctl (s, SIOCSIFFLAGS, &ifr) == -1) { logger (LOG_ERR, "ioctl SIOCSIFFLAGS: %s", strerror (errno)); - close (s); - return NULL; + goto exit; } } - close (s); - iface = xmalloc (sizeof (interface_t)); memset (iface, 0, sizeof (interface_t)); strlcpy (iface->name, ifname, IF_NAMESIZE); @@ -387,6 +379,9 @@ interface_t *read_interface (const char *ifname, int metric) /* 0 is a valid fd, so init to -1 */ iface->fd = -1; +exit: + close (s); + free (hwaddr); return iface; } @@ -600,12 +595,13 @@ static int do_route (const char *ifname, gateway.s_addr == INADDR_ANY) { /* Make us a link layer socket */ - unsigned char hwaddr[HWADDR_LEN]; + unsigned char *hwaddr; int hwlen = 0; if (netmask.s_addr == INADDR_BROADCAST) rtm.hdr.rtm_flags |= RTF_HOST; + hwaddr = xmalloc (sizeof (unsigned char *) * HWADDR_LEN); _do_interface (ifname, hwaddr, &hwlen, NULL, false, false); memset (&su, 0, sizeof (struct sockaddr_storage)); su.sdl.sdl_len = sizeof (struct sockaddr_dl); @@ -619,6 +615,7 @@ static int do_route (const char *ifname, l = SA_SIZE (&(su.sa)); memcpy (bp, &su, l); bp += l; + free (hwaddr); } else { rtm.hdr.rtm_flags |= RTF_GATEWAY; ADDADDR (gateway); @@ -650,6 +647,7 @@ static int do_route (const char *ifname, This blatently taken from libnetlink.c from the iproute2 package which is the only good source of netlink code. */ +#define BUFFERLEN 256 static int send_netlink(struct nlmsghdr *hdr) { int s; @@ -658,7 +656,7 @@ static int send_netlink(struct nlmsghdr *hdr) struct iovec iov; struct msghdr msg; static unsigned int seq; - char buffer[256]; + char *buffer; int bytes; union { @@ -699,11 +697,12 @@ static int send_netlink(struct nlmsghdr *hdr) return -1; } - memset (buffer, 0, sizeof (buffer)); + buffer = xmalloc (sizeof (char *) * BUFFERLEN); + memset (buffer, 0, BUFFERLEN); iov.iov_base = buffer; while (1) { - iov.iov_len = sizeof (buffer); + iov.iov_len = BUFFERLEN; bytes = recvmsg (s, &msg, 0); if (bytes == -1) { @@ -749,6 +748,7 @@ static int send_netlink(struct nlmsghdr *hdr) errno = -err->error; if (errno == 0) { close (s); + free (buffer); return 0; } @@ -778,6 +778,7 @@ next: eexit: close (s); + free (buffer); return -1; } @@ -824,47 +825,61 @@ static int add_attr_32(struct nlmsghdr *n, unsigned int maxlen, int type, return 0; } +struct nlma +{ + struct nlmsghdr hdr; + struct ifaddrmsg ifa; + char buffer[64]; +}; + +struct nlmr +{ + struct nlmsghdr hdr; + struct rtmsg rt; + char buffer[256]; +}; + static int do_address(const char *ifname, struct in_addr address, struct in_addr netmask, struct in_addr broadcast, int del) { - struct - { - struct nlmsghdr hdr; - struct ifaddrmsg ifa; - char buffer[64]; - } - nlm; + struct nlma *nlm; + int retval; if (!ifname) return -1; - memset (&nlm, 0, sizeof (nlm)); + nlm = xmalloc (sizeof (struct nlma)); + memset (nlm, 0, sizeof (struct nlma)); - nlm.hdr.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg)); - nlm.hdr.nlmsg_flags = NLM_F_REQUEST; + nlm->hdr.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg)); + nlm->hdr.nlmsg_flags = NLM_F_REQUEST; if (! del) - nlm.hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE; - nlm.hdr.nlmsg_type = del ? RTM_DELADDR : RTM_NEWADDR; - if (! (nlm.ifa.ifa_index = if_nametoindex (ifname))) { + nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE; + nlm->hdr.nlmsg_type = del ? RTM_DELADDR : RTM_NEWADDR; + if (! (nlm->ifa.ifa_index = if_nametoindex (ifname))) { logger (LOG_ERR, "if_nametoindex: Couldn't find index for interface `%s'", ifname); + free (nlm); return -1; } - nlm.ifa.ifa_family = AF_INET; + nlm->ifa.ifa_family = AF_INET; - nlm.ifa.ifa_prefixlen = inet_ntocidr (netmask); + nlm->ifa.ifa_prefixlen = inet_ntocidr (netmask); /* This creates the aliased interface */ - add_attr_l (&nlm.hdr, sizeof (nlm), IFA_LABEL, ifname, strlen (ifname) + 1); + add_attr_l (&nlm->hdr, sizeof (struct nlma), IFA_LABEL, + ifname, strlen (ifname) + 1); - add_attr_l (&nlm.hdr, sizeof (nlm), IFA_LOCAL, &address.s_addr, - sizeof (address.s_addr)); + add_attr_l (&nlm->hdr, sizeof (struct nlma), IFA_LOCAL, + &address.s_addr, sizeof (address.s_addr)); if (! del) - add_attr_l (&nlm.hdr, sizeof (nlm), IFA_BROADCAST, &broadcast.s_addr, - sizeof (broadcast.s_addr)); + add_attr_l (&nlm->hdr, sizeof (struct nlma), IFA_BROADCAST, + &broadcast.s_addr, sizeof (broadcast.s_addr)); - return send_netlink (&nlm.hdr); + retval = send_netlink (&nlm->hdr); + free (nlm); + return retval; } static int do_route (const char *ifname, @@ -873,63 +888,61 @@ static int do_route (const char *ifname, struct in_addr gateway, int metric, int change, int del) { + struct nlmr *nlm; unsigned int ifindex; - struct - { - struct nlmsghdr hdr; - struct rtmsg rt; - char buffer[256]; - } - nlm; + int retval; if (! ifname) return -1; log_route (destination, netmask, gateway, metric, change, del); - memset (&nlm, 0, sizeof (nlm)); + if (! (ifindex = if_nametoindex (ifname))) { + logger (LOG_ERR, "if_nametoindex: Couldn't find index for interface `%s'", + ifname); + return -1; + } + + nlm = xmalloc (sizeof (struct nlmr)); + memset (nlm, 0, sizeof (struct nlmr)); - nlm.hdr.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); + nlm->hdr.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); if (change) - nlm.hdr.nlmsg_flags = NLM_F_REPLACE; + nlm->hdr.nlmsg_flags = NLM_F_REPLACE; else if (! del) - nlm.hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL; - nlm.hdr.nlmsg_flags |= NLM_F_REQUEST; - nlm.hdr.nlmsg_type = del ? RTM_DELROUTE : RTM_NEWROUTE; - nlm.rt.rtm_family = AF_INET; - nlm.rt.rtm_table = RT_TABLE_MAIN; + nlm->hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL; + nlm->hdr.nlmsg_flags |= NLM_F_REQUEST; + nlm->hdr.nlmsg_type = del ? RTM_DELROUTE : RTM_NEWROUTE; + nlm->rt.rtm_family = AF_INET; + nlm->rt.rtm_table = RT_TABLE_MAIN; if (del) - nlm.rt.rtm_scope = RT_SCOPE_NOWHERE; + nlm->rt.rtm_scope = RT_SCOPE_NOWHERE; else { - nlm.hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL; - nlm.rt.rtm_protocol = RTPROT_BOOT; + nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL; + nlm->rt.rtm_protocol = RTPROT_BOOT; if (netmask.s_addr == INADDR_BROADCAST || gateway.s_addr == INADDR_ANY) - nlm.rt.rtm_scope = RT_SCOPE_LINK; + nlm->rt.rtm_scope = RT_SCOPE_LINK; else - nlm.rt.rtm_scope = RT_SCOPE_UNIVERSE; - nlm.rt.rtm_type = RTN_UNICAST; + nlm->rt.rtm_scope = RT_SCOPE_UNIVERSE; + nlm->rt.rtm_type = RTN_UNICAST; } - nlm.rt.rtm_dst_len = inet_ntocidr (netmask); - add_attr_l (&nlm.hdr, sizeof (nlm), RTA_DST, &destination.s_addr, - sizeof (destination.s_addr)); + nlm->rt.rtm_dst_len = inet_ntocidr (netmask); + add_attr_l (&nlm->hdr, sizeof (struct nlmr), RTA_DST, + &destination.s_addr, sizeof (destination.s_addr)); if (netmask.s_addr != INADDR_BROADCAST && destination.s_addr != gateway.s_addr) - add_attr_l (&nlm.hdr, sizeof (nlm), RTA_GATEWAY, &gateway.s_addr, - sizeof (gateway.s_addr)); + add_attr_l (&nlm->hdr, sizeof (struct nlmr), RTA_GATEWAY, + &gateway.s_addr, sizeof (gateway.s_addr)); - if (! (ifindex = if_nametoindex (ifname))) { - logger (LOG_ERR, "if_nametoindex: Couldn't find index for interface `%s'", - ifname); - return -1; - } + add_attr_32 (&nlm->hdr, sizeof (struct nlmr), RTA_OIF, ifindex); + add_attr_32 (&nlm->hdr, sizeof (struct nlmr), RTA_PRIORITY, metric); - add_attr_32 (&nlm.hdr, sizeof (nlm), RTA_OIF, ifindex); - add_attr_32 (&nlm.hdr, sizeof (nlm), RTA_PRIORITY, metric); - - return send_netlink (&nlm.hdr); + retval = send_netlink (&nlm->hdr); + free (nlm); + return retval; } #else diff --git a/socket.c b/socket.c index 832c0ab8..bb939929 100644 --- a/socket.c +++ b/socket.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -69,7 +70,6 @@ static uint16_t checksum (unsigned char *addr, uint16_t len) nleft -= 2; } - if (nleft == 1) { uint8_t a = 0; memcpy (&a, p.i, 1); @@ -234,16 +234,18 @@ int open_socket (interface_t *iface, bool arp) { int n = 0; int fd = -1; - char device[PATH_MAX]; + char *device; int flags; struct ifreq ifr; int buf = 0; struct bpf_program p; + device = xmalloc (sizeof (char *) * PATH_MAX); do { snprintf (device, PATH_MAX, "/dev/bpf%d", n++); fd = open (device, O_RDWR); } while (fd == -1 && errno == EBUSY); + free (device); if (fd == -1) { logger (LOG_ERR, "unable to open a BPF device");