]> git.saurik.com Git - apple/network_cmds.git/blame - alias/alias.c
network_cmds-85.tar.gz
[apple/network_cmds.git] / alias / alias.c
CommitLineData
b7080c8e
A
1/* -*- mode: c; tab-width: 8; c-basic-indent: 4; -*- */
2/*
3 Alias.c provides supervisory control for the functions of the
4 packet aliasing software. It consists of routines to monitor
5 TCP connection state, protocol-specific aliasing routines,
6 fragment handling and the following outside world functional
7 interfaces: SaveFragmentPtr, GetFragmentPtr, FragmentAliasIn,
8 PacketAliasIn and PacketAliasOut.
9
10 The other C program files are briefly described. The data
11 structure framework which holds information needed to translate
12 packets is encapsulated in alias_db.c. Data is accessed by
13 function calls, so other segments of the program need not know
14 about the underlying data structures. Alias_ftp.c contains
15 special code for modifying the ftp PORT command used to establish
16 data connections, while alias_irc.c do the same for IRC
17 DCC. Alias_util.c contains a few utility routines.
18
19 This software is placed into the public domain with no restrictions
20 on its distribution.
21
22 Version 1.0 August, 1996 (cjm)
23
24 Version 1.1 August 20, 1996 (cjm)
25 PPP host accepts incoming connections for ports 0 to 1023.
26 (Gary Roberts pointed out the need to handle incoming
27 connections.)
28
29 Version 1.2 September 7, 1996 (cjm)
30 Fragment handling error in alias_db.c corrected.
31 (Tom Torrance helped fix this problem.)
32
33 Version 1.4 September 16, 1996 (cjm)
34 - A more generalized method for handling incoming
35 connections, without the 0-1023 restriction, is
36 implemented in alias_db.c
37 - Improved ICMP support in alias.c. Traceroute
38 packet streams can now be correctly aliased.
39 - TCP connection closing logic simplified in
40 alias.c and now allows for additional 1 minute
41 "grace period" after FIN or RST is observed.
42
43 Version 1.5 September 17, 1996 (cjm)
44 Corrected error in handling incoming UDP packets with 0 checksum.
45 (Tom Torrance helped fix this problem.)
46
47 Version 1.6 September 18, 1996 (cjm)
48 Simplified ICMP aliasing scheme. Should now support
49 traceroute from Win95 as well as FreeBSD.
50
51 Version 1.7 January 9, 1997 (cjm)
52 - Out-of-order fragment handling.
53 - IP checksum error fixed for ftp transfers
54 from aliasing host.
55 - Integer return codes added to all
56 aliasing/de-aliasing functions.
57 - Some obsolete comments cleaned up.
58 - Differential checksum computations for
59 IP header (TCP, UDP and ICMP were already
60 differential).
61
62 Version 2.1 May 1997 (cjm)
63 - Added support for outgoing ICMP error
64 messages.
65 - Added two functions PacketAliasIn2()
66 and PacketAliasOut2() for dynamic address
67 control (e.g. round-robin allocation of
68 incoming packets).
69
70 Version 2.2 July 1997 (cjm)
71 - Rationalized API function names to begin
72 with "PacketAlias..."
73 - Eliminated PacketAliasIn2() and
74 PacketAliasOut2() as poorly conceived.
75
76 Version 2.3 Dec 1998 (dillon)
77 - Major bounds checking additions, see FreeBSD/CVS
78
79 See HISTORY file for additional revisions.
80
81*/
82
83#include <stdio.h>
84#include <unistd.h>
85
86#include <sys/param.h>
87#include <sys/types.h>
88
89#include <netinet/in_systm.h>
90#include <netinet/in.h>
91#include <netinet/ip.h>
92#include <netinet/ip_icmp.h>
93#include <netinet/tcp.h>
94#include <netinet/udp.h>
95
96#ifndef IPPROTO_GRE
97#define IPPROTO_GRE 47
98#endif
99
100#include "alias_local.h"
101#include "alias.h"
102
103#define NETBIOS_NS_PORT_NUMBER 137
104#define NETBIOS_DGM_PORT_NUMBER 138
105#define FTP_CONTROL_PORT_NUMBER 21
106#define IRC_CONTROL_PORT_NUMBER_1 6667
107#define IRC_CONTROL_PORT_NUMBER_2 6668
108#define CUSEEME_PORT_NUMBER 7648
109
110
111
112
113/* TCP Handling Routines
114
115 TcpMonitorIn() -- These routines monitor TCP connections, and
116 TcpMonitorOut() delete a link when a connection is closed.
117
118These routines look for SYN, ACK and RST flags to determine when TCP
119connections open and close. When a TCP connection closes, the data
120structure containing packet aliasing information is deleted after
121a timeout period.
122*/
123
124/* Local prototypes */
125static void TcpMonitorIn(struct ip *, struct alias_link *);
126
127static void TcpMonitorOut(struct ip *, struct alias_link *);
128
129
130static void
131TcpMonitorIn(struct ip *pip, struct alias_link *link)
132{
133 struct tcphdr *tc;
134
135 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
136
137 switch (GetStateIn(link))
138 {
139 case ALIAS_TCP_STATE_NOT_CONNECTED:
140 if (tc->th_flags & TH_SYN)
141 SetStateIn(link, ALIAS_TCP_STATE_CONNECTED);
142 break;
143 case ALIAS_TCP_STATE_CONNECTED:
144 if (tc->th_flags & TH_FIN
145 || tc->th_flags & TH_RST)
146 SetStateIn(link, ALIAS_TCP_STATE_DISCONNECTED);
147 break;
148 }
149}
150
151static void
152TcpMonitorOut(struct ip *pip, struct alias_link *link)
153{
154 struct tcphdr *tc;
155
156 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
157
158 switch (GetStateOut(link))
159 {
160 case ALIAS_TCP_STATE_NOT_CONNECTED:
161 if (tc->th_flags & TH_SYN)
162 SetStateOut(link, ALIAS_TCP_STATE_CONNECTED);
163 break;
164 case ALIAS_TCP_STATE_CONNECTED:
165 if (tc->th_flags & TH_FIN
166 || tc->th_flags & TH_RST)
167 SetStateOut(link, ALIAS_TCP_STATE_DISCONNECTED);
168 break;
169 }
170}
171
172
173
174
175
176/* Protocol Specific Packet Aliasing Routines
177
178 IcmpAliasIn(), IcmpAliasIn1(), IcmpAliasIn2(), IcmpAliasIn3()
179 IcmpAliasOut(), IcmpAliasOut1(), IcmpAliasOut2(), IcmpAliasOut3()
180 UdpAliasIn(), UdpAliasOut()
181 TcpAliasIn(), TcpAliasOut()
182
183These routines handle protocol specific details of packet aliasing.
184One may observe a certain amount of repetitive arithmetic in these
185functions, the purpose of which is to compute a revised checksum
186without actually summing over the entire data packet, which could be
187unnecessarily time consuming.
188
189The purpose of the packet aliasing routines is to replace the source
190address of the outgoing packet and then correctly put it back for
191any incoming packets. For TCP and UDP, ports are also re-mapped.
192
193For ICMP echo/timestamp requests and replies, the following scheme
194is used: the id number is replaced by an alias for the outgoing
195packet.
196
197ICMP error messages are handled by looking at the IP fragment
198in the data section of the message.
199
200For TCP and UDP protocols, a port number is chosen for an outgoing
201packet, and then incoming packets are identified by IP address and
202port numbers. For TCP packets, there is additional logic in the event
203that sequence and ack numbers have been altered (as is the case for
204FTP data port commands).
205
206The port numbers used by the packet aliasing module are not true
207ports in the Unix sense. No sockets are actually bound to ports.
208They are more correctly thought of as placeholders.
209
210All packets go through the aliasing mechanism, whether they come from
211the gateway machine or other machines on a local area network.
212*/
213
214
215/* Local prototypes */
216static int IcmpAliasIn1(struct ip *);
217static int IcmpAliasIn2(struct ip *);
218static int IcmpAliasIn3(struct ip *);
219static int IcmpAliasIn (struct ip *);
220
221static int IcmpAliasOut1(struct ip *);
222static int IcmpAliasOut2(struct ip *);
223static int IcmpAliasOut3(struct ip *);
224static int IcmpAliasOut (struct ip *);
225
226static int UdpAliasOut(struct ip *);
227static int UdpAliasIn (struct ip *);
228
229static int TcpAliasOut(struct ip *, int);
230static int TcpAliasIn (struct ip *);
231
232
233static int
234IcmpAliasIn1(struct ip *pip)
235{
236/*
237 De-alias incoming echo and timestamp replies
238*/
239 struct alias_link *link;
240 struct icmp *ic;
241
242 ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2));
243
244/* Get source address from ICMP data field and restore original data */
245 link = FindIcmpIn(pip->ip_src, pip->ip_dst, ic->icmp_id);
246 if (link != NULL)
247 {
248 u_short original_id;
249 int accumulate;
250
251 original_id = GetOriginalPort(link);
252
253/* Adjust ICMP checksum */
254 accumulate = ic->icmp_id;
255 accumulate -= original_id;
256 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum)
257
258/* Put original sequence number back in */
259 ic->icmp_id = original_id;
260
261/* Put original address back into IP header */
262 {
263 struct in_addr original_address;
264
265 original_address = GetOriginalAddress(link);
266 DifferentialChecksum(&pip->ip_sum,
267 (u_short *) &original_address,
268 (u_short *) &pip->ip_dst,
269 2);
270 pip->ip_dst = original_address;
271 }
272
273 return(PKT_ALIAS_OK);
274 }
275 return(PKT_ALIAS_IGNORED);
276}
277
278static int
279IcmpAliasIn2(struct ip *pip)
280{
281/*
282 Alias incoming ICMP error messages containing
283 IP header and first 64 bits of datagram.
284*/
285 struct ip *ip;
286 struct icmp *ic, *ic2;
287 struct udphdr *ud;
288 struct tcphdr *tc;
289 struct alias_link *link;
290
291 ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2));
292 ip = (struct ip *) ic->icmp_data;
293
294 ud = (struct udphdr *) ((char *) ip + (ip->ip_hl <<2));
295 tc = (struct tcphdr *) ud;
296 ic2 = (struct icmp *) ud;
297
298 if (ip->ip_p == IPPROTO_UDP)
299 link = FindUdpTcpIn(ip->ip_dst, ip->ip_src,
300 ud->uh_dport, ud->uh_sport,
301 IPPROTO_UDP);
302 else if (ip->ip_p == IPPROTO_TCP)
303 link = FindUdpTcpIn(ip->ip_dst, ip->ip_src,
304 tc->th_dport, tc->th_sport,
305 IPPROTO_TCP);
306 else if (ip->ip_p == IPPROTO_ICMP) {
307 if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
308 link = FindIcmpIn(ip->ip_dst, ip->ip_src, ic2->icmp_id);
309 else
310 link = NULL;
311 } else
312 link = NULL;
313
314 if (link != NULL)
315 {
316 if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP)
317 {
318 u_short *sptr;
319 int accumulate;
320 struct in_addr original_address;
321 u_short original_port;
322
323 original_address = GetOriginalAddress(link);
324 original_port = GetOriginalPort(link);
325
326/* Adjust ICMP checksum */
327 sptr = (u_short *) &(ip->ip_src);
328 accumulate = *sptr++;
329 accumulate += *sptr;
330 sptr = (u_short *) &original_address;
331 accumulate -= *sptr++;
332 accumulate -= *sptr;
333 accumulate += ud->uh_sport;
334 accumulate -= original_port;
335 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum)
336
337/* Un-alias address in IP header */
338 DifferentialChecksum(&pip->ip_sum,
339 (u_short *) &original_address,
340 (u_short *) &pip->ip_dst,
341 2);
342 pip->ip_dst = original_address;
343
344/* Un-alias address and port number of original IP packet
345fragment contained in ICMP data section */
346 ip->ip_src = original_address;
347 ud->uh_sport = original_port;
348 }
349 else if (pip->ip_p == IPPROTO_ICMP)
350 {
351 u_short *sptr;
352 int accumulate;
353 struct in_addr original_address;
354 u_short original_id;
355
356 original_address = GetOriginalAddress(link);
357 original_id = GetOriginalPort(link);
358
359/* Adjust ICMP checksum */
360 sptr = (u_short *) &(ip->ip_src);
361 accumulate = *sptr++;
362 accumulate += *sptr;
363 sptr = (u_short *) &original_address;
364 accumulate -= *sptr++;
365 accumulate -= *sptr;
366 accumulate += ic2->icmp_id;
367 accumulate -= original_id;
368 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum)
369
370/* Un-alias address in IP header */
371 DifferentialChecksum(&pip->ip_sum,
372 (u_short *) &original_address,
373 (u_short *) &pip->ip_dst,
374 2);
375 pip->ip_dst = original_address;
376
377/* Un-alias address of original IP packet and seqence number of
378 embedded icmp datagram */
379 ip->ip_src = original_address;
380 ic2->icmp_id = original_id;
381 }
382 return(PKT_ALIAS_OK);
383 }
384 return(PKT_ALIAS_IGNORED);
385}
386
387static int
388IcmpAliasIn3(struct ip *pip)
389{
390 struct in_addr original_address;
391
392 original_address = FindOriginalAddress(pip->ip_dst);
393 DifferentialChecksum(&pip->ip_sum,
394 (u_short *) &original_address,
395 (u_short *) &pip->ip_dst,
396 2);
397 pip->ip_dst = original_address;
398
399 return PKT_ALIAS_OK;
400}
401
402
403static int
404IcmpAliasIn(struct ip *pip)
405{
406 int iresult;
407 struct icmp *ic;
408
409/* Return if proxy-only mode is enabled */
410 if (packetAliasMode & PKT_ALIAS_PROXY_ONLY)
411 return PKT_ALIAS_OK;
412
413 ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2));
414
415 iresult = PKT_ALIAS_IGNORED;
416 switch (ic->icmp_type)
417 {
418 case ICMP_ECHOREPLY:
419 case ICMP_TSTAMPREPLY:
420 if (ic->icmp_code == 0)
421 {
422 iresult = IcmpAliasIn1(pip);
423 }
424 break;
425 case ICMP_UNREACH:
426 case ICMP_SOURCEQUENCH:
427 case ICMP_TIMXCEED:
428 case ICMP_PARAMPROB:
429 iresult = IcmpAliasIn2(pip);
430 break;
431 case ICMP_ECHO:
432 case ICMP_TSTAMP:
433 iresult = IcmpAliasIn3(pip);
434 break;
435 }
436 return(iresult);
437}
438
439
440static int
441IcmpAliasOut1(struct ip *pip)
442{
443/*
444 Alias ICMP echo and timestamp packets
445*/
446 struct alias_link *link;
447 struct icmp *ic;
448
449 ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2));
450
451/* Save overwritten data for when echo packet returns */
452 link = FindIcmpOut(pip->ip_src, pip->ip_dst, ic->icmp_id);
453 if (link != NULL)
454 {
455 u_short alias_id;
456 int accumulate;
457
458 alias_id = GetAliasPort(link);
459
460/* Since data field is being modified, adjust ICMP checksum */
461 accumulate = ic->icmp_id;
462 accumulate -= alias_id;
463 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum)
464
465/* Alias sequence number */
466 ic->icmp_id = alias_id;
467
468/* Change source address */
469 {
470 struct in_addr alias_address;
471
472 alias_address = GetAliasAddress(link);
473 DifferentialChecksum(&pip->ip_sum,
474 (u_short *) &alias_address,
475 (u_short *) &pip->ip_src,
476 2);
477 pip->ip_src = alias_address;
478 }
479
480 return(PKT_ALIAS_OK);
481 }
482 return(PKT_ALIAS_IGNORED);
483}
484
485
486static int
487IcmpAliasOut2(struct ip *pip)
488{
489/*
490 Alias outgoing ICMP error messages containing
491 IP header and first 64 bits of datagram.
492*/
493 struct in_addr alias_addr;
494 struct ip *ip;
495 struct icmp *ic;
496
497 ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2));
498 ip = (struct ip *) ic->icmp_data;
499
500 alias_addr = FindAliasAddress(ip->ip_src);
501
502/* Alias destination address in IP fragment */
503 DifferentialChecksum(&ic->icmp_cksum,
504 (u_short *) &alias_addr,
505 (u_short *) &ip->ip_dst,
506 2);
507 ip->ip_dst = alias_addr;
508
509/* alias source address in IP header */
510 DifferentialChecksum(&pip->ip_sum,
511 (u_short *) &alias_addr,
512 (u_short *) &pip->ip_src,
513 2);
514 pip->ip_src = alias_addr;
515
516 return PKT_ALIAS_OK;
517}
518
519
520static int
521IcmpAliasOut3(struct ip *pip)
522{
523/*
524 Handle outgoing echo and timestamp replies. The
525 only thing which is done in this case is to alias
526 the source IP address of the packet.
527*/
528 struct in_addr alias_addr;
529
530 alias_addr = FindAliasAddress(pip->ip_src);
531 DifferentialChecksum(&pip->ip_sum,
532 (u_short *) &alias_addr,
533 (u_short *) &pip->ip_src,
534 2);
535 pip->ip_src = alias_addr;
536
537 return PKT_ALIAS_OK;
538}
539
540
541static int
542IcmpAliasOut(struct ip *pip)
543{
544 int iresult;
545 struct icmp *ic;
546
547/* Return if proxy-only mode is enabled */
548 if (packetAliasMode & PKT_ALIAS_PROXY_ONLY)
549 return PKT_ALIAS_OK;
550
551 ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2));
552
553 iresult = PKT_ALIAS_IGNORED;
554 switch (ic->icmp_type)
555 {
556 case ICMP_ECHO:
557 case ICMP_TSTAMP:
558 if (ic->icmp_code == 0)
559 {
560 iresult = IcmpAliasOut1(pip);
561 }
562 break;
563 case ICMP_UNREACH:
564 case ICMP_SOURCEQUENCH:
565 case ICMP_TIMXCEED:
566 case ICMP_PARAMPROB:
567 iresult = IcmpAliasOut2(pip);
568 break;
569 case ICMP_ECHOREPLY:
570 case ICMP_TSTAMPREPLY:
571 iresult = IcmpAliasOut3(pip);
572 }
573 return(iresult);
574}
575
576
577
578static int
579PptpAliasIn(struct ip *pip)
580{
581/*
582 Handle incoming PPTP packets. The
583 only thing which is done in this case is to alias
584 the dest IP address of the packet to our inside
585 machine.
586*/
587 struct in_addr alias_addr;
588
589 if (!GetPptpAlias (&alias_addr))
590 return PKT_ALIAS_IGNORED;
591
592 if (pip->ip_src.s_addr != alias_addr.s_addr) {
593
594 DifferentialChecksum(&pip->ip_sum,
595 (u_short *) &alias_addr,
596 (u_short *) &pip->ip_dst,
597 2);
598 pip->ip_dst = alias_addr;
599 }
600
601 return PKT_ALIAS_OK;
602}
603
604
605static int
606PptpAliasOut(struct ip *pip)
607{
608/*
609 Handle outgoing PPTP packets. The
610 only thing which is done in this case is to alias
611 the source IP address of the packet.
612*/
613 struct in_addr alias_addr;
614
615 if (!GetPptpAlias (&alias_addr))
616 return PKT_ALIAS_IGNORED;
617
618 if (pip->ip_src.s_addr == alias_addr.s_addr) {
619
620 alias_addr = FindAliasAddress(pip->ip_src);
621 DifferentialChecksum(&pip->ip_sum,
622 (u_short *) &alias_addr,
623 (u_short *) &pip->ip_src,
624 2);
625 pip->ip_src = alias_addr;
626 }
627
628 return PKT_ALIAS_OK;
629}
630
631
632
633static int
634UdpAliasIn(struct ip *pip)
635{
636 struct udphdr *ud;
637 struct alias_link *link;
638
639/* Return if proxy-only mode is enabled */
640 if (packetAliasMode & PKT_ALIAS_PROXY_ONLY)
641 return PKT_ALIAS_OK;
642
643 ud = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2));
644
645 link = FindUdpTcpIn(pip->ip_src, pip->ip_dst,
646 ud->uh_sport, ud->uh_dport,
647 IPPROTO_UDP);
648 if (link != NULL)
649 {
650 struct in_addr alias_address;
651 struct in_addr original_address;
652 u_short alias_port;
653 int accumulate;
654 u_short *sptr;
655 int r = 0;
656
657 alias_address = GetAliasAddress(link);
658 original_address = GetOriginalAddress(link);
659 alias_port = ud->uh_dport;
660 ud->uh_dport = GetOriginalPort(link);
661
662/* If NETBIOS Datagram, It should be alias address in UDP Data, too */
663 if (ntohs(ud->uh_dport) == NETBIOS_DGM_PORT_NUMBER
664 || ntohs(ud->uh_sport) == NETBIOS_DGM_PORT_NUMBER )
665 {
666 r = AliasHandleUdpNbt(pip, link, &original_address, ud->uh_dport);
667 } else if (ntohs(ud->uh_dport) == NETBIOS_NS_PORT_NUMBER
668 || ntohs(ud->uh_sport) == NETBIOS_NS_PORT_NUMBER )
669 {
670 r = AliasHandleUdpNbtNS(pip, link,
671 &alias_address,
672 &alias_port,
673 &original_address,
674 &ud->uh_dport );
675 }
676
677 if (ntohs(ud->uh_dport) == CUSEEME_PORT_NUMBER)
678 AliasHandleCUSeeMeIn(pip, original_address);
679
680/* If UDP checksum is not zero, then adjust since destination port */
681/* is being unaliased and destination port is being altered. */
682 if (ud->uh_sum != 0)
683 {
684 accumulate = alias_port;
685 accumulate -= ud->uh_dport;
686 sptr = (u_short *) &alias_address;
687 accumulate += *sptr++;
688 accumulate += *sptr;
689 sptr = (u_short *) &original_address;
690 accumulate -= *sptr++;
691 accumulate -= *sptr;
692 ADJUST_CHECKSUM(accumulate, ud->uh_sum)
693 }
694
695/* Restore original IP address */
696 DifferentialChecksum(&pip->ip_sum,
697 (u_short *) &original_address,
698 (u_short *) &pip->ip_dst,
699 2);
700 pip->ip_dst = original_address;
701
702 /*
703 * If we cannot figure out the packet, ignore it.
704 */
705 if (r < 0)
706 return(PKT_ALIAS_IGNORED);
707 else
708 return(PKT_ALIAS_OK);
709 }
710 return(PKT_ALIAS_IGNORED);
711}
712
713static int
714UdpAliasOut(struct ip *pip)
715{
716 struct udphdr *ud;
717 struct alias_link *link;
718
719/* Return if proxy-only mode is enabled */
720 if (packetAliasMode & PKT_ALIAS_PROXY_ONLY)
721 return PKT_ALIAS_OK;
722
723 ud = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2));
724
725 link = FindUdpTcpOut(pip->ip_src, pip->ip_dst,
726 ud->uh_sport, ud->uh_dport,
727 IPPROTO_UDP);
728 if (link != NULL)
729 {
730 u_short alias_port;
731 struct in_addr alias_address;
732
733 alias_address = GetAliasAddress(link);
734 alias_port = GetAliasPort(link);
735
736 if (ntohs(ud->uh_dport) == CUSEEME_PORT_NUMBER)
737 AliasHandleCUSeeMeOut(pip, link);
738
739/* If NETBIOS Datagram, It should be alias address in UDP Data, too */
740 if (ntohs(ud->uh_dport) == NETBIOS_DGM_PORT_NUMBER
741 || ntohs(ud->uh_sport) == NETBIOS_DGM_PORT_NUMBER )
742 {
743 AliasHandleUdpNbt(pip, link, &alias_address, alias_port);
744 } else if (ntohs(ud->uh_dport) == NETBIOS_NS_PORT_NUMBER
745 || ntohs(ud->uh_sport) == NETBIOS_NS_PORT_NUMBER )
746 {
747 AliasHandleUdpNbtNS(pip, link,
748 &pip->ip_src,
749 &ud->uh_sport,
750 &alias_address,
751 &alias_port);
752 }
753
754/* If UDP checksum is not zero, adjust since source port is */
755/* being aliased and source address is being altered */
756 if (ud->uh_sum != 0)
757 {
758 int accumulate;
759 u_short *sptr;
760
761 accumulate = ud->uh_sport;
762 accumulate -= alias_port;
763 sptr = (u_short *) &(pip->ip_src);
764 accumulate += *sptr++;
765 accumulate += *sptr;
766 sptr = (u_short *) &alias_address;
767 accumulate -= *sptr++;
768 accumulate -= *sptr;
769 ADJUST_CHECKSUM(accumulate, ud->uh_sum)
770 }
771
772/* Put alias port in UDP header */
773 ud->uh_sport = alias_port;
774
775/* Change source address */
776 DifferentialChecksum(&pip->ip_sum,
777 (u_short *) &alias_address,
778 (u_short *) &pip->ip_src,
779 2);
780 pip->ip_src = alias_address;
781
782 return(PKT_ALIAS_OK);
783 }
784 return(PKT_ALIAS_IGNORED);
785}
786
787
788
789static int
790TcpAliasIn(struct ip *pip)
791{
792 struct tcphdr *tc;
793 struct alias_link *link;
794
795 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
796
797 link = FindUdpTcpIn(pip->ip_src, pip->ip_dst,
798 tc->th_sport, tc->th_dport,
799 IPPROTO_TCP);
800 if (link != NULL)
801 {
802 struct in_addr alias_address;
803 struct in_addr original_address;
804 struct in_addr proxy_address;
805 u_short alias_port;
806 u_short proxy_port;
807 int accumulate;
808 u_short *sptr;
809
810 alias_address = GetAliasAddress(link);
811 original_address = GetOriginalAddress(link);
812 proxy_address = GetProxyAddress(link);
813 alias_port = tc->th_dport;
814 tc->th_dport = GetOriginalPort(link);
815 proxy_port = GetProxyPort(link);
816
817/* Adjust TCP checksum since destination port is being unaliased */
818/* and destination port is being altered. */
819 accumulate = alias_port;
820 accumulate -= tc->th_dport;
821 sptr = (u_short *) &alias_address;
822 accumulate += *sptr++;
823 accumulate += *sptr;
824 sptr = (u_short *) &original_address;
825 accumulate -= *sptr++;
826 accumulate -= *sptr;
827
828/* If this is a proxy, then modify the tcp source port and
829 checksum accumulation */
830 if (proxy_port != 0)
831 {
832 accumulate += tc->th_sport;
833 tc->th_sport = proxy_port;
834 accumulate -= tc->th_sport;
835
836 sptr = (u_short *) &pip->ip_src;
837 accumulate += *sptr++;
838 accumulate += *sptr;
839 sptr = (u_short *) &proxy_address;
840 accumulate -= *sptr++;
841 accumulate -= *sptr;
842 }
843
844/* See if ack number needs to be modified */
845 if (GetAckModified(link) == 1)
846 {
847 int delta;
848
849 delta = GetDeltaAckIn(pip, link);
850 if (delta != 0)
851 {
852 sptr = (u_short *) &tc->th_ack;
853 accumulate += *sptr++;
854 accumulate += *sptr;
855 tc->th_ack = htonl(ntohl(tc->th_ack) - delta);
856 sptr = (u_short *) &tc->th_ack;
857 accumulate -= *sptr++;
858 accumulate -= *sptr;
859 }
860 }
861
862 ADJUST_CHECKSUM(accumulate, tc->th_sum);
863
864/* Restore original IP address */
865 sptr = (u_short *) &pip->ip_dst;
866 accumulate = *sptr++;
867 accumulate += *sptr;
868 pip->ip_dst = original_address;
869 sptr = (u_short *) &pip->ip_dst;
870 accumulate -= *sptr++;
871 accumulate -= *sptr;
872
873/* If this is a transparent proxy packet, then modify the source
874 address */
875 if (proxy_address.s_addr != 0)
876 {
877 sptr = (u_short *) &pip->ip_src;
878 accumulate += *sptr++;
879 accumulate += *sptr;
880 pip->ip_src = proxy_address;
881 sptr = (u_short *) &pip->ip_src;
882 accumulate -= *sptr++;
883 accumulate -= *sptr;
884 }
885
886 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
887
888/* Monitor TCP connection state */
889 TcpMonitorIn(pip, link);
890
891 return(PKT_ALIAS_OK);
892 }
893 return(PKT_ALIAS_IGNORED);
894}
895
896static int
897TcpAliasOut(struct ip *pip, int maxpacketsize)
898{
899 int proxy_type;
900 u_short dest_port;
901 u_short proxy_server_port;
902 struct in_addr dest_address;
903 struct in_addr proxy_server_address;
904 struct tcphdr *tc;
905 struct alias_link *link;
906
907 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
908
909 proxy_type = ProxyCheck(pip, &proxy_server_address, &proxy_server_port);
910
911 if (proxy_type == 0 && (packetAliasMode & PKT_ALIAS_PROXY_ONLY))
912 return PKT_ALIAS_OK;
913
914/* If this is a transparent proxy, save original destination,
915 then alter the destination and adust checksums */
916 dest_port = tc->th_dport;
917 dest_address = pip->ip_dst;
918 if (proxy_type != 0)
919 {
920 int accumulate;
921 u_short *sptr;
922
923 accumulate = tc->th_dport;
924 tc->th_dport = proxy_server_port;
925 accumulate -= tc->th_dport;
926
927 sptr = (u_short *) &(pip->ip_dst);
928 accumulate += *sptr++;
929 accumulate += *sptr;
930 sptr = (u_short *) &proxy_server_address;
931 accumulate -= *sptr++;
932 accumulate -= *sptr;
933
934 ADJUST_CHECKSUM(accumulate, tc->th_sum);
935
936 sptr = (u_short *) &(pip->ip_dst);
937 accumulate = *sptr++;
938 accumulate += *sptr;
939 pip->ip_dst = proxy_server_address;
940 sptr = (u_short *) &(pip->ip_dst);
941 accumulate -= *sptr++;
942 accumulate -= *sptr;
943
944 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
945 }
946
947 link = FindUdpTcpOut(pip->ip_src, pip->ip_dst,
948 tc->th_sport, tc->th_dport,
949 IPPROTO_TCP);
950 if (link !=NULL)
951 {
952 u_short alias_port;
953 struct in_addr alias_address;
954 int accumulate;
955 u_short *sptr;
956
957/* Save original destination address, if this is a proxy packet.
958 Also modify packet to include destination encoding. */
959 if (proxy_type != 0)
960 {
961 SetProxyPort(link, dest_port);
962 SetProxyAddress(link, dest_address);
963 ProxyModify(link, pip, maxpacketsize, proxy_type);
964 }
965
966/* Get alias address and port */
967 alias_port = GetAliasPort(link);
968 alias_address = GetAliasAddress(link);
969
970/* Monitor tcp connection state */
971 TcpMonitorOut(pip, link);
972
973/* Special processing for IP encoding protocols */
974 if (ntohs(tc->th_dport) == FTP_CONTROL_PORT_NUMBER
975 || ntohs(tc->th_sport) == FTP_CONTROL_PORT_NUMBER)
976 AliasHandleFtpOut(pip, link, maxpacketsize);
977 if (ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_1
978 || ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_2)
979 AliasHandleIrcOut(pip, link, maxpacketsize);
980
981/* Adjust TCP checksum since source port is being aliased */
982/* and source address is being altered */
983 accumulate = tc->th_sport;
984 tc->th_sport = alias_port;
985 accumulate -= tc->th_sport;
986
987 sptr = (u_short *) &(pip->ip_src);
988 accumulate += *sptr++;
989 accumulate += *sptr;
990 sptr = (u_short *) &alias_address;
991 accumulate -= *sptr++;
992 accumulate -= *sptr;
993
994/* Modify sequence number if necessary */
995 if (GetAckModified(link) == 1)
996 {
997 int delta;
998
999 delta = GetDeltaSeqOut(pip, link);
1000 if (delta != 0)
1001 {
1002 sptr = (u_short *) &tc->th_seq;
1003 accumulate += *sptr++;
1004 accumulate += *sptr;
1005 tc->th_seq = htonl(ntohl(tc->th_seq) + delta);
1006 sptr = (u_short *) &tc->th_seq;
1007 accumulate -= *sptr++;
1008 accumulate -= *sptr;
1009 }
1010 }
1011
1012 ADJUST_CHECKSUM(accumulate, tc->th_sum)
1013
1014/* Change source address */
1015 sptr = (u_short *) &(pip->ip_src);
1016 accumulate = *sptr++;
1017 accumulate += *sptr;
1018 pip->ip_src = alias_address;
1019 sptr = (u_short *) &(pip->ip_src);
1020 accumulate -= *sptr++;
1021 accumulate -= *sptr;
1022
1023 ADJUST_CHECKSUM(accumulate, pip->ip_sum)
1024
1025 return(PKT_ALIAS_OK);
1026 }
1027 return(PKT_ALIAS_IGNORED);
1028}
1029
1030
1031
1032
1033/* Fragment Handling
1034
1035 FragmentIn()
1036 FragmentOut()
1037
1038The packet aliasing module has a limited ability for handling IP
1039fragments. If the ICMP, TCP or UDP header is in the first fragment
1040received, then the id number of the IP packet is saved, and other
1041fragments are identified according to their ID number and IP address
1042they were sent from. Pointers to unresolved fragments can also be
1043saved and recalled when a header fragment is seen.
1044*/
1045
1046/* Local prototypes */
1047static int FragmentIn(struct ip *);
1048static int FragmentOut(struct ip *);
1049
1050
1051static int
1052FragmentIn(struct ip *pip)
1053{
1054 struct alias_link *link;
1055
1056 link = FindFragmentIn2(pip->ip_src, pip->ip_dst, pip->ip_id);
1057 if (link != NULL)
1058 {
1059 struct in_addr original_address;
1060
1061 GetFragmentAddr(link, &original_address);
1062 DifferentialChecksum(&pip->ip_sum,
1063 (u_short *) &original_address,
1064 (u_short *) &pip->ip_dst,
1065 2);
1066 pip->ip_dst = original_address;
1067
1068 return(PKT_ALIAS_OK);
1069 }
1070 return(PKT_ALIAS_UNRESOLVED_FRAGMENT);
1071}
1072
1073
1074static int
1075FragmentOut(struct ip *pip)
1076{
1077 struct in_addr alias_address;
1078
1079 alias_address = FindAliasAddress(pip->ip_src);
1080 DifferentialChecksum(&pip->ip_sum,
1081 (u_short *) &alias_address,
1082 (u_short *) &pip->ip_src,
1083 2);
1084 pip->ip_src = alias_address;
1085
1086 return(PKT_ALIAS_OK);
1087}
1088
1089
1090
1091
1092
1093
1094/* Outside World Access
1095
1096 PacketAliasSaveFragment()
1097 PacketAliasGetFragment()
1098 PacketAliasFragmentIn()
1099 PacketAliasIn()
1100 PacketAliasOut()
1101
1102(prototypes in alias.h)
1103*/
1104
1105
1106int
1107PacketAliasSaveFragment(char *ptr)
1108{
1109 int iresult;
1110 struct alias_link *link;
1111 struct ip *pip;
1112
1113 pip = (struct ip *) ptr;
1114 link = AddFragmentPtrLink(pip->ip_src, pip->ip_id);
1115 iresult = PKT_ALIAS_ERROR;
1116 if (link != NULL)
1117 {
1118 SetFragmentPtr(link, ptr);
1119 iresult = PKT_ALIAS_OK;
1120 }
1121 return(iresult);
1122}
1123
1124
1125char *
1126PacketAliasGetFragment(char *ptr)
1127{
1128 struct alias_link *link;
1129 char *fptr;
1130 struct ip *pip;
1131
1132 pip = (struct ip *) ptr;
1133 link = FindFragmentPtr(pip->ip_src, pip->ip_id);
1134 if (link != NULL)
1135 {
1136 GetFragmentPtr(link, &fptr);
1137 SetFragmentPtr(link, NULL);
1138 SetExpire(link, 0); /* Deletes link */
1139
1140 return(fptr);
1141 }
1142 else
1143 {
1144 return(NULL);
1145 }
1146}
1147
1148
1149void
1150PacketAliasFragmentIn(char *ptr, /* Points to correctly de-aliased
1151 header fragment */
1152 char *ptr_fragment /* Points to fragment which must
1153 be de-aliased */
1154 )
1155{
1156 struct ip *pip;
1157 struct ip *fpip;
1158
1159 pip = (struct ip *) ptr;
1160 fpip = (struct ip *) ptr_fragment;
1161
1162 DifferentialChecksum(&fpip->ip_sum,
1163 (u_short *) &pip->ip_dst,
1164 (u_short *) &fpip->ip_dst,
1165 2);
1166 fpip->ip_dst = pip->ip_dst;
1167}
1168
1169
1170int
1171PacketAliasIn(char *ptr, int maxpacketsize)
1172{
1173 struct in_addr alias_addr;
1174 struct ip *pip;
1175 int iresult;
1176
1177 if (packetAliasMode & PKT_ALIAS_REVERSE)
1178 return PacketAliasOut(ptr, maxpacketsize);
1179
1180 HouseKeeping();
1181 ClearCheckNewLink();
1182 pip = (struct ip *) ptr;
1183 alias_addr = pip->ip_dst;
1184
1185 /* Defense against mangled packets */
1186 if (ntohs(pip->ip_len) > maxpacketsize
1187 || (pip->ip_hl<<2) > maxpacketsize)
1188 return PKT_ALIAS_IGNORED;
1189
1190 iresult = PKT_ALIAS_IGNORED;
1191 if ( (ntohs(pip->ip_off) & IP_OFFMASK) == 0 )
1192 {
1193 switch (pip->ip_p)
1194 {
1195 case IPPROTO_ICMP:
1196 iresult = IcmpAliasIn(pip);
1197 break;
1198 case IPPROTO_UDP:
1199 iresult = UdpAliasIn(pip);
1200 break;
1201 case IPPROTO_TCP:
1202 iresult = TcpAliasIn(pip);
1203 break;
1204 case IPPROTO_GRE:
1205 iresult = PptpAliasIn(pip);
1206 break;
1207 }
1208
1209 if (ntohs(pip->ip_off) & IP_MF)
1210 {
1211 struct alias_link *link;
1212
1213 link = FindFragmentIn1(pip->ip_src, alias_addr, pip->ip_id);
1214 if (link != NULL)
1215 {
1216 iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
1217 SetFragmentAddr(link, pip->ip_dst);
1218 }
1219 else
1220 {
1221 iresult = PKT_ALIAS_ERROR;
1222 }
1223 }
1224 }
1225 else
1226 {
1227 iresult = FragmentIn(pip);
1228 }
1229
1230 return(iresult);
1231}
1232
1233
1234
1235/* Unregistered address ranges */
1236
1237/* 10.0.0.0 -> 10.255.255.255 */
1238#define UNREG_ADDR_A_LOWER 0x0a000000
1239#define UNREG_ADDR_A_UPPER 0x0affffff
1240
1241/* 172.16.0.0 -> 172.31.255.255 */
1242#define UNREG_ADDR_B_LOWER 0xac100000
1243#define UNREG_ADDR_B_UPPER 0xac1fffff
1244
1245/* 192.168.0.0 -> 192.168.255.255 */
1246#define UNREG_ADDR_C_LOWER 0xc0a80000
1247#define UNREG_ADDR_C_UPPER 0xc0a8ffff
1248
1249int
1250PacketAliasOut(char *ptr, /* valid IP packet */
1251 int maxpacketsize /* How much the packet data may grow
1252 (FTP and IRC inline changes) */
1253 )
1254{
1255 int iresult;
1256 struct in_addr addr_save;
1257 struct ip *pip;
1258
1259 if (packetAliasMode & PKT_ALIAS_REVERSE)
1260 return PacketAliasIn(ptr, maxpacketsize);
1261
1262 HouseKeeping();
1263 ClearCheckNewLink();
1264 pip = (struct ip *) ptr;
1265
1266 /* Defense against mangled packets */
1267 if (ntohs(pip->ip_len) > maxpacketsize
1268 || (pip->ip_hl<<2) > maxpacketsize)
1269 return PKT_ALIAS_IGNORED;
1270
1271 addr_save = GetDefaultAliasAddress();
1272 if (packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY)
1273 {
1274 unsigned int addr;
1275 int iclass;
1276
1277 iclass = 0;
1278 addr = ntohl(pip->ip_src.s_addr);
1279 if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER)
1280 iclass = 3;
1281 else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER)
1282 iclass = 2;
1283 else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER)
1284 iclass = 1;
1285
1286 if (iclass == 0)
1287 {
1288 SetDefaultAliasAddress(pip->ip_src);
1289 }
1290 }
1291
1292 iresult = PKT_ALIAS_IGNORED;
1293 if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0)
1294 {
1295 switch (pip->ip_p)
1296 {
1297 case IPPROTO_ICMP:
1298 iresult = IcmpAliasOut(pip);
1299 break;
1300 case IPPROTO_UDP:
1301 iresult = UdpAliasOut(pip);
1302 break;
1303 case IPPROTO_TCP:
1304 iresult = TcpAliasOut(pip, maxpacketsize);
1305 break;
1306 case IPPROTO_GRE:
1307 iresult = PptpAliasOut(pip);
1308 break;
1309 }
1310 }
1311 else
1312 {
1313 iresult = FragmentOut(pip);
1314 }
1315
1316 SetDefaultAliasAddress(addr_save);
1317 return(iresult);
1318}