int kernel_addresses(char *ifname, int ifindex, int ll, struct kernel_route *routes, int maxroutes) { struct ifaddrs *ifa, *ifap; int rc, i; rc = getifaddrs(&ifa); if(rc < 0) return -1; ifap = ifa; i = 0; while(ifap && i < maxroutes) { if((ifname != NULL && strcmp(ifap->ifa_name, ifname) != 0)) goto next; if(ifap->ifa_addr->sa_family == AF_INET6) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)ifap->ifa_addr; if(!!ll != !!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) goto next; memcpy(routes[i].prefix, &sin6->sin6_addr, 16); if(ll) /* This a perfect example of counter-productive optimisation : KAME encodes interface index onto bytes 2 and 3, so we have to reset those bytes to 0 before passing them to babeld. */ memset(routes[i].prefix + 2, 0, 2); routes[i].plen = 128; routes[i].metric = 0; routes[i].ifindex = ifindex; routes[i].proto = RTPROT_BABEL_LOCAL; memset(routes[i].gw, 0, 16); i++; } else if(ifap->ifa_addr->sa_family == AF_INET) { struct sockaddr_in *sin = (struct sockaddr_in*)ifap->ifa_addr; if(ll) goto next; #if defined(IN_LINKLOCAL) if(IN_LINKLOCAL(htonl(sin->sin_addr.s_addr))) goto next; #endif memcpy(routes[i].prefix, v4prefix, 12); memcpy(routes[i].prefix + 12, &sin->sin_addr, 4); routes[i].plen = 128; routes[i].metric = 0; routes[i].ifindex = ifindex; routes[i].proto = RTPROT_BABEL_LOCAL; memset(routes[i].gw, 0, 16); i++; } next: ifap = ifap->ifa_next; } freeifaddrs(ifa); return i; }
/* Check if valid address */ static int valid_addr(struct in_addr *ina) { in_addr_t addr; addr = ntohl(ina->s_addr); if (IN_ZERONET(addr) || IN_LOOPBACK(addr) || IN_LINKLOCAL(addr)) return 0; return 1; }
void ipv4ll_start(void *arg) { struct interface *ifp = arg; struct dhcp_state *state = D_STATE(ifp); uint32_t addr; eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); state->probes = 0; state->claims = 0; if (state->addr.s_addr) { state->conflicts = 0; if (IN_LINKLOCAL(htonl(state->addr.s_addr))) { arp_announce(ifp); return; } } if (state->offer == NULL) addr = 0; else { addr = state->offer->yiaddr; free(state->offer); } /* We maybe rebooting an IPv4LL address. */ if (!IN_LINKLOCAL(htonl(addr))) { syslog(LOG_INFO, "%s: probing for an IPv4LL address", ifp->name); addr = 0; } if (addr == 0) state->offer = ipv4ll_find_lease(addr); else state->offer = ipv4ll_make_lease(addr); if (state->offer == NULL) syslog(LOG_ERR, "%s: %m", __func__); else { state->lease.frominfo = 0; arp_probe(ifp); } }
static struct dhcp_message * ipv4ll_find_lease(uint32_t old_addr) { uint32_t addr; for (;;) { addr = htonl(LINKLOCAL_ADDR | (((uint32_t)abs((int)arc4random()) % 0xFD00) + 0x0100)); if (addr != old_addr && IN_LINKLOCAL(ntohl(addr))) break; } return ipv4ll_make_lease(addr); }
static Boolean _CFNetDiagnosticIsLinkLocal (CFStringRef s) { char buffer[16]; Boolean converted; Boolean retval = 0; uint32_t addr; converted = CFStringGetCString(s, buffer, 16, kCFStringEncodingASCII); if(converted) { addr = inet_addr(buffer); if(addr == INADDR_NONE) { retval = 0; } else { retval = IN_LINKLOCAL(ntohl(addr)); } } return retval; }
/* Get the IP address from interface */ static RC_TYPE do_ip_check_interface(DYN_DNS_CLIENT *p_self) { struct ifreq ifr; in_addr_t new_ip; char *new_ip_str; int i; if (p_self == NULL) { return RC_INVALID_POINTER; } if (p_self->check_interface) { logit(LOG_INFO, MODULE_TAG "Checking for IP# change, querying interface %s", p_self->check_interface); int sd = socket(PF_INET, SOCK_DGRAM, 0); if (sd < 0) { int code = os_get_socket_error(); logit(LOG_WARNING, MODULE_TAG "Failed opening network socket: %s", strerror(code)); return RC_IP_OS_SOCKET_INIT_FAILED; } memset(&ifr, 0, sizeof(struct ifreq)); ifr.ifr_addr.sa_family = AF_INET; snprintf(ifr.ifr_name, IFNAMSIZ, p_self->check_interface); if (ioctl(sd, SIOCGIFADDR, &ifr) != -1) { new_ip = ntohl(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr); new_ip_str = inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr); } else { int code = os_get_socket_error(); logit(LOG_ERR, MODULE_TAG "Failed reading IP address of interface %s: %s", p_self->check_interface, strerror(code)); return RC_ERROR; } close(sd); } else { return RC_ERROR; } if (IN_ZERONET(new_ip) || IN_LOOPBACK(new_ip) || IN_LINKLOCAL(new_ip) || IN_MULTICAST(new_ip) || IN_EXPERIMENTAL(new_ip)) { logit(LOG_WARNING, MODULE_TAG "Interface %s has invalid IP# %s", p_self->check_interface, new_ip_str); return RC_ERROR; } int anychange = 0; for (i = 0; i < p_self->info_count; i++) { DYNDNS_INFO_TYPE *info = &p_self->info[i]; info->my_ip_has_changed = strcmp(info->my_ip_address.name, new_ip_str) != 0; if (info->my_ip_has_changed) { anychange++; strcpy(info->my_ip_address.name, new_ip_str); } } if (!anychange) { logit(LOG_INFO, MODULE_TAG "No IP# change detected, still at %s", new_ip_str); } return RC_OK; }
ssize_t make_message(struct dhcp_message **message, const struct interface *iface, const struct dhcp_lease *lease, uint32_t xid, uint8_t type, const struct options *options) { struct dhcp_message *dhcp; uint8_t *m, *lp, *p; uint8_t *n_params = NULL; time_t up = uptime() - iface->start_uptime; uint32_t ul; uint16_t sz; const struct dhcp_opt *opt; size_t len; const char *hp; dhcp = xzalloc(sizeof (*dhcp)); m = (uint8_t *)dhcp; p = dhcp->options; if ((type == DHCP_INFORM || type == DHCP_RELEASE || type == DHCP_REQUEST) && !IN_LINKLOCAL(ntohl(iface->addr.s_addr))) { dhcp->ciaddr = iface->addr.s_addr; /* Just incase we haven't actually configured the address yet */ if (type == DHCP_INFORM && iface->addr.s_addr == 0) dhcp->ciaddr = lease->addr.s_addr; /* Zero the address if we're currently on a different subnet */ if (type == DHCP_REQUEST && iface->net.s_addr != lease->net.s_addr) dhcp->ciaddr = 0; } dhcp->op = DHCP_BOOTREQUEST; dhcp->hwtype = iface->family; switch (iface->family) { case ARPHRD_ETHER: case ARPHRD_IEEE802: dhcp->hwlen = ETHER_ADDR_LEN; memcpy(&dhcp->chaddr, &iface->hwaddr, ETHER_ADDR_LEN); break; case ARPHRD_IEEE1394: case ARPHRD_INFINIBAND: dhcp->hwlen = 0; if (dhcp->ciaddr == 0 && type != DHCP_DECLINE && type != DHCP_RELEASE) dhcp->flags = htons(BROADCAST_FLAG); break; } if (type != DHCP_DECLINE && type != DHCP_RELEASE) { if (up < 0 || up > (time_t)UINT16_MAX) dhcp->secs = htons((uint16_t)UINT16_MAX); else dhcp->secs = htons(up); } dhcp->xid = xid; dhcp->cookie = htonl(MAGIC_COOKIE); *p++ = DHO_MESSAGETYPE; *p++ = 1; *p++ = type; if (iface->clientid) { *p++ = DHO_CLIENTID; memcpy(p, iface->clientid, iface->clientid[0] + 1); p += iface->clientid[0] + 1; } if (lease->addr.s_addr && !IN_LINKLOCAL(htonl(lease->addr.s_addr))) { if (type == DHCP_DECLINE || type == DHCP_DISCOVER || (type == DHCP_REQUEST && lease->addr.s_addr != iface->addr.s_addr)) { PUTADDR(DHO_IPADDRESS, lease->addr); if (lease->server.s_addr) PUTADDR(DHO_SERVERID, lease->server); } } if (type == DHCP_DECLINE) { *p++ = DHO_MESSAGE; len = strlen(DAD); *p++ = len; memcpy(p, DAD, len); p += len; } if (type == DHCP_RELEASE) { if (lease->server.s_addr) PUTADDR(DHO_SERVERID, lease->server); } if (type == DHCP_DISCOVER || type == DHCP_INFORM || type == DHCP_REQUEST) { *p++ = DHO_MAXMESSAGESIZE; *p++ = 2; sz = get_mtu(iface->name); if (sz < MTU_MIN) { if (set_mtu(iface->name, MTU_MIN) == 0) sz = MTU_MIN; } sz = htons(sz); memcpy(p, &sz, 2); p += 2; if (options->userclass[0]) { *p++ = DHO_USERCLASS; memcpy(p, options->userclass, options->userclass[0] + 1); p += options->userclass[0] + 1; } if (options->vendorclassid[0]) { *p++ = DHO_VENDORCLASSID; memcpy(p, options->vendorclassid, options->vendorclassid[0] + 1); p += options->vendorclassid[0] + 1; } if (type != DHCP_INFORM) { if (options->leasetime != 0) { *p++ = DHO_LEASETIME; *p++ = 4; ul = htonl(options->leasetime); memcpy(p, &ul, 4); p += 4; } } /* Regardless of RFC2132, we should always send a hostname * upto the first dot (the short hostname) as otherwise * confuses some DHCP servers when updating DNS. * The FQDN option should be used if a FQDN is required. */ if (options->hostname[0]) { *p++ = DHO_HOSTNAME; hp = strchr(options->hostname, '.'); if (hp) len = hp - options->hostname; else len = strlen(options->hostname); *p++ = len; memcpy(p, options->hostname, len); p += len; } if (options->fqdn != FQDN_DISABLE) { /* IETF DHC-FQDN option (81), RFC4702 */ *p++ = DHO_FQDN; lp = p; *p++ = 3; /* * Flags: 0000NEOS * S: 1 => Client requests Server to update * a RR in DNS as well as PTR * O: 1 => Server indicates to client that * DNS has been updated * E: 1 => Name data is DNS format * N: 1 => Client requests Server to not * update DNS */ *p++ = (options->fqdn & 0x09) | 0x04; *p++ = 0; /* from server for PTR RR */ *p++ = 0; /* from server for A RR if S=1 */ ul = encode_rfc1035(options->hostname, p); *lp += ul; p += ul; } /* vendor is already encoded correctly, so just add it */ if (options->vendor[0]) { *p++ = DHO_VENDOR; memcpy(p, options->vendor, options->vendor[0] + 1); p += options->vendor[0] + 1; } *p++ = DHO_PARAMETERREQUESTLIST; n_params = p; *p++ = 0; for (opt = dhcp_opts; opt->option; opt++) { if (!(opt->type & REQUEST || has_option_mask(options->requestmask, opt->option))) continue; switch (opt->option) { case DHO_RENEWALTIME: /* FALLTHROUGH */ case DHO_REBINDTIME: if (type == DHCP_INFORM) continue; break; } *p++ = opt->option; } *n_params = p - n_params - 1; } *p++ = DHO_END; #ifdef BOOTP_MESSAGE_LENTH_MIN /* Some crappy DHCP servers think they have to obey the BOOTP minimum * message length. * They are wrong, but we should still cater for them. */ while (p - m < BOOTP_MESSAGE_LENTH_MIN) *p++ = DHO_PAD; #endif *message = dhcp; return p - m; }
int main(int argc, char **argv) { options_t *options; int userclasses = 0; int opt; int option_index = 0; char *prefix; pid_t pid; int debug = 0; int i; int pidfd = -1; int sig = 0; /* Close any un-needed fd's */ for (i = getdtablesize() - 1; i >= 3; --i) close (i); openlog (PACKAGE, LOG_PID, LOG_LOCAL0); 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, EXTRA_OPTS "c:dh:i:kl:m:npr:s:t:u:xAEF:GHI:LMNRTY", longopts, &option_index)) != -1) { switch (opt) { case 0: if (longopts[option_index].flag) break; logger (LOG_ERR, "option `%s' should set a flag", longopts[option_index].name); exit (EXIT_FAILURE); break; case 'c': options->script = optarg; break; case 'd': debug++; switch (debug) { case 1: setloglevel (LOG_DEBUG); break; case 2: options->daemonise = false; break; } break; #ifdef THERE_IS_NO_FORK case 'f': options->daemonised = true; close_fds (); break; case 'g': dhcpcd_skiproutes = xstrdup (optarg); break; #endif case 'h': if (! optarg) 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)); break; case 'i': if (! optarg) { 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)); break; case 'k': sig = SIGHUP; break; case 'l': 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); break; case 'n': sig = SIGALRM; break; case 'p': options->persistent = true; break; case 's': options->doinform = true; options->doarp = false; if (! optarg || strlen (optarg) == 0) { options->request_address.s_addr = 0; break; } else { char *slash = strchr (optarg, '/'); if (slash) { int cidr; /* nullify the slash, so the -r option can read the * address */ *slash++ = '\0'; if (sscanf (slash, "%d", &cidr) != 1 || inet_cidrtoaddr (cidr, &options->request_netmask) != 0) { logger (LOG_ERR, "`%s' is not a valid CIDR", slash); exit (EXIT_FAILURE); } } /* fall through */ } case 'r': if (! options->doinform) options->dorequest = true; if (strlen (optarg) > 0 && ! 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) { logger (LOG_ERR, "timeout must be a positive value"); exit (EXIT_FAILURE); } break; case 'u': { int offset = 0; for (i = 0; i < userclasses; i++) 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; } break; case 'x': sig = SIGTERM; break; case 'A': #ifndef ENABLE_ARP logger (LOG_ERR, "arp support not compiled into dhcpcd"); exit (EXIT_FAILURE); #endif 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; break; case 'F': if (strncmp (optarg, "none", strlen (optarg)) == 0) options->fqdn = FQDN_NONE; else if (strncmp (optarg, "ptr", strlen (optarg)) == 0) options->fqdn = FQDN_PTR; else if (strncmp (optarg, "both", strlen (optarg)) == 0) options->fqdn = FQDN_BOTH; else { logger (LOG_ERR, "invalid value `%s' for FQDN", optarg); exit (EXIT_FAILURE); } break; case 'G': options->dogateway = false; break; case 'H': options->dohostname++; break; case 'I': if (optarg) { if (strlen (optarg) > CLIENT_ID_MAX_LEN) { logger (LOG_ERR, "`%s' is too long for ClientID, max is %d", optarg, CLIENT_ID_MAX_LEN); exit (EXIT_FAILURE); } options->clientid_len = strlcpy (options->clientid, optarg, sizeof (options->clientid)); /* empty string disabled duid */ if (options->clientid_len == 0) options->clientid_len = -1; } else { memset (options->clientid, 0, sizeof (options->clientid)); options->clientid_len = -1; } break; case 'L': options->doipv4ll = false; break; case 'M': options->domtu = false; break; case 'N': options->dontp = false; break; case 'R': 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; break; case 'Y': options->donis = false; break; case '?': usage (); exit (EXIT_FAILURE); default: usage (); exit (EXIT_FAILURE); } } if (doversion) { printf (""PACKAGE" "VERSION"\n"); printf ("Compile time options:" #ifdef ENABLE_ARP " ARP" #endif #ifdef ENABLE_DUID " DUID" #endif #ifdef ENABLE_INFO " INFO" #endif #ifdef ENABLE_INFO_COMPAT " INFO_COMPAT" #endif #ifdef ENABLE_IPV4LL " IPV4LL" #endif #ifdef ENABLE_NIS " NIS" #endif #ifdef ENABLE_NTP " NTP" #endif #ifdef THERE_IS_NO_FORK " THERE_IS_NO_FORK" #endif "\n"); } if (dohelp) usage (); #ifdef THERE_IS_NO_FORK dhcpcd_argv = argv; dhcpcd_argc = argc; /* We need the full path to the dhcpcd */ if (*argv[0] == '/') strlcpy (dhcpcd, argv[0], sizeof (dhcpcd)); else { char pwd[PATH_MAX]; if (! getcwd (pwd, PATH_MAX)) { logger (LOG_ERR, "getcwd: %s", strerror (errno)); exit (EXIT_FAILURE); } snprintf (dhcpcd, sizeof (dhcpcd), "%s/%s", pwd, argv[0]); } #endif if (optind < argc) { if (strlen (argv[optind]) > IF_NAMESIZE) { logger (LOG_ERR, "`%s' is too long for an interface name (max=%d)", argv[optind], IF_NAMESIZE); exit (EXIT_FAILURE); } strlcpy (options->interface, argv[optind], sizeof (options->interface)); } else { /* If only version was requested then exit now */ if (doversion || dohelp) exit (EXIT_SUCCESS); logger (LOG_ERR, "no interface specified"); exit (EXIT_FAILURE); } if (strchr (options->hostname, '.')) { if (options->fqdn == FQDN_DISABLE) options->fqdn = FQDN_BOTH; } else 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 (IN_LINKLOCAL (options->request_address.s_addr)) { logger (LOG_ERR, "you are not allowed to request a link local address"); exit (EXIT_FAILURE); } if (geteuid ()) { logger (LOG_ERR, "you need to be root to run "PACKAGE); exit (EXIT_FAILURE); } 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); free (prefix); chdir ("/"); umask (022); if (mkdir (CONFIGDIR, S_IRUSR |S_IWUSR |S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) && errno != EEXIST ) { logger (LOG_ERR, "mkdir(\"%s\",0): %s\n", CONFIGDIR, strerror (errno)); exit (EXIT_FAILURE); } if (mkdir (ETCDIR, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) && errno != EEXIST ) { logger (LOG_ERR, "mkdir(\"%s\",0): %s\n", ETCDIR, strerror (errno)); exit (EXIT_FAILURE); } if (options->test) { if (options->dorequest || options->doinform) { logger (LOG_ERR, "cannot test with --inform or --request"); exit (EXIT_FAILURE); } if (options->dolastlease) { logger (LOG_ERR, "cannot test with --lastlease"); exit (EXIT_FAILURE); } if (sig != 0) { logger (LOG_ERR, "cannot test with --release or --renew"); exit (EXIT_FAILURE); } } if (sig != 0) { int killed = -1; pid = read_pid (options->pidfile); if (pid != 0) logger (LOG_INFO, "sending signal %d to pid %d", sig, pid); if (! pid || (killed = kill (pid, sig))) logger (sig == SIGALRM ? LOG_INFO : LOG_ERR, ""PACKAGE" not running"); if (pid != 0 && (sig != SIGALRM || killed != 0)) unlink (options->pidfile); if (killed == 0) exit (EXIT_SUCCESS); if (sig != SIGALRM) exit (EXIT_FAILURE); } 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); exit (EXIT_FAILURE); } pidfd = open (options->pidfile, O_WRONLY | O_CREAT | O_NONBLOCK, 0660); if (pidfd == -1) { 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)); exit (EXIT_FAILURE); } /* dhcpcd.sh should not interhit this fd */ if ((i = fcntl (pidfd, F_GETFD, 0)) == -1 || fcntl (pidfd, F_SETFD, i | FD_CLOEXEC) == -1) logger (LOG_ERR, "fcntl: %s", strerror (errno)); writepid (pidfd, getpid ()); logger (LOG_INFO, PACKAGE " " VERSION " starting"); } /* Seed random */ srandomdev (); i = EXIT_FAILURE; if (dhcp_run (options, &pidfd) == 0) i = EXIT_SUCCESS; /* If we didn't daemonise then we need to punt the pidfile now */ if (pidfd > -1) { close (pidfd); unlink (options->pidfile); } 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 */ free (dhcpcd_skiproutes); #endif logger (LOG_INFO, "exiting"); exit (i); }
size_t send_message (const interface_t *iface, const dhcp_t *dhcp, unsigned long xid, char type, const options_t *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; struct in_addr to; time_t up = uptime() - iface->start_uptime; uint32_t ul; uint16_t sz; unsigned int message_length; size_t retval; if (!iface || !options || !dhcp) return -1; memset (&from, 0, sizeof (from)); memset (&to, 0, sizeof (to)); if (type == DHCP_RELEASE) to.s_addr = dhcp->serveraddress.s_addr; 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) && ! IN_LINKLOCAL (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; /* 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; switch (iface->family) { case ARPHRD_ETHER: case ARPHRD_IEEE802: 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; break; default: logger (LOG_ERR, "dhcp: unknown hardware type %d", iface->family); } if (up < 0 || up > UINT16_MAX) message->secs = htons ((short) UINT16_MAX); else message->secs = htons (up); message->xid = xid; message->cookie = htonl (MAGIC_COOKIE); *p++ = DHCP_MESSAGETYPE; *p++ = 1; *p++ = type; if (type == DHCP_REQUEST) { *p++ = DHCP_MAXMESSAGESIZE; *p++ = 2; sz = get_mtu (iface->name); if (sz < MTU_MIN) { if (set_mtu (iface->name, MTU_MIN) == 0) sz = MTU_MIN; } sz = htons (sz); memcpy (p, &sz, 2); p += 2; } if (type != DHCP_INFORM) { #define PUTADDR(_type, _val) \ { \ *p++ = _type; \ *p++ = 4; \ memcpy (p, &_val.s_addr, 4); \ p += 4; \ } if (IN_LINKLOCAL (dhcp->address.s_addr)) logger (LOG_ERR, "cannot request a link local address"); else { 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); } #undef PUTADDR } if (type == DHCP_REQUEST || type == DHCP_DISCOVER) { if (options->leasetime != 0) { *p++ = DHCP_LEASETIME; *p++ = 4; ul = htonl (options->leasetime); memcpy (p, &ul, 4); p += 4; } } if (type == DHCP_DISCOVER || type == DHCP_INFORM || type == DHCP_REQUEST) { *p++ = DHCP_PARAMETERREQUESTLIST; n_params = p; *p++ = 0; /* Only request DNSSERVER in discover to keep the packets small. RFC2131 Section 3.5 states that the REQUEST must include the list from the DISCOVER message, so I think we can safely do this. */ if (type == DHCP_DISCOVER && ! options->test) *p++ = DHCP_DNSSERVER; else { if (type != DHCP_INFORM) { *p++ = DHCP_RENEWALTIME; *p++ = DHCP_REBINDTIME; } *p++ = DHCP_NETMASK; *p++ = DHCP_BROADCAST; *p++ = DHCP_CSR; /* RFC 3442 states classless static routes should be before routers * and static routes as classless static routes override them both */ *p++ = DHCP_STATICROUTE; *p++ = DHCP_ROUTERS; *p++ = DHCP_HOSTNAME; *p++ = DHCP_DNSSEARCH; *p++ = DHCP_DNSDOMAIN; *p++ = DHCP_DNSSERVER; *p++ = DHCP_NISDOMAIN; *p++ = DHCP_NISSERVER; *p++ = DHCP_NTPSERVER; *p++ = DHCP_MTU; *p++ = DHCP_ROOTPATH; *p++ = DHCP_SIPSERVER; } *n_params = p - n_params - 1; if (options->hostname[0]) { if (options->fqdn == FQDN_DISABLE) { *p++ = DHCP_HOSTNAME; *p++ = l = strlen (options->hostname); memcpy (p, options->hostname, l); p += l; } else { /* Draft IETF DHC-FQDN option (81) */ *p++ = DHCP_FQDN; *p++ = (l = strlen (options->hostname)) + 3; /* Flags: 0000NEOS * S: 1 => Client requests Server to update A RR in DNS as well as PTR * O: 1 => Server indicates to client that DNS has been updated * E: 1 => Name data is DNS format * N: 1 => Client requests Server to not update DNS */ *p++ = options->fqdn & 0x9; *p++ = 0; /* rcode1, response from DNS server for PTR RR */ *p++ = 0; /* rcode2, response from DNS server for A RR if S=1 */ memcpy (p, options->hostname, l); p += l; } } } if (type != DHCP_DECLINE && type != DHCP_RELEASE) { if (options->userclass_len > 0) { *p++ = DHCP_USERCLASS; *p++ = options->userclass_len; memcpy (p, &options->userclass, options->userclass_len); p += options->userclass_len; } if (options->classid_len > 0) { *p++ = DHCP_CLASSID; *p++ = options->classid_len; memcpy (p, options->classid, options->classid_len); p += options->classid_len; } } *p++ = DHCP_CLIENTID; if (options->clientid_len > 0) { *p++ = options->clientid_len + 1; *p++ = 0; /* string */ memcpy (p, options->clientid, options->clientid_len); p += options->clientid_len; #ifdef ENABLE_DUID } else if (iface->duid && options->clientid_len != -1) { *p++ = iface->duid_length + 5; *p++ = 255; /* RFC 4361 */ /* IAID is 4 bytes, so if the interface name is 4 bytes then use it */ if (strlen (iface->name) == 4) { memcpy (p, iface->name, 4); } else { /* Name isn't 4 bytes, so use the index */ ul = htonl (if_nametoindex (iface->name)); memcpy (p, &ul, 4); } p += 4; memcpy (p, iface->duid, iface->duid_length); p += iface->duid_length; #endif } else { *p++ = iface->hwlen + 1; *p++ = iface->family; memcpy (p, iface->hwaddr, iface->hwlen); p += iface->hwlen; } *p++ = DHCP_END; #ifdef BOOTP_MESSAGE_LENTH_MIN /* Some crappy DHCP servers think they have to obey the BOOTP minimum * messag length. They are wrong, but we should still cater for them */ while (p - m < BOOTP_MESSAGE_LENTH_MIN) *p++ = DHCP_PAD; #endif message_length = p - m; 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); 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); }
static int parse_kernel_route(const struct rt_msghdr *rtm, struct kernel_route *route) { struct sockaddr *sa; char *rta = (char*)rtm + sizeof(struct rt_msghdr); uint32_t excluded_flags = 0; if(ifindex_lo < 0) { ifindex_lo = if_nametoindex("lo0"); if(ifindex_lo <= 0) return -1; } memset(route, 0, sizeof(*route)); route->metric = 0; route->ifindex = rtm->rtm_index; #if defined(RTF_IFSCOPE) /* Filter out kernel route on OS X */ excluded_flags |= RTF_IFSCOPE; #endif #if defined(RTF_MULTICAST) /* Filter out multicast route on others BSD */ excluded_flags |= RTF_MULTICAST; #endif /* Filter out our own route */ excluded_flags |= RTF_PROTO2; if((rtm->rtm_flags & excluded_flags) != 0) return -1; /* Prefix */ if(!(rtm->rtm_addrs & RTA_DST)) return -1; sa = (struct sockaddr *)rta; rta += ROUNDUP(sa->sa_len); if(sa->sa_family == AF_INET6) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; memcpy(route->prefix, &sin6->sin6_addr, 16); if(IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr)) return -1; } else if(sa->sa_family == AF_INET) { struct sockaddr_in *sin = (struct sockaddr_in *)sa; #if defined(IN_LINKLOCAL) if(IN_LINKLOCAL(ntohl(sin->sin_addr.s_addr))) return -1; #endif if(IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) return -1; v4tov6(route->prefix, (unsigned char *)&sin->sin_addr); } else { return -1; } /* Gateway */ if(!(rtm->rtm_addrs & RTA_GATEWAY)) return -1; sa = (struct sockaddr *)rta; rta += ROUNDUP(sa->sa_len); if(sa->sa_family == AF_INET6) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; memcpy(route->gw, &sin6->sin6_addr, 16); if(IN6_IS_ADDR_LINKLOCAL (&sin6->sin6_addr)) { route->ifindex = IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr); SET_IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr, 0); } } else if(sa->sa_family == AF_INET) { struct sockaddr_in *sin = (struct sockaddr_in *)sa; v4tov6(route->gw, (unsigned char *)&sin->sin_addr); } if((int)route->ifindex == ifindex_lo) return -1; /* Netmask */ if((rtm->rtm_addrs & RTA_NETMASK) != 0) { sa = (struct sockaddr *)rta; rta += ROUNDUP(sa->sa_len); if(!v4mapped(route->prefix)) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; route->plen = mask2len((unsigned char*)&sin6->sin6_addr, 16); } else { struct sockaddr_in *sin = (struct sockaddr_in *)sa; route->plen = mask2len((unsigned char*)&sin->sin_addr, 4); } } if(v4mapped(route->prefix)) route->plen += 96; if(rtm->rtm_flags & RTF_HOST) route->plen = 128; return 0; }
/* handle address coming or going away */ static int rtm_dispatch_newdeladdr(struct rtm_dispinfo *di) { Address *ap; struct ifa_msghdr *ifam; struct sockaddr *sa; struct sockaddr_in *sin; int link_local; /* macro to skip to next RTA; has side-effects */ #define SKIPRTA(ifamsgp, rta, sa) \ do { \ if ((ifamsgp)->ifam_addrs & (rta)) \ (sa) = next_sa((sa)); \ } while (0) ifam = &((rtmunion_t *)di->di_buf)->ifam; assert(ifam->ifam_type == RTM_NEWADDR || ifam->ifam_type == RTM_DELADDR); daemon_log(LOG_DEBUG, "%s: %s for iface %d (%s)", __func__, ifam->ifam_type == RTM_NEWADDR ? "NEWADDR" : "DELADDR", ifam->ifam_index, (ifam->ifam_index == ifindex) ? "ours" : "not ours"); if (ifam->ifam_index != ifindex) return (0); if (!(ifam->ifam_addrs & RTA_IFA)) { daemon_log(LOG_ERR, "ifa msg has no RTA_IFA."); return (0); } /* skip over rtmsg padding correctly */ sa = (struct sockaddr *)(ifam + 1); SKIPRTA(ifam, RTA_DST, sa); SKIPRTA(ifam, RTA_GATEWAY, sa); SKIPRTA(ifam, RTA_NETMASK, sa); SKIPRTA(ifam, RTA_GENMASK, sa); SKIPRTA(ifam, RTA_IFP, sa); /* * sa now points to RTA_IFA sockaddr; we are only interested * in updates for routable addresses. */ if (sa->sa_family != AF_INET) { daemon_log(LOG_DEBUG, "%s: RTA_IFA family not AF_INET (=%d)", __func__, sa->sa_family); return (0); } sin = (struct sockaddr_in *)sa; link_local = IN_LINKLOCAL(ntohl(sin->sin_addr.s_addr)); daemon_log(LOG_DEBUG, "%s: %s for %s (%s)", __func__, ifam->ifam_type == RTM_NEWADDR ? "NEWADDR" : "DELADDR", inet_ntoa(sin->sin_addr), link_local ? "link local" : "routable"); if (link_local) return (0); for (ap = addresses; ap; ap = ap->addresses_next) { if (ap->address == sin->sin_addr.s_addr) break; } if (ifam->ifam_type == RTM_DELADDR && ap != NULL) { AVAHI_LLIST_REMOVE(Address, addresses, addresses, ap); avahi_free(ap); } if (ifam->ifam_type == RTM_NEWADDR && ap == NULL) { ap = avahi_new(Address, 1); ap->address = sin->sin_addr.s_addr; AVAHI_LLIST_PREPEND(Address, addresses, addresses, ap); } return (0); #undef SKIPRTA }
int ni_dhcp_build_message(const ni_dhcp_device_t *dev, unsigned int msg_code, const ni_addrconf_lease_t *lease, ni_buffer_t *msgbuf) { const ni_dhcp_config_t *options = dev->config; struct in_addr src_addr, dst_addr; ni_dhcp_message_t *message = NULL; if (!options || !lease) return -1; if (IN_LINKLOCAL(ntohl(lease->dhcp.address.s_addr))) { ni_error("cannot request a link local address"); goto failed; } src_addr.s_addr = dst_addr.s_addr = 0; switch (msg_code) { case DHCP_DISCOVER: if (lease->dhcp.serveraddress.s_addr != 0) return -1; break; case DHCP_REQUEST: case DHCP_RELEASE: case DHCP_INFORM: if (lease->dhcp.address.s_addr == 0 || lease->dhcp.serveraddress.s_addr == 0) return -1; src_addr = lease->dhcp.address; dst_addr = lease->dhcp.serveraddress; break; } /* Reserve some room for the IP and UDP header */ ni_buffer_reserve_head(msgbuf, sizeof(struct ip) + sizeof(struct udphdr)); /* Build the message */ message = ni_buffer_push_tail(msgbuf, sizeof(*message)); message->op = DHCP_BOOTREQUEST; message->hwtype = dev->system.arp_type; message->xid = dev->dhcp.xid; message->cookie = htonl(MAGIC_COOKIE); message->secs = htons(ni_dhcp_device_uptime(dev, 0xFFFF)); if (dev->fsm.state == NI_DHCP_STATE_BOUND || dev->fsm.state == NI_DHCP_STATE_RENEWING || dev->fsm.state == NI_DHCP_STATE_REBINDING) message->ciaddr = lease->dhcp.address.s_addr; switch (dev->system.arp_type) { case ARPHRD_ETHER: case ARPHRD_IEEE802: if (dev->system.hwaddr.len > sizeof(message->chaddr)) { ni_error("dhcp cannot handle hwaddress length %u", dev->system.hwaddr.len); goto failed; } message->hwlen = dev->system.hwaddr.len; memcpy(&message->chaddr, dev->system.hwaddr.data, dev->system.hwaddr.len); break; case ARPHRD_IEEE1394: case ARPHRD_INFINIBAND: message->hwlen = 0; if (message->ciaddr == 0) message->flags = htons(BROADCAST_FLAG); break; default: ni_error("dhcp: unknown hardware type %d", dev->system.arp_type); } ni_dhcp_option_put8(msgbuf, DHCP_MESSAGETYPE, msg_code); if (msg_code == DHCP_REQUEST) ni_dhcp_option_put16(msgbuf, DHCP_MAXMESSAGESIZE, dev->system.mtu); ni_dhcp_option_put(msgbuf, DHCP_CLIENTID, options->raw_client_id.data, options->raw_client_id.len); if (msg_code != DHCP_DECLINE && msg_code != DHCP_RELEASE) { if (options->userclass.len > 0) ni_dhcp_option_put(msgbuf, DHCP_USERCLASS, options->userclass.data, options->userclass.len); if (options->classid && options->classid[0]) ni_dhcp_option_puts(msgbuf, DHCP_CLASSID, options->classid); } if (msg_code == DHCP_DISCOVER || msg_code == DHCP_REQUEST) { if (lease->dhcp.address.s_addr) ni_dhcp_option_put_ipv4(msgbuf, DHCP_ADDRESS, lease->dhcp.address); if (lease->dhcp.lease_time != 0) ni_dhcp_option_put32(msgbuf, DHCP_LEASETIME, lease->dhcp.lease_time); } if (msg_code == DHCP_REQUEST) { if (lease->dhcp.serveraddress.s_addr) ni_dhcp_option_put_ipv4(msgbuf, DHCP_SERVERIDENTIFIER, lease->dhcp.serveraddress); } if (msg_code == DHCP_DISCOVER || msg_code == DHCP_INFORM || msg_code == DHCP_REQUEST) { unsigned int params_begin; if (options->hostname && options->hostname[0]) { if (options->fqdn == FQDN_DISABLE) { ni_dhcp_option_puts(msgbuf, DHCP_HOSTNAME, options->hostname); } else { /* IETF DHC-FQDN option(81) * http://tools.ietf.org/html/rfc4702#section-2.1 * * Flags: 0000NEOS * S: 1 => Client requests Server to update * a RR in DNS as well as PTR * O: 1 => Server indicates to client that * DNS has been updated * E: 1 => Name data is DNS format * N: 1 => Client requests Server to not * update DNS */ ni_buffer_putc(msgbuf, DHCP_FQDN); ni_buffer_putc(msgbuf, strlen(options->hostname) + 3); ni_buffer_putc(msgbuf, options->fqdn & 0x9); ni_buffer_putc(msgbuf, 0); /* from server for PTR RR */ ni_buffer_putc(msgbuf, 0); /* from server for A RR if S=1 */ ni_buffer_put(msgbuf, options->hostname, strlen(options->hostname)); } } params_begin = ni_dhcp_option_begin(msgbuf, DHCP_PARAMETERREQUESTLIST); if (msg_code == DHCP_DISCOVER) { /* dhcpcd says we should include just a single option * in discovery packets. * I'm not convinced this is right, but let's do it * this way. */ ni_buffer_putc(msgbuf, DHCP_DNSSERVER); } else { if (msg_code != DHCP_INFORM) { ni_buffer_putc(msgbuf, DHCP_RENEWALTIME); ni_buffer_putc(msgbuf, DHCP_REBINDTIME); } ni_buffer_putc(msgbuf, DHCP_NETMASK); ni_buffer_putc(msgbuf, DHCP_BROADCAST); if (options->flags & DHCP_DO_CSR) ni_buffer_putc(msgbuf, DHCP_CSR); if (options->flags & DHCP_DO_MSCSR) ni_buffer_putc(msgbuf, DHCP_MSCSR); /* RFC 3442 states classless static routes should be * before routers and static routes as classless static * routes override them both */ ni_buffer_putc(msgbuf, DHCP_STATICROUTE); ni_buffer_putc(msgbuf, DHCP_ROUTERS); ni_buffer_putc(msgbuf, DHCP_HOSTNAME); ni_buffer_putc(msgbuf, DHCP_DNSSEARCH); ni_buffer_putc(msgbuf, DHCP_DNSDOMAIN); ni_buffer_putc(msgbuf, DHCP_DNSSERVER); if (options->flags & DHCP_DO_NIS) { ni_buffer_putc(msgbuf, DHCP_NISDOMAIN); ni_buffer_putc(msgbuf, DHCP_NISSERVER); } if (options->flags & DHCP_DO_NTP) ni_buffer_putc(msgbuf, DHCP_NTPSERVER); ni_buffer_putc(msgbuf, DHCP_MTU); ni_buffer_putc(msgbuf, DHCP_ROOTPATH); ni_buffer_putc(msgbuf, DHCP_SIPSERVER); ni_buffer_putc(msgbuf, DHCP_LPRSERVER); ni_buffer_putc(msgbuf, DHCP_LOGSERVER); ni_buffer_putc(msgbuf, DHCP_NETBIOSNAMESERVER); ni_buffer_putc(msgbuf, DHCP_NETBIOSDDSERVER); ni_buffer_putc(msgbuf, DHCP_NETBIOSNODETYPE); ni_buffer_putc(msgbuf, DHCP_NETBIOSSCOPE); } ni_dhcp_option_end(msgbuf, params_begin); } ni_buffer_putc(msgbuf, DHCP_END); #ifdef BOOTP_MESSAGE_LENGTH_MIN ni_buffer_pad(msgbuf, BOOTP_MESSAGE_LENGTH_MIN, DHCP_PAD); #endif if (ni_capture_build_udp_header(msgbuf, src_addr, DHCP_CLIENT_PORT, dst_addr, DHCP_SERVER_PORT) < 0) { ni_error("unable to build packet header"); goto failed; } return 0; failed: return -1; }
int ni_dhcp4_build_message(const ni_dhcp4_device_t *dev, unsigned int msg_code, const ni_addrconf_lease_t *lease, ni_buffer_t *msgbuf) { const ni_dhcp4_config_t *options = dev->config; struct in_addr src_addr, dst_addr; int renew = dev->fsm.state == NI_DHCP4_STATE_RENEWING && msg_code == DHCP4_REQUEST; if (!options || !lease) { ni_error("%s: %s: %s: missing %s %s", __func__, dev->ifname, ni_dhcp4_message_name(msg_code), options? "" : "options", lease ? "" : "lease"); return -1; } if (IN_LINKLOCAL(ntohl(lease->dhcp4.address.s_addr))) { ni_error("%s: cannot request a link local address", dev->ifname); goto failed; } /* Reserve some room for the IP and UDP header */ if (!renew) ni_buffer_reserve_head(msgbuf, sizeof(struct ip) + sizeof(struct udphdr)); src_addr.s_addr = dst_addr.s_addr = 0; switch (msg_code) { case DHCP4_INFORM: if (__ni_dhcp4_build_msg_inform(dev, lease, msgbuf) < 0) goto failed; break; case DHCP4_DISCOVER: if (__ni_dhcp4_build_msg_discover(dev, lease, msgbuf) < 0) goto failed; break; case DHCP4_DECLINE: if (__ni_dhcp4_build_msg_decline(dev, lease, msgbuf) < 0) goto failed; break; case DHCP4_RELEASE: if (__ni_dhcp4_build_msg_release(dev, lease, msgbuf) < 0) goto failed; break; case DHCP4_REQUEST: switch (dev->fsm.state) { case NI_DHCP4_STATE_REQUESTING: src_addr.s_addr = 0; dst_addr.s_addr = 0; if (__ni_dhcp4_build_msg_request_offer(dev, lease, msgbuf) < 0) goto failed; break; case NI_DHCP4_STATE_RENEWING: src_addr = lease->dhcp4.address; dst_addr = lease->dhcp4.server_id; if (__ni_dhcp4_build_msg_request_renew(dev, lease, msgbuf) < 0) goto failed; break; case NI_DHCP4_STATE_REBINDING: src_addr = lease->dhcp4.address; dst_addr.s_addr = 0; if (__ni_dhcp4_build_msg_request_rebind(dev, lease, msgbuf) < 0) goto failed; break; case NI_DHCP4_STATE_REBOOT: src_addr.s_addr = 0; dst_addr.s_addr = 0; if (__ni_dhcp4_build_msg_request_reboot(dev, lease, msgbuf) < 0) goto failed; break; default: goto failed; } break; default: goto failed; } ni_buffer_putc(msgbuf, DHCP4_END); #ifdef BOOTP_MESSAGE_LENGTH_MIN ni_buffer_pad(msgbuf, BOOTP_MESSAGE_LENGTH_MIN, DHCP4_PAD); #endif if (!renew && ni_capture_build_udp_header(msgbuf, src_addr, DHCP4_CLIENT_PORT, dst_addr, DHCP4_SERVER_PORT) < 0) { ni_error("%s: unable to build packet header", dev->ifname); goto failed; } return 0; failed: return -1; }