cosmetics
[tomato.git] / release / src / router / openvpn / dhcp.c
blob495e187c92e4a86d017c0ed149006ace48873881
1 /*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single TCP/UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
8 * Copyright (C) 2002-2009 OpenVPN Technologies, Inc. <sales@openvpn.net>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program (see the file COPYING included with this
21 * distribution); if not, write to the Free Software Foundation, Inc.,
22 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "syshead.h"
27 #include "dhcp.h"
28 #include "socket.h"
29 #include "error.h"
31 #include "memdbg.h"
33 static int
34 get_dhcp_message_type (const struct dhcp *dhcp, const int optlen)
36 const uint8_t *p = (uint8_t *) (dhcp + 1);
37 int i;
39 for (i = 0; i < optlen; ++i)
41 const uint8_t type = p[i];
42 const int room = optlen - i;
43 if (type == DHCP_END) /* didn't find what we were looking for */
44 return -1;
45 else if (type == DHCP_PAD) /* no-operation */
47 else if (type == DHCP_MSG_TYPE) /* what we are looking for */
49 if (room >= 3)
51 if (p[i+1] == 1) /* option length should be 1 */
52 return p[i+2]; /* return message type */
54 return -1;
56 else /* some other option */
58 if (room >= 2)
60 const int len = p[i+1]; /* get option length */
61 i += (len + 1); /* advance to next option */
65 return -1;
68 static in_addr_t
69 do_extract (struct dhcp *dhcp, const int optlen)
71 uint8_t *p = (uint8_t *) (dhcp + 1);
72 int i;
73 in_addr_t ret = 0;
75 for (i = 0; i < optlen; ++i)
77 const uint8_t type = p[i];
78 const int room = optlen - i;
79 if (type == DHCP_END)
80 break;
81 else if (type == DHCP_PAD)
83 else if (type == DHCP_ROUTER)
85 if (room >= 2)
87 const int len = p[i+1]; /* get option length */
88 if (len <= (room-2))
90 if (!ret && len >= 4 && (len & 3) == 0)
92 memcpy (&ret, p+i+2, 4); /* get router IP address */
93 ret = ntohl (ret);
95 memset (p+i, DHCP_PAD, len+2); /* delete the router option by padding it out */
97 i += (len + 1); /* advance to next option */
100 else /* some other option */
102 if (room >= 2)
104 const int len = p[i+1]; /* get option length */
105 i += (len + 1); /* advance to next option */
109 return ret;
112 static uint16_t
113 udp_checksum (const uint8_t *buf,
114 const int len_udp,
115 const uint8_t *src_addr,
116 const uint8_t *dest_addr)
118 uint16_t word16;
119 uint32_t sum = 0;
120 int i;
122 /* make 16 bit words out of every two adjacent 8 bit words and */
123 /* calculate the sum of all 16 bit words */
124 for (i = 0; i < len_udp; i += 2){
125 word16 = ((buf[i] << 8) & 0xFF00) + ((i + 1 < len_udp) ? (buf[i+1] & 0xFF) : 0);
126 sum += word16;
129 /* add the UDP pseudo header which contains the IP source and destination addresses */
130 for (i = 0; i < 4; i += 2){
131 word16 =((src_addr[i] << 8) & 0xFF00) + (src_addr[i+1] & 0xFF);
132 sum += word16;
134 for (i = 0; i < 4; i += 2){
135 word16 =((dest_addr[i] << 8) & 0xFF00) + (dest_addr[i+1] & 0xFF);
136 sum += word16;
139 /* the protocol number and the length of the UDP packet */
140 sum += (uint16_t) OPENVPN_IPPROTO_UDP + (uint16_t) len_udp;
142 /* keep only the last 16 bits of the 32 bit calculated sum and add the carries */
143 while (sum >> 16)
144 sum = (sum & 0xFFFF) + (sum >> 16);
146 /* Take the one's complement of sum */
147 return ((uint16_t) ~sum);
150 in_addr_t
151 dhcp_extract_router_msg (struct buffer *ipbuf)
153 struct dhcp_full *df = (struct dhcp_full *) BPTR (ipbuf);
154 const int optlen = BLEN (ipbuf) - (sizeof (struct openvpn_iphdr) + sizeof (struct openvpn_udphdr) + sizeof (struct dhcp));
156 if (optlen >= 0
157 && df->ip.protocol == OPENVPN_IPPROTO_UDP
158 && df->udp.source == htons (BOOTPS_PORT)
159 && df->udp.dest == htons (BOOTPC_PORT)
160 && df->dhcp.op == BOOTREPLY
161 && get_dhcp_message_type (&df->dhcp, optlen) == DHCPACK)
163 /* get the router IP address while padding out all DHCP router options */
164 const in_addr_t ret = do_extract (&df->dhcp, optlen);
166 /* recompute the UDP checksum */
167 df->udp.check = htons (udp_checksum ((uint8_t *) &df->udp,
168 sizeof (struct openvpn_udphdr) + sizeof (struct dhcp) + optlen,
169 (uint8_t *)&df->ip.saddr,
170 (uint8_t *)&df->ip.daddr));
172 if (ret)
174 struct gc_arena gc = gc_new ();
175 msg (D_ROUTE, "Extracted DHCP router address: %s", print_in_addr_t (ret, 0, &gc));
176 gc_free (&gc);
179 return ret;
181 else
182 return 0;