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
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
34 get_dhcp_message_type (const struct dhcp
*dhcp
, const int optlen
)
36 const uint8_t *p
= (uint8_t *) (dhcp
+ 1);
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 */
45 else if (type
== DHCP_PAD
) /* no-operation */
47 else if (type
== DHCP_MSG_TYPE
) /* what we are looking for */
51 if (p
[i
+1] == 1) /* option length should be 1 */
52 return p
[i
+2]; /* return message type */
56 else /* some other option */
60 const int len
= p
[i
+1]; /* get option length */
61 i
+= (len
+ 1); /* advance to next option */
69 do_extract (struct dhcp
*dhcp
, const int optlen
)
71 uint8_t *p
= (uint8_t *) (dhcp
+ 1);
75 for (i
= 0; i
< optlen
; ++i
)
77 const uint8_t type
= p
[i
];
78 const int room
= optlen
- i
;
81 else if (type
== DHCP_PAD
)
83 else if (type
== DHCP_ROUTER
)
87 const int len
= p
[i
+1]; /* get option length */
90 if (!ret
&& len
>= 4 && (len
& 3) == 0)
92 memcpy (&ret
, p
+i
+2, 4); /* get router IP address */
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 */
104 const int len
= p
[i
+1]; /* get option length */
105 i
+= (len
+ 1); /* advance to next option */
113 udp_checksum (const uint8_t *buf
,
115 const uint8_t *src_addr
,
116 const uint8_t *dest_addr
)
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);
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);
134 for (i
= 0; i
< 4; i
+= 2){
135 word16
=((dest_addr
[i
] << 8) & 0xFF00) + (dest_addr
[i
+1] & 0xFF);
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 */
144 sum
= (sum
& 0xFFFF) + (sum
>> 16);
146 /* Take the one's complement of sum */
147 return ((uint16_t) ~sum
);
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
));
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
));
174 struct gc_arena gc
= gc_new ();
175 msg (D_ROUTE
, "Extracted DHCP router address: %s", print_in_addr_t (ret
, 0, &gc
));