nat_cmd.c revision 58867
18876Srgrimes/*- 24Srgrimes * The code in this file was written by Eivind Eklund <perhaps@yes.no>, 34Srgrimes * who places it in the public domain without restriction. 44Srgrimes * 58876Srgrimes * $FreeBSD: head/usr.sbin/ppp/nat_cmd.c 58867 2000-03-31 14:26:23Z brian $ 64Srgrimes */ 74Srgrimes 84Srgrimes#include <sys/param.h> 94Srgrimes#include <netinet/in.h> 104Srgrimes#include <arpa/inet.h> 118876Srgrimes#include <netdb.h> 128876Srgrimes#include <netinet/in_systm.h> 134Srgrimes#include <netinet/in.h> 144Srgrimes#include <netinet/ip.h> 158876Srgrimes#include <sys/un.h> 164Srgrimes 178876Srgrimes#include <stdio.h> 184Srgrimes#include <stdlib.h> 194Srgrimes#include <string.h> 204Srgrimes#include <termios.h> 214Srgrimes 228876Srgrimes#ifdef LOCALNAT 234Srgrimes#include "alias.h" 244Srgrimes#else 254Srgrimes#include <alias.h> 2612720Sphk#endif 274Srgrimes 28623Srgrimes#include "layer.h" 294Srgrimes#include "proto.h" 304Srgrimes#include "defs.h" 314Srgrimes#include "command.h" 324Srgrimes#include "log.h" 334Srgrimes#include "nat_cmd.h" 342056Swollman#include "descriptor.h" 352056Swollman#include "prompt.h" 362056Swollman#include "timer.h" 3712662Sdg#include "fsm.h" 3812662Sdg#include "slcompress.h" 3912662Sdg#include "throughput.h" 4012662Sdg#include "iplist.h" 4112662Sdg#include "mbuf.h" 4212662Sdg#include "lqr.h" 432056Swollman#include "hdlc.h" 444Srgrimes#include "ipcp.h" 454Srgrimes#include "lcp.h" 464Srgrimes#include "ccp.h" 474Srgrimes#include "link.h" 484Srgrimes#include "mp.h" 494Srgrimes#include "filter.h" 504Srgrimes#ifndef NORADIUS 514Srgrimes#include "radius.h" 524Srgrimes#endif 534Srgrimes#include "ip.h" 5412515Sphk#include "bundle.h" 554Srgrimes 564Srgrimes 5712720Sphk#define NAT_EXTRABUF (13) 5812515Sphk 5912515Sphkstatic int StrToAddr(const char *, struct in_addr *); 6012515Sphkstatic int StrToPortRange(const char *, u_short *, u_short *, const char *); 614Srgrimesstatic int StrToAddrAndPort(const char *, struct in_addr *, u_short *, 6212515Sphk u_short *, const char *); 6312515Sphk 6412515Sphkstatic void 6512515Sphklowhigh(u_short *a, u_short *b) 6612515Sphk{ 6712515Sphk if (a > b) { 6812515Sphk u_short c; 6912515Sphk 7012515Sphk c = *b; 7112515Sphk *b = *a; 7212515Sphk *a = c; 7312473Sbde } 7412515Sphk} 754Srgrimes 764Srgrimesint 774Srgrimesnat_RedirectPort(struct cmdargs const *arg) 784Srgrimes{ 794Srgrimes if (!arg->bundle->NatEnabled) { 804Srgrimes prompt_Printf(arg->prompt, "Alias not enabled\n"); 814Srgrimes return 1; 824Srgrimes } else if (arg->argc == arg->argn + 3 || arg->argc == arg->argn + 4) { 834Srgrimes char proto_constant; 844Srgrimes const char *proto; 854Srgrimes struct in_addr localaddr; 864Srgrimes u_short hlocalport, llocalport; 874Srgrimes struct in_addr aliasaddr; 884Srgrimes u_short haliasport, laliasport; 894Srgrimes struct in_addr remoteaddr; 904Srgrimes u_short hremoteport, lremoteport; 914Srgrimes struct alias_link *link; 924Srgrimes int error; 934Srgrimes 944Srgrimes proto = arg->argv[arg->argn]; 954Srgrimes if (strcmp(proto, "tcp") == 0) { 964Srgrimes proto_constant = IPPROTO_TCP; 974Srgrimes } else if (strcmp(proto, "udp") == 0) { 984Srgrimes proto_constant = IPPROTO_UDP; 994Srgrimes } else { 1004Srgrimes prompt_Printf(arg->prompt, "port redirect: protocol must be" 1014Srgrimes " tcp or udp\n"); 10212515Sphk return -1; 1034Srgrimes } 1044Srgrimes 1054Srgrimes error = StrToAddrAndPort(arg->argv[arg->argn+1], &localaddr, &llocalport, 1064Srgrimes &hlocalport, proto); 1074Srgrimes if (error) { 1084Srgrimes prompt_Printf(arg->prompt, "nat port: error reading localaddr:port\n"); 1094Srgrimes return -1; 1104Srgrimes } 1114Srgrimes 1124Srgrimes error = StrToPortRange(arg->argv[arg->argn+2], &laliasport, &haliasport, 1134Srgrimes proto); 1144Srgrimes if (error) { 1154Srgrimes prompt_Printf(arg->prompt, "nat port: error reading alias port\n"); 1164Srgrimes return -1; 1174Srgrimes } 1184Srgrimes aliasaddr.s_addr = INADDR_ANY; 1194Srgrimes 1204Srgrimes if (arg->argc == arg->argn + 4) { 1214Srgrimes error = StrToAddrAndPort(arg->argv[arg->argn+3], &remoteaddr, 1224Srgrimes &lremoteport, &hremoteport, proto); 1234Srgrimes if (error) { 1244Srgrimes prompt_Printf(arg->prompt, "nat port: error reading " 1254Srgrimes "remoteaddr:port\n"); 1264Srgrimes return -1; 1274Srgrimes } 1284Srgrimes } else { 1294Srgrimes remoteaddr.s_addr = INADDR_ANY; 1304Srgrimes lremoteport = hremoteport = 0; 1314Srgrimes } 1324Srgrimes 1334Srgrimes lowhigh(&llocalport, &hlocalport); 1344Srgrimes lowhigh(&laliasport, &haliasport); 1354Srgrimes lowhigh(&lremoteport, &hremoteport); 1364Srgrimes 1374Srgrimes if (haliasport - laliasport != hlocalport - llocalport) { 1384Srgrimes prompt_Printf(arg->prompt, "nat port: local & alias port ranges " 1394Srgrimes "are not equal\n"); 1404Srgrimes return -1; 1414Srgrimes } 1424Srgrimes 1434Srgrimes if (hremoteport && hremoteport - lremoteport != hlocalport - llocalport) { 1444Srgrimes prompt_Printf(arg->prompt, "nat port: local & remote port ranges " 14512515Sphk "are not equal\n"); 1464Srgrimes return -1; 1474Srgrimes } 1484Srgrimes 1494Srgrimes while (laliasport <= haliasport) { 1504Srgrimes link = PacketAliasRedirectPort(localaddr, htons(llocalport), 1514Srgrimes remoteaddr, htons(lremoteport), 1524Srgrimes aliasaddr, htons(laliasport), 1534Srgrimes proto_constant); 1544Srgrimes 1554Srgrimes if (link == NULL) { 1564Srgrimes prompt_Printf(arg->prompt, "nat port: %d: error %d\n", laliasport, 1574Srgrimes error); 1584Srgrimes return 1; 1594Srgrimes } 1604Srgrimes llocalport++; 1614Srgrimes laliasport++; 1624Srgrimes if (hremoteport) 1634Srgrimes lremoteport++; 1644Srgrimes } 1654Srgrimes 1664Srgrimes return 0; 16712515Sphk } 1684Srgrimes 1694Srgrimes return -1; 1704Srgrimes} 1714Srgrimes 1724Srgrimes 1734Srgrimesint 1744Srgrimesnat_RedirectAddr(struct cmdargs const *arg) 1754Srgrimes{ 1764Srgrimes if (!arg->bundle->NatEnabled) { 1774Srgrimes prompt_Printf(arg->prompt, "nat not enabled\n"); 1784Srgrimes return 1; 1794Srgrimes } else if (arg->argc == arg->argn+2) { 1804Srgrimes int error; 1814Srgrimes struct in_addr localaddr, aliasaddr; 1824Srgrimes struct alias_link *link; 1834Srgrimes 1844Srgrimes error = StrToAddr(arg->argv[arg->argn], &localaddr); 1854Srgrimes if (error) { 1864Srgrimes prompt_Printf(arg->prompt, "address redirect: invalid local address\n"); 1874Srgrimes return 1; 1884Srgrimes } 1894Srgrimes error = StrToAddr(arg->argv[arg->argn+1], &aliasaddr); 1904Srgrimes if (error) { 1914Srgrimes prompt_Printf(arg->prompt, "address redirect: invalid alias address\n"); 19212473Sbde prompt_Printf(arg->prompt, "Usage: nat %s %s\n", arg->cmd->name, 1934Srgrimes arg->cmd->syntax); 1944Srgrimes return 1; 1954Srgrimes } 1964Srgrimes link = PacketAliasRedirectAddr(localaddr, aliasaddr); 1974Srgrimes if (link == NULL) { 1984Srgrimes prompt_Printf(arg->prompt, "address redirect: packet aliasing" 1994Srgrimes " engine error\n"); 2004Srgrimes prompt_Printf(arg->prompt, "Usage: nat %s %s\n", arg->cmd->name, 2014Srgrimes arg->cmd->syntax); 2024Srgrimes } 2034Srgrimes } else 20412473Sbde return -1; 2054Srgrimes 2064Srgrimes return 0; 2074Srgrimes} 2084Srgrimes 2094Srgrimes 2104Srgrimesstatic int 2114SrgrimesStrToAddr(const char *str, struct in_addr *addr) 2124Srgrimes{ 2134Srgrimes struct hostent *hp; 2144Srgrimes 2154Srgrimes if (inet_aton(str, addr)) 2164Srgrimes return 0; 2174Srgrimes 2184Srgrimes hp = gethostbyname(str); 2194Srgrimes if (!hp) { 2204Srgrimes log_Printf(LogWARN, "StrToAddr: Unknown host %s.\n", str); 2214Srgrimes return -1; 22212473Sbde } 22312473Sbde *addr = *((struct in_addr *) hp->h_addr); 22412473Sbde return 0; 22512473Sbde} 22612473Sbde 2274Srgrimes 2284Srgrimesstatic int 2294SrgrimesStrToPort(const char *str, u_short *port, const char *proto) 2304Srgrimes{ 2314Srgrimes struct servent *sp; 2324Srgrimes char *end; 2334Srgrimes 2344Srgrimes *port = strtol(str, &end, 10); 2354Srgrimes if (*end != '\0') { 2364Srgrimes sp = getservbyname(str, proto); 2374Srgrimes if (sp == NULL) { 2384Srgrimes log_Printf(LogWARN, "StrToAddr: Unknown port or service %s/%s.\n", 2394Srgrimes str, proto); 2404Srgrimes return -1; 2414Srgrimes } 2424Srgrimes *port = ntohs(sp->s_port); 2434Srgrimes } 2444Srgrimes 2454Srgrimes return 0; 2464Srgrimes} 2474Srgrimes 2484Srgrimesstatic int 2494SrgrimesStrToPortRange(const char *str, u_short *low, u_short *high, const char *proto) 2504Srgrimes{ 2514Srgrimes char *minus; 2524Srgrimes int res; 2534Srgrimes 2544Srgrimes minus = strchr(str, '-'); 25512515Sphk if (minus) 25612515Sphk *minus = '\0'; /* Cheat the const-ness ! */ 2574Srgrimes 2584Srgrimes res = StrToPort(str, low, proto); 2594Srgrimes 2604Srgrimes if (minus) 2614Srgrimes *minus = '-'; /* Cheat the const-ness ! */ 2624Srgrimes 2634Srgrimes if (res == 0) { 2644Srgrimes if (minus) 2654Srgrimes res = StrToPort(minus + 1, high, proto); 2664Srgrimes else 2674Srgrimes *high = *low; 2684Srgrimes } 2694Srgrimes 2704Srgrimes return res; 2714Srgrimes} 2724Srgrimes 2734Srgrimesstatic int 2744SrgrimesStrToAddrAndPort(const char *str, struct in_addr *addr, u_short *low, 2754Srgrimes u_short *high, const char *proto) 2764Srgrimes{ 2774Srgrimes char *colon; 2784Srgrimes int res; 2794Srgrimes 2804Srgrimes colon = strchr(str, ':'); 2814Srgrimes if (!colon) { 2824Srgrimes log_Printf(LogWARN, "StrToAddrAndPort: %s is missing port number.\n", str); 2834Srgrimes return -1; 2844Srgrimes } 2854Srgrimes 2864Srgrimes *colon = '\0'; /* Cheat the const-ness ! */ 2874Srgrimes res = StrToAddr(str, addr); 2884Srgrimes *colon = ':'; /* Cheat the const-ness ! */ 2894Srgrimes if (res != 0) 29012515Sphk return -1; 291 292 return StrToPortRange(colon + 1, low, high, proto); 293} 294 295int 296nat_ProxyRule(struct cmdargs const *arg) 297{ 298 char cmd[LINE_LEN]; 299 int f, pos; 300 size_t len; 301 302 if (arg->argn >= arg->argc) 303 return -1; 304 305 for (f = arg->argn, pos = 0; f < arg->argc; f++) { 306 len = strlen(arg->argv[f]); 307 if (sizeof cmd - pos < len + (f ? 1 : 0)) 308 break; 309 if (f) 310 cmd[pos++] = ' '; 311 strcpy(cmd + pos, arg->argv[f]); 312 pos += len; 313 } 314 315 return PacketAliasProxyRule(cmd); 316} 317 318int 319nat_Pptp(struct cmdargs const *arg) 320{ 321 struct in_addr addr; 322 323 if (arg->argc == arg->argn) { 324 addr.s_addr = INADDR_NONE; 325 PacketAliasPptp(addr); 326 return 0; 327 } 328 329 if (arg->argc != arg->argn + 1) 330 return -1; 331 332 addr = GetIpAddr(arg->argv[arg->argn]); 333 if (addr.s_addr == INADDR_NONE) { 334 log_Printf(LogWARN, "%s: invalid address\n", arg->argv[arg->argn]); 335 return 1; 336 } 337 338 PacketAliasPptp(addr); 339 return 0; 340} 341 342int 343nat_SetTarget(struct cmdargs const *arg) 344{ 345 struct in_addr addr; 346 347 if (arg->argc == arg->argn) { 348 addr.s_addr = INADDR_ANY; 349 PacketAliasSetTarget(addr); 350 return 0; 351 } 352 353 if (arg->argc != arg->argn + 1) 354 return -1; 355 356 addr = GetIpAddr(arg->argv[arg->argn]); 357 if (addr.s_addr == INADDR_NONE) { 358 log_Printf(LogWARN, "%s: invalid address\n", arg->argv[arg->argn]); 359 return 1; 360 } 361 362 PacketAliasSetTarget(addr); 363 return 0; 364} 365 366static struct mbuf * 367nat_LayerPush(struct bundle *bundle, struct link *l, struct mbuf *bp, 368 int pri, u_short *proto) 369{ 370 if (!bundle->NatEnabled || *proto != PROTO_IP) 371 return bp; 372 373 log_Printf(LogDEBUG, "nat_LayerPush: PROTO_IP -> PROTO_IP\n"); 374 m_settype(bp, MB_NATOUT); 375 /* Ensure there's a bit of extra buffer for the NAT code... */ 376 bp = m_pullup(m_append(bp, NULL, NAT_EXTRABUF)); 377 PacketAliasOut(MBUF_CTOP(bp), bp->m_len); 378 bp->m_len = ntohs(((struct ip *)MBUF_CTOP(bp))->ip_len); 379 380 return bp; 381} 382 383static struct mbuf * 384nat_LayerPull(struct bundle *bundle, struct link *l, struct mbuf *bp, 385 u_short *proto) 386{ 387 static int gfrags; 388 struct ip *pip, *piip; 389 int ret, len, nfrags; 390 struct mbuf **last; 391 char *fptr; 392 393 if (!bundle->NatEnabled || *proto != PROTO_IP) 394 return bp; 395 396 log_Printf(LogDEBUG, "nat_LayerPull: PROTO_IP -> PROTO_IP\n"); 397 m_settype(bp, MB_NATIN); 398 bp = m_pullup(bp); 399 pip = (struct ip *)MBUF_CTOP(bp); 400 piip = (struct ip *)((char *)pip + (pip->ip_hl << 2)); 401 402 if (pip->ip_p == IPPROTO_IGMP || 403 (pip->ip_p == IPPROTO_IPIP && IN_CLASSD(ntohl(piip->ip_dst.s_addr)))) 404 return bp; 405 406 /* Ensure there's a bit of extra buffer for the NAT code... */ 407 bp = m_pullup(m_append(bp, NULL, NAT_EXTRABUF)); 408 ret = PacketAliasIn(MBUF_CTOP(bp), bp->m_len); 409 pip = (struct ip *)MBUF_CTOP(bp); 410 411 bp->m_len = ntohs(pip->ip_len); 412 if (bp->m_len > MAX_MRU) { 413 log_Printf(LogWARN, "nat_LayerPull: Problem with IP header length (%lu)\n", 414 (unsigned long)bp->m_len); 415 m_freem(bp); 416 return NULL; 417 } 418 419 switch (ret) { 420 case PKT_ALIAS_OK: 421 break; 422 423 case PKT_ALIAS_UNRESOLVED_FRAGMENT: 424 /* Save the data for later */ 425 fptr = malloc(bp->m_len); 426 bp = mbuf_Read(bp, fptr, bp->m_len); 427 PacketAliasSaveFragment(fptr); 428 log_Printf(LogDEBUG, "Store another frag (%lu) - now %d\n", 429 (unsigned long)((struct ip *)fptr)->ip_id, ++gfrags); 430 break; 431 432 case PKT_ALIAS_FOUND_HEADER_FRAGMENT: 433 /* Fetch all the saved fragments and chain them on the end of `bp' */ 434 last = &bp->m_nextpkt; 435 nfrags = 0; 436 while ((fptr = PacketAliasGetFragment(MBUF_CTOP(bp))) != NULL) { 437 nfrags++; 438 PacketAliasFragmentIn(MBUF_CTOP(bp), fptr); 439 len = ntohs(((struct ip *)fptr)->ip_len); 440 *last = m_get(len, MB_NATIN); 441 memcpy(MBUF_CTOP(*last), fptr, len); 442 free(fptr); 443 last = &(*last)->m_nextpkt; 444 } 445 gfrags -= nfrags; 446 log_Printf(LogDEBUG, "Found a frag header (%lu) - plus %d more frags (no" 447 "w %d)\n", (unsigned long)((struct ip *)MBUF_CTOP(bp))->ip_id, 448 nfrags, gfrags); 449 break; 450 451 case PKT_ALIAS_IGNORED: 452 if (log_IsKept(LogTCPIP)) { 453 log_Printf(LogTCPIP, "NAT engine ignored data:\n"); 454 PacketCheck(bundle, (char *)pip, ntohs(pip->ip_len), NULL); 455 } 456 m_freem(bp); 457 bp = NULL; 458 break; 459 460 default: 461 log_Printf(LogWARN, "nat_LayerPull: Dropped a packet (%d)....\n", ret); 462 m_freem(bp); 463 bp = NULL; 464 break; 465 } 466 467 return bp; 468} 469 470struct layer natlayer = 471 { LAYER_NAT, "nat", nat_LayerPush, nat_LayerPull }; 472