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(u_char, struct alias_link *);
187
188 static void TcpMonitorOut(u_char, struct alias_link *);
189
190 static void
TcpMonitorIn(u_char th_flags,struct alias_link * lnk)191 TcpMonitorIn(u_char 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(u_char th_flags,struct alias_link * lnk)208 TcpMonitorOut(u_char 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
294 LIBALIAS_LOCK_ASSERT(la);
295 ic = (struct icmp *)ip_next(pip);
296
297 /* Get source address from ICMP data field and restore original data */
298 lnk = FindIcmpIn(la, pip->ip_src, pip->ip_dst, ic->icmp_id, 1);
299 if (lnk != NULL) {
300 u_short original_id;
301 int accumulate;
302
303 original_id = GetOriginalPort(lnk);
304
305 /* Adjust ICMP checksum */
306 accumulate = ic->icmp_id;
307 accumulate -= original_id;
308 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
309
310 /* Put original sequence number back in */
311 ic->icmp_id = original_id;
312
313 /* Put original address back into IP header */
314 {
315 struct in_addr original_address;
316
317 original_address = GetOriginalAddress(lnk);
318 DifferentialChecksum(&pip->ip_sum,
319 &original_address, &pip->ip_dst, 2);
320 pip->ip_dst = original_address;
321 }
322
323 return (PKT_ALIAS_OK);
324 }
325 return (PKT_ALIAS_IGNORED);
326 }
327
328 /*
329 Alias incoming ICMP error messages containing
330 IP header and first 64 bits of datagram.
331 */
332 static int
IcmpAliasIn2(struct libalias * la,struct ip * pip)333 IcmpAliasIn2(struct libalias *la, struct ip *pip)
334 {
335 struct ip *ip;
336 struct icmp *ic, *ic2;
337 struct udphdr *ud;
338 struct tcphdr *tc;
339 struct alias_link *lnk;
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 lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
351 ud->uh_dport, ud->uh_sport,
352 IPPROTO_UDP, 0);
353 else if (ip->ip_p == IPPROTO_TCP)
354 lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
355 tc->th_dport, tc->th_sport,
356 IPPROTO_TCP, 0);
357 else if (ip->ip_p == IPPROTO_ICMP) {
358 if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
359 lnk = FindIcmpIn(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
360 else
361 lnk = NULL;
362 } else
363 lnk = NULL;
364
365 if (lnk != NULL) {
366 if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
367 int accumulate, accumulate2;
368 struct in_addr original_address;
369 u_short original_port;
370
371 original_address = GetOriginalAddress(lnk);
372 original_port = GetOriginalPort(lnk);
373
374 /* Adjust ICMP checksum */
375 accumulate = twowords(&ip->ip_src);
376 accumulate -= twowords(&original_address);
377 accumulate += ud->uh_sport;
378 accumulate -= original_port;
379 accumulate2 = accumulate;
380 accumulate2 += ip->ip_sum;
381 ADJUST_CHECKSUM(accumulate, ip->ip_sum);
382 accumulate2 -= ip->ip_sum;
383 ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum);
384
385 /* Un-alias address in IP header */
386 DifferentialChecksum(&pip->ip_sum,
387 &original_address, &pip->ip_dst, 2);
388 pip->ip_dst = original_address;
389
390 /* Un-alias address and port number of
391 * original IP packet fragment contained
392 * in ICMP data section */
393 ip->ip_src = original_address;
394 ud->uh_sport = original_port;
395 } else if (ip->ip_p == IPPROTO_ICMP) {
396 int accumulate, accumulate2;
397 struct in_addr original_address;
398 u_short original_id;
399
400 original_address = GetOriginalAddress(lnk);
401 original_id = GetOriginalPort(lnk);
402
403 /* Adjust ICMP checksum */
404 accumulate = twowords(&ip->ip_src);
405 accumulate -= twowords(&original_address);
406 accumulate += ic2->icmp_id;
407 accumulate -= original_id;
408 accumulate2 = accumulate;
409 accumulate2 += ip->ip_sum;
410 ADJUST_CHECKSUM(accumulate, ip->ip_sum);
411 accumulate2 -= ip->ip_sum;
412 ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum);
413
414 /* Un-alias address in IP header */
415 DifferentialChecksum(&pip->ip_sum,
416 &original_address, &pip->ip_dst, 2);
417 pip->ip_dst = original_address;
418
419 /* Un-alias address of original IP packet and
420 * sequence number of embedded ICMP datagram */
421 ip->ip_src = original_address;
422 ic2->icmp_id = original_id;
423 }
424 return (PKT_ALIAS_OK);
425 }
426 return (PKT_ALIAS_IGNORED);
427 }
428
429 static int
IcmpAliasIn(struct libalias * la,struct ip * pip)430 IcmpAliasIn(struct libalias *la, struct ip *pip)
431 {
432 struct icmp *ic;
433 int iresult;
434 size_t dlen;
435
436 LIBALIAS_LOCK_ASSERT(la);
437
438 dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
439 if (dlen < ICMP_MINLEN)
440 return (PKT_ALIAS_IGNORED);
441
442 /* Return if proxy-only mode is enabled */
443 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
444 return (PKT_ALIAS_OK);
445
446 ic = (struct icmp *)ip_next(pip);
447
448 iresult = PKT_ALIAS_IGNORED;
449 switch (ic->icmp_type) {
450 case ICMP_ECHOREPLY:
451 case ICMP_TSTAMPREPLY:
452 if (ic->icmp_code == 0) {
453 iresult = IcmpAliasIn1(la, pip);
454 }
455 break;
456 case ICMP_UNREACH:
457 case ICMP_SOURCEQUENCH:
458 case ICMP_TIMXCEED:
459 case ICMP_PARAMPROB:
460 if (dlen < ICMP_ADVLENMIN ||
461 dlen < (size_t)ICMP_ADVLEN(ic))
462 return (PKT_ALIAS_IGNORED);
463 iresult = IcmpAliasIn2(la, pip);
464 break;
465 case ICMP_ECHO:
466 case ICMP_TSTAMP:
467 iresult = IcmpAliasIn1(la, pip);
468 break;
469 }
470 return (iresult);
471 }
472
473 /*
474 Alias outgoing echo and timestamp requests.
475 De-alias outgoing echo and timestamp replies.
476 */
477 static int
IcmpAliasOut1(struct libalias * la,struct ip * pip,int create)478 IcmpAliasOut1(struct libalias *la, struct ip *pip, int create)
479 {
480 struct alias_link *lnk;
481 struct icmp *ic;
482
483 LIBALIAS_LOCK_ASSERT(la);
484 ic = (struct icmp *)ip_next(pip);
485
486 /* Save overwritten data for when echo packet returns */
487 lnk = FindIcmpOut(la, pip->ip_src, pip->ip_dst, ic->icmp_id, create);
488 if (lnk != NULL) {
489 u_short alias_id;
490 int accumulate;
491
492 alias_id = GetAliasPort(lnk);
493
494 /* Since data field is being modified, adjust ICMP checksum */
495 accumulate = ic->icmp_id;
496 accumulate -= alias_id;
497 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
498
499 /* Alias sequence number */
500 ic->icmp_id = alias_id;
501
502 /* Change source address */
503 {
504 struct in_addr alias_address;
505
506 alias_address = GetAliasAddress(lnk);
507 DifferentialChecksum(&pip->ip_sum,
508 &alias_address, &pip->ip_src, 2);
509 pip->ip_src = alias_address;
510 }
511
512 return (PKT_ALIAS_OK);
513 }
514 return (PKT_ALIAS_IGNORED);
515 }
516
517 /*
518 Alias outgoing ICMP error messages containing
519 IP header and first 64 bits of datagram.
520 */
521 static int
IcmpAliasOut2(struct libalias * la,struct ip * pip)522 IcmpAliasOut2(struct libalias *la, struct ip *pip)
523 {
524 struct ip *ip;
525 struct icmp *ic, *ic2;
526 struct udphdr *ud;
527 struct tcphdr *tc;
528 struct alias_link *lnk;
529
530 LIBALIAS_LOCK_ASSERT(la);
531 ic = (struct icmp *)ip_next(pip);
532 ip = &ic->icmp_ip;
533
534 ud = (struct udphdr *)ip_next(ip);
535 tc = (struct tcphdr *)ip_next(ip);
536 ic2 = (struct icmp *)ip_next(ip);
537
538 if (ip->ip_p == IPPROTO_UDP)
539 lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
540 ud->uh_dport, ud->uh_sport,
541 IPPROTO_UDP, 0);
542 else if (ip->ip_p == IPPROTO_TCP)
543 lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
544 tc->th_dport, tc->th_sport,
545 IPPROTO_TCP, 0);
546 else if (ip->ip_p == IPPROTO_ICMP) {
547 if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
548 lnk = FindIcmpOut(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
549 else
550 lnk = NULL;
551 } else
552 lnk = NULL;
553
554 if (lnk != NULL) {
555 if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
556 int accumulate;
557 struct in_addr alias_address;
558 u_short alias_port;
559
560 alias_address = GetAliasAddress(lnk);
561 alias_port = GetAliasPort(lnk);
562
563 /* Adjust ICMP checksum */
564 accumulate = twowords(&ip->ip_dst);
565 accumulate -= twowords(&alias_address);
566 accumulate += ud->uh_dport;
567 accumulate -= alias_port;
568 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
569
570 /*
571 * Alias address in IP header if it comes from the host
572 * the original TCP/UDP packet was destined for.
573 */
574 if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
575 DifferentialChecksum(&pip->ip_sum,
576 &alias_address, &pip->ip_src, 2);
577 pip->ip_src = alias_address;
578 }
579 /* Alias address and port number of original IP packet
580 * fragment contained in ICMP data section */
581 ip->ip_dst = alias_address;
582 ud->uh_dport = alias_port;
583 } else if (ip->ip_p == IPPROTO_ICMP) {
584 int accumulate;
585 struct in_addr alias_address;
586 u_short alias_id;
587
588 alias_address = GetAliasAddress(lnk);
589 alias_id = GetAliasPort(lnk);
590
591 /* Adjust ICMP checksum */
592 accumulate = twowords(&ip->ip_dst);
593 accumulate -= twowords(&alias_address);
594 accumulate += ic2->icmp_id;
595 accumulate -= alias_id;
596 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
597
598 /*
599 * Alias address in IP header if it comes from the host
600 * the original ICMP message was destined for.
601 */
602 if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
603 DifferentialChecksum(&pip->ip_sum,
604 &alias_address, &pip->ip_src, 2);
605 pip->ip_src = alias_address;
606 }
607 /* Alias address of original IP packet and
608 * sequence number of embedded ICMP datagram */
609 ip->ip_dst = alias_address;
610 ic2->icmp_id = alias_id;
611 }
612 return (PKT_ALIAS_OK);
613 }
614 return (PKT_ALIAS_IGNORED);
615 }
616
617 static int
IcmpAliasOut(struct libalias * la,struct ip * pip,int create)618 IcmpAliasOut(struct libalias *la, struct ip *pip, int create)
619 {
620 int iresult;
621 struct icmp *ic;
622
623 LIBALIAS_LOCK_ASSERT(la);
624 (void)create;
625
626 /* Return if proxy-only mode is enabled */
627 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
628 return (PKT_ALIAS_OK);
629
630 ic = (struct icmp *)ip_next(pip);
631
632 iresult = PKT_ALIAS_IGNORED;
633 switch (ic->icmp_type) {
634 case ICMP_ECHO:
635 case ICMP_TSTAMP:
636 if (ic->icmp_code == 0) {
637 iresult = IcmpAliasOut1(la, pip, create);
638 }
639 break;
640 case ICMP_UNREACH:
641 case ICMP_SOURCEQUENCH:
642 case ICMP_TIMXCEED:
643 case ICMP_PARAMPROB:
644 iresult = IcmpAliasOut2(la, pip);
645 break;
646 case ICMP_ECHOREPLY:
647 case ICMP_TSTAMPREPLY:
648 iresult = IcmpAliasOut1(la, pip, create);
649 }
650 return (iresult);
651 }
652
653 /*
654 Handle incoming IP packets. The
655 only thing which is done in this case is to alias
656 the dest IP address of the packet to our inside
657 machine.
658 */
659 static int
ProtoAliasIn(struct libalias * la,struct in_addr ip_src,struct ip * pip,u_char ip_p,u_short * ip_sum)660 ProtoAliasIn(struct libalias *la, struct in_addr ip_src,
661 struct ip *pip, u_char ip_p, u_short *ip_sum)
662 {
663 struct alias_link *lnk;
664
665 LIBALIAS_LOCK_ASSERT(la);
666 /* Return if proxy-only mode is enabled */
667 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
668 return (PKT_ALIAS_OK);
669
670 lnk = FindProtoIn(la, ip_src, pip->ip_dst, ip_p);
671 if (lnk != NULL) {
672 struct in_addr original_address;
673
674 original_address = GetOriginalAddress(lnk);
675
676 /* Restore original IP address */
677 DifferentialChecksum(ip_sum,
678 &original_address, &pip->ip_dst, 2);
679 pip->ip_dst = original_address;
680
681 return (PKT_ALIAS_OK);
682 }
683 return (PKT_ALIAS_IGNORED);
684 }
685
686 /*
687 Handle outgoing IP packets. The
688 only thing which is done in this case is to alias
689 the source IP address of the packet.
690 */
691 static int
ProtoAliasOut(struct libalias * la,struct ip * pip,struct in_addr ip_dst,u_char ip_p,u_short * ip_sum,int create)692 ProtoAliasOut(struct libalias *la, struct ip *pip,
693 struct in_addr ip_dst, u_char ip_p, u_short *ip_sum, int create)
694 {
695 struct alias_link *lnk;
696
697 LIBALIAS_LOCK_ASSERT(la);
698
699 /* Return if proxy-only mode is enabled */
700 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
701 return (PKT_ALIAS_OK);
702
703 if (!create)
704 return (PKT_ALIAS_IGNORED);
705
706 lnk = FindProtoOut(la, pip->ip_src, ip_dst, ip_p);
707 if (lnk != NULL) {
708 struct in_addr alias_address;
709
710 alias_address = GetAliasAddress(lnk);
711
712 /* Change source address */
713 DifferentialChecksum(ip_sum,
714 &alias_address, &pip->ip_src, 2);
715 pip->ip_src = alias_address;
716
717 return (PKT_ALIAS_OK);
718 }
719 return (PKT_ALIAS_IGNORED);
720 }
721
722 #define MF_ISSET(_pip) (ntohs((_pip)->ip_off) & IP_MF)
723 #define FRAG_NO_HDR(_pip) (ntohs((_pip)->ip_off) & IP_OFFMASK)
724
725 static struct udphdr *
ValidateUdpLength(struct ip * pip)726 ValidateUdpLength(struct ip *pip)
727 {
728 struct udphdr *ud;
729 size_t dlen;
730
731 #ifdef _KERNEL
732 KASSERT(!FRAG_NO_HDR(pip), ("header-less fragment isn't expected here"));
733 #endif
734 dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
735 if (dlen < sizeof(struct udphdr))
736 return (NULL);
737 ud = (struct udphdr *)ip_next(pip);
738 if (!MF_ISSET(pip) && dlen < ntohs(ud->uh_ulen))
739 return (NULL);
740 return (ud);
741 }
742
743 static int
UdpAliasIn(struct libalias * la,struct ip * pip)744 UdpAliasIn(struct libalias *la, struct ip *pip)
745 {
746 struct udphdr *ud;
747 struct alias_link *lnk;
748
749 LIBALIAS_LOCK_ASSERT(la);
750
751 ud = ValidateUdpLength(pip);
752 if (ud == NULL)
753 return (PKT_ALIAS_IGNORED);
754
755 lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
756 ud->uh_sport, ud->uh_dport,
757 IPPROTO_UDP, !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
758 if (lnk != NULL) {
759 struct in_addr alias_address;
760 struct in_addr original_address;
761 struct in_addr proxy_address;
762 u_short alias_port;
763 u_short proxy_port;
764 int accumulate;
765 int error;
766 struct alias_data ad = {
767 .lnk = lnk,
768 .oaddr = &original_address,
769 .aaddr = &alias_address,
770 .aport = &alias_port,
771 .sport = &ud->uh_sport,
772 .dport = &ud->uh_dport,
773 .maxpktsize = 0
774 };
775
776 alias_address = GetAliasAddress(lnk);
777 original_address = GetOriginalAddress(lnk);
778 proxy_address = GetProxyAddress(lnk);
779 alias_port = ud->uh_dport;
780 ud->uh_dport = GetOriginalPort(lnk);
781 proxy_port = GetProxyPort(lnk);
782
783 /* Walk out chain. */
784 error = find_handler(IN, UDP, la, pip, &ad);
785 /* If we cannot figure out the packet, ignore it. */
786 if (error < 0)
787 return (PKT_ALIAS_IGNORED);
788
789 /* If UDP checksum is not zero, then adjust since
790 * destination port is being unaliased and
791 * destination address is being altered. */
792 if (ud->uh_sum != 0) {
793 accumulate = alias_port;
794 accumulate -= ud->uh_dport;
795 accumulate += twowords(&alias_address);
796 accumulate -= twowords(&original_address);
797
798 /* If this is a proxy packet, modify checksum
799 * because of source change.*/
800 if (proxy_port != 0) {
801 accumulate += ud->uh_sport;
802 accumulate -= proxy_port;
803 }
804
805 if (proxy_address.s_addr != 0) {
806 accumulate += twowords(&pip->ip_src);
807 accumulate -= twowords(&proxy_address);
808 }
809
810 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
811 }
812
813 /* XXX: Could the two if's below be concatenated to one ? */
814 /* Restore source port and/or address in case of proxying*/
815 if (proxy_port != 0)
816 ud->uh_sport = proxy_port;
817
818 if (proxy_address.s_addr != 0) {
819 DifferentialChecksum(&pip->ip_sum,
820 &proxy_address, &pip->ip_src, 2);
821 pip->ip_src = proxy_address;
822 }
823
824 /* Restore original IP address */
825 DifferentialChecksum(&pip->ip_sum,
826 &original_address, &pip->ip_dst, 2);
827 pip->ip_dst = original_address;
828
829 return (PKT_ALIAS_OK);
830 }
831 return (PKT_ALIAS_IGNORED);
832 }
833
834 static int
UdpAliasOut(struct libalias * la,struct ip * pip,int maxpacketsize,int create)835 UdpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
836 {
837 struct udphdr *ud;
838 struct alias_link *lnk;
839 struct in_addr dest_address;
840 struct in_addr proxy_server_address;
841 u_short dest_port;
842 u_short proxy_server_port;
843 int proxy_type;
844
845 LIBALIAS_LOCK_ASSERT(la);
846
847 ud = ValidateUdpLength(pip);
848 if (ud == NULL)
849 return (PKT_ALIAS_IGNORED);
850
851 /* Return if proxy-only mode is enabled and not proxyrule found.*/
852 proxy_type = ProxyCheck(la, &proxy_server_address, &proxy_server_port,
853 pip->ip_src, pip->ip_dst, ud->uh_dport, pip->ip_p);
854 if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
855 return (PKT_ALIAS_OK);
856
857 /* If this is a transparent proxy, save original destination,
858 * then alter the destination and adjust checksums */
859 dest_port = ud->uh_dport;
860 dest_address = pip->ip_dst;
861
862 if (proxy_type != 0) {
863 int accumulate;
864
865 accumulate = twowords(&pip->ip_dst);
866 accumulate -= twowords(&proxy_server_address);
867
868 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
869
870 if (ud->uh_sum != 0) {
871 accumulate = twowords(&pip->ip_dst);
872 accumulate -= twowords(&proxy_server_address);
873 accumulate += ud->uh_dport;
874 accumulate -= proxy_server_port;
875 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
876 }
877 pip->ip_dst = proxy_server_address;
878 ud->uh_dport = proxy_server_port;
879 }
880 lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
881 ud->uh_sport, ud->uh_dport,
882 IPPROTO_UDP, create);
883 if (lnk != NULL) {
884 u_short alias_port;
885 struct in_addr alias_address;
886 struct alias_data ad = {
887 .lnk = lnk,
888 .oaddr = NULL,
889 .aaddr = &alias_address,
890 .aport = &alias_port,
891 .sport = &ud->uh_sport,
892 .dport = &ud->uh_dport,
893 .maxpktsize = 0
894 };
895
896 /* Save original destination address, if this is a proxy packet.
897 * Also modify packet to include destination encoding. This may
898 * change the size of IP header. */
899 if (proxy_type != 0) {
900 SetProxyPort(lnk, dest_port);
901 SetProxyAddress(lnk, dest_address);
902 ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
903 ud = (struct udphdr *)ip_next(pip);
904 }
905
906 alias_address = GetAliasAddress(lnk);
907 alias_port = GetAliasPort(lnk);
908
909 /* Walk out chain. */
910 find_handler(OUT, UDP, la, pip, &ad);
911
912 /* If UDP checksum is not zero, adjust since source port is */
913 /* being aliased and source address is being altered */
914 if (ud->uh_sum != 0) {
915 int accumulate;
916
917 accumulate = ud->uh_sport;
918 accumulate -= alias_port;
919 accumulate += twowords(&pip->ip_src);
920 accumulate -= twowords(&alias_address);
921 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
922 }
923 /* Put alias port in UDP header */
924 ud->uh_sport = alias_port;
925
926 /* Change source address */
927 DifferentialChecksum(&pip->ip_sum,
928 &alias_address, &pip->ip_src, 2);
929 pip->ip_src = alias_address;
930
931 return (PKT_ALIAS_OK);
932 }
933 return (PKT_ALIAS_IGNORED);
934 }
935
936 static int
TcpAliasIn(struct libalias * la,struct ip * pip)937 TcpAliasIn(struct libalias *la, struct ip *pip)
938 {
939 struct tcphdr *tc;
940 struct alias_link *lnk;
941 size_t dlen;
942
943 LIBALIAS_LOCK_ASSERT(la);
944
945 dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
946 if (dlen < sizeof(struct tcphdr))
947 return (PKT_ALIAS_IGNORED);
948 tc = (struct tcphdr *)ip_next(pip);
949
950 lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
951 tc->th_sport, tc->th_dport,
952 IPPROTO_TCP,
953 !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
954 if (lnk != NULL) {
955 struct in_addr alias_address;
956 struct in_addr original_address;
957 struct in_addr proxy_address;
958 u_short alias_port;
959 u_short proxy_port;
960 int accumulate;
961
962 /*
963 * The init of MANY vars is a bit below, but aliashandlepptpin
964 * seems to need the destination port that came within the
965 * packet and not the original one looks below [*].
966 */
967
968 struct alias_data ad = {
969 .lnk = lnk,
970 .oaddr = NULL,
971 .aaddr = NULL,
972 .aport = NULL,
973 .sport = &tc->th_sport,
974 .dport = &tc->th_dport,
975 .maxpktsize = 0
976 };
977
978 /* Walk out chain. */
979 find_handler(IN, TCP, la, pip, &ad);
980
981 alias_address = GetAliasAddress(lnk);
982 original_address = GetOriginalAddress(lnk);
983 proxy_address = GetProxyAddress(lnk);
984 alias_port = tc->th_dport;
985 tc->th_dport = GetOriginalPort(lnk);
986 proxy_port = GetProxyPort(lnk);
987
988 /*
989 * Look above, if anyone is going to add find_handler AFTER
990 * this aliashandlepptpin/point, please redo alias_data too.
991 * Uncommenting the piece here below should be enough.
992 */
993 #if 0
994 struct alias_data ad = {
995 .lnk = lnk,
996 .oaddr = &original_address,
997 .aaddr = &alias_address,
998 .aport = &alias_port,
999 .sport = &ud->uh_sport,
1000 .dport = &ud->uh_dport,
1001 .maxpktsize = 0
1002 };
1003
1004 /* Walk out chain. */
1005 error = find_handler(la, pip, &ad);
1006 if (error == EHDNOF)
1007 printf("Protocol handler not found\n");
1008 #endif
1009
1010 /* Adjust TCP checksum since destination port is being
1011 * unaliased and destination port is being altered. */
1012 accumulate = alias_port;
1013 accumulate -= tc->th_dport;
1014 accumulate += twowords(&alias_address);
1015 accumulate -= twowords(&original_address);
1016
1017 /* If this is a proxy, then modify the TCP source port
1018 * and checksum accumulation */
1019 if (proxy_port != 0) {
1020 accumulate += tc->th_sport;
1021 tc->th_sport = proxy_port;
1022 accumulate -= tc->th_sport;
1023 accumulate += twowords(&pip->ip_src);
1024 accumulate -= twowords(&proxy_address);
1025 }
1026 /* See if ACK number needs to be modified */
1027 if (GetAckModified(lnk) == 1) {
1028 int delta;
1029
1030 tc = (struct tcphdr *)ip_next(pip);
1031 delta = GetDeltaAckIn(tc->th_ack, lnk);
1032 if (delta != 0) {
1033 accumulate += twowords(&tc->th_ack);
1034 tc->th_ack = htonl(ntohl(tc->th_ack) - delta);
1035 accumulate -= twowords(&tc->th_ack);
1036 }
1037 }
1038 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1039
1040 /* Restore original IP address */
1041 accumulate = twowords(&pip->ip_dst);
1042 pip->ip_dst = original_address;
1043 accumulate -= twowords(&pip->ip_dst);
1044
1045 /* If this is a transparent proxy packet,
1046 * then modify the source address */
1047 if (proxy_address.s_addr != 0) {
1048 accumulate += twowords(&pip->ip_src);
1049 pip->ip_src = proxy_address;
1050 accumulate -= twowords(&pip->ip_src);
1051 }
1052 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1053
1054 /* Monitor TCP connection state */
1055 tc = (struct tcphdr *)ip_next(pip);
1056 TcpMonitorIn(tc->th_flags, lnk);
1057
1058 return (PKT_ALIAS_OK);
1059 }
1060 return (PKT_ALIAS_IGNORED);
1061 }
1062
1063 static int
TcpAliasOut(struct libalias * la,struct ip * pip,int maxpacketsize,int create)1064 TcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
1065 {
1066 int proxy_type;
1067 u_short dest_port;
1068 u_short proxy_server_port;
1069 size_t dlen;
1070 struct in_addr dest_address;
1071 struct in_addr proxy_server_address;
1072 struct tcphdr *tc;
1073 struct alias_link *lnk;
1074
1075 LIBALIAS_LOCK_ASSERT(la);
1076
1077 dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
1078 if (dlen < sizeof(struct tcphdr))
1079 return (PKT_ALIAS_IGNORED);
1080 tc = (struct tcphdr *)ip_next(pip);
1081
1082 if (create)
1083 proxy_type = ProxyCheck(la, &proxy_server_address,
1084 &proxy_server_port, pip->ip_src, pip->ip_dst,
1085 tc->th_dport, pip->ip_p);
1086 else
1087 proxy_type = 0;
1088
1089 if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
1090 return (PKT_ALIAS_OK);
1091
1092 /* If this is a transparent proxy, save original destination,
1093 * then alter the destination and adjust checksums */
1094 dest_port = tc->th_dport;
1095 dest_address = pip->ip_dst;
1096 if (proxy_type != 0) {
1097 int accumulate;
1098
1099 accumulate = tc->th_dport;
1100 tc->th_dport = proxy_server_port;
1101 accumulate -= tc->th_dport;
1102 accumulate += twowords(&pip->ip_dst);
1103 accumulate -= twowords(&proxy_server_address);
1104 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1105
1106 accumulate = twowords(&pip->ip_dst);
1107 pip->ip_dst = proxy_server_address;
1108 accumulate -= twowords(&pip->ip_dst);
1109 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1110 }
1111 lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
1112 tc->th_sport, tc->th_dport,
1113 IPPROTO_TCP, create);
1114 if (lnk == NULL)
1115 return (PKT_ALIAS_IGNORED);
1116 if (lnk != NULL) {
1117 u_short alias_port;
1118 struct in_addr alias_address;
1119 int accumulate;
1120 struct alias_data ad = {
1121 .lnk = lnk,
1122 .oaddr = NULL,
1123 .aaddr = &alias_address,
1124 .aport = &alias_port,
1125 .sport = &tc->th_sport,
1126 .dport = &tc->th_dport,
1127 .maxpktsize = maxpacketsize
1128 };
1129
1130 /* Save original destination address, if this is a proxy packet.
1131 * Also modify packet to include destination
1132 * encoding. This may change the size of IP header. */
1133 if (proxy_type != 0) {
1134 SetProxyPort(lnk, dest_port);
1135 SetProxyAddress(lnk, dest_address);
1136 ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
1137 tc = (struct tcphdr *)ip_next(pip);
1138 }
1139 /* Get alias address and port */
1140 alias_port = GetAliasPort(lnk);
1141 alias_address = GetAliasAddress(lnk);
1142
1143 /* Monitor TCP connection state */
1144 tc = (struct tcphdr *)ip_next(pip);
1145 TcpMonitorOut(tc->th_flags, lnk);
1146
1147 /* Walk out chain. */
1148 find_handler(OUT, TCP, la, pip, &ad);
1149
1150 /* Adjust TCP checksum since source port is being aliased
1151 * and source address is being altered */
1152 accumulate = tc->th_sport;
1153 tc->th_sport = alias_port;
1154 accumulate -= tc->th_sport;
1155 accumulate += twowords(&pip->ip_src);
1156 accumulate -= twowords(&alias_address);
1157
1158 /* Modify sequence number if necessary */
1159 if (GetAckModified(lnk) == 1) {
1160 int delta;
1161
1162 tc = (struct tcphdr *)ip_next(pip);
1163 delta = GetDeltaSeqOut(tc->th_seq, lnk);
1164 if (delta != 0) {
1165 accumulate += twowords(&tc->th_seq);
1166 tc->th_seq = htonl(ntohl(tc->th_seq) + delta);
1167 accumulate -= twowords(&tc->th_seq);
1168 }
1169 }
1170 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1171
1172 /* Change source address */
1173 accumulate = twowords(&pip->ip_src);
1174 pip->ip_src = alias_address;
1175 accumulate -= twowords(&pip->ip_src);
1176 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1177
1178 return (PKT_ALIAS_OK);
1179 }
1180 return (PKT_ALIAS_IGNORED);
1181 }
1182
1183 /* Fragment Handling
1184
1185 FragmentIn()
1186 FragmentOut()
1187
1188 The packet aliasing module has a limited ability for handling IP
1189 fragments. If the ICMP, TCP or UDP header is in the first fragment
1190 received, then the ID number of the IP packet is saved, and other
1191 fragments are identified according to their ID number and IP address
1192 they were sent from. Pointers to unresolved fragments can also be
1193 saved and recalled when a header fragment is seen.
1194 */
1195
1196 /* Local prototypes */
1197 static int FragmentIn(struct libalias *la, struct in_addr ip_src,
1198 struct ip *pip, u_short ip_id, u_short *ip_sum);
1199 static int FragmentOut(struct libalias *, struct ip *pip,
1200 u_short *ip_sum);
1201
1202 static int
FragmentIn(struct libalias * la,struct in_addr ip_src,struct ip * pip,u_short ip_id,u_short * ip_sum)1203 FragmentIn(struct libalias *la, struct in_addr ip_src, struct ip *pip,
1204 u_short ip_id, u_short *ip_sum)
1205 {
1206 struct alias_link *lnk;
1207
1208 LIBALIAS_LOCK_ASSERT(la);
1209 lnk = FindFragmentIn2(la, ip_src, pip->ip_dst, ip_id);
1210 if (lnk != NULL) {
1211 struct in_addr original_address;
1212
1213 GetFragmentAddr(lnk, &original_address);
1214 DifferentialChecksum(ip_sum,
1215 &original_address, &pip->ip_dst, 2);
1216 pip->ip_dst = original_address;
1217
1218 return (PKT_ALIAS_OK);
1219 }
1220 return (PKT_ALIAS_UNRESOLVED_FRAGMENT);
1221 }
1222
1223 static int
FragmentOut(struct libalias * la,struct ip * pip,u_short * ip_sum)1224 FragmentOut(struct libalias *la, struct ip *pip, u_short *ip_sum)
1225 {
1226 struct in_addr alias_address;
1227
1228 LIBALIAS_LOCK_ASSERT(la);
1229 alias_address = FindAliasAddress(la, pip->ip_src);
1230 DifferentialChecksum(ip_sum,
1231 &alias_address, &pip->ip_src, 2);
1232 pip->ip_src = alias_address;
1233
1234 return (PKT_ALIAS_OK);
1235 }
1236
1237 /* Outside World Access
1238
1239 PacketAliasSaveFragment()
1240 PacketAliasGetFragment()
1241 PacketAliasFragmentIn()
1242 PacketAliasIn()
1243 PacketAliasOut()
1244 PacketUnaliasOut()
1245
1246 (prototypes in alias.h)
1247 */
1248
1249 int
LibAliasSaveFragment(struct libalias * la,void * ptr)1250 LibAliasSaveFragment(struct libalias *la, void *ptr)
1251 {
1252 int iresult;
1253 struct alias_link *lnk;
1254 struct ip *pip;
1255
1256 LIBALIAS_LOCK(la);
1257 pip = (struct ip *)ptr;
1258 lnk = AddFragmentPtrLink(la, pip->ip_src, pip->ip_id);
1259 iresult = PKT_ALIAS_ERROR;
1260 if (lnk != NULL) {
1261 SetFragmentPtr(lnk, ptr);
1262 iresult = PKT_ALIAS_OK;
1263 }
1264 LIBALIAS_UNLOCK(la);
1265 return (iresult);
1266 }
1267
1268 void *
LibAliasGetFragment(struct libalias * la,void * ptr)1269 LibAliasGetFragment(struct libalias *la, void *ptr)
1270 {
1271 struct alias_link *lnk;
1272 void *fptr;
1273 struct ip *pip;
1274
1275 LIBALIAS_LOCK(la);
1276 pip = (struct ip *)ptr;
1277 lnk = FindFragmentPtr(la, pip->ip_src, pip->ip_id);
1278 if (lnk != NULL) {
1279 GetFragmentPtr(lnk, &fptr);
1280 SetFragmentPtr(lnk, NULL);
1281 SetExpire(lnk, 0); /* Deletes link */
1282 } else
1283 fptr = NULL;
1284
1285 LIBALIAS_UNLOCK(la);
1286 return (fptr);
1287 }
1288
1289 void
LibAliasFragmentIn(struct libalias * la,void * ptr,void * ptr_fragment)1290 LibAliasFragmentIn(struct libalias *la,
1291 void *ptr, /* Points to correctly de-aliased header fragment */
1292 void *ptr_fragment /* fragment which must be de-aliased */
1293 )
1294 {
1295 struct ip *pip;
1296 struct ip *fpip;
1297
1298 LIBALIAS_LOCK(la);
1299 (void)la;
1300 pip = (struct ip *)ptr;
1301 fpip = (struct ip *)ptr_fragment;
1302
1303 DifferentialChecksum(&fpip->ip_sum,
1304 &pip->ip_dst, &fpip->ip_dst, 2);
1305 fpip->ip_dst = pip->ip_dst;
1306 LIBALIAS_UNLOCK(la);
1307 }
1308
1309 /* Local prototypes */
1310 static int
1311 LibAliasOutLocked(struct libalias *la, struct ip *pip,
1312 int maxpacketsize, int create);
1313 static int
1314 LibAliasInLocked(struct libalias *la, struct ip *pip,
1315 int maxpacketsize);
1316
1317 int
LibAliasIn(struct libalias * la,void * ptr,int maxpacketsize)1318 LibAliasIn(struct libalias *la, void *ptr, int maxpacketsize)
1319 {
1320 int res;
1321
1322 LIBALIAS_LOCK(la);
1323 res = LibAliasInLocked(la, (struct ip *)ptr, maxpacketsize);
1324 LIBALIAS_UNLOCK(la);
1325 return (res);
1326 }
1327
1328 static int
LibAliasInLocked(struct libalias * la,struct ip * pip,int maxpacketsize)1329 LibAliasInLocked(struct libalias *la, struct ip *pip, int maxpacketsize)
1330 {
1331 struct in_addr alias_addr;
1332 int iresult;
1333
1334 if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1335 la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1336 iresult = LibAliasOutLocked(la, pip, maxpacketsize, 1);
1337 la->packetAliasMode |= PKT_ALIAS_REVERSE;
1338 goto getout;
1339 }
1340 HouseKeeping(la);
1341 alias_addr = pip->ip_dst;
1342
1343 /* Defense against mangled packets */
1344 if (ntohs(pip->ip_len) > maxpacketsize
1345 || (pip->ip_hl << 2) > maxpacketsize) {
1346 iresult = PKT_ALIAS_IGNORED;
1347 goto getout;
1348 }
1349
1350 if (FRAG_NO_HDR(pip)) {
1351 iresult = FragmentIn(la, pip->ip_src, pip, pip->ip_id,
1352 &pip->ip_sum);
1353 goto getout;
1354 }
1355
1356 iresult = PKT_ALIAS_IGNORED;
1357 switch (pip->ip_p) {
1358 case IPPROTO_ICMP:
1359 iresult = IcmpAliasIn(la, pip);
1360 break;
1361 case IPPROTO_UDP:
1362 iresult = UdpAliasIn(la, pip);
1363 break;
1364 case IPPROTO_TCP:
1365 iresult = TcpAliasIn(la, pip);
1366 break;
1367 #ifdef _KERNEL
1368 case IPPROTO_SCTP:
1369 iresult = SctpAlias(la, pip, SN_TO_LOCAL);
1370 break;
1371 #endif
1372 case IPPROTO_GRE: {
1373 int error;
1374 struct alias_data ad = {
1375 .lnk = NULL,
1376 .oaddr = NULL,
1377 .aaddr = NULL,
1378 .aport = NULL,
1379 .sport = NULL,
1380 .dport = NULL,
1381 .maxpktsize = 0
1382 };
1383
1384 /* Walk out chain. */
1385 error = find_handler(IN, IP, la, pip, &ad);
1386 if (error == 0)
1387 iresult = PKT_ALIAS_OK;
1388 else
1389 iresult = ProtoAliasIn(la, pip->ip_src,
1390 pip, pip->ip_p, &pip->ip_sum);
1391 break;
1392 }
1393 default:
1394 iresult = ProtoAliasIn(la, pip->ip_src, pip,
1395 pip->ip_p, &pip->ip_sum);
1396 break;
1397 }
1398
1399 if (MF_ISSET(pip)) {
1400 struct alias_link *lnk;
1401
1402 lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id);
1403 if (lnk != NULL) {
1404 iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
1405 SetFragmentAddr(lnk, pip->ip_dst);
1406 } else {
1407 iresult = PKT_ALIAS_ERROR;
1408 }
1409 }
1410
1411 getout:
1412 return (iresult);
1413 }
1414
1415 /* Unregistered address ranges */
1416
1417 /* 10.0.0.0 -> 10.255.255.255 */
1418 #define UNREG_ADDR_A_LOWER 0x0a000000
1419 #define UNREG_ADDR_A_UPPER 0x0affffff
1420
1421 /* 172.16.0.0 -> 172.31.255.255 */
1422 #define UNREG_ADDR_B_LOWER 0xac100000
1423 #define UNREG_ADDR_B_UPPER 0xac1fffff
1424
1425 /* 192.168.0.0 -> 192.168.255.255 */
1426 #define UNREG_ADDR_C_LOWER 0xc0a80000
1427 #define UNREG_ADDR_C_UPPER 0xc0a8ffff
1428
1429 /* 100.64.0.0 -> 100.127.255.255 (RFC 6598 - Carrier Grade NAT) */
1430 #define UNREG_ADDR_CGN_LOWER 0x64400000
1431 #define UNREG_ADDR_CGN_UPPER 0x647fffff
1432
1433 int
LibAliasOut(struct libalias * la,void * ptr,int maxpacketsize)1434 LibAliasOut(struct libalias *la, void *ptr, int maxpacketsize)
1435 {
1436 int res;
1437
1438 LIBALIAS_LOCK(la);
1439 res = LibAliasOutLocked(la, (struct ip *)ptr, maxpacketsize, 1);
1440 LIBALIAS_UNLOCK(la);
1441 return (res);
1442 }
1443
1444 int
LibAliasOutTry(struct libalias * la,void * ptr,int maxpacketsize,int create)1445 LibAliasOutTry(struct libalias *la, void *ptr, int maxpacketsize, int create)
1446 {
1447 int res;
1448
1449 LIBALIAS_LOCK(la);
1450 res = LibAliasOutLocked(la, (struct ip *)ptr, maxpacketsize, create);
1451 LIBALIAS_UNLOCK(la);
1452 return (res);
1453 }
1454
1455 static int
LibAliasOutLocked(struct libalias * la,struct ip * pip,int maxpacketsize,int create)1456 LibAliasOutLocked(struct libalias *la,
1457 struct ip *pip, /* valid IP packet */
1458 int maxpacketsize, /* How much the packet data may grow (FTP and IRC inline changes) */
1459 int create /* Create new entries ? */
1460 )
1461 {
1462 int iresult;
1463 struct in_addr addr_save;
1464
1465 if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1466 la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1467 iresult = LibAliasInLocked(la, pip, maxpacketsize);
1468 la->packetAliasMode |= PKT_ALIAS_REVERSE;
1469 goto getout;
1470 }
1471 HouseKeeping(la);
1472
1473 /* Defense against mangled packets */
1474 if (ntohs(pip->ip_len) > maxpacketsize
1475 || (pip->ip_hl << 2) > maxpacketsize) {
1476 iresult = PKT_ALIAS_IGNORED;
1477 goto getout;
1478 }
1479
1480 addr_save = GetDefaultAliasAddress(la);
1481 if (la->packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY ||
1482 la->packetAliasMode & PKT_ALIAS_UNREGISTERED_CGN) {
1483 u_long addr;
1484 int iclass;
1485
1486 iclass = 0;
1487 addr = ntohl(pip->ip_src.s_addr);
1488 if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER)
1489 iclass = 3;
1490 else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER)
1491 iclass = 2;
1492 else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER)
1493 iclass = 1;
1494 else if (addr >= UNREG_ADDR_CGN_LOWER && addr <= UNREG_ADDR_CGN_UPPER &&
1495 la->packetAliasMode & PKT_ALIAS_UNREGISTERED_CGN)
1496 iclass = 4;
1497
1498 if (iclass == 0) {
1499 SetDefaultAliasAddress(la, pip->ip_src);
1500 }
1501 } else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) {
1502 SetDefaultAliasAddress(la, pip->ip_src);
1503 }
1504
1505 if (FRAG_NO_HDR(pip)) {
1506 iresult = FragmentOut(la, pip, &pip->ip_sum);
1507 goto getout_restore;
1508 }
1509
1510 iresult = PKT_ALIAS_IGNORED;
1511 switch (pip->ip_p) {
1512 case IPPROTO_ICMP:
1513 iresult = IcmpAliasOut(la, pip, create);
1514 break;
1515 case IPPROTO_UDP:
1516 iresult = UdpAliasOut(la, pip, maxpacketsize, create);
1517 break;
1518 case IPPROTO_TCP:
1519 iresult = TcpAliasOut(la, pip, maxpacketsize, create);
1520 break;
1521 #ifdef _KERNEL
1522 case IPPROTO_SCTP:
1523 iresult = SctpAlias(la, pip, SN_TO_GLOBAL);
1524 break;
1525 #endif
1526 case IPPROTO_GRE: {
1527 int error;
1528 struct alias_data ad = {
1529 .lnk = NULL,
1530 .oaddr = NULL,
1531 .aaddr = NULL,
1532 .aport = NULL,
1533 .sport = NULL,
1534 .dport = NULL,
1535 .maxpktsize = 0
1536 };
1537 /* Walk out chain. */
1538 error = find_handler(OUT, IP, la, pip, &ad);
1539 if (error == 0)
1540 iresult = PKT_ALIAS_OK;
1541 else
1542 iresult = ProtoAliasOut(la, pip,
1543 pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
1544 break;
1545 }
1546 default:
1547 iresult = ProtoAliasOut(la, pip,
1548 pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
1549 break;
1550 }
1551
1552 getout_restore:
1553 SetDefaultAliasAddress(la, addr_save);
1554 getout:
1555 return (iresult);
1556 }
1557
1558 int
LibAliasUnaliasOut(struct libalias * la,void * ptr,int maxpacketsize)1559 LibAliasUnaliasOut(struct libalias *la,
1560 void *ptr, /* valid IP packet */
1561 int maxpacketsize /* for error checking */
1562 )
1563 {
1564 struct ip *pip;
1565 struct icmp *ic;
1566 struct udphdr *ud;
1567 struct tcphdr *tc;
1568 struct alias_link *lnk;
1569 int iresult = PKT_ALIAS_IGNORED;
1570
1571 LIBALIAS_LOCK(la);
1572 pip = (struct ip *)ptr;
1573
1574 /* Defense against mangled packets */
1575 if (ntohs(pip->ip_len) > maxpacketsize
1576 || (pip->ip_hl << 2) > maxpacketsize)
1577 goto getout;
1578
1579 ud = (struct udphdr *)ip_next(pip);
1580 tc = (struct tcphdr *)ip_next(pip);
1581 ic = (struct icmp *)ip_next(pip);
1582
1583 /* Find a link */
1584 if (pip->ip_p == IPPROTO_UDP)
1585 lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1586 ud->uh_dport, ud->uh_sport,
1587 IPPROTO_UDP, 0);
1588 else if (pip->ip_p == IPPROTO_TCP)
1589 lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1590 tc->th_dport, tc->th_sport,
1591 IPPROTO_TCP, 0);
1592 else if (pip->ip_p == IPPROTO_ICMP)
1593 lnk = FindIcmpIn(la, pip->ip_dst, pip->ip_src, ic->icmp_id, 0);
1594 else
1595 lnk = NULL;
1596
1597 /* Change it from an aliased packet to an unaliased packet */
1598 if (lnk != NULL) {
1599 if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP) {
1600 int accumulate;
1601 struct in_addr original_address;
1602 u_short original_port;
1603
1604 original_address = GetOriginalAddress(lnk);
1605 original_port = GetOriginalPort(lnk);
1606
1607 /* Adjust TCP/UDP checksum */
1608 accumulate = twowords(&pip->ip_src);
1609 accumulate -= twowords(&original_address);
1610
1611 if (pip->ip_p == IPPROTO_UDP) {
1612 accumulate += ud->uh_sport;
1613 accumulate -= original_port;
1614 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
1615 } else {
1616 accumulate += tc->th_sport;
1617 accumulate -= original_port;
1618 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1619 }
1620
1621 /* Adjust IP checksum */
1622 DifferentialChecksum(&pip->ip_sum,
1623 &original_address, &pip->ip_src, 2);
1624
1625 /* Un-alias source address and port number */
1626 pip->ip_src = original_address;
1627 if (pip->ip_p == IPPROTO_UDP)
1628 ud->uh_sport = original_port;
1629 else
1630 tc->th_sport = original_port;
1631
1632 iresult = PKT_ALIAS_OK;
1633 } else if (pip->ip_p == IPPROTO_ICMP) {
1634 int accumulate;
1635 struct in_addr original_address;
1636 u_short original_id;
1637
1638 original_address = GetOriginalAddress(lnk);
1639 original_id = GetOriginalPort(lnk);
1640
1641 /* Adjust ICMP checksum */
1642 accumulate = twowords(&pip->ip_src);
1643 accumulate -= twowords(&original_address);
1644 accumulate += ic->icmp_id;
1645 accumulate -= original_id;
1646 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
1647
1648 /* Adjust IP checksum */
1649 DifferentialChecksum(&pip->ip_sum,
1650 &original_address, &pip->ip_src, 2);
1651
1652 /* Un-alias source address and port number */
1653 pip->ip_src = original_address;
1654 ic->icmp_id = original_id;
1655
1656 iresult = PKT_ALIAS_OK;
1657 }
1658 }
1659 getout:
1660 LIBALIAS_UNLOCK(la);
1661 return (iresult);
1662 }
1663
1664 #ifndef _KERNEL
1665
1666 int
LibAliasRefreshModules(void)1667 LibAliasRefreshModules(void)
1668 {
1669 char buf[256], conf[] = "/etc/libalias.conf";
1670 FILE *fd;
1671 int i, len;
1672
1673 fd = fopen(conf, "r");
1674 if (fd == NULL)
1675 err(1, "fopen(%s)", conf);
1676
1677 LibAliasUnLoadAllModule();
1678
1679 for (;;) {
1680 fgets(buf, 256, fd);
1681 if (feof(fd))
1682 break;
1683 len = strlen(buf);
1684 if (len > 1) {
1685 for (i = 0; i < len; i++)
1686 if (!isspace(buf[i]))
1687 break;
1688 if (buf[i] == '#')
1689 continue;
1690 buf[len - 1] = '\0';
1691 LibAliasLoadModule(buf);
1692 }
1693 }
1694 fclose(fd);
1695 return (0);
1696 }
1697
1698 int
LibAliasLoadModule(char * path)1699 LibAliasLoadModule(char *path)
1700 {
1701 struct dll *t;
1702 void *handle;
1703 struct proto_handler *m;
1704 const char *error;
1705 moduledata_t *p;
1706
1707 handle = dlopen (path, RTLD_LAZY);
1708 if (!handle) {
1709 fprintf(stderr, "%s\n", dlerror());
1710 return (EINVAL);
1711 }
1712
1713 p = dlsym(handle, "alias_mod");
1714 if ((error = dlerror()) != NULL) {
1715 fprintf(stderr, "%s\n", dlerror());
1716 return (EINVAL);
1717 }
1718
1719 t = malloc(sizeof(struct dll));
1720 if (t == NULL)
1721 return (ENOMEM);
1722 strncpy(t->name, p->name, DLL_LEN);
1723 t->handle = handle;
1724 if (attach_dll(t) == EEXIST) {
1725 free(t);
1726 fprintf(stderr, "dll conflict\n");
1727 return (EEXIST);
1728 }
1729
1730 m = dlsym(t->handle, "handlers");
1731 if ((error = dlerror()) != NULL) {
1732 fprintf(stderr, "%s\n", error);
1733 return (EINVAL);
1734 }
1735
1736 LibAliasAttachHandlers(m);
1737 return (0);
1738 }
1739
1740 int
LibAliasUnLoadAllModule(void)1741 LibAliasUnLoadAllModule(void)
1742 {
1743 struct dll *t;
1744 struct proto_handler *p;
1745
1746 /* Unload all modules then reload everything. */
1747 while ((p = first_handler()) != NULL) {
1748 LibAliasDetachHandlers(p);
1749 }
1750 while ((t = walk_dll_chain()) != NULL) {
1751 dlclose(t->handle);
1752 free(t);
1753 }
1754 return (1);
1755 }
1756
1757 #endif
1758
1759 #ifdef _KERNEL
1760 /*
1761 * m_megapullup() - this function is a big hack.
1762 * Thankfully, it's only used in ng_nat and ipfw+nat.
1763 *
1764 * It allocates an mbuf with cluster and copies the specified part of the chain
1765 * into cluster, so that it is all contiguous and can be accessed via a plain
1766 * (char *) pointer. This is required, because libalias doesn't know how to
1767 * handle mbuf chains.
1768 *
1769 * On success, m_megapullup returns an mbuf (possibly with cluster) containing
1770 * the input packet, on failure NULL. The input packet is always consumed.
1771 */
1772 struct mbuf *
m_megapullup(struct mbuf * m,int len)1773 m_megapullup(struct mbuf *m, int len)
1774 {
1775 struct mbuf *mcl;
1776
1777 if (len > m->m_pkthdr.len)
1778 goto bad;
1779
1780 if (m->m_next == NULL && M_WRITABLE(m))
1781 return (m);
1782
1783 if (len <= MJUMPAGESIZE)
1784 mcl = m_get2(len, M_NOWAIT, MT_DATA, M_PKTHDR);
1785 else if (len <= MJUM9BYTES)
1786 mcl = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES);
1787 else if (len <= MJUM16BYTES)
1788 mcl = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM16BYTES);
1789 else
1790 goto bad;
1791 if (mcl == NULL)
1792 goto bad;
1793 m_align(mcl, len);
1794 m_move_pkthdr(mcl, m);
1795 m_copydata(m, 0, len, mtod(mcl, caddr_t));
1796 mcl->m_len = mcl->m_pkthdr.len = len;
1797 m_freem(m);
1798
1799 return (mcl);
1800 bad:
1801 m_freem(m);
1802 return (NULL);
1803 }
1804 #endif
1805