Exemple #1
0
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;
}
Exemple #3
0
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);
}
Exemple #4
0
/*
 *	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);
}
Exemple #5
0
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;
}