00001 #include <unistd.h>
00002 #include <string.h>
00003 #include <netinet/in.h>
00004 #include <sys/types.h>
00005 #include <sys/socket.h>
00006 #include <features.h>
00007 #if __GLIBC__ >=2 && __GLIBC_MINOR >= 1
00008 #include <netpacket/packet.h>
00009 #include <net/ethernet.h>
00010 #else
00011 #include <asm/types.h>
00012 #include <linux/if_packet.h>
00013 #include <linux/if_ether.h>
00014 #endif
00015 #include <errno.h>
00016
00017 #include "packet.h"
00018 #include "debug.h"
00019 #include "dhcpd.h"
00020 #include "options.h"
00021
00022
00023 void init_header(struct dhcpMessage *packet, char type)
00024 {
00025 memset(packet, 0, sizeof(struct dhcpMessage));
00026 switch (type) {
00027 case DHCPDISCOVER:
00028 case DHCPREQUEST:
00029 case DHCPRELEASE:
00030 case DHCPINFORM:
00031 packet->op = BOOTREQUEST;
00032 break;
00033 case DHCPOFFER:
00034 case DHCPACK:
00035 case DHCPNAK:
00036 packet->op = BOOTREPLY;
00037 }
00038 packet->htype = ETH_10MB;
00039 packet->hlen = ETH_10MB_LEN;
00040 packet->cookie = htonl(DHCP_MAGIC);
00041 packet->options[0] = DHCP_END;
00042 add_simple_option(packet->options, DHCP_MESSAGE_TYPE, type);
00043 }
00044
00045
00046
00047 int get_packet(struct dhcpMessage *packet, int fd)
00048 {
00049 int bytes;
00050 int i;
00051 const char broken_vendors[][8] = {
00052 "MSFT 98",
00053 ""
00054 };
00055 char unsigned *vendor;
00056
00057 memset(packet, 0, sizeof(struct dhcpMessage));
00058 bytes = read(fd, packet, sizeof(struct dhcpMessage));
00059 if (bytes < 0) {
00060
00061 DEBUG(LOG_INFO, "couldn't read on listening socket, ignoring");
00062 return -1;
00063 }
00064
00065 if (ntohl(packet->cookie) != DHCP_MAGIC) {
00066 LOG(LOG_ERR, "received bogus message, ignoring");
00067 return -2;
00068 }
00069
00070 DEBUG(LOG_INFO, "Received a packet");
00071
00072 if (packet->op == BOOTREQUEST && (vendor = get_option(packet, DHCP_VENDOR))) {
00073 for (i = 0; broken_vendors[i][0]; i++) {
00074 if (vendor[OPT_LEN - 2] == (unsigned char) strlen(broken_vendors[i]) &&
00075 !strncmp(vendor, broken_vendors[i], vendor[OPT_LEN - 2])) {
00076 DEBUG(LOG_INFO, "broken client (%s), forcing broadcast",
00077 broken_vendors[i]);
00078 packet->flags |= htons(BROADCAST_FLAG);
00079 }
00080 }
00081 }
00082
00083
00084 return bytes;
00085 }
00086
00087
00088 u_int16_t checksum(void *addr, int count)
00089 {
00090
00091
00092
00093 register int32_t sum = 0;
00094 u_int16_t *source = (u_int16_t *) addr;
00095
00096 while (count > 1) {
00097
00098 sum += *source++;
00099 count -= 2;
00100 }
00101
00102
00103 if (count > 0) {
00104
00105
00106 u_int16_t tmp = 0;
00107 *(unsigned char *) (&tmp) = * (unsigned char *) source;
00108 sum += tmp;
00109 }
00110
00111 while (sum >> 16)
00112 sum = (sum & 0xffff) + (sum >> 16);
00113
00114 return ~sum;
00115 }
00116
00117
00118
00119 int raw_packet(struct dhcpMessage *payload, u_int32_t source_ip, int source_port,
00120 u_int32_t dest_ip, int dest_port, unsigned char *dest_arp, int ifindex)
00121 {
00122 int fd;
00123 int result;
00124 struct sockaddr_ll dest;
00125 struct udp_dhcp_packet packet;
00126
00127 if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
00128
00129 DEBUG(LOG_ERR, "socket call failed: %s", strerror(errno));
00130 return -1;
00131 }
00132
00133 memset(&dest, 0, sizeof(dest));
00134 memset(&packet, 0, sizeof(packet));
00135
00136 dest.sll_family = AF_PACKET;
00137 dest.sll_protocol = htons(ETH_P_IP);
00138 dest.sll_ifindex = ifindex;
00139 dest.sll_halen = 6;
00140 memcpy(dest.sll_addr, dest_arp, 6);
00141 if (bind(fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_ll)) < 0) {
00142 DEBUG(LOG_ERR, "bind call failed: %s", strerror(errno));
00143 close(fd);
00144 return -1;
00145 }
00146
00147 packet.ip.protocol = IPPROTO_UDP;
00148 packet.ip.saddr = source_ip;
00149 packet.ip.daddr = dest_ip;
00150 packet.udp.source = htons(source_port);
00151 packet.udp.dest = htons(dest_port);
00152 packet.udp.len = htons(sizeof(packet.udp) + sizeof(struct dhcpMessage));
00153 packet.ip.tot_len = packet.udp.len;
00154 memcpy(&(packet.data), payload, sizeof(struct dhcpMessage));
00155 packet.udp.check = checksum(&packet, sizeof(struct udp_dhcp_packet));
00156
00157 packet.ip.tot_len = htons(sizeof(struct udp_dhcp_packet));
00158 packet.ip.ihl = sizeof(packet.ip) >> 2;
00159 packet.ip.version = IPVERSION;
00160 packet.ip.ttl = IPDEFTTL;
00161 packet.ip.check = checksum(&(packet.ip), sizeof(packet.ip));
00162
00163 result = sendto(fd, &packet, sizeof(struct udp_dhcp_packet), 0, (struct sockaddr *) &dest, sizeof(dest));
00164 if (result <= 0) {
00165
00166 DEBUG(LOG_ERR, "write on socket failed: %s", strerror(errno));
00167 }
00168 close(fd);
00169 return result;
00170 }
00171
00172
00173
00174 int kernel_packet(struct dhcpMessage *payload, u_int32_t source_ip, int source_port,
00175 u_int32_t dest_ip, int dest_port)
00176 {
00177 int n = 1;
00178 int fd, result;
00179 struct sockaddr_in client;
00180
00181 if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
00182 return -1;
00183
00184 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof(n)) == -1)
00185 return -1;
00186
00187 memset(&client, 0, sizeof(client));
00188 client.sin_family = AF_INET;
00189 client.sin_port = htons(source_port);
00190 client.sin_addr.s_addr = source_ip;
00191
00192 if (bind(fd, (struct sockaddr *)&client, sizeof(struct sockaddr)) == -1)
00193 return -1;
00194
00195 memset(&client, 0, sizeof(client));
00196 client.sin_family = AF_INET;
00197 client.sin_port = htons(dest_port);
00198 client.sin_addr.s_addr = dest_ip;
00199
00200 if (connect(fd, (struct sockaddr *)&client, sizeof(struct sockaddr)) == -1)
00201 return -1;
00202
00203 result = write(fd, payload, sizeof(struct dhcpMessage));
00204 close(fd);
00205
00206 return result;
00207 }
00208