diff --git a/includes/dhcp.h b/includes/dhcp.h index f916468..60f4d96 100644 --- a/includes/dhcp.h +++ b/includes/dhcp.h @@ -184,6 +184,7 @@ struct dhcp_packet { #define RAI_REMOTE_ID 2 #define RAI_AGENT_ID 3 #define RAI_LINK_SELECT 5 +#define RAI_RELAY_PORT 19 /* FQDN suboptions: */ #define FQDN_NO_CLIENT_UPDATE 1 diff --git a/includes/dhcpd.h b/includes/dhcpd.h index 261714d..2bf09f6 100644 --- a/includes/dhcpd.h +++ b/includes/dhcpd.h @@ -472,6 +472,9 @@ struct packet { /* Propogates server value SV_ECHO_CLIENT_ID so it is available * in cons_options() */ int sv_echo_client_id; + + /* Relay port check */ + isc_boolean_t relay_source_port; }; /* @@ -2397,6 +2400,8 @@ void eval_network_statements(struct option_state **options, struct packet *packet, struct group *network_group); +uint16_t dhcp_check_relayport(struct packet *packet); + /* dhcpleasequery.c */ void dhcpleasequery (struct packet *, int); void dhcpv6_leasequery (struct data_string *, struct packet *); diff --git a/server/dhcp.c b/server/dhcp.c index c9b3632..1d152d5 100644 --- a/server/dhcp.c +++ b/server/dhcp.c @@ -1061,6 +1061,17 @@ void dhcpdecline (packet, ms_nulltp) lease_dereference (&lease, MDL); } +uint16_t dhcp_check_relayport (packet) +struct packet *packet; +{ + if (lookup_option(&agent_universe, packet->options, + RAI_RELAY_PORT) != NULL) { + return (packet->client_port); + } + + return (0); +} + void dhcpinform (packet, ms_nulltp) struct packet *packet; int ms_nulltp; @@ -1081,6 +1092,7 @@ void dhcpinform (packet, ms_nulltp) isc_boolean_t zeroed_ciaddr; struct interface_info *interface; int result, h_m_client_ip = 0; + uint16_t relay_port; struct host_decl *host = NULL, *hp = NULL, *h; #if defined (DEBUG_INFORM_HOST) int h_w_fixed_addr = 0; @@ -1155,6 +1167,8 @@ void dhcpinform (packet, ms_nulltp) oc = lookup_option(&dhcp_universe, packet->options, DHO_SUBNET_SELECTION); + relay_port = dhcp_check_relayport(packet); + memset(&d1, 0, sizeof d1); if (oc && evaluate_option_cache(&d1, packet, NULL, NULL, packet->options, NULL, @@ -1672,7 +1686,7 @@ void dhcpinform (packet, ms_nulltp) */ if (!raw.ciaddr.s_addr && gip.len) { memcpy(&to.sin_addr, gip.iabuf, 4); - to.sin_port = local_port; + to.sin_port = (relay_port) ? relay_port : local_port; raw.flags |= htons(BOOTP_BROADCAST); } else { gip.len = 0; @@ -1729,6 +1743,7 @@ void nak_lease (packet, cip, network_group) unsigned char nak = DHCPNAK; struct packet outgoing; unsigned i; + uint16_t relay_port; struct option_state *options = (struct option_state *)0; struct option_cache *oc = (struct option_cache *)0; struct option_state *eval_options = NULL; @@ -1777,6 +1792,8 @@ void nak_lease (packet, cip, network_group) save_option (&dhcp_universe, options, oc); option_cache_dereference (&oc, MDL); + relay_port = dhcp_check_relayport(packet); + /* Setup the options at the global and subnet scopes. These * may be used to locate sever id option if enabled as well * for echo-client-id further on. (This allocates eval_options). */ @@ -1905,7 +1922,7 @@ void nak_lease (packet, cip, network_group) if (raw.giaddr.s_addr) { to.sin_addr = raw.giaddr; if (raw.giaddr.s_addr != htonl (INADDR_LOOPBACK)) - to.sin_port = local_port; + to.sin_port = (relay_port) ? relay_port : local_port; else to.sin_port = remote_port; /* for testing. */ @@ -3717,6 +3734,7 @@ void dhcp_reply (lease) int result; struct lease_state *state = lease -> state; int nulltp, bootpp, unicastp = 1; + uint16_t relay_port; struct data_string d1; const char *s; @@ -3886,11 +3904,13 @@ void dhcp_reply (lease) #endif memset (to.sin_zero, 0, sizeof to.sin_zero); + relay_port = dhcp_check_relayport(state->packet); + /* If this was gatewayed, send it back to the gateway... */ if (raw.giaddr.s_addr) { to.sin_addr = raw.giaddr; if (raw.giaddr.s_addr != htonl (INADDR_LOOPBACK)) - to.sin_port = local_port; + to.sin_port = (relay_port) ? relay_port : local_port; else to.sin_port = remote_port; /* For debugging. */ diff --git a/server/dhcpleasequery.c b/server/dhcpleasequery.c index 75a0e72..9bd4d7e 100644 --- a/server/dhcpleasequery.c +++ b/server/dhcpleasequery.c @@ -152,6 +152,7 @@ dhcpleasequery(struct packet *packet, int ms_nulltp) { u_int32_t time_rebinding; u_int32_t time_expiry; u_int32_t client_last_transaction_time; + uint16_t relay_port; struct sockaddr_in to; struct in_addr siaddr; struct data_string prl; @@ -660,12 +661,14 @@ dhcpleasequery(struct packet *packet, int ms_nulltp) { #endif memset(to.sin_zero, 0, sizeof(to.sin_zero)); + relay_port = dhcp_check_relayport(packet); + /* * Leasequery packets are be sent to the gateway address. */ to.sin_addr = packet->raw->giaddr; if (packet->raw->giaddr.s_addr != htonl(INADDR_LOOPBACK)) { - to.sin_port = local_port; + to.sin_port = (relay_port) ? relay_port : local_port; } else { to.sin_port = remote_port; /* XXXSK: For debugging. */ } diff --git a/server/stables.c b/server/stables.c index 445ef0f..05ce76e 100644 --- a/server/stables.c +++ b/server/stables.c @@ -169,6 +169,7 @@ static struct option agent_options[] = { { "agent-id", "I", &agent_universe, 3, 1 }, { "DOCSIS-device-class", "L", &agent_universe, 4, 1 }, { "link-selection", "I", &agent_universe, 5, 1 }, + { "relay-port", "Z", &agent_universe, 19, 1 }, { NULL, NULL, NULL, 0, 0 } };