static void send_with_socket(RADIUS_PACKET *request) { request->sockfd = sockfd; if (fr_dhcp_send(request) < 0) { fprintf(stderr, "dhcpclient: failed sending: %s\n", fr_syserror(errno)); fr_exit_now(1); } if (!reply_expected) return; reply = fr_dhcp_recv(sockfd); if (!reply) { fprintf(stderr, "dhcpclient: Error receiving reply: %s\n", fr_strerror()); fr_exit_now(1); } if (fr_debug_lvl) print_hex(reply); if (fr_dhcp_decode(reply) < 0) { fprintf(stderr, "dhcpclient: failed decoding\n"); fr_exit_now(1); } }
int main(int argc, char **argv) { char *p; int c; char const *radius_dir = RADDBDIR; char const *filename = NULL; fr_debug_flag = 0; while ((c = getopt(argc, argv, "d:f:hr:t:vx")) != EOF) switch(c) { case 'd': radius_dir = optarg; break; case 'f': filename = optarg; break; case 'r': if (!isdigit((int) *optarg)) usage(); retries = atoi(optarg); if ((retries == 0) || (retries > 1000)) usage(); break; case 't': if (!isdigit((int) *optarg)) usage(); timeout = atof(optarg); break; case 'v': printf("%s\n", dhcpclient_version); exit(0); break; case 'x': fr_debug_flag++; fr_log_fp = stdout; break; case 'h': default: usage(); break; } argc -= (optind - 1); argv += (optind - 1); if (argc < 2) usage(); if (dict_init(radius_dir, RADIUS_DICTIONARY) < 0) { fr_perror("dhcpclient"); return 1; } /* * Resolve hostname. */ server_ipaddr.af = AF_INET; if (strcmp(argv[1], "-") != 0) { char const *hostname = argv[1]; char const *portname = argv[1]; char buffer[256]; if (*argv[1] == '[') { /* IPv6 URL encoded */ p = strchr(argv[1], ']'); if ((size_t) (p - argv[1]) >= sizeof(buffer)) { usage(); } memcpy(buffer, argv[1] + 1, p - argv[1] - 1); buffer[p - argv[1] - 1] = '\0'; hostname = buffer; portname = p + 1; } p = strchr(portname, ':'); if (p && (strchr(p + 1, ':') == NULL)) { *p = '\0'; portname = p + 1; } else { portname = NULL; } if (ip_hton(hostname, AF_INET, &server_ipaddr) < 0) { fprintf(stderr, "dhcpclient: Failed to find IP address for host %s: %s\n", hostname, fr_syserror(errno)); exit(1); } /* * Strip port from hostname if needed. */ if (portname) server_port = atoi(portname); } /* * See what kind of request we want to send. */ if (strcmp(argv[2], "discover") == 0) { if (server_port == 0) server_port = 67; packet_code = PW_DHCP_DISCOVER; } else if (strcmp(argv[2], "request") == 0) { if (server_port == 0) server_port = 67; packet_code = PW_DHCP_REQUEST; } else if (strcmp(argv[2], "offer") == 0) { if (server_port == 0) server_port = 67; packet_code = PW_DHCP_OFFER; } else if (isdigit((int) argv[2][0])) { if (server_port == 0) server_port = 67; packet_code = atoi(argv[2]); } else { fprintf(stderr, "Unknown packet type %s\n", argv[2]); usage(); } request_init(filename); /* * No data read. Die. */ if (!request || !request->vps) { fprintf(stderr, "dhcpclient: Nothing to send.\n"); exit(1); } request->code = packet_code; /* * Bind to the first specified IP address and port. * This means we ignore later ones. */ if (request->src_ipaddr.af == AF_UNSPEC) { memset(&client_ipaddr, 0, sizeof(client_ipaddr)); client_ipaddr.af = server_ipaddr.af; client_port = 0; } else { client_ipaddr = request->src_ipaddr; client_port = request->src_port; } sockfd = fr_socket(&client_ipaddr, client_port); if (sockfd < 0) { fprintf(stderr, "dhcpclient: socket: %s\n", fr_strerror()); exit(1); } request->sockfd = sockfd; if (request->src_ipaddr.af == AF_UNSPEC) { request->src_ipaddr = client_ipaddr; request->src_port = client_port; } if (request->dst_ipaddr.af == AF_UNSPEC) { request->dst_ipaddr = server_ipaddr; request->dst_port = server_port; } /* * Encode the packet */ if (fr_dhcp_encode(request) < 0) { fprintf(stderr, "dhcpclient: failed encoding: %s\n", fr_strerror()); exit(1); } if (fr_debug_flag) print_hex(request); if (fr_dhcp_send(request) < 0) { fprintf(stderr, "dhcpclient: failed sending: %s\n", fr_syserror(errno)); exit(1); } reply = fr_dhcp_recv(sockfd); if (!reply) { fprintf(stderr, "dhcpclient: no reply\n"); exit(1); } if (fr_debug_flag) print_hex(reply); if (fr_dhcp_decode(reply) < 0) { fprintf(stderr, "dhcpclient: failed decoding\n"); return 1; } dict_free(); if (success) return 0; return 1; }
static int dhcprelay_process_client_request(REQUEST *request) { uint8_t maxhops = 16; VALUE_PAIR *vp, *giaddr; dhcp_socket_t *sock; rad_assert(request->packet->data[0] == 1); /* * Do the forward by ourselves, do not rely on dhcp_socket_send() */ request->reply->code = 0; /* * It's invalid to have giaddr=0 AND a relay option */ giaddr = pairfind(request->packet->vps, 266, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Gateway-IP-Address */ if (giaddr && (giaddr->vp_ipaddr == htonl(INADDR_ANY)) && pairfind(request->packet->vps, 82, DHCP_MAGIC_VENDOR, TAG_ANY)) { /* DHCP-Relay-Agent-Information */ DEBUG("DHCP: Received packet with giaddr = 0 and containing relay option: Discarding packet\n"); return 1; } /* * RFC 1542 (BOOTP), page 15 * * Drop requests if hop-count > 16 or admin specified another value */ if ((vp = pairfind(request->config_items, 271, DHCP_MAGIC_VENDOR, TAG_ANY))) { /* DHCP-Relay-Max-Hop-Count */ maxhops = vp->vp_integer; } vp = pairfind(request->packet->vps, 259, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Hop-Count */ rad_assert(vp != NULL); if (vp->vp_integer > maxhops) { DEBUG("DHCP: Number of hops is greater than %d: not relaying\n", maxhops); return 1; } else { /* Increment hop count */ vp->vp_integer++; } sock = request->listener->data; /* * Forward the request to the next server using the * incoming request as a template. */ /* set SRC ipaddr/port to the listener ipaddr/port */ request->packet->src_ipaddr.af = AF_INET; request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = sock->lsock.my_ipaddr.ipaddr.ip4addr.s_addr; request->packet->src_port = sock->lsock.my_port; vp = pairfind(request->config_items, 270, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Relay-To-IP-Address */ rad_assert(vp != NULL); /* set DEST ipaddr/port to the next server ipaddr/port */ request->packet->dst_ipaddr.af = AF_INET; request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; request->packet->dst_port = sock->lsock.my_port; if (fr_dhcp_encode(request->packet) < 0) { DEBUG("dhcprelay_process_client_request: ERROR in fr_dhcp_encode\n"); return -1; } return fr_dhcp_send(request->packet); }
/* * We've seen a reply from a server. * i.e. we're a relay. */ static int dhcprelay_process_server_reply(REQUEST *request) { VALUE_PAIR *vp, *giaddr; dhcp_socket_t *sock; rad_assert(request->packet->data[0] == 2); /* * Do the forward by ourselves, do not rely on dhcp_socket_send() */ request->reply->code = 0; sock = request->listener->data; /* * Check that packet is for us. */ giaddr = pairfind(request->packet->vps, 266, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Gateway-IP-Address */ /* --with-udpfromto is needed just for the following test */ if (!giaddr || giaddr->vp_ipaddr != request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr) { DEBUG("DHCP: Packet received from server was not for us (was for 0x%x). Discarding packet", ntohl(request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr)); return 1; } /* set SRC ipaddr/port to the listener ipaddr/port */ request->packet->src_ipaddr.af = AF_INET; request->packet->src_port = sock->lsock.my_port; /* set DEST ipaddr/port to clientip/68 or broadcast in specific cases */ request->packet->dst_ipaddr.af = AF_INET; /* * We're a relay, and send the reply to giaddr. */ request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = giaddr->vp_ipaddr; request->reply->dst_port = request->packet->dst_port; /* server port */ if ((request->packet->code == PW_DHCP_NAK) || !sock->src_interface || ((vp = pairfind(request->packet->vps, 262, DHCP_MAGIC_VENDOR, TAG_ANY)) /* DHCP-Flags */ && (vp->vp_integer & 0x8000) && ((vp = pairfind(request->packet->vps, 263, DHCP_MAGIC_VENDOR, TAG_ANY)) /* DHCP-Client-IP-Address */ && (vp->vp_ipaddr == htonl(INADDR_ANY))))) { /* * RFC 2131, page 23 * * Broadcast on * - DHCPNAK * or * - Broadcast flag is set up and ciaddr == NULL */ RDEBUG("DHCP: response will be broadcast"); request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST); } else { /* * RFC 2131, page 23 * * Unicast to * - ciaddr if present * otherwise to yiaddr */ if ((vp = pairfind(request->packet->vps, 263, DHCP_MAGIC_VENDOR, TAG_ANY)) /* DHCP-Client-IP-Address */ && (vp->vp_ipaddr != htonl(INADDR_ANY))) { request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; } else { vp = pairfind(request->packet->vps, 264, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Your-IP-Address */ if (!vp) { DEBUG("DHCP: Failed to find IP Address for request"); return -1; } RDEBUG("DHCP: response will be unicast to your-ip-address"); request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; /* * When sending a DHCP_OFFER, make sure our ARP table * contains an entry for the client IP address, or else * packet may not be forwarded if it was the first time * the client was requesting an IP address. */ if (request->packet->code == PW_DHCP_OFFER) { VALUE_PAIR *hwvp = pairfind(request->packet->vps, 267, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Client-Hardware-Address */ if (hwvp == NULL) { DEBUG("DHCP: DHCP_OFFER packet received with " "no Client Hardware Address. Discarding packet"); return 1; } if (fr_dhcp_add_arp_entry(request->packet->sockfd, sock->src_interface, hwvp, vp) < 0) { DEBUG("%s", fr_strerror()); return -1; } } } } if (fr_dhcp_encode(request->packet) < 0) { DEBUG("dhcprelay_process_server_reply: ERROR in fr_dhcp_encode\n"); return -1; } return fr_dhcp_send(request->packet); }
static int dhcp_process(REQUEST *request) { int rcode; VALUE_PAIR *vp; vp = pairfind(request->packet->vps, 53, DHCP_MAGIC_VENDOR); /* DHCP-Message-Type */ if (vp) { DICT_VALUE *dv = dict_valbyattr(53, DHCP_MAGIC_VENDOR, vp->vp_integer); DEBUG("Trying sub-section dhcp %s {...}", dv->name ? dv->name : "<unknown>"); rcode = module_post_auth(vp->vp_integer, request); } else { DEBUG("DHCP: Failed to find DHCP-Message-Type in packet!"); rcode = RLM_MODULE_FAIL; } /* * Look for Relay attribute, and forward it if necessary. */ vp = pairfind(request->config_items, 270, DHCP_MAGIC_VENDOR); if (vp) { VALUE_PAIR *giaddr; RADIUS_PACKET relayed; request->reply->code = 0; /* don't reply to the client */ /* * Find the original giaddr. * FIXME: Maybe look in the original packet? * * It's invalid to have giaddr=0 AND a relay option */ giaddr = pairfind(request->packet->vps, 266, DHCP_MAGIC_VENDOR); if (giaddr && (giaddr->vp_ipaddr == htonl(INADDR_ANY))) { if (pairfind(request->packet->vps, 82, DHCP_MAGIC_VENDOR)) { RDEBUG("DHCP: Received packet with giaddr = 0 and containing relay option: Discarding packet"); return 1; } /* * FIXME: Add cache by XID. */ RDEBUG("DHCP: Cannot yet relay packets with giaddr = 0"); return 1; } if (request->packet->data[3] > 10) { RDEBUG("DHCP: Number of hops is greater than 10: not relaying"); return 1; } /* * Forward it VERBATIM to the next server, rather * than to the client. */ memcpy(&relayed, request->packet, sizeof(relayed)); relayed.dst_ipaddr.af = AF_INET; relayed.dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; relayed.dst_port = request->packet->dst_port; relayed.src_ipaddr = request->packet->dst_ipaddr; relayed.src_port = request->packet->dst_port; relayed.data = rad_malloc(relayed.data_len); memcpy(relayed.data, request->packet->data, request->packet->data_len); relayed.vps = NULL; /* * The only field that changes is the number of hops */ relayed.data[3]++; /* number of hops */ /* * Forward the relayed packet VERBATIM, don't * respond to the client, and forget completely * about this request. */ fr_dhcp_send(&relayed); free(relayed.data); return 1; } vp = pairfind(request->reply->vps, 53, DHCP_MAGIC_VENDOR); /* DHCP-Message-Type */ if (vp) { request->reply->code = vp->vp_integer; if ((request->reply->code != 0) && (request->reply->code < PW_DHCP_OFFSET)) { request->reply->code += PW_DHCP_OFFSET; } } else switch (rcode) { case RLM_MODULE_OK: case RLM_MODULE_UPDATED: if (request->packet->code == PW_DHCP_DISCOVER) { request->reply->code = PW_DHCP_OFFER; break; } else if (request->packet->code == PW_DHCP_REQUEST) { request->reply->code = PW_DHCP_ACK; break; } request->reply->code = PW_DHCP_NAK; break; default: case RLM_MODULE_REJECT: case RLM_MODULE_FAIL: case RLM_MODULE_INVALID: case RLM_MODULE_NOOP: case RLM_MODULE_NOTFOUND: if (request->packet->code == PW_DHCP_DISCOVER) { request->reply->code = 0; /* ignore the packet */ } else { request->reply->code = PW_DHCP_NAK; } break; case RLM_MODULE_HANDLED: break; } /* * Releases don't get replies. */ if (request->packet->code == PW_DHCP_RELEASE) { request->reply->code = 0; } return 1; }