2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2001 Charles Mott <cm@linktel.net>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
29 #include <sys/cdefs.h>
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.
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.
47 Version 1.0 August, 1996 (cjm)
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
54 Version 1.2 September 7, 1996 (cjm)
55 Fragment handling error in alias_db.c corrected.
56 (Tom Torrance helped fix this problem.)
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.
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.)
72 Version 1.6 September 18, 1996 (cjm)
73 Simplified ICMP aliasing scheme. Should now support
74 traceroute from Win95 as well as FreeBSD.
76 Version 1.7 January 9, 1997 (cjm)
77 - Out-of-order fragment handling.
78 - IP checksum error fixed for ftp transfers
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
87 Version 2.1 May 1997 (cjm)
88 - Added support for outgoing ICMP error
90 - Added two functions PacketAliasIn2()
91 and PacketAliasOut2() for dynamic address
92 control (e.g. round-robin allocation of
95 Version 2.2 July 1997 (cjm)
96 - Rationalized API function names to begin
98 - Eliminated PacketAliasIn2() and
99 PacketAliasOut2() as poorly conceived.
101 Version 2.3 Dec 1998 (dillon)
102 - Major bounds checking additions, see FreeBSD/CVS
104 Version 3.1 May, 2000 (salander)
105 - Added hooks to handle PPTP.
107 Version 3.2 July, 2000 (salander and satoh)
108 - Added PacketUnaliasOut routine.
109 - Added hooks to handle RTSP/RTP.
111 See HISTORY file for additional revisions.
115 #include <sys/param.h>
116 #include <sys/systm.h>
117 #include <sys/mbuf.h>
118 #include <sys/sysctl.h>
120 #include <sys/types.h>
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>
137 #include <netinet/libalias/alias.h>
138 #include <netinet/libalias/alias_local.h>
139 #include <netinet/libalias/alias_mod.h>
143 #include "alias_local.h"
144 #include "alias_mod.h"
148 * Define libalias SYSCTL Node
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");
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];
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];
174 /* TCP Handling Routines
176 TcpMonitorIn() -- These routines monitor TCP connections, and
177 TcpMonitorOut() delete a link when a connection is closed.
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
185 /* Local prototypes */
186 static void TcpMonitorIn(u_char, struct alias_link *);
188 static void TcpMonitorOut(u_char, struct alias_link *);
191 TcpMonitorIn(u_char th_flags, struct alias_link *lnk)
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);
200 case ALIAS_TCP_STATE_CONNECTED:
201 if (th_flags & (TH_FIN | TH_RST))
202 SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED);
208 TcpMonitorOut(u_char th_flags, struct alias_link *lnk)
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);
217 case ALIAS_TCP_STATE_CONNECTED:
218 if (th_flags & (TH_FIN | TH_RST))
219 SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED);
224 /* Protocol Specific Packet Aliasing Routines
226 IcmpAliasIn(), IcmpAliasIn1(), IcmpAliasIn2()
227 IcmpAliasOut(), IcmpAliasOut1(), IcmpAliasOut2()
228 ProtoAliasIn(), ProtoAliasOut()
229 UdpAliasIn(), UdpAliasOut()
230 TcpAliasIn(), TcpAliasOut()
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.
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.
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
246 ICMP error messages are handled by looking at the IP fragment
247 in the data section of the message.
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).
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.
259 All packets go through the aliasing mechanism, whether they come from
260 the gateway machine or other machines on a local area network.
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 *);
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);
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,
278 static int UdpAliasIn(struct libalias *, struct ip *);
279 static int UdpAliasOut(struct libalias *, struct ip *, int, int create);
281 static int TcpAliasIn(struct libalias *, struct ip *);
282 static int TcpAliasOut(struct libalias *, struct ip *, int, int create);
285 De-alias incoming echo and timestamp replies.
286 Alias incoming echo and timestamp requests.
289 IcmpAliasIn1(struct libalias *la, struct ip *pip)
291 struct alias_link *lnk;
294 LIBALIAS_LOCK_ASSERT(la);
295 ic = (struct icmp *)ip_next(pip);
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);
303 original_id = GetOriginalPort(lnk);
305 /* Adjust ICMP checksum */
306 accumulate = ic->icmp_id;
307 accumulate -= original_id;
308 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
310 /* Put original sequence number back in */
311 ic->icmp_id = original_id;
313 /* Put original address back into IP header */
315 struct in_addr original_address;
317 original_address = GetOriginalAddress(lnk);
318 DifferentialChecksum(&pip->ip_sum,
319 &original_address, &pip->ip_dst, 2);
320 pip->ip_dst = original_address;
323 return (PKT_ALIAS_OK);
325 return (PKT_ALIAS_IGNORED);
329 Alias incoming ICMP error messages containing
330 IP header and first 64 bits of datagram.
333 IcmpAliasIn2(struct libalias *la, struct ip *pip)
336 struct icmp *ic, *ic2;
339 struct alias_link *lnk;
341 LIBALIAS_LOCK_ASSERT(la);
342 ic = (struct icmp *)ip_next(pip);
345 ud = (struct udphdr *)ip_next(ip);
346 tc = (struct tcphdr *)ip_next(ip);
347 ic2 = (struct icmp *)ip_next(ip);
349 if (ip->ip_p == IPPROTO_UDP)
350 lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
351 ud->uh_dport, ud->uh_sport,
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,
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);
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;
371 original_address = GetOriginalAddress(lnk);
372 original_port = GetOriginalPort(lnk);
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);
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;
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;
400 original_address = GetOriginalAddress(lnk);
401 original_id = GetOriginalPort(lnk);
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);
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;
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;
424 return (PKT_ALIAS_OK);
426 return (PKT_ALIAS_IGNORED);
430 IcmpAliasIn(struct libalias *la, struct ip *pip)
436 LIBALIAS_LOCK_ASSERT(la);
438 dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
439 if (dlen < ICMP_MINLEN)
440 return (PKT_ALIAS_IGNORED);
442 /* Return if proxy-only mode is enabled */
443 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
444 return (PKT_ALIAS_OK);
446 ic = (struct icmp *)ip_next(pip);
448 iresult = PKT_ALIAS_IGNORED;
449 switch (ic->icmp_type) {
451 case ICMP_TSTAMPREPLY:
452 if (ic->icmp_code == 0) {
453 iresult = IcmpAliasIn1(la, pip);
457 case ICMP_SOURCEQUENCH:
460 if (dlen < ICMP_ADVLENMIN ||
461 dlen < (size_t)ICMP_ADVLEN(ic))
462 return (PKT_ALIAS_IGNORED);
463 iresult = IcmpAliasIn2(la, pip);
467 iresult = IcmpAliasIn1(la, pip);
474 Alias outgoing echo and timestamp requests.
475 De-alias outgoing echo and timestamp replies.
478 IcmpAliasOut1(struct libalias *la, struct ip *pip, int create)
480 struct alias_link *lnk;
483 LIBALIAS_LOCK_ASSERT(la);
484 ic = (struct icmp *)ip_next(pip);
486 /* Save overwritten data for when echo packet returns */
487 lnk = FindIcmpOut(la, pip->ip_src, pip->ip_dst, ic->icmp_id, create);
492 alias_id = GetAliasPort(lnk);
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);
499 /* Alias sequence number */
500 ic->icmp_id = alias_id;
502 /* Change source address */
504 struct in_addr alias_address;
506 alias_address = GetAliasAddress(lnk);
507 DifferentialChecksum(&pip->ip_sum,
508 &alias_address, &pip->ip_src, 2);
509 pip->ip_src = alias_address;
512 return (PKT_ALIAS_OK);
514 return (PKT_ALIAS_IGNORED);
518 Alias outgoing ICMP error messages containing
519 IP header and first 64 bits of datagram.
522 IcmpAliasOut2(struct libalias *la, struct ip *pip)
525 struct icmp *ic, *ic2;
528 struct alias_link *lnk;
530 LIBALIAS_LOCK_ASSERT(la);
531 ic = (struct icmp *)ip_next(pip);
534 ud = (struct udphdr *)ip_next(ip);
535 tc = (struct tcphdr *)ip_next(ip);
536 ic2 = (struct icmp *)ip_next(ip);
538 if (ip->ip_p == IPPROTO_UDP)
539 lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
540 ud->uh_dport, ud->uh_sport,
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,
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);
555 if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
557 struct in_addr alias_address;
560 alias_address = GetAliasAddress(lnk);
561 alias_port = GetAliasPort(lnk);
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);
571 * Alias address in IP header if it comes from the host
572 * the original TCP/UDP packet was destined for.
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;
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) {
585 struct in_addr alias_address;
588 alias_address = GetAliasAddress(lnk);
589 alias_id = GetAliasPort(lnk);
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);
599 * Alias address in IP header if it comes from the host
600 * the original ICMP message was destined for.
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;
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;
612 return (PKT_ALIAS_OK);
614 return (PKT_ALIAS_IGNORED);
618 IcmpAliasOut(struct libalias *la, struct ip *pip, int create)
623 LIBALIAS_LOCK_ASSERT(la);
626 /* Return if proxy-only mode is enabled */
627 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
628 return (PKT_ALIAS_OK);
630 ic = (struct icmp *)ip_next(pip);
632 iresult = PKT_ALIAS_IGNORED;
633 switch (ic->icmp_type) {
636 if (ic->icmp_code == 0) {
637 iresult = IcmpAliasOut1(la, pip, create);
641 case ICMP_SOURCEQUENCH:
644 iresult = IcmpAliasOut2(la, pip);
647 case ICMP_TSTAMPREPLY:
648 iresult = IcmpAliasOut1(la, pip, create);
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
660 ProtoAliasIn(struct libalias *la, struct in_addr ip_src,
661 struct ip *pip, u_char ip_p, u_short *ip_sum)
663 struct alias_link *lnk;
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);
670 lnk = FindProtoIn(la, ip_src, pip->ip_dst, ip_p);
672 struct in_addr original_address;
674 original_address = GetOriginalAddress(lnk);
676 /* Restore original IP address */
677 DifferentialChecksum(ip_sum,
678 &original_address, &pip->ip_dst, 2);
679 pip->ip_dst = original_address;
681 return (PKT_ALIAS_OK);
683 return (PKT_ALIAS_IGNORED);
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.
692 ProtoAliasOut(struct libalias *la, struct ip *pip,
693 struct in_addr ip_dst, u_char ip_p, u_short *ip_sum, int create)
695 struct alias_link *lnk;
697 LIBALIAS_LOCK_ASSERT(la);
699 /* Return if proxy-only mode is enabled */
700 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
701 return (PKT_ALIAS_OK);
704 return (PKT_ALIAS_IGNORED);
706 lnk = FindProtoOut(la, pip->ip_src, ip_dst, ip_p);
708 struct in_addr alias_address;
710 alias_address = GetAliasAddress(lnk);
712 /* Change source address */
713 DifferentialChecksum(ip_sum,
714 &alias_address, &pip->ip_src, 2);
715 pip->ip_src = alias_address;
717 return (PKT_ALIAS_OK);
719 return (PKT_ALIAS_IGNORED);
722 #define MF_ISSET(_pip) (ntohs((_pip)->ip_off) & IP_MF)
723 #define FRAG_NO_HDR(_pip) (ntohs((_pip)->ip_off) & IP_OFFMASK)
725 static struct udphdr *
726 ValidateUdpLength(struct ip *pip)
732 KASSERT(!FRAG_NO_HDR(pip), ("header-less fragment isn't expected here"));
734 dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
735 if (dlen < sizeof(struct udphdr))
737 ud = (struct udphdr *)ip_next(pip);
738 if (!MF_ISSET(pip) && dlen < ntohs(ud->uh_ulen))
744 UdpAliasIn(struct libalias *la, struct ip *pip)
747 struct alias_link *lnk;
749 LIBALIAS_LOCK_ASSERT(la);
751 ud = ValidateUdpLength(pip);
753 return (PKT_ALIAS_IGNORED);
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));
759 struct in_addr alias_address;
760 struct in_addr original_address;
761 struct in_addr proxy_address;
766 struct alias_data ad = {
768 .oaddr = &original_address,
769 .aaddr = &alias_address,
770 .aport = &alias_port,
771 .sport = &ud->uh_sport,
772 .dport = &ud->uh_dport,
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);
783 /* Walk out chain. */
784 error = find_handler(IN, UDP, la, pip, &ad);
785 /* If we cannot figure out the packet, ignore it. */
787 return (PKT_ALIAS_IGNORED);
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);
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;
805 if (proxy_address.s_addr != 0) {
806 accumulate += twowords(&pip->ip_src);
807 accumulate -= twowords(&proxy_address);
810 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
813 /* XXX: Could the two if's below be concatenated to one ? */
814 /* Restore source port and/or address in case of proxying*/
816 ud->uh_sport = proxy_port;
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;
824 /* Restore original IP address */
825 DifferentialChecksum(&pip->ip_sum,
826 &original_address, &pip->ip_dst, 2);
827 pip->ip_dst = original_address;
829 return (PKT_ALIAS_OK);
831 return (PKT_ALIAS_IGNORED);
835 UdpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
838 struct alias_link *lnk;
839 struct in_addr dest_address;
840 struct in_addr proxy_server_address;
842 u_short proxy_server_port;
845 LIBALIAS_LOCK_ASSERT(la);
847 ud = ValidateUdpLength(pip);
849 return (PKT_ALIAS_IGNORED);
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);
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;
862 if (proxy_type != 0) {
865 accumulate = twowords(&pip->ip_dst);
866 accumulate -= twowords(&proxy_server_address);
868 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
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);
877 pip->ip_dst = proxy_server_address;
878 ud->uh_dport = proxy_server_port;
880 lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
881 ud->uh_sport, ud->uh_dport,
882 IPPROTO_UDP, create);
885 struct in_addr alias_address;
886 struct alias_data ad = {
889 .aaddr = &alias_address,
890 .aport = &alias_port,
891 .sport = &ud->uh_sport,
892 .dport = &ud->uh_dport,
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);
906 alias_address = GetAliasAddress(lnk);
907 alias_port = GetAliasPort(lnk);
909 /* Walk out chain. */
910 find_handler(OUT, UDP, la, pip, &ad);
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) {
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);
923 /* Put alias port in UDP header */
924 ud->uh_sport = alias_port;
926 /* Change source address */
927 DifferentialChecksum(&pip->ip_sum,
928 &alias_address, &pip->ip_src, 2);
929 pip->ip_src = alias_address;
931 return (PKT_ALIAS_OK);
933 return (PKT_ALIAS_IGNORED);
937 TcpAliasIn(struct libalias *la, struct ip *pip)
940 struct alias_link *lnk;
943 LIBALIAS_LOCK_ASSERT(la);
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);
950 lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
951 tc->th_sport, tc->th_dport,
953 !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
955 struct in_addr alias_address;
956 struct in_addr original_address;
957 struct in_addr proxy_address;
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 [*].
968 struct alias_data ad = {
973 .sport = &tc->th_sport,
974 .dport = &tc->th_dport,
978 /* Walk out chain. */
979 find_handler(IN, TCP, la, pip, &ad);
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);
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.
994 struct alias_data ad = {
996 .oaddr = &original_address,
997 .aaddr = &alias_address,
998 .aport = &alias_port,
999 .sport = &ud->uh_sport,
1000 .dport = &ud->uh_dport,
1004 /* Walk out chain. */
1005 error = find_handler(la, pip, &ad);
1006 if (error == EHDNOF)
1007 printf("Protocol handler not found\n");
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);
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);
1026 /* See if ACK number needs to be modified */
1027 if (GetAckModified(lnk) == 1) {
1030 tc = (struct tcphdr *)ip_next(pip);
1031 delta = GetDeltaAckIn(tc->th_ack, lnk);
1033 accumulate += twowords(&tc->th_ack);
1034 tc->th_ack = htonl(ntohl(tc->th_ack) - delta);
1035 accumulate -= twowords(&tc->th_ack);
1038 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1040 /* Restore original IP address */
1041 accumulate = twowords(&pip->ip_dst);
1042 pip->ip_dst = original_address;
1043 accumulate -= twowords(&pip->ip_dst);
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);
1052 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1054 /* Monitor TCP connection state */
1055 tc = (struct tcphdr *)ip_next(pip);
1056 TcpMonitorIn(tc->th_flags, lnk);
1058 return (PKT_ALIAS_OK);
1060 return (PKT_ALIAS_IGNORED);
1064 TcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
1068 u_short proxy_server_port;
1070 struct in_addr dest_address;
1071 struct in_addr proxy_server_address;
1073 struct alias_link *lnk;
1075 LIBALIAS_LOCK_ASSERT(la);
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);
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);
1089 if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
1090 return (PKT_ALIAS_OK);
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) {
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);
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);
1111 lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
1112 tc->th_sport, tc->th_dport,
1113 IPPROTO_TCP, create);
1115 return (PKT_ALIAS_IGNORED);
1118 struct in_addr alias_address;
1120 struct alias_data ad = {
1123 .aaddr = &alias_address,
1124 .aport = &alias_port,
1125 .sport = &tc->th_sport,
1126 .dport = &tc->th_dport,
1127 .maxpktsize = maxpacketsize
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);
1139 /* Get alias address and port */
1140 alias_port = GetAliasPort(lnk);
1141 alias_address = GetAliasAddress(lnk);
1143 /* Monitor TCP connection state */
1144 tc = (struct tcphdr *)ip_next(pip);
1145 TcpMonitorOut(tc->th_flags, lnk);
1147 /* Walk out chain. */
1148 find_handler(OUT, TCP, la, pip, &ad);
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);
1158 /* Modify sequence number if necessary */
1159 if (GetAckModified(lnk) == 1) {
1162 tc = (struct tcphdr *)ip_next(pip);
1163 delta = GetDeltaSeqOut(tc->th_seq, lnk);
1165 accumulate += twowords(&tc->th_seq);
1166 tc->th_seq = htonl(ntohl(tc->th_seq) + delta);
1167 accumulate -= twowords(&tc->th_seq);
1170 ADJUST_CHECKSUM(accumulate, tc->th_sum);
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);
1178 return (PKT_ALIAS_OK);
1180 return (PKT_ALIAS_IGNORED);
1183 /* Fragment Handling
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.
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,
1203 FragmentIn(struct libalias *la, struct in_addr ip_src, struct ip *pip,
1204 u_short ip_id, u_short *ip_sum)
1206 struct alias_link *lnk;
1208 LIBALIAS_LOCK_ASSERT(la);
1209 lnk = FindFragmentIn2(la, ip_src, pip->ip_dst, ip_id);
1211 struct in_addr original_address;
1213 GetFragmentAddr(lnk, &original_address);
1214 DifferentialChecksum(ip_sum,
1215 &original_address, &pip->ip_dst, 2);
1216 pip->ip_dst = original_address;
1218 return (PKT_ALIAS_OK);
1220 return (PKT_ALIAS_UNRESOLVED_FRAGMENT);
1224 FragmentOut(struct libalias *la, struct ip *pip, u_short *ip_sum)
1226 struct in_addr alias_address;
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;
1234 return (PKT_ALIAS_OK);
1237 /* Outside World Access
1239 PacketAliasSaveFragment()
1240 PacketAliasGetFragment()
1241 PacketAliasFragmentIn()
1246 (prototypes in alias.h)
1250 LibAliasSaveFragment(struct libalias *la, void *ptr)
1253 struct alias_link *lnk;
1257 pip = (struct ip *)ptr;
1258 lnk = AddFragmentPtrLink(la, pip->ip_src, pip->ip_id);
1259 iresult = PKT_ALIAS_ERROR;
1261 SetFragmentPtr(lnk, ptr);
1262 iresult = PKT_ALIAS_OK;
1264 LIBALIAS_UNLOCK(la);
1269 LibAliasGetFragment(struct libalias *la, void *ptr)
1271 struct alias_link *lnk;
1276 pip = (struct ip *)ptr;
1277 lnk = FindFragmentPtr(la, pip->ip_src, pip->ip_id);
1279 GetFragmentPtr(lnk, &fptr);
1280 SetFragmentPtr(lnk, NULL);
1281 SetExpire(lnk, 0); /* Deletes link */
1285 LIBALIAS_UNLOCK(la);
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 */
1300 pip = (struct ip *)ptr;
1301 fpip = (struct ip *)ptr_fragment;
1303 DifferentialChecksum(&fpip->ip_sum,
1304 &pip->ip_dst, &fpip->ip_dst, 2);
1305 fpip->ip_dst = pip->ip_dst;
1306 LIBALIAS_UNLOCK(la);
1309 /* Local prototypes */
1311 LibAliasOutLocked(struct libalias *la, struct ip *pip,
1312 int maxpacketsize, int create);
1314 LibAliasInLocked(struct libalias *la, struct ip *pip,
1318 LibAliasIn(struct libalias *la, void *ptr, int maxpacketsize)
1323 res = LibAliasInLocked(la, (struct ip *)ptr, maxpacketsize);
1324 LIBALIAS_UNLOCK(la);
1329 LibAliasInLocked(struct libalias *la, struct ip *pip, int maxpacketsize)
1331 struct in_addr alias_addr;
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;
1341 alias_addr = pip->ip_dst;
1343 /* Defense against mangled packets */
1344 if (ntohs(pip->ip_len) > maxpacketsize
1345 || (pip->ip_hl << 2) > maxpacketsize) {
1346 iresult = PKT_ALIAS_IGNORED;
1350 if (FRAG_NO_HDR(pip)) {
1351 iresult = FragmentIn(la, pip->ip_src, pip, pip->ip_id,
1356 iresult = PKT_ALIAS_IGNORED;
1357 switch (pip->ip_p) {
1359 iresult = IcmpAliasIn(la, pip);
1362 iresult = UdpAliasIn(la, pip);
1365 iresult = TcpAliasIn(la, pip);
1369 iresult = SctpAlias(la, pip, SN_TO_LOCAL);
1374 struct alias_data ad = {
1384 /* Walk out chain. */
1385 error = find_handler(IN, IP, la, pip, &ad);
1387 iresult = PKT_ALIAS_OK;
1389 iresult = ProtoAliasIn(la, pip->ip_src,
1390 pip, pip->ip_p, &pip->ip_sum);
1394 iresult = ProtoAliasIn(la, pip->ip_src, pip,
1395 pip->ip_p, &pip->ip_sum);
1399 if (MF_ISSET(pip)) {
1400 struct alias_link *lnk;
1402 lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id);
1404 iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
1405 SetFragmentAddr(lnk, pip->ip_dst);
1407 iresult = PKT_ALIAS_ERROR;
1415 /* Unregistered address ranges */
1417 /* 10.0.0.0 -> 10.255.255.255 */
1418 #define UNREG_ADDR_A_LOWER 0x0a000000
1419 #define UNREG_ADDR_A_UPPER 0x0affffff
1421 /* 172.16.0.0 -> 172.31.255.255 */
1422 #define UNREG_ADDR_B_LOWER 0xac100000
1423 #define UNREG_ADDR_B_UPPER 0xac1fffff
1425 /* 192.168.0.0 -> 192.168.255.255 */
1426 #define UNREG_ADDR_C_LOWER 0xc0a80000
1427 #define UNREG_ADDR_C_UPPER 0xc0a8ffff
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
1434 LibAliasOut(struct libalias *la, void *ptr, int maxpacketsize)
1439 res = LibAliasOutLocked(la, (struct ip *)ptr, maxpacketsize, 1);
1440 LIBALIAS_UNLOCK(la);
1445 LibAliasOutTry(struct libalias *la, void *ptr, int maxpacketsize, int create)
1450 res = LibAliasOutLocked(la, (struct ip *)ptr, maxpacketsize, create);
1451 LIBALIAS_UNLOCK(la);
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 ? */
1463 struct in_addr addr_save;
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;
1473 /* Defense against mangled packets */
1474 if (ntohs(pip->ip_len) > maxpacketsize
1475 || (pip->ip_hl << 2) > maxpacketsize) {
1476 iresult = PKT_ALIAS_IGNORED;
1480 addr_save = GetDefaultAliasAddress(la);
1481 if (la->packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY ||
1482 la->packetAliasMode & PKT_ALIAS_UNREGISTERED_CGN) {
1487 addr = ntohl(pip->ip_src.s_addr);
1488 if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER)
1490 else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER)
1492 else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER)
1494 else if (addr >= UNREG_ADDR_CGN_LOWER && addr <= UNREG_ADDR_CGN_UPPER &&
1495 la->packetAliasMode & PKT_ALIAS_UNREGISTERED_CGN)
1499 SetDefaultAliasAddress(la, pip->ip_src);
1501 } else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) {
1502 SetDefaultAliasAddress(la, pip->ip_src);
1505 if (FRAG_NO_HDR(pip)) {
1506 iresult = FragmentOut(la, pip, &pip->ip_sum);
1507 goto getout_restore;
1510 iresult = PKT_ALIAS_IGNORED;
1511 switch (pip->ip_p) {
1513 iresult = IcmpAliasOut(la, pip, create);
1516 iresult = UdpAliasOut(la, pip, maxpacketsize, create);
1519 iresult = TcpAliasOut(la, pip, maxpacketsize, create);
1523 iresult = SctpAlias(la, pip, SN_TO_GLOBAL);
1528 struct alias_data ad = {
1537 /* Walk out chain. */
1538 error = find_handler(OUT, IP, la, pip, &ad);
1540 iresult = PKT_ALIAS_OK;
1542 iresult = ProtoAliasOut(la, pip,
1543 pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
1547 iresult = ProtoAliasOut(la, pip,
1548 pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
1553 SetDefaultAliasAddress(la, addr_save);
1559 LibAliasUnaliasOut(struct libalias *la,
1560 void *ptr, /* valid IP packet */
1561 int maxpacketsize /* for error checking */
1568 struct alias_link *lnk;
1569 int iresult = PKT_ALIAS_IGNORED;
1572 pip = (struct ip *)ptr;
1574 /* Defense against mangled packets */
1575 if (ntohs(pip->ip_len) > maxpacketsize
1576 || (pip->ip_hl << 2) > maxpacketsize)
1579 ud = (struct udphdr *)ip_next(pip);
1580 tc = (struct tcphdr *)ip_next(pip);
1581 ic = (struct icmp *)ip_next(pip);
1584 if (pip->ip_p == IPPROTO_UDP)
1585 lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1586 ud->uh_dport, ud->uh_sport,
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,
1592 else if (pip->ip_p == IPPROTO_ICMP)
1593 lnk = FindIcmpIn(la, pip->ip_dst, pip->ip_src, ic->icmp_id, 0);
1597 /* Change it from an aliased packet to an unaliased packet */
1599 if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP) {
1601 struct in_addr original_address;
1602 u_short original_port;
1604 original_address = GetOriginalAddress(lnk);
1605 original_port = GetOriginalPort(lnk);
1607 /* Adjust TCP/UDP checksum */
1608 accumulate = twowords(&pip->ip_src);
1609 accumulate -= twowords(&original_address);
1611 if (pip->ip_p == IPPROTO_UDP) {
1612 accumulate += ud->uh_sport;
1613 accumulate -= original_port;
1614 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
1616 accumulate += tc->th_sport;
1617 accumulate -= original_port;
1618 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1621 /* Adjust IP checksum */
1622 DifferentialChecksum(&pip->ip_sum,
1623 &original_address, &pip->ip_src, 2);
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;
1630 tc->th_sport = original_port;
1632 iresult = PKT_ALIAS_OK;
1633 } else if (pip->ip_p == IPPROTO_ICMP) {
1635 struct in_addr original_address;
1636 u_short original_id;
1638 original_address = GetOriginalAddress(lnk);
1639 original_id = GetOriginalPort(lnk);
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);
1648 /* Adjust IP checksum */
1649 DifferentialChecksum(&pip->ip_sum,
1650 &original_address, &pip->ip_src, 2);
1652 /* Un-alias source address and port number */
1653 pip->ip_src = original_address;
1654 ic->icmp_id = original_id;
1656 iresult = PKT_ALIAS_OK;
1660 LIBALIAS_UNLOCK(la);
1667 LibAliasRefreshModules(void)
1669 char buf[256], conf[] = "/etc/libalias.conf";
1673 fd = fopen(conf, "r");
1675 err(1, "fopen(%s)", conf);
1677 LibAliasUnLoadAllModule();
1680 fgets(buf, 256, fd);
1685 for (i = 0; i < len; i++)
1686 if (!isspace(buf[i]))
1690 buf[len - 1] = '\0';
1691 LibAliasLoadModule(buf);
1699 LibAliasLoadModule(char *path)
1703 struct proto_handler *m;
1707 handle = dlopen (path, RTLD_LAZY);
1709 fprintf(stderr, "%s\n", dlerror());
1713 p = dlsym(handle, "alias_mod");
1714 if ((error = dlerror()) != NULL) {
1715 fprintf(stderr, "%s\n", dlerror());
1719 t = malloc(sizeof(struct dll));
1722 strncpy(t->name, p->name, DLL_LEN);
1724 if (attach_dll(t) == EEXIST) {
1726 fprintf(stderr, "dll conflict\n");
1730 m = dlsym(t->handle, "handlers");
1731 if ((error = dlerror()) != NULL) {
1732 fprintf(stderr, "%s\n", error);
1736 LibAliasAttachHandlers(m);
1741 LibAliasUnLoadAllModule(void)
1744 struct proto_handler *p;
1746 /* Unload all modules then reload everything. */
1747 while ((p = first_handler()) != NULL) {
1748 LibAliasDetachHandlers(p);
1750 while ((t = walk_dll_chain()) != NULL) {
1761 * m_megapullup() - this function is a big hack.
1762 * Thankfully, it's only used in ng_nat and ipfw+nat.
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.
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.
1773 m_megapullup(struct mbuf *m, int len)
1777 if (len > m->m_pkthdr.len)
1780 if (m->m_next == NULL && M_WRITABLE(m))
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);
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;