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