48
52
uint32_t siaddr; /* 20 */
49
53
uint32_t giaddr; /* 24 */
50
54
uint8_t chaddr[DHCP_CHADDR_LEN]; /* 28 */
51
char sname[DHCP_SNAME_LEN]; /* 44 */
52
char file[DHCP_FILE_LEN]; /* 108 */
55
uint8_t sname[DHCP_SNAME_LEN]; /* 44 */
56
uint8_t file[DHCP_FILE_LEN]; /* 108 */
53
57
uint32_t option_format; /* 236 */
54
58
uint8_t options[DHCP_VEND_LEN];
61
typedef struct dhcp_option_t {
58
67
* INADDR_ANY : 68 -> INADDR_BROADCAST : 67 DISCOVER
59
68
* INADDR_BROADCAST : 68 <- SERVER_IP : 67 OFFER
106
115
* Some clients silently ignore responses less than 300 bytes.
108
117
#define MIN_PACKET_SIZE (244)
109
#define DEFAULT_PACKET_SIZE (576)
118
#define DEFAULT_PACKET_SIZE (300)
110
119
#define MAX_PACKET_SIZE (1500 - 40)
121
#define DHCP_OPTION_FIELD (0)
122
#define DHCP_FILE_FIELD (1)
123
#define DHCP_SNAME_FIELD (2)
125
static uint8_t *dhcp_get_option(dhcp_packet_t *packet, size_t packet_size,
130
int field = DHCP_OPTION_FIELD;
132
uint8_t *data = packet->options;
135
size = packet_size - offsetof(dhcp_packet_t, options);
136
data = &packet->options[where];
138
while (where < size) {
139
if (data[0] == 0) { /* padding */
144
if (data[0] == 255) { /* end of options */
145
if ((field == DHCP_OPTION_FIELD) &&
146
(overload & DHCP_FILE_FIELD)) {
149
size = sizeof(packet->file);
150
field = DHCP_FILE_FIELD;
153
} else if ((field == DHCP_FILE_FIELD) &&
154
(overload && DHCP_SNAME_FIELD)) {
155
data = packet->sname;
157
size = sizeof(packet->sname);
158
field = DHCP_SNAME_FIELD;
166
* We MUST have a real option here.
168
if ((where + 2) > size) {
169
fr_strerror_printf("Options overflow field at %u",
170
data - (uint8_t *) packet);
174
if ((where + 2 + data[1]) > size) {
175
fr_strerror_printf("Option length overflows field at %u",
176
data - (uint8_t *) packet);
180
if (data[0] == option) return data;
182
if (data[0] == 52) { /* overload sname and/or file */
186
where += data[1] + 2;
113
194
* DHCPv4 is only for IPv4. Broadcast only works if udpfromto is
119
200
struct sockaddr_storage src;
120
201
struct sockaddr_storage dst;
121
socklen_t sizeof_src = sizeof(src);
122
socklen_t sizeof_dst = sizeof(dst);
202
socklen_t sizeof_src;
203
socklen_t sizeof_dst;
123
204
RADIUS_PACKET *packet;
125
memset(&src, 0, sizeof_src);
126
memset(&dst, 0, sizeof_dst);
128
208
packet = rad_alloc(0);
129
209
if (!packet) return NULL;
138
218
packet->sockfd = sockfd;
219
sizeof_src = sizeof(src);
220
#ifdef WITH_UDPFROMTO
221
sizeof_dst = sizeof(dst);
222
packet->data_len = recvfromto(sockfd, packet->data, MAX_PACKET_SIZE, 0,
223
(struct sockaddr *)&src, &sizeof_src,
224
(struct sockaddr *)&dst, &sizeof_dst);
139
226
packet->data_len = recvfrom(sockfd, packet->data, MAX_PACKET_SIZE, 0,
140
227
(struct sockaddr *)&src, &sizeof_src);
141
230
if (packet->data_len <= 0) {
142
231
fprintf(stderr, "Failed reading DHCP socket: %s", strerror(errno));
143
232
rad_free(&packet);
185
274
memcpy(&magic, packet->data + 4, 4);
186
275
packet->id = ntohl(magic);
189
* Check that it's a known packet type.
191
if ((packet->data[240] != 53) ||
192
(packet->data[241] != 1) ||
193
(packet->data[242] == 0) ||
194
(packet->data[242] >= 8)) {
195
fprintf(stderr, "Unknown, or badly formatted DHCP packet\n");
277
code = dhcp_get_option((dhcp_packet_t *) packet->data,
278
packet->data_len, 53);
280
fr_strerror_printf("No message-type option was found in the packet");
285
if ((code[1] < 1) || (code[2] == 0) || (code[2] > 8)) {
286
fr_strerror_printf("Unknown value for message-type option");
291
packet->code = code[2] | PW_DHCP_OFFSET;
201
294
* Create a unique vector from the MAC address and the
211
304
memset(packet->vector, 0, sizeof(packet->vector));
212
305
memcpy(packet->vector, packet->data + 28, packet->data[2]);
213
packet->vector[packet->data[2]] = packet->data[242];
306
packet->vector[packet->data[2]] = packet->code & 0xff;
216
309
* FIXME: for DISCOVER / REQUEST: src_port == dst_port + 1
217
310
* FIXME: for OFFER / ACK : src_port = dst_port - 1
220
packet->code = PW_DHCP_OFFSET | packet->data[242];
223
314
* Unique keys are xid, client mac, and client ID?
227
318
* FIXME: More checks, like DHCP packet type?
231
struct sockaddr_in *s4;
232
struct sockaddr_storage si;
233
socklen_t si_len = sizeof(si);
236
* This should never fail...
238
getsockname(sockfd, (struct sockaddr *) &si, &si_len);
240
s4 = (struct sockaddr_in *)&src;
241
packet->src_ipaddr.af = AF_INET;
242
packet->src_ipaddr.ipaddr.ip4addr = s4->sin_addr;
243
packet->src_port = ntohs(s4->sin_port);
245
s4 = (struct sockaddr_in *)&si;
246
packet->dst_ipaddr.af = AF_INET;
247
packet->dst_ipaddr.ipaddr.ip4addr = s4->sin_addr;
248
packet->dst_port = ntohs(s4->sin_port);
251
if (librad_debug > 1) {
321
sizeof_dst = sizeof(dst);
323
#ifndef WITH_UDPFROMTO
325
* This should never fail...
327
getsockname(sockfd, (struct sockaddr *) &dst, &sizeof_dst);
330
fr_sockaddr2ipaddr(&dst, sizeof_dst, &packet->dst_ipaddr, &port);
331
packet->dst_port = port;
333
fr_sockaddr2ipaddr(&src, sizeof_src, &packet->src_ipaddr, &port);
334
packet->src_port = port;
336
if (fr_debug_flag > 1) {
252
337
char type_buf[64];
253
338
const char *name = type_buf;
254
339
char src_ip_buf[256], dst_ip_buf[256];
261
346
packet->code - PW_DHCP_OFFSET);
264
printf("Received %s of id %u from %s:%d to %s:%d\n",
349
printf("Received %s of id %08x from %s:%d to %s:%d\n",
265
350
name, (unsigned int) packet->id,
266
351
inet_ntop(packet->src_ipaddr.af,
267
352
&packet->src_ipaddr.ipaddr,
284
369
int fr_dhcp_send(RADIUS_PACKET *packet)
286
371
struct sockaddr_storage dst;
372
socklen_t sizeof_dst;
373
#ifdef WITH_UDPFROMTO
287
374
struct sockaddr_storage src;
288
socklen_t sizeof_dst = sizeof(dst);
289
socklen_t sizeof_src = sizeof(src);
291
memset(&src, 0, sizeof(src));
292
memset(&dst, 0, sizeof(dst));
295
* Only IPv4 is supported.
298
struct sockaddr_in *s4;
300
s4 = (struct sockaddr_in *)&dst;
301
sizeof_dst = sizeof(struct sockaddr_in);
303
s4->sin_family = AF_INET;
304
s4->sin_addr = packet->dst_ipaddr.ipaddr.ip4addr;
305
s4->sin_port = htons(packet->dst_port);
307
s4 = (struct sockaddr_in *)&src;
308
sizeof_src = sizeof(struct sockaddr_in);
310
s4->sin_family = AF_INET;
311
s4->sin_addr = packet->src_ipaddr.ipaddr.ip4addr;
312
s4->sin_port = htons(packet->src_port);
375
socklen_t sizeof_src;
378
fr_ipaddr2sockaddr(&packet->dst_ipaddr, packet->dst_port,
381
#ifndef WITH_UDPFROMTO
316
383
* Assume that the packet is encoded before sending it.
318
385
return sendto(packet->sockfd, packet->data, packet->data_len, 0,
319
386
(struct sockaddr *)&dst, sizeof_dst);
388
fr_ipaddr2sockaddr(&packet->src_ipaddr, packet->src_port,
391
return sendfromto(packet->sockfd,
392
packet->data, packet->data_len, 0,
393
(struct sockaddr *)&src, sizeof_src,
394
(struct sockaddr *)&dst, sizeof_dst);
335
411
p = packet->data;
337
if ((librad_debug > 2) && fr_log_fp) {
413
if ((fr_debug_flag > 2) && fr_log_fp) {
338
414
for (i = 0; i < packet->data_len; i++) {
339
415
if ((i & 0x0f) == 0x00) fprintf(stderr, "%d: ", i);
340
416
fprintf(fr_log_fp, "%02x ", packet->data[i]);
355
431
for (i = 0; i < 14; i++) {
356
432
vp = pairmake(dhcp_header_names[i], NULL, T_OP_EQ);
358
fprintf(stderr, "Parse error %s\n", librad_errstr);
434
fprintf(stderr, "Parse error %s\n", fr_strerror());
755
835
if (packet->code == 0) packet->code = PW_DHCP_NAK;
757
if (librad_debug > 1) {
838
* FIXME: allow it to send client packets.
841
fr_strerror_printf("Need original to send response!");
845
packet->dst_ipaddr.af = AF_INET;
846
packet->src_ipaddr.af = AF_INET;
848
packet->dst_port = original->src_port;
849
packet->src_port = original->dst_port;
852
* Note that for DHCP, we NEVER send the response to the
853
* source IP address of the request. It may have
854
* traversed multiple relays, and we need to send the request
855
* to the relay closest to the client.
857
* if giaddr, send to giaddr.
858
* if NAK, send broadcast packet
859
* if ciaddr, unicast to ciaddr
860
* if flags & 0x8000, broadcast (client request)
861
* if sent from 0.0.0.0, broadcast response
862
* unicast to client yiaddr
866
* FIXME: alignment issues. We likely don't want to
867
* de-reference the packet structure directly..
869
dhcp = (dhcp_packet_t *) original->data;
871
if (dhcp->giaddr != htonl(INADDR_ANY)) {
872
packet->dst_ipaddr.ipaddr.ip4addr.s_addr = dhcp->giaddr;
874
if (dhcp->giaddr != htonl(INADDR_LOOPBACK)) {
875
packet->dst_port = original->dst_port;
877
packet->dst_port = original->src_port; /* debugging */
880
} else if (packet->code == PW_DHCP_NAK) {
881
packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
883
} else if (dhcp->ciaddr != htonl(INADDR_ANY)) {
884
packet->dst_ipaddr.ipaddr.ip4addr.s_addr = dhcp->ciaddr;
886
} else if ((dhcp->flags & 0x8000) != 0) {
887
packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
889
} else if (packet->dst_ipaddr.ipaddr.ip4addr.s_addr == htonl(INADDR_ANY)) {
890
packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
892
} else if (dhcp->yiaddr != htonl(INADDR_ANY)) {
893
packet->dst_ipaddr.ipaddr.ip4addr.s_addr = dhcp->yiaddr;
896
/* leave destination IP alone. */
900
* Rewrite the source IP to be our own, if we know it.
902
if (packet->src_ipaddr.ipaddr.ip4addr.s_addr == htonl(INADDR_BROADCAST)) {
903
packet->src_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_ANY);
906
if (fr_debug_flag > 1) {
758
907
char type_buf[64];
759
908
const char *name = type_buf;
760
909
char src_ip_buf[256], dst_ip_buf[256];
767
916
packet->code - PW_DHCP_OFFSET);
770
printf("Sending %s of id %u from %s:%d to %s:%d\n",
919
printf("Sending %s of id %08x from %s:%d to %s:%d\n",
771
920
name, (unsigned int) packet->id,
772
921
inet_ntop(packet->src_ipaddr.af,
773
922
&packet->src_ipaddr.ipaddr,
865
1014
memcpy(p, original->data + 10, 6); /* copy flags && ciaddr */
1017
* Allow the admin to set the broadcast flag.
1019
vp = pairfind(packet->vps, DHCP2ATTR(262));
1021
p[0] |= (vp->vp_integer & 0xff00) >> 8;
1022
p[1] |= (vp->vp_integer & 0xff);
877
1036
memcpy(p, &lvalue, 4); /* your IP address */
880
memset(p, 0, 4); /* siaddr is zero */
883
memset(p, 0, 4); /* gateway address is zero */
887
* FIXME: allow it to send client packets.
890
librad_log("Need original to send response!");
1039
vp = pairfind(packet->vps, DHCP2ATTR(265)); /* server IP address */
1040
if (!vp) vp = pairfind(packet->vps, DHCP2ATTR(54)); /* identifier */
1042
lvalue = vp->vp_ipaddr;
1044
lvalue = htonl(INADDR_ANY);
1046
memcpy(p, &lvalue, 4); /* Server IP address */
1049
memcpy(p, original->data + 24, 4); /* copy gateway IP address */
894
1052
memcpy(p, original->data + 28, DHCP_CHADDR_LEN);
895
1053
p += DHCP_CHADDR_LEN;
912
1070
for (i = 0; i < 14; i++) {
913
1071
vp = pairmake(dhcp_header_names[i], NULL, T_OP_EQ);
915
fprintf(stderr, "Parse error %s\n", librad_errstr);
1073
fprintf(stderr, "Parse error %s\n", fr_strerror());
949
1107
vp->length = packet->data[2];
1110
case PW_TYPE_ETHERNET: /* only for Client HW Address */
1111
memcpy(vp->vp_ether, p, sizeof(vp->vp_ether));
1112
vp->length = sizeof(vp->vp_ether);
953
1116
fprintf(stderr, "Internal sanity check failed %d %d\n", vp->type, __LINE__);
971
vp = pairfind(packet->vps, DHCP2ATTR(53));
972
if (vp && (vp->vp_integer != (packet->code - PW_DHCP_OFFSET))) {
973
fprintf(stderr, "Message-Type doesn't match! %d %d\n",
974
packet->code, vp->vp_integer);
976
pairdelete(&packet->vps, DHCP2ATTR(0x35));
979
1135
* Before packing the attributes, re-order them so that
980
1136
* the array ones are all contiguous. This simplifies
1122
1279
packet->data_len = dhcp_size;
1124
packet->dst_ipaddr.af = AF_INET;
1125
packet->src_ipaddr.af = AF_INET;
1127
packet->dst_port = original->src_port;
1128
packet->src_port = original->dst_port;
1131
* Note that for DHCP, we NEVER send the response to the
1132
* source IP address of the request. It may have
1133
* traversed multiple relays, and we need to send the request
1134
* to the relay closest to the client.
1136
* if giaddr, send to giaddr.
1137
* if NAK, send broadcast packet
1138
* if ciaddr, unicast to ciaddr
1139
* if flags & 0x8000, broadcast (client request)
1140
* if sent from 0.0.0.0, broadcast response
1141
* unicast to client yiaddr
1145
* FIXME: alignment issues. We likely don't want to
1146
* de-reference the packet structure directly..
1148
dhcp = (dhcp_packet_t *) original->data;
1150
if (dhcp->giaddr != htonl(INADDR_ANY)) {
1151
packet->dst_ipaddr.ipaddr.ip4addr.s_addr = dhcp->giaddr;
1153
} else if (packet->code == PW_DHCP_NAK) {
1154
packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
1156
} else if (dhcp->ciaddr != htonl(INADDR_ANY)) {
1157
packet->dst_ipaddr.ipaddr.ip4addr.s_addr = dhcp->ciaddr;
1159
} else if ((dhcp->flags & 0x8000) != 0) {
1160
packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
1162
} else if (packet->dst_ipaddr.ipaddr.ip4addr.s_addr == htonl(INADDR_ANY)) {
1163
packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
1166
packet->dst_ipaddr.ipaddr.ip4addr.s_addr = dhcp->yiaddr;
1170
1282
* FIXME: This may set it to broadcast, which we don't
1171
1283
* want. Instead, set it to the real address of the
1181
1293
packet->data_len = DEFAULT_PACKET_SIZE;
1184
if ((librad_debug > 2) && fr_log_fp) {
1296
if ((fr_debug_flag > 2) && fr_log_fp) {
1185
1297
for (i = 0; i < packet->data_len; i++) {
1186
1298
if ((i & 0x0f) == 0x00) fprintf(fr_log_fp, "%d: ", i);
1187
1299
fprintf(fr_log_fp, "%02x ", packet->data[i]);