1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2001 Charles Mott <cm@linktel.net>
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
29 #include <sys/cdefs.h>
30 /*
31 Alias.c provides supervisory control for the functions of the
32 packet aliasing software. It consists of routines to monitor
33 TCP connection state, protocol-specific aliasing routines,
34 fragment handling and the following outside world functional
35 interfaces: SaveFragmentPtr, GetFragmentPtr, FragmentAliasIn,
36 PacketAliasIn and PacketAliasOut.
37
38 The other C program files are briefly described. The data
39 structure framework which holds information needed to translate
40 packets is encapsulated in alias_db.c. Data is accessed by
41 function calls, so other segments of the program need not know
42 about the underlying data structures. Alias_ftp.c contains
43 special code for modifying the ftp PORT command used to establish
44 data connections, while alias_irc.c does the same for IRC
45 DCC. Alias_util.c contains a few utility routines.
46
47 Version 1.0 August, 1996 (cjm)
48
49 Version 1.1 August 20, 1996 (cjm)
50 PPP host accepts incoming connections for ports 0 to 1023.
51 (Gary Roberts pointed out the need to handle incoming
52 connections.)
53
54 Version 1.2 September 7, 1996 (cjm)
55 Fragment handling error in alias_db.c corrected.
56 (Tom Torrance helped fix this problem.)
57
58 Version 1.4 September 16, 1996 (cjm)
59 - A more generalized method for handling incoming
60 connections, without the 0-1023 restriction, is
61 implemented in alias_db.c
62 - Improved ICMP support in alias.c. Traceroute
63 packet streams can now be correctly aliased.
64 - TCP connection closing logic simplified in
65 alias.c and now allows for additional 1 minute
66 "grace period" after FIN or RST is observed.
67
68 Version 1.5 September 17, 1996 (cjm)
69 Corrected error in handling incoming UDP packets with 0 checksum.
70 (Tom Torrance helped fix this problem.)
71
72 Version 1.6 September 18, 1996 (cjm)
73 Simplified ICMP aliasing scheme. Should now support
74 traceroute from Win95 as well as FreeBSD.
75
76 Version 1.7 January 9, 1997 (cjm)
77 - Out-of-order fragment handling.
78 - IP checksum error fixed for ftp transfers
79 from aliasing host.
80 - Integer return codes added to all
81 aliasing/de-aliasing functions.
82 - Some obsolete comments cleaned up.
83 - Differential checksum computations for
84 IP header (TCP, UDP and ICMP were already
85 differential).
86
87 Version 2.1 May 1997 (cjm)
88 - Added support for outgoing ICMP error
89 messages.
90 - Added two functions PacketAliasIn2()
91 and PacketAliasOut2() for dynamic address
92 control (e.g. round-robin allocation of
93 incoming packets).
94
95 Version 2.2 July 1997 (cjm)
96 - Rationalized API function names to begin
97 with "PacketAlias..."
98 - Eliminated PacketAliasIn2() and
99 PacketAliasOut2() as poorly conceived.
100
101 Version 2.3 Dec 1998 (dillon)
102 - Major bounds checking additions, see FreeBSD/CVS
103
104 Version 3.1 May, 2000 (salander)
105 - Added hooks to handle PPTP.
106
107 Version 3.2 July, 2000 (salander and satoh)
108 - Added PacketUnaliasOut routine.
109 - Added hooks to handle RTSP/RTP.
110
111 See HISTORY file for additional revisions.
112 */
113
114 #ifdef _KERNEL
115 #include <sys/param.h>
116 #include <sys/systm.h>
117 #include <sys/mbuf.h>
118 #include <sys/sysctl.h>
119 #else
120 #include <sys/types.h>
121 #include <stdlib.h>
122 #include <stdio.h>
123 #include <ctype.h>
124 #include <dlfcn.h>
125 #include <errno.h>
126 #include <string.h>
127 #endif
128
129 #include <netinet/in_systm.h>
130 #include <netinet/in.h>
131 #include <netinet/ip.h>
132 #include <netinet/ip_icmp.h>
133 #include <netinet/tcp.h>
134 #include <netinet/udp.h>
135
136 #ifdef _KERNEL
137 #include <netinet/libalias/alias.h>
138 #include <netinet/libalias/alias_local.h>
139 #include <netinet/libalias/alias_mod.h>
140 #else
141 #include <err.h>
142 #include "alias.h"
143 #include "alias_local.h"
144 #include "alias_mod.h"
145 #endif
146
147 /*
148 * Define libalias SYSCTL Node
149 */
150 #ifdef SYSCTL_NODE
151
152 SYSCTL_DECL(_net_inet);
153 SYSCTL_DECL(_net_inet_ip);
154 SYSCTL_NODE(_net_inet_ip, OID_AUTO, alias, CTLFLAG_RW | CTLFLAG_MPSAFE, NULL,
155 "Libalias sysctl API");
156
157 #endif
158
159 static __inline int
twowords(void * p)160 twowords(void *p)
161 {
162 uint8_t *c = p;
163
164 #if BYTE_ORDER == LITTLE_ENDIAN
165 uint16_t s1 = ((uint16_t)c[1] << 8) + (uint16_t)c[0];
166 uint16_t s2 = ((uint16_t)c[3] << 8) + (uint16_t)c[2];
167 #else
168 uint16_t s1 = ((uint16_t)c[0] << 8) + (uint16_t)c[1];
169 uint16_t s2 = ((uint16_t)c[2] << 8) + (uint16_t)c[3];
170 #endif
171 return (s1 + s2);
172 }
173
174 /* TCP Handling Routines
175
176 TcpMonitorIn() -- These routines monitor TCP connections, and
177 TcpMonitorOut() delete a link when a connection is closed.
178
179 These routines look for SYN, FIN and RST flags to determine when TCP
180 connections open and close. When a TCP connection closes, the data
181 structure containing packet aliasing information is deleted after
182 a timeout period.
183 */
184
185 /* Local prototypes */
186 static void TcpMonitorIn(uint16_t, struct alias_link *);
187
188 static void TcpMonitorOut(uint16_t, struct alias_link *);
189
190 static void
TcpMonitorIn(uint16_t th_flags,struct alias_link * lnk)191 TcpMonitorIn(uint16_t th_flags, struct alias_link *lnk)
192 {
193 switch (GetStateIn(lnk)) {
194 case ALIAS_TCP_STATE_NOT_CONNECTED:
195 if (th_flags & TH_RST)
196 SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED);
197 else if (th_flags & TH_SYN)
198 SetStateIn(lnk, ALIAS_TCP_STATE_CONNECTED);
199 break;
200 case ALIAS_TCP_STATE_CONNECTED:
201 if (th_flags & (TH_FIN | TH_RST))
202 SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED);
203 break;
204 }
205 }
206
207 static void
TcpMonitorOut(uint16_t th_flags,struct alias_link * lnk)208 TcpMonitorOut(uint16_t th_flags, struct alias_link *lnk)
209 {
210 switch (GetStateOut(lnk)) {
211 case ALIAS_TCP_STATE_NOT_CONNECTED:
212 if (th_flags & TH_RST)
213 SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED);
214 else if (th_flags & TH_SYN)
215 SetStateOut(lnk, ALIAS_TCP_STATE_CONNECTED);
216 break;
217 case ALIAS_TCP_STATE_CONNECTED:
218 if (th_flags & (TH_FIN | TH_RST))
219 SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED);
220 break;
221 }
222 }
223
224 /* Protocol Specific Packet Aliasing Routines
225
226 IcmpAliasIn(), IcmpAliasIn1(), IcmpAliasIn2()
227 IcmpAliasOut(), IcmpAliasOut1(), IcmpAliasOut2()
228 ProtoAliasIn(), ProtoAliasOut()
229 UdpAliasIn(), UdpAliasOut()
230 TcpAliasIn(), TcpAliasOut()
231
232 These routines handle protocol specific details of packet aliasing.
233 One may observe a certain amount of repetitive arithmetic in these
234 functions, the purpose of which is to compute a revised checksum
235 without actually summing over the entire data packet, which could be
236 unnecessarily time consuming.
237
238 The purpose of the packet aliasing routines is to replace the source
239 address of the outgoing packet and then correctly put it back for
240 any incoming packets. For TCP and UDP, ports are also re-mapped.
241
242 For ICMP echo/timestamp requests and replies, the following scheme
243 is used: the ID number is replaced by an alias for the outgoing
244 packet.
245
246 ICMP error messages are handled by looking at the IP fragment
247 in the data section of the message.
248
249 For TCP and UDP protocols, a port number is chosen for an outgoing
250 packet, and then incoming packets are identified by IP address and
251 port numbers. For TCP packets, there is additional logic in the event
252 that sequence and ACK numbers have been altered (as in the case for
253 FTP data port commands).
254
255 The port numbers used by the packet aliasing module are not true
256 ports in the Unix sense. No sockets are actually bound to ports.
257 They are more correctly thought of as placeholders.
258
259 All packets go through the aliasing mechanism, whether they come from
260 the gateway machine or other machines on a local area network.
261 */
262
263 /* Local prototypes */
264 static int IcmpAliasIn1(struct libalias *, struct ip *);
265 static int IcmpAliasIn2(struct libalias *, struct ip *);
266 static int IcmpAliasIn(struct libalias *, struct ip *);
267
268 static int IcmpAliasOut1(struct libalias *, struct ip *, int create);
269 static int IcmpAliasOut2(struct libalias *, struct ip *);
270 static int IcmpAliasOut(struct libalias *, struct ip *, int create);
271
272 static int ProtoAliasIn(struct libalias *la, struct in_addr ip_src,
273 struct ip *pip, u_char ip_p, u_short *ip_sum);
274 static int ProtoAliasOut(struct libalias *la, struct ip *pip,
275 struct in_addr ip_dst, u_char ip_p, u_short *ip_sum,
276 int create);
277
278 static int UdpAliasIn(struct libalias *, struct ip *);
279 static int UdpAliasOut(struct libalias *, struct ip *, int, int create);
280
281 static int TcpAliasIn(struct libalias *, struct ip *);
282 static int TcpAliasOut(struct libalias *, struct ip *, int, int create);
283
284 /*
285 De-alias incoming echo and timestamp replies.
286 Alias incoming echo and timestamp requests.
287 */
288 static int
IcmpAliasIn1(struct libalias * la,struct ip * pip)289 IcmpAliasIn1(struct libalias *la, struct ip *pip)
290 {
291 struct alias_link *lnk;
292 struct icmp *ic;
293 int ret;
294
295 LIBALIAS_LOCK_ASSERT(la);
296 ic = (struct icmp *)ip_next(pip);
297
298 /* Get source address from ICMP data field and restore original data */
299 ret = FindIcmpIn(la, pip->ip_src, pip->ip_dst, ic->icmp_id, 1, &lnk);
300 if (ret == PKT_ALIAS_OK) {
301 u_short original_id;
302 int accumulate;
303
304 original_id = GetOriginalPort(lnk);
305
306 /* Adjust ICMP checksum */
307 accumulate = ic->icmp_id;
308 accumulate -= original_id;
309 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
310
311 /* Put original sequence number back in */
312 ic->icmp_id = original_id;
313
314 /* Put original address back into IP header */
315 {
316 struct in_addr original_address;
317
318 original_address = GetOriginalAddress(lnk);
319 DifferentialChecksum(&pip->ip_sum,
320 &original_address, &pip->ip_dst, 2);
321 pip->ip_dst = original_address;
322 }
323 }
324 return (ret);
325 }
326
327 /*
328 Alias incoming ICMP error messages containing
329 IP header and first 64 bits of datagram.
330 */
331 static int
IcmpAliasIn2(struct libalias * la,struct ip * pip)332 IcmpAliasIn2(struct libalias *la, struct ip *pip)
333 {
334 struct ip *ip;
335 struct icmp *ic, *ic2;
336 struct udphdr *ud;
337 struct tcphdr *tc;
338 struct alias_link *lnk;
339 int ret;
340
341 LIBALIAS_LOCK_ASSERT(la);
342 ic = (struct icmp *)ip_next(pip);
343 ip = &ic->icmp_ip;
344
345 ud = (struct udphdr *)ip_next(ip);
346 tc = (struct tcphdr *)ip_next(ip);
347 ic2 = (struct icmp *)ip_next(ip);
348
349 if (ip->ip_p == IPPROTO_UDP) {
350 ret = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
351 ud->uh_dport, ud->uh_sport,
352 IPPROTO_UDP, 0, &lnk);
353 if (ret != PKT_ALIAS_OK)
354 return (ret);
355 } else if (ip->ip_p == IPPROTO_TCP) {
356 ret = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
357 tc->th_dport, tc->th_sport,
358 IPPROTO_TCP, 0, &lnk);
359 if (ret != PKT_ALIAS_OK)
360 return (ret);
361 } else if (ip->ip_p == IPPROTO_ICMP) {
362 if (ic2->icmp_type == ICMP_ECHO ||
363 ic2->icmp_type == ICMP_TSTAMP) {
364 ret = FindIcmpIn(la, ip->ip_dst, ip->ip_src,
365 ic2->icmp_id, 0, &lnk);
366 if (ret != PKT_ALIAS_OK)
367 return (ret);
368 } else
369 lnk = NULL;
370 } else
371 lnk = NULL;
372
373 if (lnk != NULL) {
374 if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
375 int accumulate, accumulate2;
376 struct in_addr original_address;
377 u_short original_port;
378
379 original_address = GetOriginalAddress(lnk);
380 original_port = GetOriginalPort(lnk);
381
382 /* Adjust ICMP checksum */
383 accumulate = twowords(&ip->ip_src);
384 accumulate -= twowords(&original_address);
385 accumulate += ud->uh_sport;
386 accumulate -= original_port;
387 accumulate2 = accumulate;
388 accumulate2 += ip->ip_sum;
389 ADJUST_CHECKSUM(accumulate, ip->ip_sum);
390 accumulate2 -= ip->ip_sum;
391 ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum);
392
393 /* Un-alias address in IP header */
394 DifferentialChecksum(&pip->ip_sum,
395 &original_address, &pip->ip_dst, 2);
396 pip->ip_dst = original_address;
397
398 /* Un-alias address and port number of
399 * original IP packet fragment contained
400 * in ICMP data section */
401 ip->ip_src = original_address;
402 ud->uh_sport = original_port;
403 } else if (ip->ip_p == IPPROTO_ICMP) {
404 int accumulate, accumulate2;
405 struct in_addr original_address;
406 u_short original_id;
407
408 original_address = GetOriginalAddress(lnk);
409 original_id = GetOriginalPort(lnk);
410
411 /* Adjust ICMP checksum */
412 accumulate = twowords(&ip->ip_src);
413 accumulate -= twowords(&original_address);
414 accumulate += ic2->icmp_id;
415 accumulate -= original_id;
416 accumulate2 = accumulate;
417 accumulate2 += ip->ip_sum;
418 ADJUST_CHECKSUM(accumulate, ip->ip_sum);
419 accumulate2 -= ip->ip_sum;
420 ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum);
421
422 /* Un-alias address in IP header */
423 DifferentialChecksum(&pip->ip_sum,
424 &original_address, &pip->ip_dst, 2);
425 pip->ip_dst = original_address;
426
427 /* Un-alias address of original IP packet and
428 * sequence number of embedded ICMP datagram */
429 ip->ip_src = original_address;
430 ic2->icmp_id = original_id;
431 }
432 return (PKT_ALIAS_OK);
433 }
434 return (PKT_ALIAS_IGNORED);
435 }
436
437 static int
IcmpAliasIn(struct libalias * la,struct ip * pip)438 IcmpAliasIn(struct libalias *la, struct ip *pip)
439 {
440 struct icmp *ic;
441 int iresult;
442 size_t dlen;
443
444 LIBALIAS_LOCK_ASSERT(la);
445
446 dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
447 if (dlen < ICMP_MINLEN)
448 return (PKT_ALIAS_IGNORED);
449
450 /* Return if proxy-only mode is enabled */
451 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
452 return (PKT_ALIAS_OK);
453
454 ic = (struct icmp *)ip_next(pip);
455
456 iresult = PKT_ALIAS_IGNORED;
457 switch (ic->icmp_type) {
458 case ICMP_ECHOREPLY:
459 case ICMP_TSTAMPREPLY:
460 if (ic->icmp_code == 0) {
461 iresult = IcmpAliasIn1(la, pip);
462 }
463 break;
464 case ICMP_UNREACH:
465 case ICMP_SOURCEQUENCH:
466 case ICMP_TIMXCEED:
467 case ICMP_PARAMPROB:
468 if (dlen < ICMP_ADVLENMIN ||
469 dlen < (size_t)ICMP_ADVLEN(ic))
470 return (PKT_ALIAS_IGNORED);
471 iresult = IcmpAliasIn2(la, pip);
472 break;
473 case ICMP_ECHO:
474 case ICMP_TSTAMP:
475 iresult = IcmpAliasIn1(la, pip);
476 break;
477 }
478 return (iresult);
479 }
480
481 /*
482 Alias outgoing echo and timestamp requests.
483 De-alias outgoing echo and timestamp replies.
484 */
485 static int
IcmpAliasOut1(struct libalias * la,struct ip * pip,int create)486 IcmpAliasOut1(struct libalias *la, struct ip *pip, int create)
487 {
488 struct alias_link *lnk;
489 struct icmp *ic;
490 int ret;
491
492 LIBALIAS_LOCK_ASSERT(la);
493 ic = (struct icmp *)ip_next(pip);
494
495 /* Save overwritten data for when echo packet returns */
496 ret = FindIcmpOut(la, pip->ip_src, pip->ip_dst, ic->icmp_id, create,
497 &lnk);
498 if (ret == PKT_ALIAS_OK) {
499 u_short alias_id;
500 int accumulate;
501
502 alias_id = GetAliasPort(lnk);
503
504 /* Since data field is being modified, adjust ICMP checksum */
505 accumulate = ic->icmp_id;
506 accumulate -= alias_id;
507 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
508
509 /* Alias sequence number */
510 ic->icmp_id = alias_id;
511
512 /* Change source address */
513 {
514 struct in_addr alias_address;
515
516 alias_address = GetAliasAddress(lnk);
517 DifferentialChecksum(&pip->ip_sum,
518 &alias_address, &pip->ip_src, 2);
519 pip->ip_src = alias_address;
520 }
521 }
522 return (ret);
523 }
524
525 /*
526 Alias outgoing ICMP error messages containing
527 IP header and first 64 bits of datagram.
528 */
529 static int
IcmpAliasOut2(struct libalias * la,struct ip * pip)530 IcmpAliasOut2(struct libalias *la, struct ip *pip)
531 {
532 struct ip *ip;
533 struct icmp *ic, *ic2;
534 struct udphdr *ud;
535 struct tcphdr *tc;
536 struct alias_link *lnk;
537 int ret;
538
539 LIBALIAS_LOCK_ASSERT(la);
540 ic = (struct icmp *)ip_next(pip);
541 ip = &ic->icmp_ip;
542
543 ud = (struct udphdr *)ip_next(ip);
544 tc = (struct tcphdr *)ip_next(ip);
545 ic2 = (struct icmp *)ip_next(ip);
546
547 if (ip->ip_p == IPPROTO_UDP) {
548 ret = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
549 ud->uh_dport, ud->uh_sport,
550 IPPROTO_UDP, 0, &lnk);
551 if (ret != PKT_ALIAS_OK)
552 return (ret);
553 } else if (ip->ip_p == IPPROTO_TCP) {
554 ret = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
555 tc->th_dport, tc->th_sport,
556 IPPROTO_TCP, 0, &lnk);
557 if (ret != PKT_ALIAS_OK)
558 return (ret);
559 } else if (ip->ip_p == IPPROTO_ICMP) {
560 if (ic2->icmp_type == ICMP_ECHO ||
561 ic2->icmp_type == ICMP_TSTAMP) {
562 ret = FindIcmpOut(la, ip->ip_dst, ip->ip_src,
563 ic2->icmp_id, 0, &lnk);
564 if (ret != PKT_ALIAS_OK)
565 return (ret);
566 } else
567 lnk = NULL;
568 } else
569 lnk = NULL;
570
571 if (lnk != NULL) {
572 if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
573 int accumulate;
574 struct in_addr alias_address;
575 u_short alias_port;
576
577 alias_address = GetAliasAddress(lnk);
578 alias_port = GetAliasPort(lnk);
579
580 /* Adjust ICMP checksum */
581 accumulate = twowords(&ip->ip_dst);
582 accumulate -= twowords(&alias_address);
583 accumulate += ud->uh_dport;
584 accumulate -= alias_port;
585 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
586
587 /*
588 * Alias address in IP header if it comes from the host
589 * the original TCP/UDP packet was destined for.
590 */
591 if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
592 DifferentialChecksum(&pip->ip_sum,
593 &alias_address, &pip->ip_src, 2);
594 pip->ip_src = alias_address;
595 }
596 /* Alias address and port number of original IP packet
597 * fragment contained in ICMP data section */
598 ip->ip_dst = alias_address;
599 ud->uh_dport = alias_port;
600 } else if (ip->ip_p == IPPROTO_ICMP) {
601 int accumulate;
602 struct in_addr alias_address;
603 u_short alias_id;
604
605 alias_address = GetAliasAddress(lnk);
606 alias_id = GetAliasPort(lnk);
607
608 /* Adjust ICMP checksum */
609 accumulate = twowords(&ip->ip_dst);
610 accumulate -= twowords(&alias_address);
611 accumulate += ic2->icmp_id;
612 accumulate -= alias_id;
613 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
614
615 /*
616 * Alias address in IP header if it comes from the host
617 * the original ICMP message was destined for.
618 */
619 if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
620 DifferentialChecksum(&pip->ip_sum,
621 &alias_address, &pip->ip_src, 2);
622 pip->ip_src = alias_address;
623 }
624 /* Alias address of original IP packet and
625 * sequence number of embedded ICMP datagram */
626 ip->ip_dst = alias_address;
627 ic2->icmp_id = alias_id;
628 }
629 return (PKT_ALIAS_OK);
630 }
631 return (PKT_ALIAS_IGNORED);
632 }
633
634 static int
IcmpAliasOut(struct libalias * la,struct ip * pip,int create)635 IcmpAliasOut(struct libalias *la, struct ip *pip, int create)
636 {
637 int iresult;
638 struct icmp *ic;
639
640 LIBALIAS_LOCK_ASSERT(la);
641 (void)create;
642
643 /* Return if proxy-only mode is enabled */
644 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
645 return (PKT_ALIAS_OK);
646
647 ic = (struct icmp *)ip_next(pip);
648
649 iresult = PKT_ALIAS_IGNORED;
650 switch (ic->icmp_type) {
651 case ICMP_ECHO:
652 case ICMP_TSTAMP:
653 if (ic->icmp_code == 0) {
654 iresult = IcmpAliasOut1(la, pip, create);
655 }
656 break;
657 case ICMP_UNREACH:
658 case ICMP_SOURCEQUENCH:
659 case ICMP_TIMXCEED:
660 case ICMP_PARAMPROB:
661 iresult = IcmpAliasOut2(la, pip);
662 break;
663 case ICMP_ECHOREPLY:
664 case ICMP_TSTAMPREPLY:
665 iresult = IcmpAliasOut1(la, pip, create);
666 }
667 return (iresult);
668 }
669
670 /*
671 Handle incoming IP packets. The
672 only thing which is done in this case is to alias
673 the dest IP address of the packet to our inside
674 machine.
675 */
676 static int
ProtoAliasIn(struct libalias * la,struct in_addr ip_src,struct ip * pip,u_char ip_p,u_short * ip_sum)677 ProtoAliasIn(struct libalias *la, struct in_addr ip_src,
678 struct ip *pip, u_char ip_p, u_short *ip_sum)
679 {
680 struct alias_link *lnk;
681 int ret;
682
683 LIBALIAS_LOCK_ASSERT(la);
684 /* Return if proxy-only mode is enabled */
685 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
686 return (PKT_ALIAS_OK);
687
688 ret = FindProtoIn(la, ip_src, pip->ip_dst, ip_p, &lnk);
689 if (ret == PKT_ALIAS_OK) {
690 struct in_addr original_address;
691
692 original_address = GetOriginalAddress(lnk);
693
694 /* Restore original IP address */
695 DifferentialChecksum(ip_sum,
696 &original_address, &pip->ip_dst, 2);
697 pip->ip_dst = original_address;
698 }
699 return (ret);
700 }
701
702 /*
703 Handle outgoing IP packets. The
704 only thing which is done in this case is to alias
705 the source IP address of the packet.
706 */
707 static int
ProtoAliasOut(struct libalias * la,struct ip * pip,struct in_addr ip_dst,u_char ip_p,u_short * ip_sum,int create)708 ProtoAliasOut(struct libalias *la, struct ip *pip,
709 struct in_addr ip_dst, u_char ip_p, u_short *ip_sum, int create)
710 {
711 struct alias_link *lnk;
712 int ret;
713
714 LIBALIAS_LOCK_ASSERT(la);
715
716 /* Return if proxy-only mode is enabled */
717 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
718 return (PKT_ALIAS_OK);
719
720 if (!create)
721 return (PKT_ALIAS_IGNORED);
722
723 ret = FindProtoOut(la, pip->ip_src, ip_dst, ip_p, &lnk);
724 if (ret == PKT_ALIAS_OK) {
725 struct in_addr alias_address;
726
727 alias_address = GetAliasAddress(lnk);
728
729 /* Change source address */
730 DifferentialChecksum(ip_sum,
731 &alias_address, &pip->ip_src, 2);
732 pip->ip_src = alias_address;
733 }
734 return (ret);
735 }
736
737 #define MF_ISSET(_pip) (ntohs((_pip)->ip_off) & IP_MF)
738 #define FRAG_NO_HDR(_pip) (ntohs((_pip)->ip_off) & IP_OFFMASK)
739
740 static struct udphdr *
ValidateUdpLength(struct ip * pip)741 ValidateUdpLength(struct ip *pip)
742 {
743 struct udphdr *ud;
744 size_t dlen;
745
746 #ifdef _KERNEL
747 KASSERT(!FRAG_NO_HDR(pip), ("header-less fragment isn't expected here"));
748 #endif
749 dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
750 if (dlen < sizeof(struct udphdr))
751 return (NULL);
752 ud = (struct udphdr *)ip_next(pip);
753 if (!MF_ISSET(pip) && dlen < ntohs(ud->uh_ulen))
754 return (NULL);
755 return (ud);
756 }
757
758 static int
UdpAliasIn(struct libalias * la,struct ip * pip)759 UdpAliasIn(struct libalias *la, struct ip *pip)
760 {
761 struct udphdr *ud;
762 struct alias_link *lnk;
763 int ret;
764
765 LIBALIAS_LOCK_ASSERT(la);
766
767 ud = ValidateUdpLength(pip);
768 if (ud == NULL)
769 return (PKT_ALIAS_IGNORED);
770
771 ret = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
772 ud->uh_sport, ud->uh_dport,
773 IPPROTO_UDP, !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY), &lnk);
774 if (ret != PKT_ALIAS_OK)
775 return (ret);
776 {
777 struct in_addr alias_address;
778 struct in_addr original_address;
779 struct in_addr proxy_address;
780 u_short alias_port;
781 u_short proxy_port;
782 int accumulate;
783 int error;
784 struct alias_data ad = {
785 .lnk = lnk,
786 .oaddr = &original_address,
787 .aaddr = &alias_address,
788 .aport = &alias_port,
789 .sport = &ud->uh_sport,
790 .dport = &ud->uh_dport,
791 .maxpktsize = 0
792 };
793
794 alias_address = GetAliasAddress(lnk);
795 original_address = GetOriginalAddress(lnk);
796 proxy_address = GetProxyAddress(lnk);
797 alias_port = ud->uh_dport;
798 ud->uh_dport = GetOriginalPort(lnk);
799 proxy_port = GetProxyPort(lnk);
800
801 /* Walk out chain. */
802 error = find_handler(IN, UDP, la, pip, &ad);
803 /* If we cannot figure out the packet, ignore it. */
804 if (error < 0)
805 return (PKT_ALIAS_IGNORED);
806
807 /* If UDP checksum is not zero, then adjust since
808 * destination port is being unaliased and
809 * destination address is being altered. */
810 if (ud->uh_sum != 0) {
811 accumulate = alias_port;
812 accumulate -= ud->uh_dport;
813 accumulate += twowords(&alias_address);
814 accumulate -= twowords(&original_address);
815
816 /* If this is a proxy packet, modify checksum
817 * because of source change.*/
818 if (proxy_port != 0) {
819 accumulate += ud->uh_sport;
820 accumulate -= proxy_port;
821 }
822
823 if (proxy_address.s_addr != 0) {
824 accumulate += twowords(&pip->ip_src);
825 accumulate -= twowords(&proxy_address);
826 }
827
828 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
829 }
830
831 /* XXX: Could the two if's below be concatenated to one ? */
832 /* Restore source port and/or address in case of proxying*/
833 if (proxy_port != 0)
834 ud->uh_sport = proxy_port;
835
836 if (proxy_address.s_addr != 0) {
837 DifferentialChecksum(&pip->ip_sum,
838 &proxy_address, &pip->ip_src, 2);
839 pip->ip_src = proxy_address;
840 }
841
842 /* Restore original IP address */
843 DifferentialChecksum(&pip->ip_sum,
844 &original_address, &pip->ip_dst, 2);
845 pip->ip_dst = original_address;
846
847 return (PKT_ALIAS_OK);
848 }
849 }
850
851 static int
UdpAliasOut(struct libalias * la,struct ip * pip,int maxpacketsize,int create)852 UdpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
853 {
854 struct udphdr *ud;
855 struct alias_link *lnk;
856 struct in_addr dest_address;
857 struct in_addr proxy_server_address;
858 u_short dest_port;
859 u_short proxy_server_port;
860 int proxy_type, ret;
861
862 LIBALIAS_LOCK_ASSERT(la);
863
864 ud = ValidateUdpLength(pip);
865 if (ud == NULL)
866 return (PKT_ALIAS_IGNORED);
867
868 /* Return if proxy-only mode is enabled and not proxyrule found.*/
869 proxy_type = ProxyCheck(la, &proxy_server_address, &proxy_server_port,
870 pip->ip_src, pip->ip_dst, ud->uh_dport, pip->ip_p);
871 if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
872 return (PKT_ALIAS_OK);
873
874 /* If this is a transparent proxy, save original destination,
875 * then alter the destination and adjust checksums */
876 dest_port = ud->uh_dport;
877 dest_address = pip->ip_dst;
878
879 if (proxy_type != 0) {
880 int accumulate;
881
882 accumulate = twowords(&pip->ip_dst);
883 accumulate -= twowords(&proxy_server_address);
884
885 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
886
887 if (ud->uh_sum != 0) {
888 accumulate = twowords(&pip->ip_dst);
889 accumulate -= twowords(&proxy_server_address);
890 accumulate += ud->uh_dport;
891 accumulate -= proxy_server_port;
892 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
893 }
894 pip->ip_dst = proxy_server_address;
895 ud->uh_dport = proxy_server_port;
896 }
897 ret = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
898 ud->uh_sport, ud->uh_dport,
899 IPPROTO_UDP, create, &lnk);
900 if (ret != PKT_ALIAS_OK)
901 return (ret);
902 {
903 u_short alias_port;
904 struct in_addr alias_address;
905 struct alias_data ad = {
906 .lnk = lnk,
907 .oaddr = NULL,
908 .aaddr = &alias_address,
909 .aport = &alias_port,
910 .sport = &ud->uh_sport,
911 .dport = &ud->uh_dport,
912 .maxpktsize = 0
913 };
914
915 /* Save original destination address, if this is a proxy packet.
916 * Also modify packet to include destination encoding. This may
917 * change the size of IP header. */
918 if (proxy_type != 0) {
919 SetProxyPort(lnk, dest_port);
920 SetProxyAddress(lnk, dest_address);
921 ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
922 ud = (struct udphdr *)ip_next(pip);
923 }
924
925 alias_address = GetAliasAddress(lnk);
926 alias_port = GetAliasPort(lnk);
927
928 /* Walk out chain. */
929 find_handler(OUT, UDP, la, pip, &ad);
930
931 /* If UDP checksum is not zero, adjust since source port is */
932 /* being aliased and source address is being altered */
933 if (ud->uh_sum != 0) {
934 int accumulate;
935
936 accumulate = ud->uh_sport;
937 accumulate -= alias_port;
938 accumulate += twowords(&pip->ip_src);
939 accumulate -= twowords(&alias_address);
940 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
941 }
942 /* Put alias port in UDP header */
943 ud->uh_sport = alias_port;
944
945 /* Change source address */
946 DifferentialChecksum(&pip->ip_sum,
947 &alias_address, &pip->ip_src, 2);
948 pip->ip_src = alias_address;
949
950 return (PKT_ALIAS_OK);
951 }
952 }
953
954 static int
TcpAliasIn(struct libalias * la,struct ip * pip)955 TcpAliasIn(struct libalias *la, struct ip *pip)
956 {
957 struct tcphdr *tc;
958 struct alias_link *lnk;
959 size_t dlen;
960 int ret;
961
962 LIBALIAS_LOCK_ASSERT(la);
963
964 dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
965 if (dlen < sizeof(struct tcphdr))
966 return (PKT_ALIAS_IGNORED);
967 tc = (struct tcphdr *)ip_next(pip);
968
969 ret = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
970 tc->th_sport, tc->th_dport,
971 IPPROTO_TCP,
972 !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY),
973 &lnk);
974 if (ret == PKT_ALIAS_OK) {
975 struct in_addr alias_address;
976 struct in_addr original_address;
977 struct in_addr proxy_address;
978 u_short alias_port;
979 u_short proxy_port;
980 int accumulate;
981
982 /*
983 * The init of MANY vars is a bit below, but aliashandlepptpin
984 * seems to need the destination port that came within the
985 * packet and not the original one looks below [*].
986 */
987
988 struct alias_data ad = {
989 .lnk = lnk,
990 .oaddr = NULL,
991 .aaddr = NULL,
992 .aport = NULL,
993 .sport = &tc->th_sport,
994 .dport = &tc->th_dport,
995 .maxpktsize = 0
996 };
997
998 /* Walk out chain. */
999 find_handler(IN, TCP, la, pip, &ad);
1000
1001 alias_address = GetAliasAddress(lnk);
1002 original_address = GetOriginalAddress(lnk);
1003 proxy_address = GetProxyAddress(lnk);
1004 alias_port = tc->th_dport;
1005 tc->th_dport = GetOriginalPort(lnk);
1006 proxy_port = GetProxyPort(lnk);
1007
1008 /*
1009 * Look above, if anyone is going to add find_handler AFTER
1010 * this aliashandlepptpin/point, please redo alias_data too.
1011 * Uncommenting the piece here below should be enough.
1012 */
1013 #if 0
1014 struct alias_data ad = {
1015 .lnk = lnk,
1016 .oaddr = &original_address,
1017 .aaddr = &alias_address,
1018 .aport = &alias_port,
1019 .sport = &ud->uh_sport,
1020 .dport = &ud->uh_dport,
1021 .maxpktsize = 0
1022 };
1023
1024 /* Walk out chain. */
1025 error = find_handler(la, pip, &ad);
1026 if (error == EHDNOF)
1027 printf("Protocol handler not found\n");
1028 #endif
1029
1030 /* Adjust TCP checksum since destination port is being
1031 * unaliased and destination port is being altered. */
1032 accumulate = alias_port;
1033 accumulate -= tc->th_dport;
1034 accumulate += twowords(&alias_address);
1035 accumulate -= twowords(&original_address);
1036
1037 /* If this is a proxy, then modify the TCP source port
1038 * and checksum accumulation */
1039 if (proxy_port != 0) {
1040 accumulate += tc->th_sport;
1041 tc->th_sport = proxy_port;
1042 accumulate -= tc->th_sport;
1043 accumulate += twowords(&pip->ip_src);
1044 accumulate -= twowords(&proxy_address);
1045 }
1046 /* See if ACK number needs to be modified */
1047 if (GetAckModified(lnk) == 1) {
1048 int delta;
1049
1050 tc = (struct tcphdr *)ip_next(pip);
1051 delta = GetDeltaAckIn(tc->th_ack, lnk);
1052 if (delta != 0) {
1053 accumulate += twowords(&tc->th_ack);
1054 tc->th_ack = htonl(ntohl(tc->th_ack) - delta);
1055 accumulate -= twowords(&tc->th_ack);
1056 }
1057 }
1058 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1059
1060 /* Restore original IP address */
1061 accumulate = twowords(&pip->ip_dst);
1062 pip->ip_dst = original_address;
1063 accumulate -= twowords(&pip->ip_dst);
1064
1065 /* If this is a transparent proxy packet,
1066 * then modify the source address */
1067 if (proxy_address.s_addr != 0) {
1068 accumulate += twowords(&pip->ip_src);
1069 pip->ip_src = proxy_address;
1070 accumulate -= twowords(&pip->ip_src);
1071 }
1072 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1073
1074 /* Monitor TCP connection state */
1075 tc = (struct tcphdr *)ip_next(pip);
1076 TcpMonitorIn(__tcp_get_flags(tc), lnk);
1077
1078 return (PKT_ALIAS_OK);
1079 }
1080 return (ret);
1081 }
1082
1083 static int
TcpAliasOut(struct libalias * la,struct ip * pip,int maxpacketsize,int create)1084 TcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
1085 {
1086 int proxy_type, ret;
1087 u_short dest_port;
1088 u_short proxy_server_port;
1089 size_t dlen;
1090 struct in_addr dest_address;
1091 struct in_addr proxy_server_address;
1092 struct tcphdr *tc;
1093 struct alias_link *lnk;
1094
1095 LIBALIAS_LOCK_ASSERT(la);
1096
1097 dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
1098 if (dlen < sizeof(struct tcphdr))
1099 return (PKT_ALIAS_IGNORED);
1100 tc = (struct tcphdr *)ip_next(pip);
1101
1102 if (create)
1103 proxy_type = ProxyCheck(la, &proxy_server_address,
1104 &proxy_server_port, pip->ip_src, pip->ip_dst,
1105 tc->th_dport, pip->ip_p);
1106 else
1107 proxy_type = 0;
1108
1109 if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
1110 return (PKT_ALIAS_OK);
1111
1112 /* If this is a transparent proxy, save original destination,
1113 * then alter the destination and adjust checksums */
1114 dest_port = tc->th_dport;
1115 dest_address = pip->ip_dst;
1116 if (proxy_type != 0) {
1117 int accumulate;
1118
1119 accumulate = tc->th_dport;
1120 tc->th_dport = proxy_server_port;
1121 accumulate -= tc->th_dport;
1122 accumulate += twowords(&pip->ip_dst);
1123 accumulate -= twowords(&proxy_server_address);
1124 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1125
1126 accumulate = twowords(&pip->ip_dst);
1127 pip->ip_dst = proxy_server_address;
1128 accumulate -= twowords(&pip->ip_dst);
1129 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1130 }
1131 ret = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
1132 tc->th_sport, tc->th_dport,
1133 IPPROTO_TCP, create, &lnk);
1134 if (ret != PKT_ALIAS_OK)
1135 return (ret);
1136 {
1137 u_short alias_port;
1138 struct in_addr alias_address;
1139 int accumulate;
1140 struct alias_data ad = {
1141 .lnk = lnk,
1142 .oaddr = NULL,
1143 .aaddr = &alias_address,
1144 .aport = &alias_port,
1145 .sport = &tc->th_sport,
1146 .dport = &tc->th_dport,
1147 .maxpktsize = maxpacketsize
1148 };
1149
1150 /* Save original destination address, if this is a proxy packet.
1151 * Also modify packet to include destination
1152 * encoding. This may change the size of IP header. */
1153 if (proxy_type != 0) {
1154 SetProxyPort(lnk, dest_port);
1155 SetProxyAddress(lnk, dest_address);
1156 ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
1157 tc = (struct tcphdr *)ip_next(pip);
1158 }
1159 /* Get alias address and port */
1160 alias_port = GetAliasPort(lnk);
1161 alias_address = GetAliasAddress(lnk);
1162
1163 /* Monitor TCP connection state */
1164 tc = (struct tcphdr *)ip_next(pip);
1165 TcpMonitorOut(__tcp_get_flags(tc), lnk);
1166
1167 /* Walk out chain. */
1168 find_handler(OUT, TCP, la, pip, &ad);
1169
1170 /* Adjust TCP checksum since source port is being aliased
1171 * and source address is being altered */
1172 accumulate = tc->th_sport;
1173 tc->th_sport = alias_port;
1174 accumulate -= tc->th_sport;
1175 accumulate += twowords(&pip->ip_src);
1176 accumulate -= twowords(&alias_address);
1177
1178 /* Modify sequence number if necessary */
1179 if (GetAckModified(lnk) == 1) {
1180 int delta;
1181
1182 tc = (struct tcphdr *)ip_next(pip);
1183 delta = GetDeltaSeqOut(tc->th_seq, lnk);
1184 if (delta != 0) {
1185 accumulate += twowords(&tc->th_seq);
1186 tc->th_seq = htonl(ntohl(tc->th_seq) + delta);
1187 accumulate -= twowords(&tc->th_seq);
1188 }
1189 }
1190 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1191
1192 /* Change source address */
1193 accumulate = twowords(&pip->ip_src);
1194 pip->ip_src = alias_address;
1195 accumulate -= twowords(&pip->ip_src);
1196 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1197
1198 return (PKT_ALIAS_OK);
1199 }
1200 }
1201
1202 /* Fragment Handling
1203
1204 FragmentIn()
1205 FragmentOut()
1206
1207 The packet aliasing module has a limited ability for handling IP
1208 fragments. If the ICMP, TCP or UDP header is in the first fragment
1209 received, then the ID number of the IP packet is saved, and other
1210 fragments are identified according to their ID number and IP address
1211 they were sent from. Pointers to unresolved fragments can also be
1212 saved and recalled when a header fragment is seen.
1213 */
1214
1215 /* Local prototypes */
1216 static int FragmentIn(struct libalias *la, struct in_addr ip_src,
1217 struct ip *pip, u_short ip_id, u_short *ip_sum);
1218 static int FragmentOut(struct libalias *, struct ip *pip,
1219 u_short *ip_sum);
1220
1221 static int
FragmentIn(struct libalias * la,struct in_addr ip_src,struct ip * pip,u_short ip_id,u_short * ip_sum)1222 FragmentIn(struct libalias *la, struct in_addr ip_src, struct ip *pip,
1223 u_short ip_id, u_short *ip_sum)
1224 {
1225 struct alias_link *lnk;
1226
1227 LIBALIAS_LOCK_ASSERT(la);
1228 lnk = FindFragmentIn2(la, ip_src, pip->ip_dst, ip_id);
1229 if (lnk != NULL) {
1230 struct in_addr original_address;
1231
1232 GetFragmentAddr(lnk, &original_address);
1233 DifferentialChecksum(ip_sum,
1234 &original_address, &pip->ip_dst, 2);
1235 pip->ip_dst = original_address;
1236
1237 return (PKT_ALIAS_OK);
1238 }
1239 return (PKT_ALIAS_UNRESOLVED_FRAGMENT);
1240 }
1241
1242 static int
FragmentOut(struct libalias * la,struct ip * pip,u_short * ip_sum)1243 FragmentOut(struct libalias *la, struct ip *pip, u_short *ip_sum)
1244 {
1245 struct in_addr alias_address;
1246
1247 LIBALIAS_LOCK_ASSERT(la);
1248 alias_address = FindAliasAddress(la, pip->ip_src);
1249 DifferentialChecksum(ip_sum,
1250 &alias_address, &pip->ip_src, 2);
1251 pip->ip_src = alias_address;
1252
1253 return (PKT_ALIAS_OK);
1254 }
1255
1256 /* Outside World Access
1257
1258 PacketAliasSaveFragment()
1259 PacketAliasGetFragment()
1260 PacketAliasFragmentIn()
1261 PacketAliasIn()
1262 PacketAliasOut()
1263 PacketUnaliasOut()
1264
1265 (prototypes in alias.h)
1266 */
1267
1268 int
LibAliasSaveFragment(struct libalias * la,void * ptr)1269 LibAliasSaveFragment(struct libalias *la, void *ptr)
1270 {
1271 int iresult;
1272 struct alias_link *lnk;
1273 struct ip *pip;
1274
1275 LIBALIAS_LOCK(la);
1276 pip = (struct ip *)ptr;
1277 lnk = AddFragmentPtrLink(la, pip->ip_src, pip->ip_id);
1278 iresult = PKT_ALIAS_ERROR;
1279 if (lnk != NULL) {
1280 SetFragmentPtr(lnk, ptr);
1281 iresult = PKT_ALIAS_OK;
1282 }
1283 LIBALIAS_UNLOCK(la);
1284 return (iresult);
1285 }
1286
1287 void *
LibAliasGetFragment(struct libalias * la,void * ptr)1288 LibAliasGetFragment(struct libalias *la, void *ptr)
1289 {
1290 struct alias_link *lnk;
1291 void *fptr;
1292 struct ip *pip;
1293
1294 LIBALIAS_LOCK(la);
1295 pip = (struct ip *)ptr;
1296 lnk = FindFragmentPtr(la, pip->ip_src, pip->ip_id);
1297 if (lnk != NULL) {
1298 GetFragmentPtr(lnk, &fptr);
1299 SetFragmentPtr(lnk, NULL);
1300 SetExpire(lnk, 0); /* Deletes link */
1301 } else
1302 fptr = NULL;
1303
1304 LIBALIAS_UNLOCK(la);
1305 return (fptr);
1306 }
1307
1308 void
LibAliasFragmentIn(struct libalias * la,void * ptr,void * ptr_fragment)1309 LibAliasFragmentIn(struct libalias *la,
1310 void *ptr, /* Points to correctly de-aliased header fragment */
1311 void *ptr_fragment /* fragment which must be de-aliased */
1312 )
1313 {
1314 struct ip *pip;
1315 struct ip *fpip;
1316
1317 LIBALIAS_LOCK(la);
1318 (void)la;
1319 pip = (struct ip *)ptr;
1320 fpip = (struct ip *)ptr_fragment;
1321
1322 DifferentialChecksum(&fpip->ip_sum,
1323 &pip->ip_dst, &fpip->ip_dst, 2);
1324 fpip->ip_dst = pip->ip_dst;
1325 LIBALIAS_UNLOCK(la);
1326 }
1327
1328 /* Local prototypes */
1329 static int
1330 LibAliasOutLocked(struct libalias *la, struct ip *pip,
1331 int maxpacketsize, int create);
1332 static int
1333 LibAliasInLocked(struct libalias *la, struct ip *pip,
1334 int maxpacketsize);
1335
1336 int
LibAliasIn(struct libalias * la,void * ptr,int maxpacketsize)1337 LibAliasIn(struct libalias *la, void *ptr, int maxpacketsize)
1338 {
1339 int res;
1340
1341 LIBALIAS_LOCK(la);
1342 res = LibAliasInLocked(la, (struct ip *)ptr, maxpacketsize);
1343 LIBALIAS_UNLOCK(la);
1344 return (res);
1345 }
1346
1347 static int
LibAliasInLocked(struct libalias * la,struct ip * pip,int maxpacketsize)1348 LibAliasInLocked(struct libalias *la, struct ip *pip, int maxpacketsize)
1349 {
1350 struct in_addr alias_addr;
1351 int iresult;
1352
1353 if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1354 la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1355 iresult = LibAliasOutLocked(la, pip, maxpacketsize, 1);
1356 la->packetAliasMode |= PKT_ALIAS_REVERSE;
1357 goto getout;
1358 }
1359 HouseKeeping(la);
1360 alias_addr = pip->ip_dst;
1361
1362 /* Defense against mangled packets */
1363 if (ntohs(pip->ip_len) > maxpacketsize
1364 || (pip->ip_hl << 2) > maxpacketsize) {
1365 iresult = PKT_ALIAS_IGNORED;
1366 goto getout;
1367 }
1368
1369 if (FRAG_NO_HDR(pip)) {
1370 iresult = FragmentIn(la, pip->ip_src, pip, pip->ip_id,
1371 &pip->ip_sum);
1372 goto getout;
1373 }
1374
1375 iresult = PKT_ALIAS_IGNORED;
1376 switch (pip->ip_p) {
1377 case IPPROTO_ICMP:
1378 iresult = IcmpAliasIn(la, pip);
1379 break;
1380 case IPPROTO_UDP:
1381 iresult = UdpAliasIn(la, pip);
1382 break;
1383 case IPPROTO_TCP:
1384 iresult = TcpAliasIn(la, pip);
1385 break;
1386 #ifdef _KERNEL
1387 case IPPROTO_SCTP:
1388 iresult = SctpAlias(la, pip, SN_TO_LOCAL);
1389 break;
1390 #endif
1391 case IPPROTO_GRE: {
1392 int error;
1393 struct alias_data ad = {
1394 .lnk = NULL,
1395 .oaddr = NULL,
1396 .aaddr = NULL,
1397 .aport = NULL,
1398 .sport = NULL,
1399 .dport = NULL,
1400 .maxpktsize = 0
1401 };
1402
1403 /* Walk out chain. */
1404 error = find_handler(IN, IP, la, pip, &ad);
1405 if (error == 0)
1406 iresult = PKT_ALIAS_OK;
1407 else
1408 iresult = ProtoAliasIn(la, pip->ip_src,
1409 pip, pip->ip_p, &pip->ip_sum);
1410 break;
1411 }
1412 default:
1413 iresult = ProtoAliasIn(la, pip->ip_src, pip,
1414 pip->ip_p, &pip->ip_sum);
1415 break;
1416 }
1417
1418 if (MF_ISSET(pip)) {
1419 struct alias_link *lnk;
1420
1421 lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id);
1422 if (lnk != NULL) {
1423 iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
1424 SetFragmentAddr(lnk, pip->ip_dst);
1425 } else {
1426 iresult = PKT_ALIAS_ERROR;
1427 }
1428 }
1429
1430 getout:
1431 return (iresult);
1432 }
1433
1434 /* Unregistered address ranges */
1435
1436 /* 10.0.0.0 -> 10.255.255.255 */
1437 #define UNREG_ADDR_A_LOWER 0x0a000000
1438 #define UNREG_ADDR_A_UPPER 0x0affffff
1439
1440 /* 172.16.0.0 -> 172.31.255.255 */
1441 #define UNREG_ADDR_B_LOWER 0xac100000
1442 #define UNREG_ADDR_B_UPPER 0xac1fffff
1443
1444 /* 192.168.0.0 -> 192.168.255.255 */
1445 #define UNREG_ADDR_C_LOWER 0xc0a80000
1446 #define UNREG_ADDR_C_UPPER 0xc0a8ffff
1447
1448 /* 100.64.0.0 -> 100.127.255.255 (RFC 6598 - Carrier Grade NAT) */
1449 #define UNREG_ADDR_CGN_LOWER 0x64400000
1450 #define UNREG_ADDR_CGN_UPPER 0x647fffff
1451
1452 int
LibAliasOut(struct libalias * la,void * ptr,int maxpacketsize)1453 LibAliasOut(struct libalias *la, void *ptr, int maxpacketsize)
1454 {
1455 int res;
1456
1457 LIBALIAS_LOCK(la);
1458 res = LibAliasOutLocked(la, (struct ip *)ptr, maxpacketsize, 1);
1459 LIBALIAS_UNLOCK(la);
1460 return (res);
1461 }
1462
1463 int
LibAliasOutTry(struct libalias * la,void * ptr,int maxpacketsize,int create)1464 LibAliasOutTry(struct libalias *la, void *ptr, int maxpacketsize, int create)
1465 {
1466 int res;
1467
1468 LIBALIAS_LOCK(la);
1469 res = LibAliasOutLocked(la, (struct ip *)ptr, maxpacketsize, create);
1470 LIBALIAS_UNLOCK(la);
1471 return (res);
1472 }
1473
1474 static int
LibAliasOutLocked(struct libalias * la,struct ip * pip,int maxpacketsize,int create)1475 LibAliasOutLocked(struct libalias *la,
1476 struct ip *pip, /* valid IP packet */
1477 int maxpacketsize, /* How much the packet data may grow (FTP and IRC inline changes) */
1478 int create /* Create new entries ? */
1479 )
1480 {
1481 int iresult;
1482 struct in_addr addr_save;
1483
1484 if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1485 la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1486 iresult = LibAliasInLocked(la, pip, maxpacketsize);
1487 la->packetAliasMode |= PKT_ALIAS_REVERSE;
1488 goto getout;
1489 }
1490 HouseKeeping(la);
1491
1492 /* Defense against mangled packets */
1493 if (ntohs(pip->ip_len) > maxpacketsize
1494 || (pip->ip_hl << 2) > maxpacketsize) {
1495 iresult = PKT_ALIAS_IGNORED;
1496 goto getout;
1497 }
1498
1499 addr_save = GetDefaultAliasAddress(la);
1500 if (la->packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY ||
1501 la->packetAliasMode & PKT_ALIAS_UNREGISTERED_CGN) {
1502 u_long addr;
1503 int iclass;
1504
1505 iclass = 0;
1506 addr = ntohl(pip->ip_src.s_addr);
1507 if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER)
1508 iclass = 3;
1509 else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER)
1510 iclass = 2;
1511 else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER)
1512 iclass = 1;
1513 else if (addr >= UNREG_ADDR_CGN_LOWER && addr <= UNREG_ADDR_CGN_UPPER &&
1514 la->packetAliasMode & PKT_ALIAS_UNREGISTERED_CGN)
1515 iclass = 4;
1516
1517 if (iclass == 0) {
1518 SetDefaultAliasAddress(la, pip->ip_src);
1519 }
1520 } else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) {
1521 SetDefaultAliasAddress(la, pip->ip_src);
1522 }
1523
1524 if (FRAG_NO_HDR(pip)) {
1525 iresult = FragmentOut(la, pip, &pip->ip_sum);
1526 goto getout_restore;
1527 }
1528
1529 iresult = PKT_ALIAS_IGNORED;
1530 switch (pip->ip_p) {
1531 case IPPROTO_ICMP:
1532 iresult = IcmpAliasOut(la, pip, create);
1533 break;
1534 case IPPROTO_UDP:
1535 iresult = UdpAliasOut(la, pip, maxpacketsize, create);
1536 break;
1537 case IPPROTO_TCP:
1538 iresult = TcpAliasOut(la, pip, maxpacketsize, create);
1539 break;
1540 #ifdef _KERNEL
1541 case IPPROTO_SCTP:
1542 iresult = SctpAlias(la, pip, SN_TO_GLOBAL);
1543 break;
1544 #endif
1545 case IPPROTO_GRE: {
1546 int error;
1547 struct alias_data ad = {
1548 .lnk = NULL,
1549 .oaddr = NULL,
1550 .aaddr = NULL,
1551 .aport = NULL,
1552 .sport = NULL,
1553 .dport = NULL,
1554 .maxpktsize = 0
1555 };
1556 /* Walk out chain. */
1557 error = find_handler(OUT, IP, la, pip, &ad);
1558 if (error == 0)
1559 iresult = PKT_ALIAS_OK;
1560 else
1561 iresult = ProtoAliasOut(la, pip,
1562 pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
1563 break;
1564 }
1565 default:
1566 iresult = ProtoAliasOut(la, pip,
1567 pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
1568 break;
1569 }
1570
1571 getout_restore:
1572 SetDefaultAliasAddress(la, addr_save);
1573 getout:
1574 return (iresult);
1575 }
1576
1577 int
LibAliasUnaliasOut(struct libalias * la,void * ptr,int maxpacketsize)1578 LibAliasUnaliasOut(struct libalias *la,
1579 void *ptr, /* valid IP packet */
1580 int maxpacketsize /* for error checking */
1581 )
1582 {
1583 struct ip *pip;
1584 struct icmp *ic;
1585 struct udphdr *ud;
1586 struct tcphdr *tc;
1587 struct alias_link *lnk;
1588 int iresult = PKT_ALIAS_IGNORED;
1589
1590 LIBALIAS_LOCK(la);
1591 pip = (struct ip *)ptr;
1592
1593 /* Defense against mangled packets */
1594 if (ntohs(pip->ip_len) > maxpacketsize
1595 || (pip->ip_hl << 2) > maxpacketsize)
1596 goto getout;
1597
1598 ud = (struct udphdr *)ip_next(pip);
1599 tc = (struct tcphdr *)ip_next(pip);
1600 ic = (struct icmp *)ip_next(pip);
1601
1602 /* Find a link */
1603 if (pip->ip_p == IPPROTO_UDP) {
1604 iresult = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1605 ud->uh_dport, ud->uh_sport,
1606 IPPROTO_UDP, 0, &lnk);
1607 if (iresult != PKT_ALIAS_OK)
1608 goto getout;
1609 } else if (pip->ip_p == IPPROTO_TCP) {
1610 iresult = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1611 tc->th_dport, tc->th_sport,
1612 IPPROTO_TCP, 0, &lnk);
1613 if (iresult != PKT_ALIAS_OK)
1614 goto getout;
1615 } else if (pip->ip_p == IPPROTO_ICMP) {
1616 iresult = FindIcmpIn(la, pip->ip_dst, pip->ip_src,
1617 ic->icmp_id, 0, &lnk);
1618 if (iresult != PKT_ALIAS_OK)
1619 goto getout;
1620 } else
1621 lnk = NULL;
1622
1623 /* Change it from an aliased packet to an unaliased packet */
1624 if (lnk != NULL) {
1625 if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP) {
1626 int accumulate;
1627 struct in_addr original_address;
1628 u_short original_port;
1629
1630 original_address = GetOriginalAddress(lnk);
1631 original_port = GetOriginalPort(lnk);
1632
1633 /* Adjust TCP/UDP checksum */
1634 accumulate = twowords(&pip->ip_src);
1635 accumulate -= twowords(&original_address);
1636
1637 if (pip->ip_p == IPPROTO_UDP) {
1638 accumulate += ud->uh_sport;
1639 accumulate -= original_port;
1640 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
1641 } else {
1642 accumulate += tc->th_sport;
1643 accumulate -= original_port;
1644 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1645 }
1646
1647 /* Adjust IP checksum */
1648 DifferentialChecksum(&pip->ip_sum,
1649 &original_address, &pip->ip_src, 2);
1650
1651 /* Un-alias source address and port number */
1652 pip->ip_src = original_address;
1653 if (pip->ip_p == IPPROTO_UDP)
1654 ud->uh_sport = original_port;
1655 else
1656 tc->th_sport = original_port;
1657
1658 iresult = PKT_ALIAS_OK;
1659 } else if (pip->ip_p == IPPROTO_ICMP) {
1660 int accumulate;
1661 struct in_addr original_address;
1662 u_short original_id;
1663
1664 original_address = GetOriginalAddress(lnk);
1665 original_id = GetOriginalPort(lnk);
1666
1667 /* Adjust ICMP checksum */
1668 accumulate = twowords(&pip->ip_src);
1669 accumulate -= twowords(&original_address);
1670 accumulate += ic->icmp_id;
1671 accumulate -= original_id;
1672 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
1673
1674 /* Adjust IP checksum */
1675 DifferentialChecksum(&pip->ip_sum,
1676 &original_address, &pip->ip_src, 2);
1677
1678 /* Un-alias source address and port number */
1679 pip->ip_src = original_address;
1680 ic->icmp_id = original_id;
1681
1682 iresult = PKT_ALIAS_OK;
1683 }
1684 }
1685 getout:
1686 LIBALIAS_UNLOCK(la);
1687 return (iresult);
1688 }
1689
1690 #ifndef _KERNEL
1691
1692 int
LibAliasRefreshModules(void)1693 LibAliasRefreshModules(void)
1694 {
1695 char buf[256], conf[] = "/etc/libalias.conf";
1696 FILE *fd;
1697 int i, len;
1698
1699 fd = fopen(conf, "r");
1700 if (fd == NULL)
1701 err(1, "fopen(%s)", conf);
1702
1703 LibAliasUnLoadAllModule();
1704
1705 for (;;) {
1706 fgets(buf, 256, fd);
1707 if (feof(fd))
1708 break;
1709 len = strlen(buf);
1710 if (len > 1) {
1711 for (i = 0; i < len; i++)
1712 if (!isspace(buf[i]))
1713 break;
1714 if (buf[i] == '#')
1715 continue;
1716 buf[len - 1] = '\0';
1717 LibAliasLoadModule(buf);
1718 }
1719 }
1720 fclose(fd);
1721 return (0);
1722 }
1723
1724 int
LibAliasLoadModule(char * path)1725 LibAliasLoadModule(char *path)
1726 {
1727 struct dll *t;
1728 void *handle;
1729 struct proto_handler *m;
1730 const char *error;
1731 moduledata_t *p;
1732
1733 handle = dlopen (path, RTLD_LAZY);
1734 if (!handle) {
1735 fprintf(stderr, "%s\n", dlerror());
1736 return (EINVAL);
1737 }
1738
1739 p = dlsym(handle, "alias_mod");
1740 if ((error = dlerror()) != NULL) {
1741 fprintf(stderr, "%s\n", dlerror());
1742 return (EINVAL);
1743 }
1744
1745 t = malloc(sizeof(struct dll));
1746 if (t == NULL)
1747 return (ENOMEM);
1748 strncpy(t->name, p->name, DLL_LEN);
1749 t->handle = handle;
1750 if (attach_dll(t) == EEXIST) {
1751 free(t);
1752 fprintf(stderr, "dll conflict\n");
1753 return (EEXIST);
1754 }
1755
1756 m = dlsym(t->handle, "handlers");
1757 if ((error = dlerror()) != NULL) {
1758 fprintf(stderr, "%s\n", error);
1759 return (EINVAL);
1760 }
1761
1762 LibAliasAttachHandlers(m);
1763 return (0);
1764 }
1765
1766 int
LibAliasUnLoadAllModule(void)1767 LibAliasUnLoadAllModule(void)
1768 {
1769 struct dll *t;
1770 struct proto_handler *p;
1771
1772 /* Unload all modules then reload everything. */
1773 while ((p = first_handler()) != NULL) {
1774 LibAliasDetachHandlers(p);
1775 }
1776 while ((t = walk_dll_chain()) != NULL) {
1777 dlclose(t->handle);
1778 free(t);
1779 }
1780 return (1);
1781 }
1782
1783 #endif
1784
1785 #ifdef _KERNEL
1786 /*
1787 * m_megapullup() - this function is a big hack.
1788 * Thankfully, it's only used in ng_nat and ipfw+nat.
1789 *
1790 * It allocates an mbuf with cluster and copies the specified part of the chain
1791 * into cluster, so that it is all contiguous and can be accessed via a plain
1792 * (char *) pointer. This is required, because libalias doesn't know how to
1793 * handle mbuf chains.
1794 *
1795 * On success, m_megapullup returns an mbuf (possibly with cluster) containing
1796 * the input packet, on failure NULL. The input packet is always consumed.
1797 */
1798 struct mbuf *
m_megapullup(struct mbuf * m,int len)1799 m_megapullup(struct mbuf *m, int len)
1800 {
1801 struct mbuf *mcl;
1802
1803 if (len > m->m_pkthdr.len)
1804 goto bad;
1805
1806 if (m->m_next == NULL && M_WRITABLE(m))
1807 return (m);
1808
1809 if (len <= MJUMPAGESIZE)
1810 mcl = m_get2(len, M_NOWAIT, MT_DATA, M_PKTHDR);
1811 else if (len <= MJUM9BYTES)
1812 mcl = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES);
1813 else if (len <= MJUM16BYTES)
1814 mcl = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM16BYTES);
1815 else
1816 goto bad;
1817 if (mcl == NULL)
1818 goto bad;
1819 m_align(mcl, len);
1820 m_move_pkthdr(mcl, m);
1821 m_copydata(m, 0, len, mtod(mcl, caddr_t));
1822 mcl->m_len = mcl->m_pkthdr.len = len;
1823 m_freem(m);
1824
1825 return (mcl);
1826 bad:
1827 m_freem(m);
1828 return (NULL);
1829 }
1830 #endif
1831