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