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