mirror of https://github.com/ipxe/ipxe.git
[dhcp] Use a random DHCP transaction identifier (xid)
iPXE currently uses the last four bytes of the MAC address as the DHCP transaction identifier. Reduce the probability of collisions by generating a random transaction identifier. Originally-implemented-by: Amos Kong <akong@redhat.com> Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/5/head
parent
8b092f4c50
commit
12767d2202
|
@ -660,15 +660,18 @@ struct dhcphdr {
|
||||||
/** Setting block name used for BootServerDHCP responses */
|
/** Setting block name used for BootServerDHCP responses */
|
||||||
#define PXEBS_SETTINGS_NAME "pxebs"
|
#define PXEBS_SETTINGS_NAME "pxebs"
|
||||||
|
|
||||||
|
extern uint32_t dhcp_last_xid;
|
||||||
extern unsigned int dhcp_chaddr ( struct net_device *netdev, void *chaddr,
|
extern unsigned int dhcp_chaddr ( struct net_device *netdev, void *chaddr,
|
||||||
uint16_t *flags );
|
uint16_t *flags );
|
||||||
extern int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
|
extern int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
|
||||||
struct net_device *netdev, uint8_t msgtype,
|
struct net_device *netdev, uint8_t msgtype,
|
||||||
const void *options, size_t options_len,
|
uint32_t xid, const void *options,
|
||||||
void *data, size_t max_len );
|
size_t options_len, void *data,
|
||||||
|
size_t max_len );
|
||||||
extern int dhcp_create_request ( struct dhcp_packet *dhcppkt,
|
extern int dhcp_create_request ( struct dhcp_packet *dhcppkt,
|
||||||
struct net_device *netdev,
|
struct net_device *netdev,
|
||||||
unsigned int msgtype, struct in_addr ciaddr,
|
unsigned int msgtype, uint32_t xid,
|
||||||
|
struct in_addr ciaddr,
|
||||||
void *data, size_t max_len );
|
void *data, size_t max_len );
|
||||||
extern int start_dhcp ( struct interface *job, struct net_device *netdev );
|
extern int start_dhcp ( struct interface *job, struct net_device *netdev );
|
||||||
extern int start_pxebs ( struct interface *job, struct net_device *netdev,
|
extern int start_pxebs ( struct interface *job, struct net_device *netdev,
|
||||||
|
|
|
@ -114,7 +114,8 @@ int create_fakedhcpdiscover ( struct net_device *netdev,
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if ( ( rc = dhcp_create_request ( &dhcppkt, netdev, DHCPDISCOVER,
|
if ( ( rc = dhcp_create_request ( &dhcppkt, netdev, DHCPDISCOVER,
|
||||||
ciaddr, data, max_len ) ) != 0 ) {
|
dhcp_last_xid, ciaddr, data,
|
||||||
|
max_len ) ) != 0 ) {
|
||||||
DBG ( "Could not create DHCPDISCOVER: %s\n",
|
DBG ( "Could not create DHCPDISCOVER: %s\n",
|
||||||
strerror ( rc ) );
|
strerror ( rc ) );
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -139,7 +140,8 @@ int create_fakedhcpack ( struct net_device *netdev,
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Create base DHCPACK packet */
|
/* Create base DHCPACK packet */
|
||||||
if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK, NULL, 0,
|
if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK,
|
||||||
|
dhcp_last_xid, NULL, 0,
|
||||||
data, max_len ) ) != 0 ) {
|
data, max_len ) ) != 0 ) {
|
||||||
DBG ( "Could not create DHCPACK: %s\n", strerror ( rc ) );
|
DBG ( "Could not create DHCPACK: %s\n", strerror ( rc ) );
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -190,7 +192,8 @@ int create_fakepxebsack ( struct net_device *netdev,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create base DHCPACK packet */
|
/* Create base DHCPACK packet */
|
||||||
if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK, NULL, 0,
|
if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK,
|
||||||
|
dhcp_last_xid, NULL, 0,
|
||||||
data, max_len ) ) != 0 ) {
|
data, max_len ) ) != 0 ) {
|
||||||
DBG ( "Could not create PXE BS ACK: %s\n",
|
DBG ( "Could not create PXE BS ACK: %s\n",
|
||||||
strerror ( rc ) );
|
strerror ( rc ) );
|
||||||
|
|
|
@ -116,6 +116,14 @@ struct setting use_cached_setting __setting ( SETTING_MISC ) = {
|
||||||
.type = &setting_type_uint8,
|
.type = &setting_type_uint8,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Most recent DHCP transaction ID
|
||||||
|
*
|
||||||
|
* This is exposed for use by the fakedhcp code when reconstructing
|
||||||
|
* DHCP packets for PXE NBPs.
|
||||||
|
*/
|
||||||
|
uint32_t dhcp_last_xid;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name a DHCP packet type
|
* Name a DHCP packet type
|
||||||
*
|
*
|
||||||
|
@ -137,23 +145,6 @@ static inline const char * dhcp_msgtype_name ( unsigned int msgtype ) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate DHCP transaction ID for a network device
|
|
||||||
*
|
|
||||||
* @v netdev Network device
|
|
||||||
* @ret xid DHCP XID
|
|
||||||
*
|
|
||||||
* Extract the least significant bits of the hardware address for use
|
|
||||||
* as the transaction ID.
|
|
||||||
*/
|
|
||||||
static uint32_t dhcp_xid ( struct net_device *netdev ) {
|
|
||||||
uint32_t xid;
|
|
||||||
|
|
||||||
memcpy ( &xid, ( netdev->ll_addr + netdev->ll_protocol->ll_addr_len
|
|
||||||
- sizeof ( xid ) ), sizeof ( xid ) );
|
|
||||||
return xid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
*
|
*
|
||||||
* DHCP session
|
* DHCP session
|
||||||
|
@ -219,6 +210,8 @@ struct dhcp_session {
|
||||||
struct sockaddr_in local;
|
struct sockaddr_in local;
|
||||||
/** State of the session */
|
/** State of the session */
|
||||||
struct dhcp_session_state *state;
|
struct dhcp_session_state *state;
|
||||||
|
/** Transaction ID (in network-endian order) */
|
||||||
|
uint32_t xid;
|
||||||
|
|
||||||
/** Offered IP address */
|
/** Offered IP address */
|
||||||
struct in_addr offer;
|
struct in_addr offer;
|
||||||
|
@ -916,6 +909,7 @@ unsigned int dhcp_chaddr ( struct net_device *netdev, void *chaddr,
|
||||||
* @v dhcppkt DHCP packet structure to fill in
|
* @v dhcppkt DHCP packet structure to fill in
|
||||||
* @v netdev Network device
|
* @v netdev Network device
|
||||||
* @v msgtype DHCP message type
|
* @v msgtype DHCP message type
|
||||||
|
* @v xid Transaction ID (in network-endian order)
|
||||||
* @v options Initial options to include (or NULL)
|
* @v options Initial options to include (or NULL)
|
||||||
* @v options_len Length of initial options
|
* @v options_len Length of initial options
|
||||||
* @v data Buffer for DHCP packet
|
* @v data Buffer for DHCP packet
|
||||||
|
@ -927,7 +921,7 @@ unsigned int dhcp_chaddr ( struct net_device *netdev, void *chaddr,
|
||||||
*/
|
*/
|
||||||
int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
|
int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
|
||||||
struct net_device *netdev, uint8_t msgtype,
|
struct net_device *netdev, uint8_t msgtype,
|
||||||
const void *options, size_t options_len,
|
uint32_t xid, const void *options, size_t options_len,
|
||||||
void *data, size_t max_len ) {
|
void *data, size_t max_len ) {
|
||||||
struct dhcphdr *dhcphdr = data;
|
struct dhcphdr *dhcphdr = data;
|
||||||
int rc;
|
int rc;
|
||||||
|
@ -938,7 +932,7 @@ int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
|
||||||
|
|
||||||
/* Initialise DHCP packet content */
|
/* Initialise DHCP packet content */
|
||||||
memset ( dhcphdr, 0, max_len );
|
memset ( dhcphdr, 0, max_len );
|
||||||
dhcphdr->xid = dhcp_xid ( netdev );
|
dhcphdr->xid = xid;
|
||||||
dhcphdr->magic = htonl ( DHCP_MAGIC_COOKIE );
|
dhcphdr->magic = htonl ( DHCP_MAGIC_COOKIE );
|
||||||
dhcphdr->htype = ntohs ( netdev->ll_protocol->ll_proto );
|
dhcphdr->htype = ntohs ( netdev->ll_protocol->ll_proto );
|
||||||
dhcphdr->op = dhcp_op[msgtype];
|
dhcphdr->op = dhcp_op[msgtype];
|
||||||
|
@ -964,6 +958,7 @@ int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
|
||||||
* @v dhcppkt DHCP packet structure to fill in
|
* @v dhcppkt DHCP packet structure to fill in
|
||||||
* @v netdev Network device
|
* @v netdev Network device
|
||||||
* @v msgtype DHCP message type
|
* @v msgtype DHCP message type
|
||||||
|
* @v xid Transaction ID (in network-endian order)
|
||||||
* @v ciaddr Client IP address
|
* @v ciaddr Client IP address
|
||||||
* @v data Buffer for DHCP packet
|
* @v data Buffer for DHCP packet
|
||||||
* @v max_len Size of DHCP packet buffer
|
* @v max_len Size of DHCP packet buffer
|
||||||
|
@ -974,7 +969,8 @@ int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
|
||||||
*/
|
*/
|
||||||
int dhcp_create_request ( struct dhcp_packet *dhcppkt,
|
int dhcp_create_request ( struct dhcp_packet *dhcppkt,
|
||||||
struct net_device *netdev, unsigned int msgtype,
|
struct net_device *netdev, unsigned int msgtype,
|
||||||
struct in_addr ciaddr, void *data, size_t max_len ) {
|
uint32_t xid, struct in_addr ciaddr,
|
||||||
|
void *data, size_t max_len ) {
|
||||||
struct dhcp_netdev_desc dhcp_desc;
|
struct dhcp_netdev_desc dhcp_desc;
|
||||||
struct dhcp_client_id client_id;
|
struct dhcp_client_id client_id;
|
||||||
struct dhcp_client_uuid client_uuid;
|
struct dhcp_client_uuid client_uuid;
|
||||||
|
@ -985,7 +981,7 @@ int dhcp_create_request ( struct dhcp_packet *dhcppkt,
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Create DHCP packet */
|
/* Create DHCP packet */
|
||||||
if ( ( rc = dhcp_create_packet ( dhcppkt, netdev, msgtype,
|
if ( ( rc = dhcp_create_packet ( dhcppkt, netdev, msgtype, xid,
|
||||||
dhcp_request_options_data,
|
dhcp_request_options_data,
|
||||||
sizeof ( dhcp_request_options_data ),
|
sizeof ( dhcp_request_options_data ),
|
||||||
data, max_len ) ) != 0 ) {
|
data, max_len ) ) != 0 ) {
|
||||||
|
@ -1099,7 +1095,8 @@ static int dhcp_tx ( struct dhcp_session *dhcp ) {
|
||||||
|
|
||||||
/* Create basic DHCP packet in temporary buffer */
|
/* Create basic DHCP packet in temporary buffer */
|
||||||
if ( ( rc = dhcp_create_request ( &dhcppkt, dhcp->netdev, msgtype,
|
if ( ( rc = dhcp_create_request ( &dhcppkt, dhcp->netdev, msgtype,
|
||||||
dhcp->local.sin_addr, iobuf->data,
|
dhcp->xid, dhcp->local.sin_addr,
|
||||||
|
iobuf->data,
|
||||||
iob_tailroom ( iobuf ) ) ) != 0 ) {
|
iob_tailroom ( iobuf ) ) ) != 0 ) {
|
||||||
DBGC ( dhcp, "DHCP %p could not construct DHCP request: %s\n",
|
DBGC ( dhcp, "DHCP %p could not construct DHCP request: %s\n",
|
||||||
dhcp, strerror ( rc ) );
|
dhcp, strerror ( rc ) );
|
||||||
|
@ -1187,7 +1184,7 @@ static int dhcp_deliver ( struct dhcp_session *dhcp,
|
||||||
&server_id, sizeof ( server_id ) );
|
&server_id, sizeof ( server_id ) );
|
||||||
|
|
||||||
/* Check for matching transaction ID */
|
/* Check for matching transaction ID */
|
||||||
if ( dhcphdr->xid != dhcp_xid ( dhcp->netdev ) ) {
|
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 "
|
||||||
"ID\n", dhcp, dhcp_msgtype_name ( msgtype ),
|
"ID\n", dhcp, dhcp_msgtype_name ( msgtype ),
|
||||||
inet_ntoa ( peer->sin_addr ),
|
inet_ntoa ( peer->sin_addr ),
|
||||||
|
@ -1311,6 +1308,10 @@ int start_dhcp ( struct interface *job, struct net_device *netdev ) {
|
||||||
dhcp->netdev = netdev_get ( netdev );
|
dhcp->netdev = netdev_get ( netdev );
|
||||||
dhcp->local.sin_family = AF_INET;
|
dhcp->local.sin_family = AF_INET;
|
||||||
dhcp->local.sin_port = htons ( BOOTPC_PORT );
|
dhcp->local.sin_port = htons ( BOOTPC_PORT );
|
||||||
|
dhcp->xid = random();
|
||||||
|
|
||||||
|
/* Store DHCP transaction ID for fakedhcp code */
|
||||||
|
dhcp_last_xid = dhcp->xid;
|
||||||
|
|
||||||
/* Instantiate child objects and attach to our interfaces */
|
/* Instantiate child objects and attach to our interfaces */
|
||||||
if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM, &dhcp_peer,
|
if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM, &dhcp_peer,
|
||||||
|
|
Loading…
Reference in New Issue