2 * Copyright (c) 2001 Charles Mott <cm@linktel.net>
3 * Brian Somers <brian@Awfulhak.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * $FreeBSD: src/usr.sbin/ppp/nat_cmd.c,v 1.35.2.13 2002/09/01 02:12:29 brian Exp $
28 * $DragonFly: src/usr.sbin/ppp/nat_cmd.c,v 1.2 2003/06/17 04:30:00 dillon Exp $
31 #include <sys/param.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
35 #include <netinet/in_systm.h>
36 #include <netinet/in.h>
37 #include <netinet/ip.h>
38 #include <sys/socket.h>
59 #include "descriptor.h"
63 #include "slcompress.h"
64 #include "throughput.h"
85 #define NAT_EXTRABUF (13)
87 static int StrToAddr(const char *, struct in_addr
*);
88 static int StrToPortRange(const char *, u_short
*, u_short
*, const char *);
89 static int StrToAddrAndPort(const char *, struct in_addr
*, u_short
*,
90 u_short
*, const char *);
93 lowhigh(u_short
*a
, u_short
*b
)
105 nat_RedirectPort(struct cmdargs
const *arg
)
107 if (!arg
->bundle
->NatEnabled
) {
108 prompt_Printf(arg
->prompt
, "Alias not enabled\n");
110 } else if (arg
->argc
== arg
->argn
+ 3 || arg
->argc
== arg
->argn
+ 4) {
113 struct in_addr localaddr
;
114 u_short hlocalport
, llocalport
;
115 struct in_addr aliasaddr
;
116 u_short haliasport
, laliasport
;
117 struct in_addr remoteaddr
;
118 u_short hremoteport
, lremoteport
;
119 struct alias_link
*link
;
122 proto
= arg
->argv
[arg
->argn
];
123 if (strcmp(proto
, "tcp") == 0) {
124 proto_constant
= IPPROTO_TCP
;
125 } else if (strcmp(proto
, "udp") == 0) {
126 proto_constant
= IPPROTO_UDP
;
128 prompt_Printf(arg
->prompt
, "port redirect: protocol must be"
133 error
= StrToAddrAndPort(arg
->argv
[arg
->argn
+1], &localaddr
, &llocalport
,
136 prompt_Printf(arg
->prompt
, "nat port: error reading localaddr:port\n");
140 error
= StrToPortRange(arg
->argv
[arg
->argn
+2], &laliasport
, &haliasport
,
143 prompt_Printf(arg
->prompt
, "nat port: error reading alias port\n");
146 aliasaddr
.s_addr
= INADDR_ANY
;
148 if (arg
->argc
== arg
->argn
+ 4) {
149 error
= StrToAddrAndPort(arg
->argv
[arg
->argn
+3], &remoteaddr
,
150 &lremoteport
, &hremoteport
, proto
);
152 prompt_Printf(arg
->prompt
, "nat port: error reading "
153 "remoteaddr:port\n");
157 remoteaddr
.s_addr
= INADDR_ANY
;
158 lremoteport
= hremoteport
= 0;
161 lowhigh(&llocalport
, &hlocalport
);
162 lowhigh(&laliasport
, &haliasport
);
163 lowhigh(&lremoteport
, &hremoteport
);
165 if (haliasport
- laliasport
!= hlocalport
- llocalport
) {
166 prompt_Printf(arg
->prompt
, "nat port: local & alias port ranges "
171 if (hremoteport
&& hremoteport
- lremoteport
!= hlocalport
- llocalport
) {
172 prompt_Printf(arg
->prompt
, "nat port: local & remote port ranges "
177 while (laliasport
<= haliasport
) {
178 link
= PacketAliasRedirectPort(localaddr
, htons(llocalport
),
179 remoteaddr
, htons(lremoteport
),
180 aliasaddr
, htons(laliasport
),
184 prompt_Printf(arg
->prompt
, "nat port: %d: error %d\n", laliasport
,
202 nat_RedirectAddr(struct cmdargs
const *arg
)
204 if (!arg
->bundle
->NatEnabled
) {
205 prompt_Printf(arg
->prompt
, "nat not enabled\n");
207 } else if (arg
->argc
== arg
->argn
+2) {
209 struct in_addr localaddr
, aliasaddr
;
210 struct alias_link
*link
;
212 error
= StrToAddr(arg
->argv
[arg
->argn
], &localaddr
);
214 prompt_Printf(arg
->prompt
, "address redirect: invalid local address\n");
217 error
= StrToAddr(arg
->argv
[arg
->argn
+1], &aliasaddr
);
219 prompt_Printf(arg
->prompt
, "address redirect: invalid alias address\n");
220 prompt_Printf(arg
->prompt
, "usage: nat %s %s\n", arg
->cmd
->name
,
224 link
= PacketAliasRedirectAddr(localaddr
, aliasaddr
);
226 prompt_Printf(arg
->prompt
, "address redirect: packet aliasing"
228 prompt_Printf(arg
->prompt
, "usage: nat %s %s\n", arg
->cmd
->name
,
239 nat_RedirectProto(struct cmdargs
const *arg
)
241 if (!arg
->bundle
->NatEnabled
) {
242 prompt_Printf(arg
->prompt
, "nat not enabled\n");
244 } else if (arg
->argc
>= arg
->argn
+ 2 && arg
->argc
<= arg
->argn
+ 4) {
245 struct in_addr localIP
, publicIP
, remoteIP
;
246 struct alias_link
*link
;
250 len
= strlen(arg
->argv
[arg
->argn
]);
252 prompt_Printf(arg
->prompt
, "proto redirect: invalid protocol\n");
255 if (strspn(arg
->argv
[arg
->argn
], "01234567") == len
)
256 pe
= getprotobynumber(atoi(arg
->argv
[arg
->argn
]));
258 pe
= getprotobyname(arg
->argv
[arg
->argn
]);
260 prompt_Printf(arg
->prompt
, "proto redirect: invalid protocol\n");
264 error
= StrToAddr(arg
->argv
[arg
->argn
+ 1], &localIP
);
266 prompt_Printf(arg
->prompt
, "proto redirect: invalid src address\n");
270 if (arg
->argc
>= arg
->argn
+ 3) {
271 error
= StrToAddr(arg
->argv
[arg
->argn
+ 2], &publicIP
);
273 prompt_Printf(arg
->prompt
, "proto redirect: invalid alias address\n");
274 prompt_Printf(arg
->prompt
, "usage: nat %s %s\n", arg
->cmd
->name
,
279 publicIP
.s_addr
= INADDR_ANY
;
281 if (arg
->argc
== arg
->argn
+ 4) {
282 error
= StrToAddr(arg
->argv
[arg
->argn
+ 2], &remoteIP
);
284 prompt_Printf(arg
->prompt
, "proto redirect: invalid dst address\n");
285 prompt_Printf(arg
->prompt
, "usage: nat %s %s\n", arg
->cmd
->name
,
290 remoteIP
.s_addr
= INADDR_ANY
;
292 link
= PacketAliasRedirectProto(localIP
, remoteIP
, publicIP
, pe
->p_proto
);
294 prompt_Printf(arg
->prompt
, "proto redirect: packet aliasing"
296 prompt_Printf(arg
->prompt
, "usage: nat %s %s\n", arg
->cmd
->name
,
307 StrToAddr(const char *str
, struct in_addr
*addr
)
311 if (inet_aton(str
, addr
))
314 hp
= gethostbyname(str
);
316 log_Printf(LogWARN
, "StrToAddr: Unknown host %s.\n", str
);
319 *addr
= *((struct in_addr
*) hp
->h_addr
);
325 StrToPort(const char *str
, u_short
*port
, const char *proto
)
330 *port
= strtol(str
, &end
, 10);
332 sp
= getservbyname(str
, proto
);
334 log_Printf(LogWARN
, "StrToAddr: Unknown port or service %s/%s.\n",
338 *port
= ntohs(sp
->s_port
);
345 StrToPortRange(const char *str
, u_short
*low
, u_short
*high
, const char *proto
)
350 minus
= strchr(str
, '-');
352 *minus
= '\0'; /* Cheat the const-ness ! */
354 res
= StrToPort(str
, low
, proto
);
357 *minus
= '-'; /* Cheat the const-ness ! */
361 res
= StrToPort(minus
+ 1, high
, proto
);
370 StrToAddrAndPort(const char *str
, struct in_addr
*addr
, u_short
*low
,
371 u_short
*high
, const char *proto
)
376 colon
= strchr(str
, ':');
378 log_Printf(LogWARN
, "StrToAddrAndPort: %s is missing port number.\n", str
);
382 *colon
= '\0'; /* Cheat the const-ness ! */
383 res
= StrToAddr(str
, addr
);
384 *colon
= ':'; /* Cheat the const-ness ! */
388 return StrToPortRange(colon
+ 1, low
, high
, proto
);
392 nat_ProxyRule(struct cmdargs
const *arg
)
398 if (arg
->argn
>= arg
->argc
)
401 for (f
= arg
->argn
, pos
= 0; f
< arg
->argc
; f
++) {
402 len
= strlen(arg
->argv
[f
]);
403 if (sizeof cmd
- pos
< len
+ (len
? 1 : 0))
407 strcpy(cmd
+ pos
, arg
->argv
[f
]);
411 return PacketAliasProxyRule(cmd
);
415 nat_SetTarget(struct cmdargs
const *arg
)
419 if (arg
->argc
== arg
->argn
) {
420 addr
.s_addr
= INADDR_ANY
;
421 PacketAliasSetTarget(addr
);
425 if (arg
->argc
!= arg
->argn
+ 1)
428 if (!strcasecmp(arg
->argv
[arg
->argn
], "MYADDR")) {
429 addr
.s_addr
= INADDR_ANY
;
430 PacketAliasSetTarget(addr
);
434 addr
= GetIpAddr(arg
->argv
[arg
->argn
]);
435 if (addr
.s_addr
== INADDR_NONE
) {
436 log_Printf(LogWARN
, "%s: invalid address\n", arg
->argv
[arg
->argn
]);
440 PacketAliasSetTarget(addr
);
446 nat_PunchFW(struct cmdargs
const *arg
)
451 if (arg
->argc
== arg
->argn
) {
452 PacketAliasSetMode(0, PKT_ALIAS_PUNCH_FW
);
456 if (arg
->argc
!= arg
->argn
+ 2)
459 base
= strtol(arg
->argv
[arg
->argn
], &end
, 10);
460 if (*end
!= '\0' || base
< 0)
463 count
= strtol(arg
->argv
[arg
->argn
+ 1], &end
, 10);
464 if (*end
!= '\0' || count
< 0)
467 PacketAliasSetFWBase(base
, count
);
468 PacketAliasSetMode(PKT_ALIAS_PUNCH_FW
, PKT_ALIAS_PUNCH_FW
);
475 nat_LayerPush(struct bundle
*bundle
, struct link
*l
, struct mbuf
*bp
,
476 int pri
, u_short
*proto
)
478 if (!bundle
->NatEnabled
|| *proto
!= PROTO_IP
)
481 log_Printf(LogDEBUG
, "nat_LayerPush: PROTO_IP -> PROTO_IP\n");
482 m_settype(bp
, MB_NATOUT
);
483 /* Ensure there's a bit of extra buffer for the NAT code... */
484 bp
= m_pullup(m_append(bp
, NULL
, NAT_EXTRABUF
));
485 PacketAliasOut(MBUF_CTOP(bp
), bp
->m_len
);
486 bp
->m_len
= ntohs(((struct ip
*)MBUF_CTOP(bp
))->ip_len
);
492 nat_LayerPull(struct bundle
*bundle
, struct link
*l
, struct mbuf
*bp
,
496 int ret
, len
, nfrags
;
500 if (!bundle
->NatEnabled
|| *proto
!= PROTO_IP
)
503 log_Printf(LogDEBUG
, "nat_LayerPull: PROTO_IP -> PROTO_IP\n");
504 m_settype(bp
, MB_NATIN
);
505 /* Ensure there's a bit of extra buffer for the NAT code... */
506 bp
= m_pullup(m_append(bp
, NULL
, NAT_EXTRABUF
));
507 ret
= PacketAliasIn(MBUF_CTOP(bp
), bp
->m_len
);
509 bp
->m_len
= ntohs(((struct ip
*)MBUF_CTOP(bp
))->ip_len
);
510 if (bp
->m_len
> MAX_MRU
) {
511 log_Printf(LogWARN
, "nat_LayerPull: Problem with IP header length (%lu)\n",
512 (unsigned long)bp
->m_len
);
521 case PKT_ALIAS_UNRESOLVED_FRAGMENT
:
522 /* Save the data for later */
523 fptr
= malloc(bp
->m_len
);
524 bp
= mbuf_Read(bp
, fptr
, bp
->m_len
);
525 PacketAliasSaveFragment(fptr
);
526 log_Printf(LogDEBUG
, "Store another frag (%lu) - now %d\n",
527 (unsigned long)((struct ip
*)fptr
)->ip_id
, ++gfrags
);
530 case PKT_ALIAS_FOUND_HEADER_FRAGMENT
:
531 /* Fetch all the saved fragments and chain them on the end of `bp' */
532 last
= &bp
->m_nextpkt
;
534 while ((fptr
= PacketAliasGetFragment(MBUF_CTOP(bp
))) != NULL
) {
536 PacketAliasFragmentIn(MBUF_CTOP(bp
), fptr
);
537 len
= ntohs(((struct ip
*)fptr
)->ip_len
);
538 *last
= m_get(len
, MB_NATIN
);
539 memcpy(MBUF_CTOP(*last
), fptr
, len
);
541 last
= &(*last
)->m_nextpkt
;
544 log_Printf(LogDEBUG
, "Found a frag header (%lu) - plus %d more frags (no"
545 "w %d)\n", (unsigned long)((struct ip
*)MBUF_CTOP(bp
))->ip_id
,
549 case PKT_ALIAS_IGNORED
:
550 if (PacketAliasSetMode(0, 0) & PKT_ALIAS_DENY_INCOMING
) {
551 log_Printf(LogTCPIP
, "NAT engine denied data:\n");
554 } else if (log_IsKept(LogTCPIP
)) {
555 log_Printf(LogTCPIP
, "NAT engine ignored data:\n");
556 PacketCheck(bundle
, AF_INET
, MBUF_CTOP(bp
), bp
->m_len
, NULL
,
562 log_Printf(LogWARN
, "nat_LayerPull: Dropped a packet (%d)....\n", ret
);
571 struct layer natlayer
=
572 { LAYER_NAT
, "nat", nat_LayerPush
, nat_LayerPull
};