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 $
30 #include <sys/param.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
34 #include <netinet/in_systm.h>
35 #include <netinet/ip.h>
36 #include <sys/socket.h>
57 #include "descriptor.h"
61 #include "slcompress.h"
62 #include "throughput.h"
83 #define NAT_EXTRABUF (13)
85 static int StrToAddr(const char *, struct in_addr
*);
86 static int StrToPortRange(const char *, u_short
*, u_short
*, const char *);
87 static int StrToAddrAndPort(const char *, struct in_addr
*, u_short
*,
88 u_short
*, const char *);
91 lowhigh(u_short
*a
, u_short
*b
)
103 nat_RedirectPort(struct cmdargs
const *arg
)
105 if (!arg
->bundle
->NatEnabled
) {
106 prompt_Printf(arg
->prompt
, "Alias not enabled\n");
108 } else if (arg
->argc
== arg
->argn
+ 3 || arg
->argc
== arg
->argn
+ 4) {
111 struct in_addr localaddr
;
112 u_short hlocalport
, llocalport
;
113 struct in_addr aliasaddr
;
114 u_short haliasport
, laliasport
;
115 struct in_addr remoteaddr
;
116 u_short hremoteport
, lremoteport
;
117 struct alias_link
*link
;
120 proto
= arg
->argv
[arg
->argn
];
121 if (strcmp(proto
, "tcp") == 0) {
122 proto_constant
= IPPROTO_TCP
;
123 } else if (strcmp(proto
, "udp") == 0) {
124 proto_constant
= IPPROTO_UDP
;
126 prompt_Printf(arg
->prompt
, "port redirect: protocol must be"
131 error
= StrToAddrAndPort(arg
->argv
[arg
->argn
+1], &localaddr
, &llocalport
,
134 prompt_Printf(arg
->prompt
, "nat port: error reading localaddr:port\n");
138 error
= StrToPortRange(arg
->argv
[arg
->argn
+2], &laliasport
, &haliasport
,
141 prompt_Printf(arg
->prompt
, "nat port: error reading alias port\n");
144 aliasaddr
.s_addr
= INADDR_ANY
;
146 if (arg
->argc
== arg
->argn
+ 4) {
147 error
= StrToAddrAndPort(arg
->argv
[arg
->argn
+3], &remoteaddr
,
148 &lremoteport
, &hremoteport
, proto
);
150 prompt_Printf(arg
->prompt
, "nat port: error reading "
151 "remoteaddr:port\n");
155 remoteaddr
.s_addr
= INADDR_ANY
;
156 lremoteport
= hremoteport
= 0;
159 lowhigh(&llocalport
, &hlocalport
);
160 lowhigh(&laliasport
, &haliasport
);
161 lowhigh(&lremoteport
, &hremoteport
);
163 if (haliasport
- laliasport
!= hlocalport
- llocalport
) {
164 prompt_Printf(arg
->prompt
, "nat port: local & alias port ranges "
169 if (hremoteport
&& hremoteport
- lremoteport
!= hlocalport
- llocalport
) {
170 prompt_Printf(arg
->prompt
, "nat port: local & remote port ranges "
175 while (laliasport
<= haliasport
) {
176 link
= PacketAliasRedirectPort(localaddr
, htons(llocalport
),
177 remoteaddr
, htons(lremoteport
),
178 aliasaddr
, htons(laliasport
),
182 prompt_Printf(arg
->prompt
, "nat port: %d: error %d\n", laliasport
,
200 nat_RedirectAddr(struct cmdargs
const *arg
)
202 if (!arg
->bundle
->NatEnabled
) {
203 prompt_Printf(arg
->prompt
, "nat not enabled\n");
205 } else if (arg
->argc
== arg
->argn
+2) {
207 struct in_addr localaddr
, aliasaddr
;
208 struct alias_link
*link
;
210 error
= StrToAddr(arg
->argv
[arg
->argn
], &localaddr
);
212 prompt_Printf(arg
->prompt
, "address redirect: invalid local address\n");
215 error
= StrToAddr(arg
->argv
[arg
->argn
+1], &aliasaddr
);
217 prompt_Printf(arg
->prompt
, "address redirect: invalid alias address\n");
218 prompt_Printf(arg
->prompt
, "usage: nat %s %s\n", arg
->cmd
->name
,
222 link
= PacketAliasRedirectAddr(localaddr
, aliasaddr
);
224 prompt_Printf(arg
->prompt
, "address redirect: packet aliasing"
226 prompt_Printf(arg
->prompt
, "usage: nat %s %s\n", arg
->cmd
->name
,
237 nat_RedirectProto(struct cmdargs
const *arg
)
239 if (!arg
->bundle
->NatEnabled
) {
240 prompt_Printf(arg
->prompt
, "nat not enabled\n");
242 } else if (arg
->argc
>= arg
->argn
+ 2 && arg
->argc
<= arg
->argn
+ 4) {
243 struct in_addr localIP
, publicIP
, remoteIP
;
244 struct alias_link
*link
;
249 len
= strlen(arg
->argv
[arg
->argn
]);
251 prompt_Printf(arg
->prompt
, "proto redirect: invalid protocol\n");
254 if (strspn(arg
->argv
[arg
->argn
], "01234567") == len
)
255 pe
= getprotobynumber(atoi(arg
->argv
[arg
->argn
]));
257 pe
= getprotobyname(arg
->argv
[arg
->argn
]);
259 prompt_Printf(arg
->prompt
, "proto redirect: invalid protocol\n");
263 error
= StrToAddr(arg
->argv
[arg
->argn
+ 1], &localIP
);
265 prompt_Printf(arg
->prompt
, "proto redirect: invalid src address\n");
269 if (arg
->argc
>= arg
->argn
+ 3) {
270 error
= StrToAddr(arg
->argv
[arg
->argn
+ 2], &publicIP
);
272 prompt_Printf(arg
->prompt
, "proto redirect: invalid alias address\n");
273 prompt_Printf(arg
->prompt
, "usage: nat %s %s\n", arg
->cmd
->name
,
278 publicIP
.s_addr
= INADDR_ANY
;
280 if (arg
->argc
== arg
->argn
+ 4) {
281 error
= StrToAddr(arg
->argv
[arg
->argn
+ 2], &remoteIP
);
283 prompt_Printf(arg
->prompt
, "proto redirect: invalid dst address\n");
284 prompt_Printf(arg
->prompt
, "usage: nat %s %s\n", arg
->cmd
->name
,
289 remoteIP
.s_addr
= INADDR_ANY
;
291 link
= PacketAliasRedirectProto(localIP
, remoteIP
, publicIP
, pe
->p_proto
);
293 prompt_Printf(arg
->prompt
, "proto redirect: packet aliasing"
295 prompt_Printf(arg
->prompt
, "usage: nat %s %s\n", arg
->cmd
->name
,
306 StrToAddr(const char *str
, struct in_addr
*addr
)
310 if (inet_aton(str
, addr
))
313 hp
= gethostbyname(str
);
315 log_Printf(LogWARN
, "StrToAddr: Unknown host %s.\n", str
);
318 *addr
= *((struct in_addr
*) hp
->h_addr
);
324 StrToPort(const char *str
, u_short
*port
, const char *proto
)
329 *port
= strtol(str
, &end
, 10);
331 sp
= getservbyname(str
, proto
);
333 log_Printf(LogWARN
, "StrToAddr: Unknown port or service %s/%s.\n",
337 *port
= ntohs(sp
->s_port
);
344 StrToPortRange(const char *str
, u_short
*low
, u_short
*high
, const char *proto
)
349 minus
= strchr(str
, '-');
351 *minus
= '\0'; /* Cheat the const-ness ! */
353 res
= StrToPort(str
, low
, proto
);
356 *minus
= '-'; /* Cheat the const-ness ! */
360 res
= StrToPort(minus
+ 1, high
, proto
);
369 StrToAddrAndPort(const char *str
, struct in_addr
*addr
, u_short
*low
,
370 u_short
*high
, const char *proto
)
375 colon
= strchr(str
, ':');
377 log_Printf(LogWARN
, "StrToAddrAndPort: %s is missing port number.\n", str
);
381 *colon
= '\0'; /* Cheat the const-ness ! */
382 res
= StrToAddr(str
, addr
);
383 *colon
= ':'; /* Cheat the const-ness ! */
387 return StrToPortRange(colon
+ 1, low
, high
, proto
);
391 nat_ProxyRule(struct cmdargs
const *arg
)
397 if (arg
->argn
>= arg
->argc
)
400 for (f
= arg
->argn
, pos
= 0; f
< arg
->argc
; f
++) {
401 len
= strlen(arg
->argv
[f
]);
402 if (sizeof cmd
- pos
< len
+ (len
? 1 : 0))
406 strcpy(cmd
+ pos
, arg
->argv
[f
]);
410 return PacketAliasProxyRule(cmd
);
414 nat_SetTarget(struct cmdargs
const *arg
)
418 if (arg
->argc
== arg
->argn
) {
419 addr
.s_addr
= INADDR_ANY
;
420 PacketAliasSetTarget(addr
);
424 if (arg
->argc
!= arg
->argn
+ 1)
427 if (!strcasecmp(arg
->argv
[arg
->argn
], "MYADDR")) {
428 addr
.s_addr
= INADDR_ANY
;
429 PacketAliasSetTarget(addr
);
433 addr
= GetIpAddr(arg
->argv
[arg
->argn
]);
434 if (addr
.s_addr
== INADDR_NONE
) {
435 log_Printf(LogWARN
, "%s: invalid address\n", arg
->argv
[arg
->argn
]);
439 PacketAliasSetTarget(addr
);
445 nat_PunchFW(struct cmdargs
const *arg
)
450 if (arg
->argc
== arg
->argn
) {
451 PacketAliasSetMode(0, PKT_ALIAS_PUNCH_FW
);
455 if (arg
->argc
!= arg
->argn
+ 2)
458 base
= strtol(arg
->argv
[arg
->argn
], &end
, 10);
459 if (*end
!= '\0' || base
< 0)
462 count
= strtol(arg
->argv
[arg
->argn
+ 1], &end
, 10);
463 if (*end
!= '\0' || count
< 0)
466 PacketAliasSetFWBase(base
, count
);
467 PacketAliasSetMode(PKT_ALIAS_PUNCH_FW
, PKT_ALIAS_PUNCH_FW
);
474 nat_LayerPush(struct bundle
*bundle
, struct link
*l __unused
, struct mbuf
*bp
,
475 int pri __unused
, u_short
*proto
)
477 if (!bundle
->NatEnabled
|| *proto
!= PROTO_IP
)
480 log_Printf(LogDEBUG
, "nat_LayerPush: PROTO_IP -> PROTO_IP\n");
481 m_settype(bp
, MB_NATOUT
);
482 /* Ensure there's a bit of extra buffer for the NAT code... */
483 bp
= m_pullup(m_append(bp
, NULL
, NAT_EXTRABUF
));
484 PacketAliasOut(MBUF_CTOP(bp
), bp
->m_len
);
485 bp
->m_len
= ntohs(((struct ip
*)MBUF_CTOP(bp
))->ip_len
);
491 nat_LayerPull(struct bundle
*bundle
, struct link
*l __unused
, struct mbuf
*bp
,
495 int ret
, len
, nfrags
;
499 if (!bundle
->NatEnabled
|| *proto
!= PROTO_IP
)
502 log_Printf(LogDEBUG
, "nat_LayerPull: PROTO_IP -> PROTO_IP\n");
503 m_settype(bp
, MB_NATIN
);
504 /* Ensure there's a bit of extra buffer for the NAT code... */
505 bp
= m_pullup(m_append(bp
, NULL
, NAT_EXTRABUF
));
506 ret
= PacketAliasIn(MBUF_CTOP(bp
), bp
->m_len
);
508 bp
->m_len
= ntohs(((struct ip
*)MBUF_CTOP(bp
))->ip_len
);
509 if (bp
->m_len
> MAX_MRU
) {
510 log_Printf(LogWARN
, "nat_LayerPull: Problem with IP header length (%lu)\n",
511 (unsigned long)bp
->m_len
);
520 case PKT_ALIAS_UNRESOLVED_FRAGMENT
:
521 /* Save the data for later */
522 fptr
= malloc(bp
->m_len
);
523 bp
= mbuf_Read(bp
, fptr
, bp
->m_len
);
524 PacketAliasSaveFragment(fptr
);
525 log_Printf(LogDEBUG
, "Store another frag (%lu) - now %d\n",
526 (unsigned long)((struct ip
*)fptr
)->ip_id
, ++gfrags
);
529 case PKT_ALIAS_FOUND_HEADER_FRAGMENT
:
530 /* Fetch all the saved fragments and chain them on the end of `bp' */
531 last
= &bp
->m_nextpkt
;
533 while ((fptr
= PacketAliasGetFragment(MBUF_CTOP(bp
))) != NULL
) {
535 PacketAliasFragmentIn(MBUF_CTOP(bp
), fptr
);
536 len
= ntohs(((struct ip
*)fptr
)->ip_len
);
537 *last
= m_get(len
, MB_NATIN
);
538 memcpy(MBUF_CTOP(*last
), fptr
, len
);
540 last
= &(*last
)->m_nextpkt
;
543 log_Printf(LogDEBUG
, "Found a frag header (%lu) - plus %d more frags (no"
544 "w %d)\n", (unsigned long)((struct ip
*)MBUF_CTOP(bp
))->ip_id
,
548 case PKT_ALIAS_IGNORED
:
549 if (PacketAliasSetMode(0, 0) & PKT_ALIAS_DENY_INCOMING
) {
550 log_Printf(LogTCPIP
, "NAT engine denied data:\n");
553 } else if (log_IsKept(LogTCPIP
)) {
554 log_Printf(LogTCPIP
, "NAT engine ignored data:\n");
555 PacketCheck(bundle
, AF_INET
, MBUF_CTOP(bp
), bp
->m_len
, NULL
,
561 log_Printf(LogWARN
, "nat_LayerPull: Dropped a packet (%d)....\n", ret
);
570 struct layer natlayer
=
571 { LAYER_NAT
, "nat", nat_LayerPush
, nat_LayerPull
};