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