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