nat_cmd.c revision 79433
1/*- 2 * Copyright (c) 2001 Charles Mott <cmott@scientech.com> 3 * Brian Somers <brian@Awfulhak.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 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. 14 * 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 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD: head/usr.sbin/ppp/nat_cmd.c 79433 2001-07-09 00:07:56Z brian $ 28 */ 29 30#include <sys/param.h> 31#include <netinet/in.h> 32#include <arpa/inet.h> 33#include <netdb.h> 34#include <netinet/in_systm.h> 35#include <netinet/in.h> 36#include <netinet/ip.h> 37#include <sys/un.h> 38 39#include <stdio.h> 40#include <stdlib.h> 41#include <string.h> 42#include <termios.h> 43 44#ifdef LOCALNAT 45#include "alias.h" 46#else 47#include <alias.h> 48#endif 49 50#include "layer.h" 51#include "proto.h" 52#include "defs.h" 53#include "command.h" 54#include "log.h" 55#include "nat_cmd.h" 56#include "descriptor.h" 57#include "prompt.h" 58#include "timer.h" 59#include "fsm.h" 60#include "slcompress.h" 61#include "throughput.h" 62#include "iplist.h" 63#include "mbuf.h" 64#include "lqr.h" 65#include "hdlc.h" 66#include "ipcp.h" 67#include "lcp.h" 68#include "ccp.h" 69#include "link.h" 70#include "mp.h" 71#include "filter.h" 72#ifndef NORADIUS 73#include "radius.h" 74#endif 75#include "ip.h" 76#include "bundle.h" 77 78 79#define NAT_EXTRABUF (13) 80 81static int StrToAddr(const char *, struct in_addr *); 82static int StrToPortRange(const char *, u_short *, u_short *, const char *); 83static int StrToAddrAndPort(const char *, struct in_addr *, u_short *, 84 u_short *, const char *); 85 86static void 87lowhigh(u_short *a, u_short *b) 88{ 89 if (a > b) { 90 u_short c; 91 92 c = *b; 93 *b = *a; 94 *a = c; 95 } 96} 97 98int 99nat_RedirectPort(struct cmdargs const *arg) 100{ 101 if (!arg->bundle->NatEnabled) { 102 prompt_Printf(arg->prompt, "Alias not enabled\n"); 103 return 1; 104 } else if (arg->argc == arg->argn + 3 || arg->argc == arg->argn + 4) { 105 char proto_constant; 106 const char *proto; 107 struct in_addr localaddr; 108 u_short hlocalport, llocalport; 109 struct in_addr aliasaddr; 110 u_short haliasport, laliasport; 111 struct in_addr remoteaddr; 112 u_short hremoteport, lremoteport; 113 struct alias_link *link; 114 int error; 115 116 proto = arg->argv[arg->argn]; 117 if (strcmp(proto, "tcp") == 0) { 118 proto_constant = IPPROTO_TCP; 119 } else if (strcmp(proto, "udp") == 0) { 120 proto_constant = IPPROTO_UDP; 121 } else { 122 prompt_Printf(arg->prompt, "port redirect: protocol must be" 123 " tcp or udp\n"); 124 return -1; 125 } 126 127 error = StrToAddrAndPort(arg->argv[arg->argn+1], &localaddr, &llocalport, 128 &hlocalport, proto); 129 if (error) { 130 prompt_Printf(arg->prompt, "nat port: error reading localaddr:port\n"); 131 return -1; 132 } 133 134 error = StrToPortRange(arg->argv[arg->argn+2], &laliasport, &haliasport, 135 proto); 136 if (error) { 137 prompt_Printf(arg->prompt, "nat port: error reading alias port\n"); 138 return -1; 139 } 140 aliasaddr.s_addr = INADDR_ANY; 141 142 if (arg->argc == arg->argn + 4) { 143 error = StrToAddrAndPort(arg->argv[arg->argn+3], &remoteaddr, 144 &lremoteport, &hremoteport, proto); 145 if (error) { 146 prompt_Printf(arg->prompt, "nat port: error reading " 147 "remoteaddr:port\n"); 148 return -1; 149 } 150 } else { 151 remoteaddr.s_addr = INADDR_ANY; 152 lremoteport = hremoteport = 0; 153 } 154 155 lowhigh(&llocalport, &hlocalport); 156 lowhigh(&laliasport, &haliasport); 157 lowhigh(&lremoteport, &hremoteport); 158 159 if (haliasport - laliasport != hlocalport - llocalport) { 160 prompt_Printf(arg->prompt, "nat port: local & alias port ranges " 161 "are not equal\n"); 162 return -1; 163 } 164 165 if (hremoteport && hremoteport - lremoteport != hlocalport - llocalport) { 166 prompt_Printf(arg->prompt, "nat port: local & remote port ranges " 167 "are not equal\n"); 168 return -1; 169 } 170 171 while (laliasport <= haliasport) { 172 link = PacketAliasRedirectPort(localaddr, htons(llocalport), 173 remoteaddr, htons(lremoteport), 174 aliasaddr, htons(laliasport), 175 proto_constant); 176 177 if (link == NULL) { 178 prompt_Printf(arg->prompt, "nat port: %d: error %d\n", laliasport, 179 error); 180 return 1; 181 } 182 llocalport++; 183 laliasport++; 184 if (hremoteport) 185 lremoteport++; 186 } 187 188 return 0; 189 } 190 191 return -1; 192} 193 194 195int 196nat_RedirectAddr(struct cmdargs const *arg) 197{ 198 if (!arg->bundle->NatEnabled) { 199 prompt_Printf(arg->prompt, "nat not enabled\n"); 200 return 1; 201 } else if (arg->argc == arg->argn+2) { 202 int error; 203 struct in_addr localaddr, aliasaddr; 204 struct alias_link *link; 205 206 error = StrToAddr(arg->argv[arg->argn], &localaddr); 207 if (error) { 208 prompt_Printf(arg->prompt, "address redirect: invalid local address\n"); 209 return 1; 210 } 211 error = StrToAddr(arg->argv[arg->argn+1], &aliasaddr); 212 if (error) { 213 prompt_Printf(arg->prompt, "address redirect: invalid alias address\n"); 214 prompt_Printf(arg->prompt, "Usage: nat %s %s\n", arg->cmd->name, 215 arg->cmd->syntax); 216 return 1; 217 } 218 link = PacketAliasRedirectAddr(localaddr, aliasaddr); 219 if (link == NULL) { 220 prompt_Printf(arg->prompt, "address redirect: packet aliasing" 221 " engine error\n"); 222 prompt_Printf(arg->prompt, "Usage: nat %s %s\n", arg->cmd->name, 223 arg->cmd->syntax); 224 } 225 } else 226 return -1; 227 228 return 0; 229} 230 231 232int 233nat_RedirectProto(struct cmdargs const *arg) 234{ 235 if (!arg->bundle->NatEnabled) { 236 prompt_Printf(arg->prompt, "nat not enabled\n"); 237 return 1; 238 } else if (arg->argc >= arg->argn + 2 && arg->argc <= arg->argn + 4) { 239 struct in_addr localIP, publicIP, remoteIP; 240 struct alias_link *link; 241 struct protoent *pe; 242 int error, len; 243 244 len = strlen(arg->argv[arg->argn]); 245 if (len == 0) { 246 prompt_Printf(arg->prompt, "proto redirect: invalid protocol\n"); 247 return 1; 248 } 249 if (strspn(arg->argv[arg->argn], "01234567") == len) 250 pe = getprotobynumber(atoi(arg->argv[arg->argn])); 251 else 252 pe = getprotobyname(arg->argv[arg->argn]); 253 if (pe == NULL) { 254 prompt_Printf(arg->prompt, "proto redirect: invalid protocol\n"); 255 return 1; 256 } 257 258 error = StrToAddr(arg->argv[arg->argn + 1], &localIP); 259 if (error) { 260 prompt_Printf(arg->prompt, "proto redirect: invalid src address\n"); 261 return 1; 262 } 263 264 if (arg->argc >= arg->argn + 3) { 265 error = StrToAddr(arg->argv[arg->argn + 2], &publicIP); 266 if (error) { 267 prompt_Printf(arg->prompt, "proto redirect: invalid alias address\n"); 268 prompt_Printf(arg->prompt, "Usage: nat %s %s\n", arg->cmd->name, 269 arg->cmd->syntax); 270 return 1; 271 } 272 } else 273 publicIP.s_addr = INADDR_ANY; 274 275 if (arg->argc == arg->argn + 4) { 276 error = StrToAddr(arg->argv[arg->argn + 2], &remoteIP); 277 if (error) { 278 prompt_Printf(arg->prompt, "proto redirect: invalid dst address\n"); 279 prompt_Printf(arg->prompt, "Usage: nat %s %s\n", arg->cmd->name, 280 arg->cmd->syntax); 281 return 1; 282 } 283 } else 284 remoteIP.s_addr = INADDR_ANY; 285 286 link = PacketAliasRedirectProto(localIP, remoteIP, publicIP, pe->p_proto); 287 if (link == NULL) { 288 prompt_Printf(arg->prompt, "proto redirect: packet aliasing" 289 " engine error\n"); 290 prompt_Printf(arg->prompt, "Usage: nat %s %s\n", arg->cmd->name, 291 arg->cmd->syntax); 292 } 293 } else 294 return -1; 295 296 return 0; 297} 298 299 300static int 301StrToAddr(const char *str, struct in_addr *addr) 302{ 303 struct hostent *hp; 304 305 if (inet_aton(str, addr)) 306 return 0; 307 308 hp = gethostbyname(str); 309 if (!hp) { 310 log_Printf(LogWARN, "StrToAddr: Unknown host %s.\n", str); 311 return -1; 312 } 313 *addr = *((struct in_addr *) hp->h_addr); 314 return 0; 315} 316 317 318static int 319StrToPort(const char *str, u_short *port, const char *proto) 320{ 321 struct servent *sp; 322 char *end; 323 324 *port = strtol(str, &end, 10); 325 if (*end != '\0') { 326 sp = getservbyname(str, proto); 327 if (sp == NULL) { 328 log_Printf(LogWARN, "StrToAddr: Unknown port or service %s/%s.\n", 329 str, proto); 330 return -1; 331 } 332 *port = ntohs(sp->s_port); 333 } 334 335 return 0; 336} 337 338static int 339StrToPortRange(const char *str, u_short *low, u_short *high, const char *proto) 340{ 341 char *minus; 342 int res; 343 344 minus = strchr(str, '-'); 345 if (minus) 346 *minus = '\0'; /* Cheat the const-ness ! */ 347 348 res = StrToPort(str, low, proto); 349 350 if (minus) 351 *minus = '-'; /* Cheat the const-ness ! */ 352 353 if (res == 0) { 354 if (minus) 355 res = StrToPort(minus + 1, high, proto); 356 else 357 *high = *low; 358 } 359 360 return res; 361} 362 363static int 364StrToAddrAndPort(const char *str, struct in_addr *addr, u_short *low, 365 u_short *high, const char *proto) 366{ 367 char *colon; 368 int res; 369 370 colon = strchr(str, ':'); 371 if (!colon) { 372 log_Printf(LogWARN, "StrToAddrAndPort: %s is missing port number.\n", str); 373 return -1; 374 } 375 376 *colon = '\0'; /* Cheat the const-ness ! */ 377 res = StrToAddr(str, addr); 378 *colon = ':'; /* Cheat the const-ness ! */ 379 if (res != 0) 380 return -1; 381 382 return StrToPortRange(colon + 1, low, high, proto); 383} 384 385int 386nat_ProxyRule(struct cmdargs const *arg) 387{ 388 char cmd[LINE_LEN]; 389 int f, pos; 390 size_t len; 391 392 if (arg->argn >= arg->argc) 393 return -1; 394 395 for (f = arg->argn, pos = 0; f < arg->argc; f++) { 396 len = strlen(arg->argv[f]); 397 if (sizeof cmd - pos < len + (len ? 1 : 0)) 398 break; 399 if (len) 400 cmd[pos++] = ' '; 401 strcpy(cmd + pos, arg->argv[f]); 402 pos += len; 403 } 404 405 return PacketAliasProxyRule(cmd); 406} 407 408int 409nat_SetTarget(struct cmdargs const *arg) 410{ 411 struct in_addr addr; 412 413 if (arg->argc == arg->argn) { 414 addr.s_addr = INADDR_ANY; 415 PacketAliasSetTarget(addr); 416 return 0; 417 } 418 419 if (arg->argc != arg->argn + 1) 420 return -1; 421 422 if (!strcasecmp(arg->argv[arg->argn], "MYADDR")) { 423 addr.s_addr = INADDR_ANY; 424 PacketAliasSetTarget(addr); 425 return 0; 426 } 427 428 addr = GetIpAddr(arg->argv[arg->argn]); 429 if (addr.s_addr == INADDR_NONE) { 430 log_Printf(LogWARN, "%s: invalid address\n", arg->argv[arg->argn]); 431 return 1; 432 } 433 434 PacketAliasSetTarget(addr); 435 return 0; 436} 437 438static struct mbuf * 439nat_LayerPush(struct bundle *bundle, struct link *l, struct mbuf *bp, 440 int pri, u_short *proto) 441{ 442 if (!bundle->NatEnabled || *proto != PROTO_IP) 443 return bp; 444 445 log_Printf(LogDEBUG, "nat_LayerPush: PROTO_IP -> PROTO_IP\n"); 446 m_settype(bp, MB_NATOUT); 447 /* Ensure there's a bit of extra buffer for the NAT code... */ 448 bp = m_pullup(m_append(bp, NULL, NAT_EXTRABUF)); 449 PacketAliasOut(MBUF_CTOP(bp), bp->m_len); 450 bp->m_len = ntohs(((struct ip *)MBUF_CTOP(bp))->ip_len); 451 452 return bp; 453} 454 455static struct mbuf * 456nat_LayerPull(struct bundle *bundle, struct link *l, struct mbuf *bp, 457 u_short *proto) 458{ 459 static int gfrags; 460 int ret, len, nfrags; 461 struct mbuf **last; 462 char *fptr; 463 464 if (!bundle->NatEnabled || *proto != PROTO_IP) 465 return bp; 466 467 log_Printf(LogDEBUG, "nat_LayerPull: PROTO_IP -> PROTO_IP\n"); 468 m_settype(bp, MB_NATIN); 469 /* Ensure there's a bit of extra buffer for the NAT code... */ 470 bp = m_pullup(m_append(bp, NULL, NAT_EXTRABUF)); 471 ret = PacketAliasIn(MBUF_CTOP(bp), bp->m_len); 472 473 bp->m_len = ntohs(((struct ip *)MBUF_CTOP(bp))->ip_len); 474 if (bp->m_len > MAX_MRU) { 475 log_Printf(LogWARN, "nat_LayerPull: Problem with IP header length (%lu)\n", 476 (unsigned long)bp->m_len); 477 m_freem(bp); 478 return NULL; 479 } 480 481 switch (ret) { 482 case PKT_ALIAS_OK: 483 break; 484 485 case PKT_ALIAS_UNRESOLVED_FRAGMENT: 486 /* Save the data for later */ 487 fptr = malloc(bp->m_len); 488 bp = mbuf_Read(bp, fptr, bp->m_len); 489 PacketAliasSaveFragment(fptr); 490 log_Printf(LogDEBUG, "Store another frag (%lu) - now %d\n", 491 (unsigned long)((struct ip *)fptr)->ip_id, ++gfrags); 492 break; 493 494 case PKT_ALIAS_FOUND_HEADER_FRAGMENT: 495 /* Fetch all the saved fragments and chain them on the end of `bp' */ 496 last = &bp->m_nextpkt; 497 nfrags = 0; 498 while ((fptr = PacketAliasGetFragment(MBUF_CTOP(bp))) != NULL) { 499 nfrags++; 500 PacketAliasFragmentIn(MBUF_CTOP(bp), fptr); 501 len = ntohs(((struct ip *)fptr)->ip_len); 502 *last = m_get(len, MB_NATIN); 503 memcpy(MBUF_CTOP(*last), fptr, len); 504 free(fptr); 505 last = &(*last)->m_nextpkt; 506 } 507 gfrags -= nfrags; 508 log_Printf(LogDEBUG, "Found a frag header (%lu) - plus %d more frags (no" 509 "w %d)\n", (unsigned long)((struct ip *)MBUF_CTOP(bp))->ip_id, 510 nfrags, gfrags); 511 break; 512 513 case PKT_ALIAS_IGNORED: 514 if (PacketAliasSetMode(0, 0) & PKT_ALIAS_DENY_INCOMING) { 515 log_Printf(LogTCPIP, "NAT engine denied data:\n"); 516 m_freem(bp); 517 bp = NULL; 518 } else if (log_IsKept(LogTCPIP)) { 519 log_Printf(LogTCPIP, "NAT engine ignored data:\n"); 520 PacketCheck(bundle, MBUF_CTOP(bp), bp->m_len, NULL, NULL, NULL); 521 } 522 break; 523 524 default: 525 log_Printf(LogWARN, "nat_LayerPull: Dropped a packet (%d)....\n", ret); 526 m_freem(bp); 527 bp = NULL; 528 break; 529 } 530 531 return bp; 532} 533 534struct layer natlayer = 535 { LAYER_NAT, "nat", nat_LayerPush, nat_LayerPull }; 536