1/* serverpacket.c 2 * 3 * Constuct and send DHCP server packets 4 * 5 * Russ Dill <Russ.Dill@asu.edu> July 2001 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 */ 21 22#include <sys/socket.h> 23#include <netinet/in.h> 24#include <arpa/inet.h> 25#include <string.h> 26#include <time.h> 27 28#include "packet.h" 29#include "debug.h" 30#include "dhcpd.h" 31#include "options.h" 32#include "leases.h" 33 34/* send a packet to giaddr using the kernel ip stack */ 35static int send_packet_to_relay(struct dhcpMessage *payload) 36{ 37 DEBUG(LOG_INFO, "Forwarding packet to relay"); 38 39 return kernel_packet(payload, server_config.server, SERVER_PORT, 40 payload->giaddr, SERVER_PORT); 41} 42 43 44/* send a packet to a specific arp address and ip address by creating our own ip packet */ 45static int send_packet_to_client(struct dhcpMessage *payload, int force_broadcast) 46{ 47 unsigned char *chaddr; 48 u_int32_t ciaddr; 49 50 if (force_broadcast) { 51 DEBUG(LOG_INFO, "broadcasting packet to client (NAK)"); 52 ciaddr = INADDR_BROADCAST; 53 chaddr = MAC_BCAST_ADDR; 54 } else if (payload->ciaddr) { 55 DEBUG(LOG_INFO, "unicasting packet to client ciaddr"); 56 ciaddr = payload->ciaddr; 57 chaddr = payload->chaddr; 58 } else if (ntohs(payload->flags) & BROADCAST_FLAG) { 59 DEBUG(LOG_INFO, "broadcasting packet to client (requested)"); 60 ciaddr = INADDR_BROADCAST; 61 chaddr = MAC_BCAST_ADDR; 62 } else { 63 DEBUG(LOG_INFO, "unicasting packet to client yiaddr"); 64 ciaddr = payload->yiaddr; 65 chaddr = payload->chaddr; 66 } 67 return raw_packet(payload, server_config.server, SERVER_PORT, 68 ciaddr, CLIENT_PORT, chaddr, server_config.ifindex); 69} 70 71 72/* send a dhcp packet, if force broadcast is set, the packet will be broadcast to the client */ 73static int send_packet(struct dhcpMessage *payload, int force_broadcast) 74{ 75 int ret; 76 77 if (payload->giaddr) 78 ret = send_packet_to_relay(payload); 79 else ret = send_packet_to_client(payload, force_broadcast); 80 return ret; 81} 82 83 84static void init_packet(struct dhcpMessage *packet, struct dhcpMessage *oldpacket, char type) 85{ 86 init_header(packet, type); 87 packet->xid = oldpacket->xid; 88 memcpy(packet->chaddr, oldpacket->chaddr, 16); 89 packet->flags = oldpacket->flags; 90 packet->giaddr = oldpacket->giaddr; 91 packet->ciaddr = oldpacket->ciaddr; 92 add_simple_option(packet->options, DHCP_SERVER_ID, server_config.server); 93} 94 95 96/* add in the bootp options */ 97static void add_bootp_options(struct dhcpMessage *packet) 98{ 99 packet->siaddr = server_config.siaddr; 100 if (server_config.sname) 101 strncpy(packet->sname, server_config.sname, sizeof(packet->sname) - 1); 102 if (server_config.boot_file) 103 strncpy(packet->file, server_config.boot_file, sizeof(packet->file) - 1); 104} 105 106 107/* send a DHCP OFFER to a DHCP DISCOVER */ 108int sendOffer(struct dhcpMessage *oldpacket) 109{ 110 struct dhcpMessage packet; 111 struct dhcpOfferedAddr *lease = NULL; 112 u_int32_t req_align, lease_time_align = server_config.lease; 113 unsigned char *req, *lease_time; 114 struct option_set *curr; 115 struct in_addr addr; 116 unsigned char mac[6]; 117 u_int32_t reserved_ip; 118 119 memcpy(mac, oldpacket->chaddr, 6); 120 121 init_packet(&packet, oldpacket, DHCPOFFER); 122 123 /* ADDME: if static, short circuit */ 124 /* the client is in our lease/offered table */ 125 if ((lease = find_lease_by_chaddr(oldpacket->chaddr)) && 126 127 /* Make sure the IP is not already used on network */ 128 !check_ip(lease->yiaddr)) { 129 130 if (!lease_expired(lease)) 131 lease_time_align = lease->expires - time(0); 132 packet.yiaddr = lease->yiaddr; 133 134 /* Find a reserved ip for this MAC */ 135 } else if ( (reserved_ip = find_reserved_ip(mac)) != 0) { 136 packet.yiaddr = htonl(reserved_ip); 137 138 /* Or the client has a requested ip */ 139 } else if ((req = get_option(oldpacket, DHCP_REQUESTED_IP)) && 140 141 /* Don't look here (ugly hackish thing to do) */ 142 memcpy(&req_align, req, 4) && 143 144 /* check if the requested ip has been reserved */ 145 check_reserved_ip(req_align, mac) && 146 147 /* and the ip is in the lease range */ 148 ntohl(req_align) >= ntohl(server_config.start) && 149 ntohl(req_align) <= ntohl(server_config.end) && 150 151 /* Check that this request ip is not on network */ 152 //!check_ip(ntohl(req_align)) && 153 /* the input parameter of check_ip() should be network order */ 154 !check_ip(req_align) && /* Foxconn modified by Max Ding, 07/07/2011 @TD #42 of WNR3500Lv2 */ 155 156 /* and its not already taken/offered */ /* ADDME: check that its not a static lease */ 157 ((!(lease = find_lease_by_yiaddr(req_align)) || 158 159 /* or its taken, but expired */ /* ADDME: or maybe in here */ 160 lease_expired(lease)))) { 161 packet.yiaddr = req_align; 162 163 /* otherwise, find a free IP */ /*ADDME: is it a static lease? */ 164 } else { 165 packet.yiaddr = find_address2(0, mac); 166 167 /* try for an expired lease */ 168 if (!packet.yiaddr) packet.yiaddr = find_address2(1, mac); 169 } 170 171 if(!packet.yiaddr) { 172 LOG(LOG_WARNING, "no IP addresses to give -- OFFER abandoned"); 173 return -1; 174 } 175 176 if (!add_lease(packet.chaddr, packet.yiaddr, server_config.offer_time)) { 177 LOG(LOG_WARNING, "lease pool is full -- OFFER abandoned"); 178 return -1; 179 } 180 181 if ((lease_time = get_option(oldpacket, DHCP_LEASE_TIME))) { 182 memcpy(&lease_time_align, lease_time, 4); 183 lease_time_align = ntohl(lease_time_align); 184 if (lease_time_align > server_config.lease) 185 lease_time_align = server_config.lease; 186 } 187 188 /* Make sure we aren't just using the lease time from the previous offer */ 189 if (lease_time_align < server_config.min_lease) 190 lease_time_align = server_config.lease; 191 /* ADDME: end of short circuit */ 192 add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_align)); 193 194 curr = server_config.options; 195 while (curr) { 196 if (curr->data[OPT_CODE] != DHCP_LEASE_TIME) 197 add_option_string(packet.options, curr->data); 198 curr = curr->next; 199 } 200 201 add_bootp_options(&packet); 202 203 addr.s_addr = packet.yiaddr; 204 LOG(LOG_INFO, "sending OFFER of %s", inet_ntoa(addr)); 205 return send_packet(&packet, 0); 206} 207 208 209int sendNAK(struct dhcpMessage *oldpacket) 210{ 211 struct dhcpMessage packet; 212 213 init_packet(&packet, oldpacket, DHCPNAK); 214 215 DEBUG(LOG_INFO, "sending NAK"); 216 return send_packet(&packet, 1); 217} 218 219 220int sendACK(struct dhcpMessage *oldpacket, u_int32_t yiaddr) 221{ 222 struct dhcpMessage packet; 223 struct option_set *curr; 224 unsigned char *lease_time; 225 226 //Foxconn added start Bob Guo 11/15/2006 227 FILE *fp; 228 unsigned char *client_mac, *client_ip; 229 char logBuffer[96]; 230 //Foxconn added end Bob Guo 11/15/2006 231 232 u_int32_t lease_time_align = server_config.lease; 233 struct in_addr addr; 234 235 init_packet(&packet, oldpacket, DHCPACK); 236 packet.yiaddr = yiaddr; 237 238 if ((lease_time = get_option(oldpacket, DHCP_LEASE_TIME))) { 239 memcpy(&lease_time_align, lease_time, 4); 240 lease_time_align = ntohl(lease_time_align); 241 if (lease_time_align > server_config.lease) 242 lease_time_align = server_config.lease; 243 else if (lease_time_align < server_config.min_lease) 244 lease_time_align = server_config.lease; 245 } 246 247 add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_align)); 248 249 curr = server_config.options; 250 while (curr) { 251 if (curr->data[OPT_CODE] != DHCP_LEASE_TIME) 252 add_option_string(packet.options, curr->data); 253 curr = curr->next; 254 } 255 256 add_bootp_options(&packet); 257 258 addr.s_addr = packet.yiaddr; 259 LOG(LOG_INFO, "sending ACK to %s", inet_ntoa(addr)); 260 261 if (send_packet(&packet, 0) < 0) 262 return -1; 263 264 add_lease(packet.chaddr, packet.yiaddr, lease_time_align); 265 //Foxconn added start Bob Guo 11/15/2006 266 client_mac = (unsigned char *)packet.chaddr; 267 client_ip = (unsigned char *)&packet.yiaddr; 268 sprintf(logBuffer, "[DHCP IP: (%d.%d.%d.%d)] to MAC address %02X:%02X:%02X:%02X:%02X:%02X,", 269 *client_ip, *(client_ip+1), *(client_ip+2), *(client_ip+3), 270 *client_mac, *(client_mac+1), *(client_mac+2), *(client_mac+3), *(client_mac+4), *(client_mac+5)); 271 if ((fp = fopen("/dev/aglog", "r+")) != NULL) 272 { 273 fwrite(logBuffer, sizeof(char), strlen(logBuffer)+1, fp); 274 fclose(fp); 275 } 276 //Foxconn added end Bob Guo 11/15/2006 277 278 return 0; 279} 280 281 282int send_inform(struct dhcpMessage *oldpacket) 283{ 284 struct dhcpMessage packet; 285 struct option_set *curr; 286 287 init_packet(&packet, oldpacket, DHCPACK); 288 289 curr = server_config.options; 290 while (curr) { 291 if (curr->data[OPT_CODE] != DHCP_LEASE_TIME) 292 add_option_string(packet.options, curr->data); 293 curr = curr->next; 294 } 295 296 add_bootp_options(&packet); 297 298 return send_packet(&packet, 0); 299} 300 301 302 303