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; unsigned char *n_params = NULL; unsigned long l; struct in_addr from; struct in_addr to; long up = uptime() - iface->start_uptime; uint32_t ul; uint16_t sz; unsigned int message_length; 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; memset (&message, 0, sizeof (dhcpmessage_t)); if (type == DHCP_INFORM || type == DHCP_RELEASE || type == DHCP_REQUEST) { message.ciaddr = iface->previous_address.s_addr; from.s_addr = iface->previous_address.s_addr; } 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 = 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; } #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); 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) *p++ = DHCP_DNSSERVER; else { *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; /* These parameters were requested by dhcpcd-2.0 and earlier but we never did anything with them */ /* *p++ = DHCP_DEFAULTIPTTL; *p++ = DHCP_MASKDISCOVERY; *p++ = DHCP_ROUTERDISCOVERY; */ } *n_params = p - n_params - 1; if (*options->hostname) { 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; } *p++ = DHCP_CLASSID; *p++ = l = strlen (options->classid); memcpy (p, options->classid, l); p += l; } *p++ = DHCP_CLIENTID; if (options->clientid[0]) { l = strlen (options->clientid); *p++ = l + 1; *p++ = 0; /* string */ memcpy (p, options->clientid, l); p += l; } else { *p++ = iface->hwlen + 1; *p++ = iface->family; memcpy (p, iface->hwaddr, iface->hwlen); p += iface->hwlen; } #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 - 1) *p++ = DHCP_PAD; #endif *p++ = DHCP_END; message_length = p - m; 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)); }
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; }
size_t send_message (interface_t *iface, dhcp_t *dhcp, unsigned long xid, char type, options_t *options) { dhcpmessage_t message; unsigned char *p = (unsigned char *) &message.options; unsigned char *n_params = NULL; unsigned long l; struct in_addr from; struct in_addr to; if (!iface || !options || !dhcp) return -1; if (type == DHCP_RELEASE || type == DHCP_INFORM || (type == DHCP_REQUEST && iface->previous_address.s_addr == dhcp->address.s_addr)) from.s_addr = dhcp->address.s_addr; else from.s_addr = 0; if (type == DHCP_RELEASE) to.s_addr = dhcp->serveraddress.s_addr; else to.s_addr = 0; memset (&message, 0, sizeof (dhcpmessage_t)); message.op = DHCP_BOOTREQUEST; message.hwtype = ARPHRD_ETHER; message.hwlen = ETHER_ADDR_LEN; message.secs = htons (10); message.xid = xid; memcpy (&message.hwaddr, &iface->ethernet_address, ETHER_ADDR_LEN); message.cookie = htonl (MAGIC_COOKIE); /* This logic should be improved so that we don't need to set the 0 flag as it's done in the above memset statement */ if (type == DHCP_REQUEST && dhcp->address.s_addr == iface->previous_address.s_addr && iface->previous_address.s_addr != 0) message.flags = 0; else message.flags = htons (BROADCAST_FLAG); if (iface->previous_address.s_addr != 0 && (type == DHCP_INFORM || type == DHCP_RELEASE || (type == DHCP_REQUEST && iface->previous_address.s_addr == dhcp->address.s_addr))) message.ciaddr = iface->previous_address.s_addr; *p++ = DHCP_MESSAGETYPE; *p++ = 1; *p++ = type; if (type == DHCP_REQUEST) { *p++ = DHCP_MAXMESSAGESIZE; *p++ = 2; uint16_t sz = htons (sizeof (struct udp_dhcp_packet)); memcpy (p, &sz, 2); p += 2; } #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); 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; uint32_t 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; /* If we don't request one item, then we get defaults back which we don't want */ if (type == DHCP_DISCOVER) { *p++ = DHCP_DNSSERVER; } else { *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_ROUTERS; *p++ = DHCP_STATICROUTE; *p++ = DHCP_HOSTNAME; *p++ = DHCP_DNSSEARCH; *p++ = DHCP_DNSDOMAIN; *p++ = DHCP_DNSSERVER; *p++ = DHCP_NISDOMAIN; *p++ = DHCP_NISSERVER; *p++ = DHCP_NTPSERVER; /* These parameters were requested by dhcpcd-2.0 and earlier but we never did anything with them */ /* *p++ = DHCP_DEFAULTIPTTL; *p++ = DHCP_MASKDISCOVERY; *p++ = DHCP_ROUTERDISCOVERY; */ } *n_params = p - n_params - 1; } if (type == DHCP_REQUEST) { if (options->hostname) { 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) { *p++ = DHCP_USERCLASS; *p++ = l = strlen (options->userclass); memcpy (p, options->userclass, l); p += l; } *p++ = DHCP_CLASSID; *p++ = l = strlen (options->classid); memcpy (p, options->classid, l); p += l; } *p++ = DHCP_CLIENTID; if (options->clientid[0]) { l = strlen (options->clientid); *p++ = l + 1; *p++ = 0; /* string */ memcpy (p, options, l); p += l; } else { *p++ = ETHER_ADDR_LEN + 1; *p++ = ARPHRD_ETHER; memcpy (p, &iface->ethernet_address, ETHER_ADDR_LEN); p += ETHER_ADDR_LEN; } *p = DHCP_END; struct udp_dhcp_packet packet; memset (&packet, 0, sizeof (struct udp_dhcp_packet)); make_dhcp_packet (&packet, (unsigned char *) &message, from, to); logger (LOG_DEBUG, "Sending %s with xid %d", dhcp_message[(int) type], xid); return send_packet (iface, ETHERTYPE_IP, (unsigned char *) &packet, sizeof (struct udp_dhcp_packet)); }
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); }