#include <freeradius-devel/udpfromto.h>
#include <freeradius-devel/dhcp.h>
-/*
- * This doesn't appear to work right now.
- */
-#undef WITH_UDPFROMTO
-
#ifdef WITH_DHCP
#include <sys/ioctl.h>
*/
RADIUS_PACKET *fr_dhcp_recv(int sockfd)
{
- ssize_t len;
uint32_t magic;
struct sockaddr_storage src;
struct sockaddr_storage dst;
sizeof_src = sizeof(src);
#ifdef WITH_UDPFROMTO
sizeof_dst = sizeof(dst);
- len = recvfromto(sockfd, packet->data, MAX_PACKET_SIZE, 0,
- (struct sockaddr *)&src, &sizeof_src,
- (struct sockaddr *)&dst, &sizeof_dst);
+ packet->data_len = recvfromto(sockfd, packet->data, MAX_PACKET_SIZE, 0,
+ (struct sockaddr *)&src, &sizeof_src,
+ (struct sockaddr *)&dst, &sizeof_dst);
#else
- len = recvfrom(sockfd, packet->data, MAX_PACKET_SIZE, 0,
- (struct sockaddr *)&src, &sizeof_src);
+ packet->data_len = recvfrom(sockfd, packet->data, MAX_PACKET_SIZE, 0,
+ (struct sockaddr *)&src, &sizeof_src);
#endif
- if (len <= 0) {
+ if (packet->data_len <= 0) {
fr_strerror_printf("Failed reading DHCP socket: %s", strerror(errno));
rad_free(&packet);
return NULL;
}
- if (len < MIN_PACKET_SIZE) {
- fr_strerror_printf("DHCP packet is too small (%d < %d)",
- (int) len, MIN_PACKET_SIZE);
+ if (packet->data_len < MIN_PACKET_SIZE) {
+ fr_strerror_printf("DHCP packet is too small (%zu < %d)",
+ packet->data_len, MIN_PACKET_SIZE);
rad_free(&packet);
return NULL;
}
return NULL;
}
- packet->data_len = len;
-
memcpy(&magic, packet->data + 236, 4);
magic = ntohl(magic);
if (magic != DHCP_OPTION_MAGIC_NUMBER) {
#ifdef WITH_UDPFROMTO
struct sockaddr_storage src;
socklen_t sizeof_src;
+
+ fr_ipaddr2sockaddr(&packet->src_ipaddr, packet->src_port,
+ &src, &sizeof_src);
#endif
- if (!fr_ipaddr2sockaddr(&packet->dst_ipaddr, packet->dst_port,
- &dst, &sizeof_dst)) {
- return -1;
- }
+ fr_ipaddr2sockaddr(&packet->dst_ipaddr, packet->dst_port,
+ &dst, &sizeof_dst);
- /*
- * The client doesn't yet have an IP address, but is
- * expecting an ethernet packet unicast to it's MAC
- * address. We need to build a raw frame.
- */
- if (packet->offset == 0) {
- /*
- * FIXME: Insert code here!
- */
+ if (fr_debug_flag > 1) {
+ char type_buf[64];
+ const char *name = type_buf;
+#ifdef WITH_UDPFROMTO
+ char src_ip_buf[256];
+#endif
+ char dst_ip_buf[256];
+
+ if ((packet->code >= PW_DHCP_DISCOVER) &&
+ (packet->code <= PW_DHCP_INFORM)) {
+ name = dhcp_message_types[packet->code - PW_DHCP_OFFSET];
+ } else {
+ snprintf(type_buf, sizeof(type_buf), "%d",
+ packet->code - PW_DHCP_OFFSET);
+ }
+
+ DEBUG(
+#ifdef WITH_UDPFROMTO
+ "Sending %s of id %08x from %s:%d to %s:%d\n",
+#else
+ "Sending %s of id %08x to %s:%d\n",
+#endif
+ name, (unsigned int) packet->id,
+#ifdef WITH_UDPFROMTO
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ src_ip_buf, sizeof(src_ip_buf)),
+ packet->src_port,
+#endif
+ inet_ntop(packet->dst_ipaddr.af,
+ &packet->dst_ipaddr.ipaddr,
+ dst_ip_buf, sizeof(dst_ip_buf)),
+ packet->dst_port);
}
#ifndef WITH_UDPFROMTO
return sendto(packet->sockfd, packet->data, packet->data_len, 0,
(struct sockaddr *)&dst, sizeof_dst);
#else
- if (!fr_ipaddr2sockaddr(&packet->src_ipaddr, packet->src_port,
- &src, &sizeof_src)) {
- return -1;
- }
- return sendfromto(packet->sockfd,
- packet->data, packet->data_len, 0,
- (struct sockaddr *)&src, sizeof_src,
+ return sendfromto(packet->sockfd, packet->data, packet->data_len, 0,
+ (struct sockaddr *)&src, sizeof_src,
(struct sockaddr *)&dst, sizeof_dst);
#endif
}
/*
* Hack for ease of use.
*/
- if (fr_dhcp_attr2vp(vp, p, alen) < 0) {
+ if ((da->vendor == DHCP_MAGIC_VENDOR) &&
+ (da->attr == 61) && !da->flags.array &&
+ (alen == 7) && (*p == 1) && (num_entries == 1)) {
+ vp->type = PW_TYPE_ETHERNET;
+ memcpy(vp->vp_octets, p + 1, 6);
+ vp->length = alen;
+
+ } else if (fr_dhcp_attr2vp(vp, p, alen) < 0) {
pairfree(&vp);
pairfree(head);
return -1;
return -1;
}
- if ((i == 11) &&
+ if ((i == 11) &&
(packet->data[1] == 1) &&
(packet->data[2] != 6)) {
fr_strerror_printf("chaddr of incorrect length for ethernet");
*/
/*
- * Nothing uses tail after this call, if it does in the future
- * it'll need to find the new tail...
+ * Nothing uses tail after this call, if it does in the future
+ * it'll need to find the new tail...
*/
if (fr_dhcp_decode_options(packet->data + 240, packet->data_len - 240,
tail) < 0) {
* Reply should be broadcast.
*/
if (vp) vp->vp_integer |= 0x8000;
- packet->data[10] |= 0x80;
+ packet->data[10] |= 0x80;
}
}
}
* Relay-Agent is last
*/
if (((*a)->da->attr == 82) &&
- (*b)->da->attr != 82) return +1;
+ (*b)->da->attr != 82) return 1;
return ((*a)->da->attr - (*b)->da->attr);
}
VALUE_PAIR *vp;
uint32_t lvalue, mms;
size_t dhcp_size, length;
- dhcp_packet_t *dhcp;
+#ifndef NDEBUG
+ const char *name;
+# ifdef WITH_UDPFROMTO
+ char src_ip_buf[256];
+# endif
+ char dst_ip_buf[256];
+#endif
if (packet->data) return 0;
packet->data = malloc(MAX_PACKET_SIZE);
- if (!packet->data) return -1;
-
packet->data_len = MAX_PACKET_SIZE;
+ memset(packet->data, 0, packet->data_len);
+ /* XXX Ugly ... should be set by the caller */
if (packet->code == 0) packet->code = PW_DHCP_NAK;
- /*
- * If there's a request, use it as a template.
- * Otherwise, assume that the caller has set up
- * everything appropriately.
- */
- if (original) {
- packet->dst_ipaddr.af = AF_INET;
- packet->src_ipaddr.af = AF_INET;
-
- packet->dst_port = original->src_port;
- packet->src_port = original->dst_port;
-
- /*
- * Note that for DHCP, we NEVER send the response
- * to the source IP address of the request. It
- * may have traversed multiple relays, and we
- * need to send the request to the relay closest
- * to the client.
- *
- * if giaddr, send to giaddr.
- * if NAK, send broadcast.
- * if broadcast flag, send broadcast.
- * if ciaddr is empty, send broadcast.
- * otherwise unicast to ciaddr.
- */
-
- /*
- * FIXME: alignment issues. We likely don't want to
- * de-reference the packet structure directly..
- */
- dhcp = (dhcp_packet_t *) original->data;
-
- /*
- * Default to sending it via sendto(), without using
- * raw sockets.
- */
- packet->offset = 1;
-
- if (dhcp->giaddr != htonl(INADDR_ANY)) {
- packet->dst_ipaddr.ipaddr.ip4addr.s_addr = dhcp->giaddr;
-
- if (dhcp->giaddr != htonl(INADDR_LOOPBACK)) {
- packet->dst_port = original->dst_port;
- } else {
- packet->dst_port = original->src_port; /* debugging */
- }
-
- } else if ((packet->code == PW_DHCP_NAK) ||
- ((dhcp->flags & 0x8000) != 0) ||
- (dhcp->ciaddr == htonl(INADDR_ANY))) {
- /*
- * The kernel will take care of sending it to
- * the broadcast MAC.
- */
- packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
-
- } else {
- /*
- * It was broadcast to us: we need to
- * broadcast the response.
- */
- if (packet->src_ipaddr.ipaddr.ip4addr.s_addr != dhcp->ciaddr) {
- packet->offset = 0;
- }
- packet->dst_ipaddr.ipaddr.ip4addr.s_addr = dhcp->ciaddr;
- }
-
- /*
- * Rewrite the source IP to be our own, if we know it.
- */
- if (packet->src_ipaddr.ipaddr.ip4addr.s_addr == htonl(INADDR_BROADCAST)) {
- packet->src_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_ANY);
- }
+#ifndef NDEBUG
+ if ((packet->code >= PW_DHCP_DISCOVER) &&
+ (packet->code <= PW_DHCP_INFORM)) {
+ name = dhcp_message_types[packet->code - PW_DHCP_OFFSET];
} else {
- memset(packet->data, 0, packet->data_len);
- }
-
- if (fr_debug_flag > 1) {
- char type_buf[64];
- const char *name = type_buf;
- char src_ip_buf[256], dst_ip_buf[256];
-
- if ((packet->code >= PW_DHCP_DISCOVER) &&
- (packet->code <= PW_DHCP_INFORM)) {
- name = dhcp_message_types[packet->code - PW_DHCP_OFFSET];
- } else {
- snprintf(type_buf, sizeof(type_buf), "%d",
- packet->code - PW_DHCP_OFFSET);
- }
-
- DEBUG("Sending %s of id %08x from %s:%d to %s:%d\n",
- name, (unsigned int) packet->id,
- inet_ntop(packet->src_ipaddr.af,
- &packet->src_ipaddr.ipaddr,
- src_ip_buf, sizeof(src_ip_buf)),
- packet->src_port,
- inet_ntop(packet->dst_ipaddr.af,
- &packet->dst_ipaddr.ipaddr,
- dst_ip_buf, sizeof(dst_ip_buf)),
- packet->dst_port);
-
- if (fr_debug_flag) {
- for (i = 256; i < 269; i++) {
- vp = pairfind(packet->vps, i, DHCP_MAGIC_VENDOR, TAG_ANY);
- if (!vp) continue;
-
- debug_pair(vp);
- }
- }
+ name = "?Unknown?";
}
+#endif
+
+ DEBUG(
+#ifdef WITH_UDPFROMTO
+ "Encoding %s of id %08x from %s:%d to %s:%d\n",
+#else
+ "Encoding %s of id %08x to %s:%d\n",
+#endif
+ name, (unsigned int) packet->id,
+#ifdef WITH_UDPFROMTO
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ src_ip_buf, sizeof(src_ip_buf)),
+ packet->src_port,
+#endif
+ inet_ntop(packet->dst_ipaddr.af,
+ &packet->dst_ipaddr.ipaddr,
+ dst_ip_buf, sizeof(dst_ip_buf)),
+ packet->dst_port);
p = packet->data;
mms = DEFAULT_PACKET_SIZE; /* maximum message size */
- if (original) {
- /*
- * Clients can request a LARGER size, but not a
- * smaller one. They also cannot request a size
- * larger than MTU.
- */
- vp = pairfind(original->vps, 57, DHCP_MAGIC_VENDOR, TAG_ANY);
- if (vp && (vp->vp_integer > mms)) {
- mms = vp->vp_integer;
-
- if (mms > MAX_PACKET_SIZE) mms = MAX_PACKET_SIZE;
- }
+ /*
+ * Clients can request a LARGER size, but not a
+ * smaller one. They also cannot request a size
+ * larger than MTU.
+ */
+
+ /* DHCP-DHCP-Maximum-Msg-Size */
+ vp = pairfind(packet->vps, 57, DHCP_MAGIC_VENDOR, TAG_ANY);
+ if (vp && (vp->vp_integer > mms)) {
+ mms = vp->vp_integer;
+
+ if (mms > MAX_PACKET_SIZE) mms = MAX_PACKET_SIZE;
}
/*
}
} else { /* we don't support this type! */
fr_strerror_printf("DHCP-Authentication %d unsupported",
- vp->vp_octets[0]);
+ vp->vp_octets[0]);
}
}
if (vp) {
*p++ = vp->vp_integer & 0xff;
} else {
- if (!original) {
- *p++ = 1; /* client message */
- } else {
- *p++ = 2; /* server message */
- }
+ *p++ = 1; /* client message */
+ }
+
+ /* DHCP-Hardware-Type */
+ if ((vp = pairfind(packet->vps, 257, DHCP_MAGIC_VENDOR, TAG_ANY))) {
+ *p++ = vp->vp_integer & 0xFF;
+ } else {
+ *p++ = 1; /* hardware type = ethernet */
}
- *p++ = 1; /* hardware type = ethernet */
- *p++ = 6; /* 6 bytes of ethernet */
- vp = pairfind(packet->vps, 259, DHCP_MAGIC_VENDOR, TAG_ANY);
- if (vp) {
- *p++ = vp->vp_integer & 0xff;
+ /* DHCP-Hardware-Address-Length */
+ if ((vp = pairfind(packet->vps, 258, DHCP_MAGIC_VENDOR, TAG_ANY))) {
+ *p++ = vp->vp_integer & 0xFF;
} else {
- *p++ = 0; /* hops */
+ *p++ = 6; /* 6 bytes of ethernet */
}
- if (original) { /* Xid */
- memcpy(p, original->data + 4, 4);
+ /* DHCP-Hop-Count */
+ if ((vp = pairfind(packet->vps, 259, DHCP_MAGIC_VENDOR, TAG_ANY))) {
+ *p = vp->vp_integer & 0xff;
+ }
+ p++;
+
+ /* DHCP-Transaction-Id */
+ if ((vp = pairfind(packet->vps, 260, DHCP_MAGIC_VENDOR, TAG_ANY))) {
+ lvalue = htonl(vp->vp_integer);
} else {
lvalue = fr_rand();
- memcpy(p, &lvalue, 4);
}
+ memcpy(p, &lvalue, 4);
p += 4;
- memset(p, 0, 2); /* secs are zero */
+ /* DHCP-Number-of-Seconds */
+ if ((vp = pairfind(packet->vps, 261, DHCP_MAGIC_VENDOR, TAG_ANY))) {
+ lvalue = htonl(vp->vp_integer);
+ memcpy(p, &lvalue, 2);
+ }
p += 2;
- if (original) {
- memcpy(p, original->data + 10, 6); /* copy flags && ciaddr */
+ /* DHCP-Flags */
+ if ((vp = pairfind(packet->vps, 262, DHCP_MAGIC_VENDOR, TAG_ANY))) {
+ lvalue = htons(vp->vp_integer);
+ memcpy(p, &lvalue, 2);
}
+ p += 2;
- /*
- * Allow the admin to set the broadcast flag.
- */
- vp = pairfind(packet->vps, 262, DHCP_MAGIC_VENDOR, TAG_ANY);
- if (vp) {
- p[0] |= (vp->vp_integer & 0xff00) >> 8;
- p[1] |= (vp->vp_integer & 0xff);
+ /* DHCP-Client-IP-Address */
+ if ((vp = pairfind(packet->vps, 263, DHCP_MAGIC_VENDOR, TAG_ANY))) {
+ memcpy(p, &vp->vp_ipaddr, 4);
}
+ p += 4;
- p += 6;
-
- /*
- * Set client IP address.
- */
- vp = pairfind(packet->vps, 264, DHCP_MAGIC_VENDOR, TAG_ANY); /* Your IP address */
- if (vp) {
+ /* DHCP-Your-IP-address */
+ if ((vp = pairfind(packet->vps, 264, DHCP_MAGIC_VENDOR, TAG_ANY))) {
lvalue = vp->vp_ipaddr;
} else {
lvalue = htonl(INADDR_ANY);
}
- memcpy(p, &lvalue, 4); /* your IP address */
+ memcpy(p, &lvalue, 4);
p += 4;
- vp = pairfind(packet->vps, 265, DHCP_MAGIC_VENDOR, TAG_ANY); /* server IP address */
- if (!vp) vp = pairfind(packet->vps, 54, DHCP_MAGIC_VENDOR, TAG_ANY); /* identifier */
- if (vp) {
+ /* DHCP-Server-IP-Address */
+ vp = pairfind(packet->vps, 265, DHCP_MAGIC_VENDOR, TAG_ANY);
+
+ /* DHCP-DHCP-Server-Identifier */
+ if (!vp && (vp = pairfind(packet->vps, 54, DHCP_MAGIC_VENDOR, TAG_ANY))) {
lvalue = vp->vp_ipaddr;
} else {
lvalue = htonl(INADDR_ANY);
}
- memcpy(p, &lvalue, 4); /* Server IP address */
+ memcpy(p, &lvalue, 4);
p += 4;
- if (original) {
- memcpy(p, original->data + 24, 4); /* copy gateway IP address */
+ /*
+ * DHCP-Gateway-IP-Address
+ */
+ if ((vp = pairfind(packet->vps, 266, DHCP_MAGIC_VENDOR, TAG_ANY))) {
+ lvalue = vp->vp_ipaddr;
} else {
- vp = pairfind(packet->vps, 266, DHCP_MAGIC_VENDOR, TAG_ANY);
- if (vp) {
- lvalue = vp->vp_ipaddr;
- } else {
- lvalue = htonl(INADDR_NONE);
- }
- memcpy(p, &lvalue, 4);
+ lvalue = htonl(INADDR_ANY);
}
+ memcpy(p, &lvalue, 4);
p += 4;
- if (original) {
- memcpy(p, original->data + 28, DHCP_CHADDR_LEN);
- } else {
- vp = pairfind(packet->vps, 267, DHCP_MAGIC_VENDOR, TAG_ANY);
- if (vp) {
- if (vp->length > DHCP_CHADDR_LEN) {
- memcpy(p, vp->vp_octets, DHCP_CHADDR_LEN);
- } else {
- memcpy(p, vp->vp_octets, vp->length);
- }
+ /* DHCP-Client-Hardware-Address */
+ if ((vp = pairfind(packet->vps, 267, DHCP_MAGIC_VENDOR, TAG_ANY))) {
+ if (vp->length > DHCP_CHADDR_LEN) {
+ memcpy(p, vp->vp_octets, DHCP_CHADDR_LEN);
+ } else {
+ memcpy(p, vp->vp_octets, vp->length);
}
}
p += DHCP_CHADDR_LEN;
- /*
- * Zero our sname && filename fields.
- */
- memset(p, 0, DHCP_SNAME_LEN + DHCP_FILE_LEN);
+ /* DHCP-Server-Host-Name */
+ if ((vp = pairfind(packet->vps, 268, DHCP_MAGIC_VENDOR, TAG_ANY))) {
+ if (vp->length > DHCP_SNAME_LEN) {
+ memcpy(p, vp->vp_strvalue, DHCP_SNAME_LEN);
+ } else {
+ memcpy(p, vp->vp_strvalue, vp->length);
+ }
+ }
p += DHCP_SNAME_LEN;
/*
* When that happens, the boot filename is passed as an option,
* instead of being placed verbatim in the filename field.
*/
- vp = pairfind(packet->vps, 269, DHCP_MAGIC_VENDOR, TAG_ANY);
- if (vp) {
+
+ /* DHCP-Boot-Filename */
+ if ((vp = pairfind(packet->vps, 269, DHCP_MAGIC_VENDOR, TAG_ANY))) {
if (vp->length > DHCP_FILE_LEN) {
memcpy(p, vp->vp_strvalue, DHCP_FILE_LEN);
} else {
}
p += DHCP_FILE_LEN;
- lvalue = htonl(DHCP_OPTION_MAGIC_NUMBER); /* DHCP magic number */
+ /* DHCP magic number */
+ lvalue = htonl(DHCP_OPTION_MAGIC_NUMBER);
memcpy(p, &lvalue, 4);
p += 4;