1 /* $KAME: natpt_dispatch.c,v 1.9 2000/03/25 07:23:54 sumikawa Exp $ */
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/param.h>
33 #include <sys/malloc.h>
35 #include <sys/socket.h>
36 #include <sys/syslog.h>
37 #include <sys/systm.h>
40 # include <sys/kernel.h>
44 #include <net/net_osdep.h>
46 #include <netinet/in.h>
47 #include <netinet/in_systm.h>
48 #include <netinet/ip.h>
49 #include <netinet/ip_icmp.h>
51 #include <netinet/ip6.h>
52 #include <netinet6/ip6_var.h>
53 #include <netinet/icmp6.h>
55 #include <netinet6/natpt_defs.h>
56 #include <netinet6/natpt_list.h>
57 #include <netinet6/natpt_log.h>
58 #include <netinet6/natpt_var.h>
68 static struct _cell
*ifBox
;
70 struct ifnet
*natpt_ip6src
;
72 struct in6_addr faith_prefix
73 = {{{0x00000000, 0x00000000, 0x00000000, 0x00000000}}};
74 struct in6_addr faith_prefixmask
75 = {{{0x00000000, 0x00000000, 0x00000000, 0x00000000}}};
76 struct in6_addr natpt_prefix
77 = {{{0x00000000, 0x00000000, 0x00000000, 0x00000000}}};
78 struct in6_addr natpt_prefixmask
79 = {{{0x00000000, 0x00000000, 0x00000000, 0x00000000}}};
81 int natpt_in4
__P((struct mbuf
*, struct mbuf
**));
82 int natpt_in6
__P((struct mbuf
*, struct mbuf
**));
83 int natpt_out4
__P((struct mbuf
*, struct mbuf
**));
84 int natpt_out6
__P((struct mbuf
*, struct mbuf
**));
85 int natpt_incomingIPv4
__P((int, struct mbuf
*, struct mbuf
**));
86 int natpt_outgoingIPv4
__P((int, struct mbuf
*, struct mbuf
**));
87 int natpt_incomingIPv6
__P((int, struct mbuf
*, struct mbuf
**));
88 int natpt_outgoingIPv6
__P((int, struct mbuf
*, struct mbuf
**));
90 int configCv4
__P((int, struct mbuf
*, struct _cv
*));
91 int configCv6
__P((int, struct mbuf
*, struct _cv
*));
92 caddr_t foundFinalPayload
__P((struct mbuf
*, int *, int *));
93 int sanityCheckIn4
__P((struct _cv
*));
94 int sanityCheckOut6
__P((struct _cv
*));
95 int checkMTU
__P((struct _cv
*));
98 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
99 static MALLOC_DEFINE(M_NATPT
, "NATPT", "Network Address Translation - Protocol Translation");
108 natpt_in4(struct mbuf
*m4
, struct mbuf
**m6
)
115 if (natpt_initialized
== 0)
116 return (IPPROTO_IP
); /* goto ours */
118 if (isDump(D_DIVEIN4
))
119 natpt_logMBuf(LOG_DEBUG
, m4
, "dive into natpt_in4.");
121 ifnet
= m4
->m_pkthdr
.rcvif
;
122 for (p
= ifBox
; p
; p
= CDR(p
))
124 ifb
= (struct ifBox
*)CAR(p
);
125 if (ifb
->ifnet
== ifnet
)
127 if (ifb
->side
== outSide
)
128 rv
= natpt_incomingIPv4(NATPT_INBOUND
, m4
, m6
);
130 rv
= natpt_outgoingIPv4(NATPT_OUTBOUND
, m4
, m6
);
141 natpt_in6(struct mbuf
*m6
, struct mbuf
**m4
)
147 struct in6_addr cand
;
150 if (natpt_initialized
== 0)
151 return (IPPROTO_IP
); /* goto mcastcheck */
153 if (isDump(D_DIVEIN6
))
154 natpt_logMBuf(LOG_DEBUG
, m6
, "dive into natpt_in6.");
156 ip6
= mtod(m6
, struct ip6_hdr
*);
158 cand
.s6_addr32
[0] = ip6
->ip6_dst
.s6_addr32
[0] & natpt_prefixmask
.s6_addr32
[0];
159 cand
.s6_addr32
[1] = ip6
->ip6_dst
.s6_addr32
[1] & natpt_prefixmask
.s6_addr32
[1];
160 cand
.s6_addr32
[2] = ip6
->ip6_dst
.s6_addr32
[2] & natpt_prefixmask
.s6_addr32
[2];
161 cand
.s6_addr32
[3] = ip6
->ip6_dst
.s6_addr32
[3] & natpt_prefixmask
.s6_addr32
[3];
163 if ((cand
.s6_addr32
[0] != natpt_prefix
.s6_addr32
[0])
164 || (cand
.s6_addr32
[1] != natpt_prefix
.s6_addr32
[1])
165 || (cand
.s6_addr32
[2] != natpt_prefix
.s6_addr32
[2])
166 || (cand
.s6_addr32
[3] != natpt_prefix
.s6_addr32
[3]))
168 if (isDump(D_IN6REJECT
))
169 natpt_logMBuf(LOG_DEBUG
, m6
, "v6 translation rejected.");
171 return (IPPROTO_IP
); /* goto mcastcheck */
174 if (isDump(D_IN6ACCEPT
))
175 natpt_logMBuf(LOG_DEBUG
, m6
, "v6 translation start.");
177 ifnet
= m6
->m_pkthdr
.rcvif
;
178 for (p
= ifBox
; p
; p
= CDR(p
))
180 ifb
= (struct ifBox
*)CAR(p
);
181 if (ifb
->ifnet
== ifnet
)
183 if (ifb
->side
== outSide
)
184 rv
= natpt_incomingIPv6(NATPT_INBOUND
, m6
, m4
);
186 rv
= natpt_outgoingIPv6(NATPT_OUTBOUND
, m6
, m4
);
197 natpt_out4(struct mbuf
*m4
, struct mbuf
**m6
)
204 ifnet
= m4
->m_pkthdr
.rcvif
;
205 for (p
= ifBox
; p
; p
= CDR(p
))
207 ifb
= (struct ifBox
*)CAR(p
);
208 if (ifb
->ifnet
== ifnet
)
210 if (ifb
->side
== outSide
)
211 rv
= natpt_outgoingIPv4(NATPT_OUTBOUND
, m4
, m6
);
213 rv
= natpt_incomingIPv4(NATPT_INBOUND
, m4
, m6
);
225 natpt_out6(struct mbuf
*m6
, struct mbuf
**m4
)
232 ifnet
= m6
->m_pkthdr
.rcvif
;
233 for (p
= ifBox
; p
; p
= CDR(p
))
235 ifb
= (struct ifBox
*)CAR(p
);
236 if (ifb
->ifnet
== ifnet
)
238 if (ifb
->side
== outSide
)
239 rv
= natpt_outgoingIPv6(NATPT_OUTBOUND
, m6
, m4
);
241 rv
= natpt_incomingIPv6(NATPT_INBOUND
, m6
, m4
);
252 natpt_incomingIPv4(int sess
, struct mbuf
*m4
, struct mbuf
**m6
)
259 if ((rv
= configCv4(sess
, m4
, &cv
)) == IPPROTO_MAX
)
260 return (IPPROTO_MAX
); /* discard this packet */
262 if ((rv
= sanityCheckIn4(&cv
)) != IPPROTO_IPV4
)
263 return (IPPROTO_DONE
); /* discard this packet without free */
265 cv
.ats
= lookingForIncomingV4Hash(&cv
);
266 if ((ats
= checkTraceroute6Return(&cv
)) != NULL
)
271 if ((acs
= lookingForIncomingV4Rule(&cv
)) == NULL
)
272 return (IPPROTO_IP
); /* goto ours */
274 if ((cv
.ats
= internIncomingV4Hash(sess
, acs
, &cv
)) == NULL
)
275 return (IPPROTO_IP
); /* goto ours */
278 if (checkMTU(&cv
) != IPPROTO_IPV4
)
279 return (IPPROTO_DONE
); /* discard this packet without free */
282 if (cv
.ats
->local
.sa_family
== AF_INET
)
284 if ((*m6
= translatingIPv4To4(&cv
, &cv
.ats
->local
)) != NULL
)
285 return (IPPROTO_IPV4
);
290 if ((*m6
= translatingIPv4To6(&cv
, &cv
.ats
->local
)) != NULL
)
291 return (IPPROTO_IPV6
);
294 return (IPPROTO_MAX
); /* discard this packet */
299 natpt_outgoingIPv4(int sess
, struct mbuf
*m4
, struct mbuf
**m6
)
306 if ((rv
= configCv4(sess
, m4
, &cv
)) == IPPROTO_MAX
)
307 return (IPPROTO_MAX
); /* discard this packet */
309 if ((cv
.ats
= lookingForOutgoingV4Hash(&cv
)) == NULL
)
311 if ((acs
= lookingForOutgoingV4Rule(&cv
)) == NULL
)
312 return (IPPROTO_IP
); /* goto ours */
314 ip4
= mtod(m4
, struct ip
*);
315 if (ip4
->ip_ttl
<= IPTTLDEC
)
319 icmp_error(m4
, ICMP_TIMXCEED
, ICMP_TIMXCEED_INTRANS
, dest
, 0);
320 return (IPPROTO_MAX
); /* discard this packet */
323 if ((cv
.ats
= internOutgoingV4Hash(sess
, acs
, &cv
)) == NULL
)
324 return (IPPROTO_IP
); /* goto ours */
328 if (cv
.ats
->remote
.sa_family
== AF_INET
)
330 if ((*m6
= translatingIPv4To4(&cv
, &cv
.ats
->remote
)) != NULL
)
331 return (IPPROTO_IPV4
);
336 if ((*m6
= translatingIPv4To6(&cv
, &cv
.ats
->remote
)) != NULL
)
337 return (IPPROTO_IPV6
);
340 return (IPPROTO_MAX
); /* discard this packet */
345 natpt_incomingIPv6(int sess
, struct mbuf
*m6
, struct mbuf
**m4
)
352 rv
= configCv6(sess
, m6
, &cv
);
353 if ((rv
== IPPROTO_IP
) || (rv
== IPPROTO_MAX
) || (rv
== IPPROTO_DONE
))
356 if ((cv
.ats
= lookingForIncomingV6Hash(&cv
)) == NULL
)
358 if ((acs
= lookingForIncomingV6Rule(&cv
)) == NULL
)
359 return (IPPROTO_IP
); /* goto mcastcheck */
361 ip6
= mtod(m6
, struct ip6_hdr
*);
362 if (ip6
->ip6_hlim
<= IPV6_HLIMDEC
)
364 icmp6_error(m6
, ICMP6_TIME_EXCEEDED
, ICMP6_TIME_EXCEED_TRANSIT
, 0);
365 return (IPPROTO_MAX
); /* discard this packet */
368 if ((cv
.ats
= internIncomingV6Hash(sess
, acs
, &cv
)) == NULL
)
369 return (IPPROTO_IP
); /* goto mcastcheck */
372 if ((*m4
= translatingIPv6To4(&cv
, &cv
.ats
->local
)) != NULL
)
373 return (IPPROTO_IPV4
);
375 return (IPPROTO_MAX
); /* discard this packet */
380 natpt_outgoingIPv6(int sess
, struct mbuf
*m6
, struct mbuf
**m4
)
386 rv
= configCv6(sess
, m6
, &cv6
);
387 if ((rv
== IPPROTO_IP
) || (rv
== IPPROTO_MAX
) || (rv
== IPPROTO_DONE
))
390 if ((rv
= sanityCheckOut6(&cv6
)) != IPPROTO_IPV6
)
391 return (IPPROTO_DONE
); /* discard this packet */
393 if (isDump(D_PEEKOUTGOINGV6
))
394 natpt_logIp6(LOG_DEBUG
, cv6
._ip
._ip6
);
396 if ((cv6
.ats
= lookingForOutgoingV6Hash(&cv6
)) == NULL
)
398 if ((acs
= lookingForOutgoingV6Rule(&cv6
)) == NULL
)
399 return (IPPROTO_IP
); /* goto mcastcheck */
401 if ((cv6
.ats
= internOutgoingV6Hash(sess
, acs
, &cv6
)) == NULL
)
402 return (IPPROTO_IP
); /* goto mcastcheck */
405 if ((*m4
= translatingIPv6To4(&cv6
, &cv6
.ats
->remote
)) != NULL
)
406 return (IPPROTO_IPV4
);
408 return (IPPROTO_MAX
); /* discard this packet */
413 configCv4(int sess
, struct mbuf
*m
, struct _cv
*cv
)
415 struct ip
*ip
= mtod(m
, struct ip
*);
417 bzero(cv
, sizeof(struct _cv
));
428 cv
->ip_payload
= ip
->ip_p
;
429 cv
->_payload
._caddr
= (caddr_t
)((u_long
*)ip
+ ip
->ip_hl
);
430 cv
->poff
= cv
->_payload
._caddr
- (caddr_t
)cv
->_ip
._ip4
;
431 cv
->plen
= (caddr_t
)m
->m_data
+ m
->m_len
- cv
->_payload
._caddr
;
435 return (IPPROTO_MAX
);
440 configCv6(int sess
, struct mbuf
*m
, struct _cv
*cv
)
446 bzero(cv
, sizeof(struct _cv
));
448 cv
->_ip
._ip6
= mtod(m
, struct ip6_hdr
*);
451 if ((tcpudp
= foundFinalPayload(m
, &proto
, &offset
)))
460 cv
->ip_payload
= proto
;
461 if (proto
== IPPROTO_ICMPV6
)
462 cv
->ip_payload
= IPPROTO_ICMP
;
463 cv
->_payload
._caddr
= tcpudp
;
465 cv
->plen
= (caddr_t
)m
->m_data
+ m
->m_len
- cv
->_payload
._caddr
;
475 foundFinalPayload(struct mbuf
*m
, int *proto
, int *offset
)
480 struct ip6_ext
*ip6ext
;
482 ip6
= mtod(m
, struct ip6_hdr
*);
484 off
= sizeof(struct ip6_hdr
);
485 ip6ext
= (struct ip6_ext
*)((struct ip6_hdr
*)(ip6
+ 1));
486 while (nxt
!= IPPROTO_NONE
&& off
+ sizeof(*ip6ext
) < m
->m_len
)
490 case IPPROTO_HOPOPTS
:
491 case IPPROTO_ROUTING
:
493 case IPPROTO_FRAGMENT
:
495 case IPPROTO_DSTOPTS
:
496 nxt
= ip6ext
->ip6e_nxt
;
497 off
+= ip6ext
->ip6e_len
;
498 ip6ext
= (struct ip6_ext
*)(((caddr_t
)ip6ext
) + ip6ext
->ip6e_len
);
506 return ((caddr_t
)ip6ext
);
509 *proto
= IPPROTO_IP
; /* goto mcastcheck */
515 *proto
= IPPROTO_IP
; /* goto mcastcheck */
522 sanityCheckIn4(struct _cv
*cv4
)
524 struct mbuf
*m4
= cv4
->m
;
525 struct ip
*ip4
= mtod(m4
, struct ip
*);
527 if (ip4
->ip_ttl
<= IPTTLDEC
)
531 icmp_error(m4
, ICMP_TIMXCEED
, ICMP_TIMXCEED_INTRANS
, dest
, 0);
532 return (IPPROTO_DONE
); /* discard this packet without free */
535 return (IPPROTO_IPV4
);
540 sanityCheckOut6(struct _cv
*cv6
)
542 struct mbuf
*m6
= cv6
->m
;
543 struct ip6_hdr
*ip6
= mtod(m6
, struct ip6_hdr
*);
545 if (ip6
->ip6_hlim
<= IPV6_HLIMDEC
)
547 icmp6_error(m6
, ICMP6_TIME_EXCEEDED
, ICMP6_TIME_EXCEED_TRANSIT
, 0);
548 return (IPPROTO_DONE
); /* discard this packet */
551 return (IPPROTO_IPV6
);
556 checkMTU(struct _cv
*cv4
)
559 struct mbuf
*m4
= cv4
->m
;
560 struct ip
*ip4
= mtod(m4
, struct ip
*);
562 mmtu
= IPV6_MMTU
- sizeof(struct ip6_hdr
) - sizeof(struct ip6_frag
);
563 /* This should be 1232[byte] */
565 if ((m4
->m_flags
& M_PKTHDR
)
566 && (m4
->m_pkthdr
.len
>= mmtu
))
568 if (ip4
->ip_off
& IP_DF
)
573 bzero(&destif
, sizeof(struct ifnet
));
574 destif
.if_mtu
= mmtu
;
576 #ifdef fixSuMiReICMPBug
577 ip4
->ip_dst
.s_addr
= IPDST
; /* XXX */
580 icmp_error(m4
, ICMP_UNREACH
, ICMP_UNREACH_NEEDFRAG
, dest
, &destif
);
581 return (IPPROTO_DONE
); /* discard this packet without free */
584 cv4
->flags
|= NATPT_NEEDFRAGMENT
; /* fragment, then translate */
587 return (IPPROTO_IPV4
);
597 natpt_asIfBox(char *ifName
)
601 for (p
= ifBox
; p
; p
= CDR(p
))
603 if (strcmp(ifName
, ((struct ifBox
*)CAR(p
))->ifName
) == SAME
)
604 return ((struct ifBox
*)CAR(p
));
612 natpt_setIfBox(char *ifName
)
618 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
619 for (p
= ifnet
; p
; p
= p
->if_next
)
621 for (p
= TAILQ_FIRST(&ifnet
); p
; p
= TAILQ_NEXT(p
, if_list
))
625 sprintf(Wow
, "%s%c", p
->if_xname
, '\0');
627 sprintf(Wow
, "%s%d%c", p
->if_name
, p
->if_unit
, '\0');
629 if (strcmp(ifName
, Wow
) != SAME
)
634 MALLOC(q
, struct ifBox
*, sizeof(struct ifBox
), M_NATPT
, M_WAITOK
);
635 bzero(q
, sizeof(struct ifBox
));
639 sprintf(q
->ifName
, "%s%c", p
->if_xname
, '\0');
641 sprintf(q
->ifName
, "%s%d%c", p
->if_name
, p
->if_unit
, '\0');
644 LST_hookup_list((Cell
**)&ifBox
, q
);
658 printf("DebugProbe");
663 natpt_assert(const char *file
, int line
, const char *failedexpr
)
665 (void)printf("natpt assertion \"%s\" failed: file \"%s\", line %d\n",
666 failedexpr
, file
, line
);
667 panic("natpt assertion");
683 if (natpt_initialized
)
686 natpt_initialized
= 1;
688 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
689 for (ifn
= ifnet
; ifn
; ifn
= ifn
->if_next
)
691 for (ifn
= TAILQ_FIRST(&ifnet
); ifn
; ifn
= TAILQ_NEXT(ifn
, if_list
))
694 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
695 for (ifa
= ifn
->if_addrlist
; ifa
; ifa
= ifa
->ifa_next
)
697 for (ifa
= ifn
->if_addrlist
.tqh_first
; ifa
;
698 ifa
= ifa
->ifa_list
.tqe_next
)
701 if (((ifa
->ifa_addr
->sa_family
) == AF_INET
)
702 || ((ifa
->ifa_addr
->sa_family
) == AF_INET6
))
704 MALLOC(ibox
, struct ifBox
*, sizeof(struct ifBox
), M_TEMP
, M_WAITOK
);
706 sprintf(ibox
->ifName
, "%s", ifn
->if_xname
);
708 sprintf(ibox
->ifName
, "%s%d", ifn
->if_name
, ifn
->if_unit
);
712 LST_hookup_list(&ifBox
, ibox
);