26 |
#include "options.h" |
#include "options.h" |
27 |
|
|
28 |
|
|
29 |
/* send a packet to giaddr using the kernel ip stack */ |
/* send a packet to gateway_nip using the kernel ip stack */ |
30 |
static int send_packet_to_relay(struct dhcpMessage *payload) |
static int send_packet_to_relay(struct dhcp_packet *dhcp_pkt) |
31 |
{ |
{ |
32 |
DEBUG("Forwarding packet to relay"); |
log1("Forwarding packet to relay"); |
33 |
|
|
34 |
return udhcp_send_kernel_packet(payload, server_config.server, SERVER_PORT, |
return udhcp_send_kernel_packet(dhcp_pkt, |
35 |
payload->giaddr, SERVER_PORT); |
server_config.server_nip, SERVER_PORT, |
36 |
|
dhcp_pkt->gateway_nip, SERVER_PORT); |
37 |
} |
} |
38 |
|
|
39 |
|
|
40 |
/* send a packet to a specific arp address and ip address by creating our own ip packet */ |
/* send a packet to a specific mac address and ip address by creating our own ip packet */ |
41 |
static int send_packet_to_client(struct dhcpMessage *payload, int force_broadcast) |
static int send_packet_to_client(struct dhcp_packet *dhcp_pkt, int force_broadcast) |
42 |
{ |
{ |
43 |
const uint8_t *chaddr; |
const uint8_t *chaddr; |
44 |
uint32_t ciaddr; |
uint32_t ciaddr; |
45 |
|
|
46 |
if (force_broadcast) { |
// Was: |
47 |
DEBUG("broadcasting packet to client (NAK)"); |
//if (force_broadcast) { /* broadcast */ } |
48 |
ciaddr = INADDR_BROADCAST; |
//else if (dhcp_pkt->ciaddr) { /* unicast to dhcp_pkt->ciaddr */ } |
49 |
chaddr = MAC_BCAST_ADDR; |
//else if (dhcp_pkt->flags & htons(BROADCAST_FLAG)) { /* broadcast */ } |
50 |
} else if (payload->ciaddr) { |
//else { /* unicast to dhcp_pkt->yiaddr */ } |
51 |
DEBUG("unicasting packet to client ciaddr"); |
// But this is wrong: yiaddr is _our_ idea what client's IP is |
52 |
ciaddr = payload->ciaddr; |
// (for example, from lease file). Client may not know that, |
53 |
chaddr = payload->chaddr; |
// and may not have UDP socket listening on that IP! |
54 |
} else if (payload->flags & htons(BROADCAST_FLAG)) { |
// We should never unicast to dhcp_pkt->yiaddr! |
55 |
DEBUG("broadcasting packet to client (requested)"); |
// dhcp_pkt->ciaddr, OTOH, comes from client's request packet, |
56 |
|
// and can be used. |
57 |
|
|
58 |
|
if (force_broadcast |
59 |
|
|| (dhcp_pkt->flags & htons(BROADCAST_FLAG)) |
60 |
|
|| !dhcp_pkt->ciaddr |
61 |
|
) { |
62 |
|
log1("Broadcasting packet to client"); |
63 |
ciaddr = INADDR_BROADCAST; |
ciaddr = INADDR_BROADCAST; |
64 |
chaddr = MAC_BCAST_ADDR; |
chaddr = MAC_BCAST_ADDR; |
65 |
} else { |
} else { |
66 |
DEBUG("unicasting packet to client yiaddr"); |
log1("Unicasting packet to client ciaddr"); |
67 |
ciaddr = payload->yiaddr; |
ciaddr = dhcp_pkt->ciaddr; |
68 |
chaddr = payload->chaddr; |
chaddr = dhcp_pkt->chaddr; |
69 |
} |
} |
70 |
return udhcp_send_raw_packet(payload, |
|
71 |
/*src*/ server_config.server, SERVER_PORT, |
return udhcp_send_raw_packet(dhcp_pkt, |
72 |
|
/*src*/ server_config.server_nip, SERVER_PORT, |
73 |
/*dst*/ ciaddr, CLIENT_PORT, chaddr, |
/*dst*/ ciaddr, CLIENT_PORT, chaddr, |
74 |
server_config.ifindex); |
server_config.ifindex); |
75 |
} |
} |
76 |
|
|
77 |
|
|
78 |
/* send a dhcp packet, if force broadcast is set, the packet will be broadcast to the client */ |
/* send a dhcp packet, if force broadcast is set, the packet will be broadcast to the client */ |
79 |
static int send_packet(struct dhcpMessage *payload, int force_broadcast) |
static int send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast) |
80 |
{ |
{ |
81 |
if (payload->giaddr) |
if (dhcp_pkt->gateway_nip) |
82 |
return send_packet_to_relay(payload); |
return send_packet_to_relay(dhcp_pkt); |
83 |
return send_packet_to_client(payload, force_broadcast); |
return send_packet_to_client(dhcp_pkt, force_broadcast); |
84 |
} |
} |
85 |
|
|
86 |
|
|
87 |
static void init_packet(struct dhcpMessage *packet, struct dhcpMessage *oldpacket, char type) |
static void init_packet(struct dhcp_packet *packet, struct dhcp_packet *oldpacket, char type) |
88 |
{ |
{ |
89 |
udhcp_init_header(packet, type); |
udhcp_init_header(packet, type); |
90 |
packet->xid = oldpacket->xid; |
packet->xid = oldpacket->xid; |
91 |
memcpy(packet->chaddr, oldpacket->chaddr, 16); |
memcpy(packet->chaddr, oldpacket->chaddr, sizeof(oldpacket->chaddr)); |
92 |
packet->flags = oldpacket->flags; |
packet->flags = oldpacket->flags; |
93 |
packet->giaddr = oldpacket->giaddr; |
packet->gateway_nip = oldpacket->gateway_nip; |
94 |
packet->ciaddr = oldpacket->ciaddr; |
packet->ciaddr = oldpacket->ciaddr; |
95 |
add_simple_option(packet->options, DHCP_SERVER_ID, server_config.server); |
add_simple_option(packet->options, DHCP_SERVER_ID, server_config.server_nip); |
96 |
} |
} |
97 |
|
|
98 |
|
|
99 |
/* add in the bootp options */ |
/* add in the bootp options */ |
100 |
static void add_bootp_options(struct dhcpMessage *packet) |
static void add_bootp_options(struct dhcp_packet *packet) |
101 |
{ |
{ |
102 |
packet->siaddr = server_config.siaddr; |
packet->siaddr_nip = server_config.siaddr_nip; |
103 |
if (server_config.sname) |
if (server_config.sname) |
104 |
strncpy((char*)packet->sname, server_config.sname, sizeof(packet->sname) - 1); |
strncpy((char*)packet->sname, server_config.sname, sizeof(packet->sname) - 1); |
105 |
if (server_config.boot_file) |
if (server_config.boot_file) |
107 |
} |
} |
108 |
|
|
109 |
|
|
110 |
|
static uint32_t select_lease_time(struct dhcp_packet *packet) |
111 |
|
{ |
112 |
|
uint32_t lease_time_sec = server_config.max_lease_sec; |
113 |
|
uint8_t *lease_time_opt = get_option(packet, DHCP_LEASE_TIME); |
114 |
|
if (lease_time_opt) { |
115 |
|
move_from_unaligned32(lease_time_sec, lease_time_opt); |
116 |
|
lease_time_sec = ntohl(lease_time_sec); |
117 |
|
if (lease_time_sec > server_config.max_lease_sec) |
118 |
|
lease_time_sec = server_config.max_lease_sec; |
119 |
|
if (lease_time_sec < server_config.min_lease_sec) |
120 |
|
lease_time_sec = server_config.min_lease_sec; |
121 |
|
} |
122 |
|
return lease_time_sec; |
123 |
|
} |
124 |
|
|
125 |
|
|
126 |
/* send a DHCP OFFER to a DHCP DISCOVER */ |
/* send a DHCP OFFER to a DHCP DISCOVER */ |
127 |
int FAST_FUNC send_offer(struct dhcpMessage *oldpacket) |
int FAST_FUNC send_offer(struct dhcp_packet *oldpacket) |
128 |
{ |
{ |
129 |
struct dhcpMessage packet; |
struct dhcp_packet packet; |
130 |
struct dhcpOfferedAddr *lease = NULL; |
uint32_t req_nip; |
131 |
uint32_t req_align, lease_time_align = server_config.lease; |
uint32_t lease_time_sec = server_config.max_lease_sec; |
132 |
uint8_t *req, *lease_time; |
uint32_t static_lease_ip; |
133 |
|
uint8_t *req_ip_opt; |
134 |
|
const char *p_host_name; |
135 |
struct option_set *curr; |
struct option_set *curr; |
136 |
struct in_addr addr; |
struct in_addr addr; |
137 |
|
|
|
uint32_t static_lease_ip; |
|
|
|
|
138 |
init_packet(&packet, oldpacket, DHCPOFFER); |
init_packet(&packet, oldpacket, DHCPOFFER); |
139 |
|
|
140 |
static_lease_ip = getIpByMac(server_config.static_leases, oldpacket->chaddr); |
static_lease_ip = get_static_nip_by_mac(server_config.static_leases, oldpacket->chaddr); |
141 |
|
|
142 |
/* ADDME: if static, short circuit */ |
/* ADDME: if static, short circuit */ |
143 |
if (!static_lease_ip) { |
if (!static_lease_ip) { |
144 |
/* the client is in our lease/offered table */ |
struct dyn_lease *lease; |
145 |
lease = find_lease_by_chaddr(oldpacket->chaddr); |
|
146 |
|
lease = find_lease_by_mac(oldpacket->chaddr); |
147 |
|
/* The client is in our lease/offered table */ |
148 |
if (lease) { |
if (lease) { |
149 |
if (!lease_expired(lease)) |
signed_leasetime_t tmp = lease->expires - time(NULL); |
150 |
lease_time_align = lease->expires - time(0); |
if (tmp >= 0) |
151 |
packet.yiaddr = lease->yiaddr; |
lease_time_sec = tmp; |
152 |
/* Or the client has a requested ip */ |
packet.yiaddr = lease->lease_nip; |
153 |
} else if ((req = get_option(oldpacket, DHCP_REQUESTED_IP)) |
} |
154 |
/* Don't look here (ugly hackish thing to do) */ |
/* Or the client has requested an IP */ |
155 |
&& memcpy(&req_align, req, 4) |
else if ((req_ip_opt = get_option(oldpacket, DHCP_REQUESTED_IP)) != NULL |
156 |
/* and the ip is in the lease range */ |
/* (read IP) */ |
157 |
&& ntohl(req_align) >= server_config.start_ip |
&& (move_from_unaligned32(req_nip, req_ip_opt), 1) |
158 |
&& ntohl(req_align) <= server_config.end_ip |
/* and the IP is in the lease range */ |
159 |
&& !static_lease_ip /* Check that its not a static lease */ |
&& ntohl(req_nip) >= server_config.start_ip |
160 |
|
&& ntohl(req_nip) <= server_config.end_ip |
161 |
/* and is not already taken/offered */ |
/* and is not already taken/offered */ |
162 |
&& (!(lease = find_lease_by_yiaddr(req_align)) |
&& (!(lease = find_lease_by_nip(req_nip)) |
163 |
/* or its taken, but expired */ /* ADDME: or maybe in here */ |
/* or its taken, but expired */ |
164 |
|| lease_expired(lease)) |
|| is_expired_lease(lease)) |
165 |
) { |
) { |
166 |
packet.yiaddr = req_align; /* FIXME: oh my, is there a host using this IP? */ |
packet.yiaddr = req_nip; |
167 |
/* otherwise, find a free IP */ |
} |
168 |
} else { |
/* Otherwise, find a free IP */ |
169 |
/* Is it a static lease? (No, because find_address skips static lease) */ |
else { |
170 |
packet.yiaddr = find_address(0); |
packet.yiaddr = find_free_or_expired_nip(oldpacket->chaddr); |
|
/* try for an expired lease */ |
|
|
if (!packet.yiaddr) |
|
|
packet.yiaddr = find_address(1); |
|
171 |
} |
} |
172 |
|
|
173 |
if (!packet.yiaddr) { |
if (!packet.yiaddr) { |
174 |
bb_error_msg("no IP addresses to give - OFFER abandoned"); |
bb_error_msg("no IP addresses to give - OFFER abandoned"); |
175 |
return -1; |
return -1; |
176 |
} |
} |
177 |
if (!add_lease(packet.chaddr, packet.yiaddr, server_config.offer_time)) { |
p_host_name = (const char*) get_option(oldpacket, DHCP_HOST_NAME); |
178 |
|
if (add_lease(packet.chaddr, packet.yiaddr, |
179 |
|
server_config.offer_time, |
180 |
|
p_host_name, |
181 |
|
p_host_name ? (unsigned char)p_host_name[OPT_LEN - OPT_DATA] : 0 |
182 |
|
) == 0 |
183 |
|
) { |
184 |
bb_error_msg("lease pool is full - OFFER abandoned"); |
bb_error_msg("lease pool is full - OFFER abandoned"); |
185 |
return -1; |
return -1; |
186 |
} |
} |
187 |
lease_time = get_option(oldpacket, DHCP_LEASE_TIME); |
lease_time_sec = select_lease_time(oldpacket); |
|
if (lease_time) { |
|
|
memcpy(&lease_time_align, lease_time, 4); |
|
|
lease_time_align = ntohl(lease_time_align); |
|
|
if (lease_time_align > server_config.lease) |
|
|
lease_time_align = server_config.lease; |
|
|
} |
|
|
|
|
|
/* Make sure we aren't just using the lease time from the previous offer */ |
|
|
if (lease_time_align < server_config.min_lease) |
|
|
lease_time_align = server_config.lease; |
|
|
/* ADDME: end of short circuit */ |
|
188 |
} else { |
} else { |
189 |
/* It is a static lease... use it */ |
/* It is a static lease... use it */ |
190 |
packet.yiaddr = static_lease_ip; |
packet.yiaddr = static_lease_ip; |
191 |
} |
} |
192 |
|
|
193 |
add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_align)); |
add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_sec)); |
194 |
|
|
195 |
curr = server_config.options; |
curr = server_config.options; |
196 |
while (curr) { |
while (curr) { |
207 |
} |
} |
208 |
|
|
209 |
|
|
210 |
int FAST_FUNC send_NAK(struct dhcpMessage *oldpacket) |
int FAST_FUNC send_NAK(struct dhcp_packet *oldpacket) |
211 |
{ |
{ |
212 |
struct dhcpMessage packet; |
struct dhcp_packet packet; |
213 |
|
|
214 |
init_packet(&packet, oldpacket, DHCPNAK); |
init_packet(&packet, oldpacket, DHCPNAK); |
215 |
|
|
216 |
DEBUG("Sending NAK"); |
log1("Sending NAK"); |
217 |
return send_packet(&packet, 1); |
return send_packet(&packet, 1); |
218 |
} |
} |
219 |
|
|
220 |
|
|
221 |
int FAST_FUNC send_ACK(struct dhcpMessage *oldpacket, uint32_t yiaddr) |
int FAST_FUNC send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr) |
222 |
{ |
{ |
223 |
struct dhcpMessage packet; |
struct dhcp_packet packet; |
224 |
struct option_set *curr; |
struct option_set *curr; |
225 |
uint8_t *lease_time; |
uint32_t lease_time_sec; |
|
uint32_t lease_time_align = server_config.lease; |
|
226 |
struct in_addr addr; |
struct in_addr addr; |
227 |
|
const char *p_host_name; |
228 |
|
|
229 |
init_packet(&packet, oldpacket, DHCPACK); |
init_packet(&packet, oldpacket, DHCPACK); |
230 |
packet.yiaddr = yiaddr; |
packet.yiaddr = yiaddr; |
231 |
|
|
232 |
lease_time = get_option(oldpacket, DHCP_LEASE_TIME); |
lease_time_sec = select_lease_time(oldpacket); |
|
if (lease_time) { |
|
|
memcpy(&lease_time_align, lease_time, 4); |
|
|
lease_time_align = ntohl(lease_time_align); |
|
|
if (lease_time_align > server_config.lease) |
|
|
lease_time_align = server_config.lease; |
|
|
else if (lease_time_align < server_config.min_lease) |
|
|
lease_time_align = server_config.lease; |
|
|
} |
|
233 |
|
|
234 |
add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_align)); |
add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_sec)); |
235 |
|
|
236 |
curr = server_config.options; |
curr = server_config.options; |
237 |
while (curr) { |
while (curr) { |
248 |
if (send_packet(&packet, 0) < 0) |
if (send_packet(&packet, 0) < 0) |
249 |
return -1; |
return -1; |
250 |
|
|
251 |
add_lease(packet.chaddr, packet.yiaddr, lease_time_align); |
p_host_name = (const char*) get_option(oldpacket, DHCP_HOST_NAME); |
252 |
|
add_lease(packet.chaddr, packet.yiaddr, |
253 |
|
lease_time_sec, |
254 |
|
p_host_name, |
255 |
|
p_host_name ? (unsigned char)p_host_name[OPT_LEN - OPT_DATA] : 0 |
256 |
|
); |
257 |
if (ENABLE_FEATURE_UDHCPD_WRITE_LEASES_EARLY) { |
if (ENABLE_FEATURE_UDHCPD_WRITE_LEASES_EARLY) { |
258 |
/* rewrite the file with leases at every new acceptance */ |
/* rewrite the file with leases at every new acceptance */ |
259 |
write_leases(); |
write_leases(); |
263 |
} |
} |
264 |
|
|
265 |
|
|
266 |
int FAST_FUNC send_inform(struct dhcpMessage *oldpacket) |
int FAST_FUNC send_inform(struct dhcp_packet *oldpacket) |
267 |
{ |
{ |
268 |
struct dhcpMessage packet; |
struct dhcp_packet packet; |
269 |
struct option_set *curr; |
struct option_set *curr; |
270 |
|
|
271 |
init_packet(&packet, oldpacket, DHCPACK); |
init_packet(&packet, oldpacket, DHCPACK); |