david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

[dhcp] Allow pseudo-DHCP servers to use pseudo-identifiers

Some ProxyDHCP servers and PXE boot servers do not specify a DHCP
server identifier via option 54.  We currently work around this in a
variety of ad-hoc ways:

 - if a ProxyDHCPACK has no server identifier then we treat it as
   having the correct server identifier,

 - if a boot server ACK has no server identifier then we use the
   packet's source IP address as the server identifier.

Introduce the concept of a DHCP server pseudo-identifier, defined as
being:

 - the server identifier (option 54), or

 - if there is no server identifier, then the next-server address
   (siaddr),

 - if there is no server identifier or next-server address, then the
   DHCP packet's source IP address.

Use the pseudo-identifier in place of the server identifier when
handling ProxyDHCP and PXE boot server responses.

Originally-fixed-by: Wissam Shoukair <wissams@mellanox.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown 2015-08-18 15:43:06 +01:00
parent c0b61bad99
commit 60e2b71471
1 changed files with 54 additions and 27 deletions

View File

@ -154,22 +154,23 @@ struct dhcp_session_state {
* @v dhcppkt DHCP packet * @v dhcppkt DHCP packet
* @v peer Destination address * @v peer Destination address
*/ */
int ( * tx ) ( struct dhcp_session *dhcp, int ( * tx ) ( struct dhcp_session *dhcp, struct dhcp_packet *dhcppkt,
struct dhcp_packet *dhcppkt,
struct sockaddr_in *peer ); struct sockaddr_in *peer );
/** Handle received packet /**
* Handle received packet
* *
* @v dhcp DHCP session * @v dhcp DHCP session
* @v dhcppkt DHCP packet * @v dhcppkt DHCP packet
* @v peer DHCP server address * @v peer DHCP server address
* @v msgtype DHCP message type * @v msgtype DHCP message type
* @v server_id DHCP server ID * @v server_id DHCP server ID
* @v pseudo_id DHCP server pseudo-ID
*/ */
void ( * rx ) ( struct dhcp_session *dhcp, void ( * rx ) ( struct dhcp_session *dhcp, struct dhcp_packet *dhcppkt,
struct dhcp_packet *dhcppkt, struct sockaddr_in *peer, uint8_t msgtype,
struct sockaddr_in *peer, struct in_addr server_id, struct in_addr pseudo_id );
uint8_t msgtype, struct in_addr server_id ); /**
/** Handle timer expiry * Handle timer expiry
* *
* @v dhcp DHCP session * @v dhcp DHCP session
*/ */
@ -340,11 +341,13 @@ static int dhcp_discovery_tx ( struct dhcp_session *dhcp,
* @v peer DHCP server address * @v peer DHCP server address
* @v msgtype DHCP message type * @v msgtype DHCP message type
* @v server_id DHCP server ID * @v server_id DHCP server ID
* @v pseudo_id DHCP server pseudo-ID
*/ */
static void dhcp_discovery_rx ( struct dhcp_session *dhcp, static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
struct dhcp_packet *dhcppkt, struct dhcp_packet *dhcppkt,
struct sockaddr_in *peer, uint8_t msgtype, struct sockaddr_in *peer, uint8_t msgtype,
struct in_addr server_id ) { struct in_addr server_id,
struct in_addr pseudo_id ) {
struct in_addr ip; struct in_addr ip;
char vci[9]; /* "PXEClient" */ char vci[9]; /* "PXEClient" */
int vci_len; int vci_len;
@ -356,8 +359,11 @@ static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp, DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ), dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
ntohs ( peer->sin_port ) ); ntohs ( peer->sin_port ) );
if ( server_id.s_addr != peer->sin_addr.s_addr ) if ( ( server_id.s_addr != peer->sin_addr.s_addr ) ||
DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) ); ( pseudo_id.s_addr != peer->sin_addr.s_addr ) ) {
DBGC ( dhcp, " (%s/", inet_ntoa ( server_id ) );
DBGC ( dhcp, "%s)", inet_ntoa ( pseudo_id ) );
}
/* Identify offered IP address */ /* Identify offered IP address */
ip = dhcppkt->dhcphdr->yiaddr; ip = dhcppkt->dhcphdr->yiaddr;
@ -398,10 +404,10 @@ static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
} }
/* Select as ProxyDHCP offer, if applicable */ /* Select as ProxyDHCP offer, if applicable */
if ( server_id.s_addr && has_pxeclient && if ( pseudo_id.s_addr && has_pxeclient &&
( priority >= dhcp->proxy_priority ) ) { ( priority >= dhcp->proxy_priority ) ) {
dhcppkt_put ( dhcp->proxy_offer ); dhcppkt_put ( dhcp->proxy_offer );
dhcp->proxy_server = server_id; dhcp->proxy_server = pseudo_id;
dhcp->proxy_offer = dhcppkt_get ( dhcppkt ); dhcp->proxy_offer = dhcppkt_get ( dhcppkt );
dhcp->proxy_priority = priority; dhcp->proxy_priority = priority;
} }
@ -510,11 +516,13 @@ static int dhcp_request_tx ( struct dhcp_session *dhcp,
* @v peer DHCP server address * @v peer DHCP server address
* @v msgtype DHCP message type * @v msgtype DHCP message type
* @v server_id DHCP server ID * @v server_id DHCP server ID
* @v pseudo_id DHCP server pseudo-ID
*/ */
static void dhcp_request_rx ( struct dhcp_session *dhcp, static void dhcp_request_rx ( struct dhcp_session *dhcp,
struct dhcp_packet *dhcppkt, struct dhcp_packet *dhcppkt,
struct sockaddr_in *peer, uint8_t msgtype, struct sockaddr_in *peer, uint8_t msgtype,
struct in_addr server_id ) { struct in_addr server_id,
struct in_addr pseudo_id ) {
struct in_addr ip; struct in_addr ip;
struct settings *parent; struct settings *parent;
struct settings *settings; struct settings *settings;
@ -523,8 +531,11 @@ static void dhcp_request_rx ( struct dhcp_session *dhcp,
DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp, DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ), dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
ntohs ( peer->sin_port ) ); ntohs ( peer->sin_port ) );
if ( server_id.s_addr != peer->sin_addr.s_addr ) if ( ( server_id.s_addr != peer->sin_addr.s_addr ) ||
DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) ); ( pseudo_id.s_addr != peer->sin_addr.s_addr ) ) {
DBGC ( dhcp, " (%s/", inet_ntoa ( server_id ) );
DBGC ( dhcp, "%s)", inet_ntoa ( pseudo_id ) );
}
/* Identify leased IP address */ /* Identify leased IP address */
ip = dhcppkt->dhcphdr->yiaddr; ip = dhcppkt->dhcphdr->yiaddr;
@ -641,19 +652,24 @@ static int dhcp_proxy_tx ( struct dhcp_session *dhcp,
* @v peer DHCP server address * @v peer DHCP server address
* @v msgtype DHCP message type * @v msgtype DHCP message type
* @v server_id DHCP server ID * @v server_id DHCP server ID
* @v pseudo_id DHCP server pseudo-ID
*/ */
static void dhcp_proxy_rx ( struct dhcp_session *dhcp, static void dhcp_proxy_rx ( struct dhcp_session *dhcp,
struct dhcp_packet *dhcppkt, struct dhcp_packet *dhcppkt,
struct sockaddr_in *peer, uint8_t msgtype, struct sockaddr_in *peer, uint8_t msgtype,
struct in_addr server_id ) { struct in_addr server_id,
struct in_addr pseudo_id ) {
struct settings *settings = &dhcppkt->settings; struct settings *settings = &dhcppkt->settings;
int rc; int rc;
DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp, DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ), dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
ntohs ( peer->sin_port ) ); ntohs ( peer->sin_port ) );
if ( server_id.s_addr != peer->sin_addr.s_addr ) if ( ( server_id.s_addr != peer->sin_addr.s_addr ) ||
DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) ); ( pseudo_id.s_addr != peer->sin_addr.s_addr ) ) {
DBGC ( dhcp, " (%s/", inet_ntoa ( server_id ) );
DBGC ( dhcp, "%s)", inet_ntoa ( pseudo_id ) );
}
DBGC ( dhcp, "\n" ); DBGC ( dhcp, "\n" );
/* Filter out unacceptable responses */ /* Filter out unacceptable responses */
@ -661,8 +677,7 @@ static void dhcp_proxy_rx ( struct dhcp_session *dhcp,
return; return;
if ( ( msgtype != DHCPOFFER ) && ( msgtype != DHCPACK ) ) if ( ( msgtype != DHCPOFFER ) && ( msgtype != DHCPACK ) )
return; return;
if ( server_id.s_addr /* Linux PXE server omits server ID */ && if ( ( pseudo_id.s_addr != dhcp->proxy_server.s_addr ) )
( server_id.s_addr != dhcp->proxy_server.s_addr ) )
return; return;
/* Register settings */ /* Register settings */
@ -772,19 +787,24 @@ static int dhcp_pxebs_accept ( struct dhcp_session *dhcp,
* @v peer DHCP server address * @v peer DHCP server address
* @v msgtype DHCP message type * @v msgtype DHCP message type
* @v server_id DHCP server ID * @v server_id DHCP server ID
* @v pseudo_id DHCP server pseudo-ID
*/ */
static void dhcp_pxebs_rx ( struct dhcp_session *dhcp, static void dhcp_pxebs_rx ( struct dhcp_session *dhcp,
struct dhcp_packet *dhcppkt, struct dhcp_packet *dhcppkt,
struct sockaddr_in *peer, uint8_t msgtype, struct sockaddr_in *peer, uint8_t msgtype,
struct in_addr server_id ) { struct in_addr server_id,
struct in_addr pseudo_id ) {
struct dhcp_pxe_boot_menu_item menu_item = { 0, 0 }; struct dhcp_pxe_boot_menu_item menu_item = { 0, 0 };
int rc; int rc;
DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp, DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ), dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
ntohs ( peer->sin_port ) ); ntohs ( peer->sin_port ) );
if ( server_id.s_addr != peer->sin_addr.s_addr ) if ( ( server_id.s_addr != peer->sin_addr.s_addr ) ||
DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) ); ( pseudo_id.s_addr != peer->sin_addr.s_addr ) ) {
DBGC ( dhcp, " (%s/", inet_ntoa ( server_id ) );
DBGC ( dhcp, "%s)", inet_ntoa ( pseudo_id ) );
}
/* Identify boot menu item */ /* Identify boot menu item */
dhcppkt_fetch ( dhcppkt, DHCP_PXE_BOOT_MENU_ITEM, dhcppkt_fetch ( dhcppkt, DHCP_PXE_BOOT_MENU_ITEM,
@ -801,8 +821,7 @@ static void dhcp_pxebs_rx ( struct dhcp_session *dhcp,
return; return;
if ( menu_item.type != dhcp->pxe_type ) if ( menu_item.type != dhcp->pxe_type )
return; return;
if ( ! dhcp_pxebs_accept ( dhcp, ( server_id.s_addr ? if ( ! dhcp_pxebs_accept ( dhcp, pseudo_id ) )
server_id : peer->sin_addr ) ) )
return; return;
/* Register settings */ /* Register settings */
@ -1134,6 +1153,7 @@ static int dhcp_deliver ( struct dhcp_session *dhcp,
struct dhcphdr *dhcphdr; struct dhcphdr *dhcphdr;
uint8_t msgtype = 0; uint8_t msgtype = 0;
struct in_addr server_id = { 0 }; struct in_addr server_id = { 0 };
struct in_addr pseudo_id;
int rc = 0; int rc = 0;
/* Sanity checks */ /* Sanity checks */
@ -1168,6 +1188,13 @@ static int dhcp_deliver ( struct dhcp_session *dhcp,
dhcppkt_fetch ( dhcppkt, DHCP_SERVER_IDENTIFIER, dhcppkt_fetch ( dhcppkt, DHCP_SERVER_IDENTIFIER,
&server_id, sizeof ( server_id ) ); &server_id, sizeof ( server_id ) );
/* Identify server pseudo-ID */
pseudo_id = server_id;
if ( ! pseudo_id.s_addr )
pseudo_id = dhcppkt->dhcphdr->siaddr;
if ( ! pseudo_id.s_addr )
pseudo_id = peer->sin_addr;
/* Check for matching transaction ID */ /* Check for matching transaction ID */
if ( dhcphdr->xid != dhcp->xid ) { if ( dhcphdr->xid != dhcp->xid ) {
DBGC ( dhcp, "DHCP %p %s from %s:%d has bad transaction " DBGC ( dhcp, "DHCP %p %s from %s:%d has bad transaction "
@ -1190,7 +1217,7 @@ static int dhcp_deliver ( struct dhcp_session *dhcp,
} }
/* Handle packet based on current state */ /* Handle packet based on current state */
dhcp->state->rx ( dhcp, dhcppkt, peer, msgtype, server_id ); dhcp->state->rx ( dhcp, dhcppkt, peer, msgtype, server_id, pseudo_id );
err_chaddr: err_chaddr:
err_xid: err_xid: