File: | src/usr.sbin/npppd/npppd/npppd_subr.c |
Warning: | line 144, column 2 Value stored to 'sock' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: npppd_subr.c,v 1.21 2021/03/29 03:54:39 yasuoka Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2009 Internet Initiative Japan Inc. |
5 | * All rights reserved. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions |
9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. |
15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
26 | * SUCH DAMAGE. |
27 | */ |
28 | /**@file |
29 | * This file provides helper functions for npppd. |
30 | */ |
31 | |
32 | #include <sys/types.h> |
33 | #include <sys/socket.h> |
34 | #include <netinet/in.h> |
35 | #include <netinet/ip.h> |
36 | #include <netinet/udp.h> |
37 | #include <netinet/tcp.h> |
38 | #include <net/route.h> |
39 | #include <net/if_dl.h> |
40 | #include <net/if.h> |
41 | #include <arpa/inet.h> |
42 | #include <stdlib.h> |
43 | #include <fcntl.h> |
44 | #include <stdio.h> |
45 | #include <syslog.h> |
46 | #include <stddef.h> |
47 | #include <unistd.h> |
48 | #include <errno(*__errno()).h> |
49 | #include <ctype.h> |
50 | #include <string.h> |
51 | #include <resolv.h> |
52 | |
53 | #include "debugutil.h" |
54 | #include "addr_range.h" |
55 | |
56 | #include "npppd_defs.h" |
57 | #include "npppd_subr.h" |
58 | #include "privsep.h" |
59 | |
60 | #define MINIMUM(a, b)(((a) < (b)) ? (a) : (b)) (((a) < (b)) ? (a) : (b)) |
61 | |
62 | static u_int16_t route_seq = 0; |
63 | static int in_route0(int, struct in_addr *, struct in_addr *, struct in_addr *, int, const char *, uint32_t); |
64 | #define ROUNDUP(a)((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof (long)) \ |
65 | ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) |
66 | |
67 | static const char * |
68 | skip_space(const char *s) |
69 | { |
70 | const char *r; |
71 | for (r = s; *r != '\0' && isspace((unsigned char)*r); r++) |
72 | ;; /* skip */ |
73 | |
74 | return r; |
75 | } |
76 | |
77 | /** |
78 | * Read and store IPv4 address of name server from resolv.conf. |
79 | * The path of resolv.conf is taken from _PATH_RESCONF in resolv.h. |
80 | */ |
81 | int |
82 | load_resolv_conf(struct in_addr *pri, struct in_addr *sec) |
83 | { |
84 | FILE *filep; |
85 | int i; |
86 | struct in_addr *addr; |
87 | char *ap, *line, buf[BUFSIZ1024]; |
88 | |
89 | pri->s_addr = INADDR_NONE((u_int32_t)(0xffffffff)); |
90 | sec->s_addr = INADDR_NONE((u_int32_t)(0xffffffff)); |
91 | |
92 | filep = NULL((void*)0); |
93 | if ((filep = priv_fopen(_PATH_RESCONF"/etc/resolv.conf")) == NULL((void*)0)) |
94 | return 1; |
95 | |
96 | i = 0; |
97 | while (fgets(buf, sizeof(buf), filep) != NULL((void*)0)) { |
98 | line = (char *)skip_space(buf); |
99 | if (strncmp(line, "nameserver", 10) != 0) |
100 | continue; |
101 | line += 10; |
102 | if (!isspace((unsigned char)*line)) |
103 | continue; |
104 | while ((ap = strsep(&line, " \t\r\n")) != NULL((void*)0)) { |
105 | if (*ap == '\0') |
106 | continue; |
107 | if (i == 0) |
108 | addr = pri; |
109 | else |
110 | addr = sec; |
111 | if (inet_aton(ap, addr) != 1) { |
112 | /* |
113 | * FIXME: If configured IPv6, it may have IPv6 |
114 | * FIXME: address. For the present, continue. |
115 | */ |
116 | continue; |
117 | } |
118 | addr->s_addr = addr->s_addr; |
119 | if (++i >= 2) |
120 | goto end_loop; |
121 | } |
122 | } |
123 | end_loop: |
124 | if (filep != NULL((void*)0)) |
125 | fclose(filep); |
126 | |
127 | return 0; |
128 | } |
129 | |
130 | /* Add and delete routing entry. */ |
131 | static int |
132 | in_route0(int type, struct in_addr *dest, struct in_addr *mask, |
133 | struct in_addr *gate, int mtu, const char *ifname, uint32_t rtm_flags) |
134 | { |
135 | struct rt_msghdr *rtm; |
136 | struct sockaddr_in sdest, smask, sgate; |
137 | struct sockaddr_dl *sdl; |
138 | char dl_buf[512]; /* enough size */ |
139 | char *cp, buf[sizeof(*rtm) + sizeof(struct sockaddr_in) * 3 + |
140 | sizeof(dl_buf) + 128]; |
141 | const char *strtype; |
142 | int rval, flags, sock; |
143 | |
144 | sock = -1; |
Value stored to 'sock' is never read | |
145 | |
146 | ASSERT(type == RTM_ADD || type == RTM_DELETE)((void)0);; |
147 | if(type == RTM_ADD0x1) |
148 | strtype = "RTM_ADD"; |
149 | else |
150 | strtype = "RTM_DELETE"; |
151 | |
152 | memset(buf, 0, sizeof(buf)); |
153 | memset(&sdest, 0, sizeof(sdest)); |
154 | memset(&smask, 0, sizeof(smask)); |
155 | memset(&sgate, 0, sizeof(sgate)); |
156 | memset(&dl_buf, 0, sizeof(dl_buf)); |
157 | |
158 | sdl = (struct sockaddr_dl *)dl_buf; |
159 | |
160 | sdest.sin_addr = *dest; |
161 | if (mask != NULL((void*)0)) |
162 | smask.sin_addr = *mask; |
163 | if (gate != NULL((void*)0)) |
164 | sgate.sin_addr = *gate; |
165 | |
166 | sdest.sin_family = smask.sin_family = sgate.sin_family = AF_INET2; |
167 | sdest.sin_len = smask.sin_len = sgate.sin_len = sizeof(sgate); |
168 | |
169 | rtm = (struct rt_msghdr *)buf; |
170 | |
171 | rtm->rtm_version = RTM_VERSION5; |
172 | rtm->rtm_type = type; |
173 | rtm->rtm_flags = rtm_flags; |
174 | if (gate != NULL((void*)0)) |
175 | rtm->rtm_flags |= RTF_GATEWAY0x2; |
176 | if (mask == NULL((void*)0)) |
177 | rtm->rtm_flags |= RTF_HOST0x4; |
178 | |
179 | if (type == RTM_ADD0x1 && mtu > 0) { |
180 | rtm->rtm_inits = RTV_MTU0x1; |
181 | rtm->rtm_rmx.rmx_mtu = mtu; |
182 | } |
183 | |
184 | if (type == RTM_ADD0x1) |
185 | rtm->rtm_flags |= RTF_UP0x1; |
186 | |
187 | rtm->rtm_addrs = RTA_DST0x1; |
188 | if (gate != NULL((void*)0)) |
189 | rtm->rtm_addrs |= RTA_GATEWAY0x2; |
190 | if (mask != NULL((void*)0)) |
191 | rtm->rtm_addrs |= RTA_NETMASK0x4; |
192 | #ifdef RTA_IFP0x10 |
193 | if (ifname != NULL((void*)0)) |
194 | rtm->rtm_addrs |= RTA_IFP0x10; |
195 | #endif |
196 | |
197 | rtm->rtm_pid = getpid(); |
198 | route_seq = ((route_seq + 1)&0x0000ffff); |
199 | rtm->rtm_seq = route_seq; |
200 | |
201 | cp = (char *)rtm; |
202 | cp += ROUNDUP(sizeof(*rtm))((sizeof(*rtm)) > 0 ? (1 + (((sizeof(*rtm)) - 1) | (sizeof (long) - 1))) : sizeof(long)); |
203 | |
204 | memcpy(cp, &sdest, sdest.sin_len); |
205 | cp += ROUNDUP(sdest.sin_len)((sdest.sin_len) > 0 ? (1 + (((sdest.sin_len) - 1) | (sizeof (long) - 1))) : sizeof(long)); |
206 | if (gate != NULL((void*)0)) { |
207 | memcpy(cp, &sgate, sgate.sin_len); |
208 | cp += ROUNDUP(sgate.sin_len)((sgate.sin_len) > 0 ? (1 + (((sgate.sin_len) - 1) | (sizeof (long) - 1))) : sizeof(long)); |
209 | } |
210 | if (mask != NULL((void*)0)) { |
211 | memcpy(cp, &smask, smask.sin_len); |
212 | cp += ROUNDUP(smask.sin_len)((smask.sin_len) > 0 ? (1 + (((smask.sin_len) - 1) | (sizeof (long) - 1))) : sizeof(long)); |
213 | } |
214 | #ifdef RTA_IFP0x10 |
215 | if (ifname != NULL((void*)0)) { |
216 | strlcpy(sdl->sdl_data, ifname, IFNAMSIZ16); |
217 | sdl->sdl_family = AF_LINK18; |
218 | sdl->sdl_len = offsetof(struct sockaddr_dl, sdl_data)__builtin_offsetof(struct sockaddr_dl, sdl_data) +IFNAMSIZ16; |
219 | sdl->sdl_index = if_nametoindex(ifname); |
220 | memcpy(cp, sdl, sdl->sdl_len); |
221 | cp += ROUNDUP(sdl->sdl_len)((sdl->sdl_len) > 0 ? (1 + (((sdl->sdl_len) - 1) | ( sizeof(long) - 1))) : sizeof(long)); |
222 | } |
223 | #endif |
224 | |
225 | rtm->rtm_msglen = cp - buf; |
226 | |
227 | if ((sock = priv_socket(AF_ROUTE17, SOCK_RAW3, AF_UNSPEC0)) < 0) { |
228 | log_printf(LOG_ERR3, "socket() failed in %s() on %s : %m", |
229 | __func__, strtype); |
230 | goto fail; |
231 | } |
232 | |
233 | if ((flags = fcntl(sock, F_GETFL3)) < 0) { |
234 | log_printf(LOG_ERR3, "fcntl(,F_GETFL) failed on %s : %m", |
235 | __func__); |
236 | goto fail; |
237 | } |
238 | |
239 | if (fcntl(sock, F_SETFL4, flags | O_NONBLOCK0x0004) < 0) { |
240 | log_printf(LOG_ERR3, "fcntl(,F_SETFL) failed on %s : %m", |
241 | __func__); |
242 | goto fail; |
243 | } |
244 | |
245 | if ((rval = priv_send(sock, buf, rtm->rtm_msglen, 0)) <= 0) { |
246 | if ((type == RTM_DELETE0x2 && errno(*__errno()) == ESRCH3) || |
247 | (type == RTM_ADD0x1 && errno(*__errno()) == EEXIST17)) { |
248 | log_printf(LOG_DEBUG7, |
249 | "write() failed in %s on %s : %m", __func__, |
250 | strtype); |
251 | } else { |
252 | log_printf(LOG_WARNING4, |
253 | "write() failed in %s on %s : %m", __func__, |
254 | strtype); |
255 | } |
256 | goto fail; |
257 | } |
258 | |
259 | close(sock); |
260 | |
261 | return 0; |
262 | |
263 | fail: |
264 | if (sock >= 0) |
265 | close(sock); |
266 | |
267 | return 1; |
268 | } |
269 | |
270 | /** Add host routing entry. */ |
271 | int |
272 | in_host_route_add(struct in_addr *dest, struct in_addr *gate, |
273 | const char *ifname, int mtu) |
274 | { |
275 | return in_route0(RTM_ADD0x1, dest, NULL((void*)0), gate, mtu, ifname, 0); |
276 | } |
277 | |
278 | /** Delete host routing entry. */ |
279 | int |
280 | in_host_route_delete(struct in_addr *dest, struct in_addr *gate) |
281 | { |
282 | return in_route0(RTM_DELETE0x2, dest, NULL((void*)0), gate, 0, NULL((void*)0), 0); |
283 | } |
284 | |
285 | /** Add network routing entry. */ |
286 | int |
287 | in_route_add(struct in_addr *dest, struct in_addr *mask, struct in_addr *gate, |
288 | const char *ifname, uint32_t rtm_flags, int mtu) |
289 | { |
290 | return in_route0(RTM_ADD0x1, dest, mask, gate, mtu, ifname, rtm_flags); |
291 | } |
292 | |
293 | /** Delete network routing entry. */ |
294 | int |
295 | in_route_delete(struct in_addr *dest, struct in_addr *mask, |
296 | struct in_addr *gate, uint32_t rtm_flags) |
297 | { |
298 | return in_route0(RTM_DELETE0x2, dest, mask, gate, 0, NULL((void*)0), rtm_flags); |
299 | } |
300 | |
301 | /** |
302 | * Check whether a packet should reset idle timer |
303 | * Returns 1 to don't reset timer (i.e. the packet is "idle" packet) |
304 | */ |
305 | int |
306 | ip_is_idle_packet(const struct ip * pip, int len) |
307 | { |
308 | u_int16_t ip_off; |
309 | const struct udphdr *uh; |
310 | |
311 | /* |
312 | * Fragmented packet is not idle packet. |
313 | * (Long packet which needs to fragment is not idle packet.) |
314 | */ |
315 | ip_off = ntohs(pip->ip_off)(__uint16_t)(__builtin_constant_p(pip->ip_off) ? (__uint16_t )(((__uint16_t)(pip->ip_off) & 0xffU) << 8 | ((__uint16_t )(pip->ip_off) & 0xff00U) >> 8) : __swap16md(pip ->ip_off)); |
316 | if ((ip_off & IP_MF0x2000) || ((ip_off & IP_OFFMASK0x1fff) != 0)) |
317 | return 0; |
318 | |
319 | switch (pip->ip_p) { |
320 | case IPPROTO_IGMP2: |
321 | return 1; |
322 | case IPPROTO_ICMP1: |
323 | /* Is length enough? */ |
324 | if (pip->ip_hl * 4 + 8 > len) |
325 | return 1; |
326 | |
327 | switch (((unsigned char *) pip)[pip->ip_hl * 4]) { |
328 | case 0: /* Echo Reply */ |
329 | case 8: /* Echo Request */ |
330 | return 0; |
331 | default: |
332 | return 1; |
333 | } |
334 | case IPPROTO_UDP17: |
335 | case IPPROTO_TCP6: |
336 | /* |
337 | * The place of port number of UDP and TCP is the same, |
338 | * so can be shared. |
339 | */ |
340 | uh = (const struct udphdr *) (((const char *) pip) + |
341 | (pip->ip_hl * 4)); |
342 | |
343 | /* Is length enough? */ |
344 | if (pip->ip_hl * 4 + sizeof(struct udphdr) > len) |
345 | return 1; |
346 | |
347 | switch (ntohs(uh->uh_sport)(__uint16_t)(__builtin_constant_p(uh->uh_sport) ? (__uint16_t )(((__uint16_t)(uh->uh_sport) & 0xffU) << 8 | (( __uint16_t)(uh->uh_sport) & 0xff00U) >> 8) : __swap16md (uh->uh_sport))) { |
348 | case 53: /* DOMAIN */ |
349 | case 67: /* BOOTPS */ |
350 | case 68: /* BOOTPC */ |
351 | case 123: /* NTP */ |
352 | case 137: /* NETBIOS-NS */ |
353 | case 520: /* RIP */ |
354 | return 1; |
355 | } |
356 | switch (ntohs(uh->uh_dport)(__uint16_t)(__builtin_constant_p(uh->uh_dport) ? (__uint16_t )(((__uint16_t)(uh->uh_dport) & 0xffU) << 8 | (( __uint16_t)(uh->uh_dport) & 0xff00U) >> 8) : __swap16md (uh->uh_dport))) { |
357 | case 53: /* DOMAIN */ |
358 | case 67: /* BOOTPS */ |
359 | case 68: /* BOOTPC */ |
360 | case 123: /* NTP */ |
361 | case 137: /* NETBIOS-NS */ |
362 | case 520: /* RIP */ |
363 | return 1; |
364 | } |
365 | return 0; |
366 | default: |
367 | return 0; |
368 | } |
369 | } |
370 | |
371 | /*********************************************************************** |
372 | * Add and delete routing entry for the pool address. |
373 | ***********************************************************************/ |
374 | void |
375 | in_addr_range_add_route(struct in_addr_range *range) |
376 | { |
377 | struct in_addr_range *range0; |
378 | struct in_addr dest, mask, loop; |
379 | |
380 | for (range0 = range; range0 != NULL((void*)0); range0 = range0->next){ |
381 | dest.s_addr = htonl(range0->addr)(__uint32_t)(__builtin_constant_p(range0->addr) ? (__uint32_t )(((__uint32_t)(range0->addr) & 0xff) << 24 | (( __uint32_t)(range0->addr) & 0xff00) << 8 | ((__uint32_t )(range0->addr) & 0xff0000) >> 8 | ((__uint32_t) (range0->addr) & 0xff000000) >> 24) : __swap32md (range0->addr)); |
382 | mask.s_addr = htonl(range0->mask)(__uint32_t)(__builtin_constant_p(range0->mask) ? (__uint32_t )(((__uint32_t)(range0->mask) & 0xff) << 24 | (( __uint32_t)(range0->mask) & 0xff00) << 8 | ((__uint32_t )(range0->mask) & 0xff0000) >> 8 | ((__uint32_t) (range0->mask) & 0xff000000) >> 24) : __swap32md (range0->mask)); |
383 | loop.s_addr = htonl(INADDR_LOOPBACK)(__uint32_t)(__builtin_constant_p(((u_int32_t)(0x7f000001))) ? (__uint32_t)(((__uint32_t)(((u_int32_t)(0x7f000001))) & 0xff ) << 24 | ((__uint32_t)(((u_int32_t)(0x7f000001))) & 0xff00) << 8 | ((__uint32_t)(((u_int32_t)(0x7f000001)) ) & 0xff0000) >> 8 | ((__uint32_t)(((u_int32_t)(0x7f000001 ))) & 0xff000000) >> 24) : __swap32md(((u_int32_t)( 0x7f000001)))); |
384 | in_route_add(&dest, &mask, &loop, LOOPBACK_IFNAME"lo0", |
385 | RTF_BLACKHOLE0x1000, 0); |
386 | } |
387 | log_printf(LOG_INFO6, "Added routes for pooled addresses"); |
388 | } |
389 | |
390 | void |
391 | in_addr_range_delete_route(struct in_addr_range *range) |
392 | { |
393 | struct in_addr_range *range0; |
394 | struct in_addr dest, mask, loop; |
395 | |
396 | for (range0 = range; range0 != NULL((void*)0); range0 = range0->next){ |
397 | dest.s_addr = htonl(range0->addr)(__uint32_t)(__builtin_constant_p(range0->addr) ? (__uint32_t )(((__uint32_t)(range0->addr) & 0xff) << 24 | (( __uint32_t)(range0->addr) & 0xff00) << 8 | ((__uint32_t )(range0->addr) & 0xff0000) >> 8 | ((__uint32_t) (range0->addr) & 0xff000000) >> 24) : __swap32md (range0->addr)); |
398 | mask.s_addr = htonl(range0->mask)(__uint32_t)(__builtin_constant_p(range0->mask) ? (__uint32_t )(((__uint32_t)(range0->mask) & 0xff) << 24 | (( __uint32_t)(range0->mask) & 0xff00) << 8 | ((__uint32_t )(range0->mask) & 0xff0000) >> 8 | ((__uint32_t) (range0->mask) & 0xff000000) >> 24) : __swap32md (range0->mask)); |
399 | loop.s_addr = htonl(INADDR_LOOPBACK)(__uint32_t)(__builtin_constant_p(((u_int32_t)(0x7f000001))) ? (__uint32_t)(((__uint32_t)(((u_int32_t)(0x7f000001))) & 0xff ) << 24 | ((__uint32_t)(((u_int32_t)(0x7f000001))) & 0xff00) << 8 | ((__uint32_t)(((u_int32_t)(0x7f000001)) ) & 0xff0000) >> 8 | ((__uint32_t)(((u_int32_t)(0x7f000001 ))) & 0xff000000) >> 24) : __swap32md(((u_int32_t)( 0x7f000001)))); |
400 | |
401 | in_route_delete(&dest, &mask, &loop, RTF_BLACKHOLE0x1000); |
402 | } |
403 | log_printf(LOG_NOTICE5, "Deleted routes for pooled addresses"); |
404 | } |
405 | |
406 | |
407 | /* GETSHORT is also defined in #include <arpa/nameser_compat.h>. */ |
408 | #undef GETCHAR |
409 | #undef GETSHORT |
410 | #undef PUTSHORT |
411 | |
412 | #define GETCHAR(c, cp){ (c) = *(cp)++; } { (c) = *(cp)++; } |
413 | #define GETSHORT(s, cp){ (s) = *(cp)++ << 8; (s) |= *(cp)++; } { \ |
414 | (s) = *(cp)++ << 8; \ |
415 | (s) |= *(cp)++; \ |
416 | } |
417 | #define PUTSHORT(s, cp){ *(cp)++ = (u_char) ((s) >> 8); *(cp)++ = (u_char) (s) ; } { \ |
418 | *(cp)++ = (u_char) ((s) >> 8); \ |
419 | *(cp)++ = (u_char) (s); \ |
420 | } |
421 | #define TCP_OPTLEN_IN_SEGMENT12 12 /* timestamp option and padding */ |
422 | #define MAXMSS(mtu)(mtu - sizeof(struct ip) - sizeof(struct tcphdr) - 12) (mtu - sizeof(struct ip) - sizeof(struct tcphdr) - \ |
423 | TCP_OPTLEN_IN_SEGMENT12) |
424 | |
425 | /* adapted from FreeBSD:src/usr.sbin/ppp/tcpmss.c */ |
426 | /* |
427 | * Copyright (c) 2000 Ruslan Ermilov and Brian Somers <brian@Awfulhak.org> |
428 | * All rights reserved. |
429 | * |
430 | * Redistribution and use in source and binary forms, with or without |
431 | * modification, are permitted provided that the following conditions |
432 | * are met: |
433 | * 1. Redistributions of source code must retain the above copyright |
434 | * notice, this list of conditions and the following disclaimer. |
435 | * 2. Redistributions in binary form must reproduce the above copyright |
436 | * notice, this list of conditions and the following disclaimer in the |
437 | * documentation and/or other materials provided with the distribution. |
438 | * |
439 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
440 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
441 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
442 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
443 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
444 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
445 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
446 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
447 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
448 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
449 | * SUCH DAMAGE. |
450 | * |
451 | * $FreeBSD: src/usr.sbin/ppp/tcpmss.c,v 1.1.4.3 2001/07/19 11:39:54 brian Exp $ |
452 | */ |
453 | |
454 | /* |
455 | * The following macro is used to update an internet checksum. "acc" is a |
456 | * 32-bit accumulation of all the changes to the checksum (adding in old |
457 | * 16-bit words and subtracting out new words), and "cksum" is the checksum |
458 | * value to be updated. |
459 | */ |
460 | #define ADJUST_CHECKSUM(acc, cksum){ acc += cksum; if (acc < 0) { acc = -acc; acc = (acc >> 16) + (acc & 0xffff); acc += acc >> 16; cksum = (u_short ) ~acc; } else { acc = (acc >> 16) + (acc & 0xffff) ; acc += acc >> 16; cksum = (u_short) acc; } } { \ |
461 | acc += cksum; \ |
462 | if (acc < 0) { \ |
463 | acc = -acc; \ |
464 | acc = (acc >> 16) + (acc & 0xffff); \ |
465 | acc += acc >> 16; \ |
466 | cksum = (u_short) ~acc; \ |
467 | } else { \ |
468 | acc = (acc >> 16) + (acc & 0xffff); \ |
469 | acc += acc >> 16; \ |
470 | cksum = (u_short) acc; \ |
471 | } \ |
472 | } |
473 | |
474 | /** |
475 | * Adjust mss to make IP packet be shorter than or equal MTU. |
476 | * |
477 | * @param pktp pointer that indicates IP packet |
478 | * @param lpktp length |
479 | * @param mtu MTU |
480 | */ |
481 | int |
482 | adjust_tcp_mss(u_char *pktp, int lpktp, int mtu) |
483 | { |
484 | int opt, optlen, acc, ip_off, mss, maxmss; |
485 | struct ip *pip; |
486 | struct tcphdr *th; |
487 | |
488 | if (lpktp < sizeof(struct ip) + sizeof(struct tcphdr)) |
489 | return 1; |
490 | |
491 | pip = (struct ip *)pktp; |
492 | ip_off = ntohs(pip->ip_off)(__uint16_t)(__builtin_constant_p(pip->ip_off) ? (__uint16_t )(((__uint16_t)(pip->ip_off) & 0xffU) << 8 | ((__uint16_t )(pip->ip_off) & 0xff00U) >> 8) : __swap16md(pip ->ip_off)); |
493 | |
494 | /* exclude non-TCP packet or fragmented packet. */ |
495 | if (pip->ip_p != IPPROTO_TCP6 || (ip_off & IP_MF0x2000) != 0 || |
496 | (ip_off & IP_OFFMASK0x1fff) != 0) |
497 | return 0; |
498 | |
499 | pktp += pip->ip_hl << 2; |
500 | lpktp -= pip->ip_hl << 2; |
501 | |
502 | /* broken packet */ |
503 | if (sizeof(struct tcphdr) > lpktp) |
504 | return 1; |
505 | |
506 | th = (struct tcphdr *)pktp; |
507 | /* MSS is selected only from SYN segment. (See RFC 793) */ |
508 | if ((th->th_flags & TH_SYN0x02) == 0) |
509 | return 0; |
510 | |
511 | lpktp = MINIMUM(th->th_off << 4, lpktp)(((th->th_off << 4) < (lpktp)) ? (th->th_off << 4) : (lpktp)); |
512 | |
513 | pktp += sizeof(struct tcphdr); |
514 | lpktp -= sizeof(struct tcphdr); |
515 | |
516 | while (lpktp >= TCPOLEN_MAXSEG4) { |
517 | GETCHAR(opt, pktp){ (opt) = *(pktp)++; }; |
518 | switch (opt) { |
519 | case TCPOPT_MAXSEG2: |
520 | GETCHAR(optlen, pktp){ (optlen) = *(pktp)++; }; |
521 | GETSHORT(mss, pktp){ (mss) = *(pktp)++ << 8; (mss) |= *(pktp)++; }; |
522 | maxmss = MAXMSS(mtu)(mtu - sizeof(struct ip) - sizeof(struct tcphdr) - 12); |
523 | if (mss > maxmss) { |
524 | pktp-=2; |
525 | PUTSHORT(maxmss, pktp){ *(pktp)++ = (u_char) ((maxmss) >> 8); *(pktp)++ = (u_char ) (maxmss); }; |
526 | acc = htons(mss)(__uint16_t)(__builtin_constant_p(mss) ? (__uint16_t)(((__uint16_t )(mss) & 0xffU) << 8 | ((__uint16_t)(mss) & 0xff00U ) >> 8) : __swap16md(mss)); |
527 | acc -= htons(maxmss)(__uint16_t)(__builtin_constant_p(maxmss) ? (__uint16_t)(((__uint16_t )(maxmss) & 0xffU) << 8 | ((__uint16_t)(maxmss) & 0xff00U) >> 8) : __swap16md(maxmss)); |
528 | ADJUST_CHECKSUM(acc, th->th_sum){ acc += th->th_sum; if (acc < 0) { acc = -acc; acc = ( acc >> 16) + (acc & 0xffff); acc += acc >> 16 ; th->th_sum = (u_short) ~acc; } else { acc = (acc >> 16) + (acc & 0xffff); acc += acc >> 16; th->th_sum = (u_short) acc; } }; |
529 | } |
530 | return 0; |
531 | /* NOTREACHED */ |
532 | break; |
533 | case TCPOPT_EOL0: |
534 | return 0; |
535 | /* NOTREACHED */ |
536 | break; |
537 | case TCPOPT_NOP1: |
538 | lpktp--; |
539 | break; |
540 | default: |
541 | GETCHAR(optlen, pktp){ (optlen) = *(pktp)++; }; |
542 | if (optlen < 2) /* packet is broken */ |
543 | return 1; |
544 | pktp += optlen - 2; |
545 | lpktp -= optlen; |
546 | break; |
547 | } |
548 | } |
549 | return 0; |
550 | } |