nat_cmd.c revision 58042
1/*- 2 * The code in this file was written by Eivind Eklund <perhaps@yes.no>, 3 * who places it in the public domain without restriction. 4 * 5 * $FreeBSD: head/usr.sbin/ppp/nat_cmd.c 58042 2000-03-14 01:47:19Z brian $ 6 */ 7 8#include <sys/param.h> 9#include <netinet/in.h> 10#include <arpa/inet.h> 11#include <netdb.h> 12#include <netinet/in_systm.h> 13#include <netinet/in.h> 14#include <netinet/ip.h> 15#include <sys/un.h> 16 17#include <stdio.h> 18#include <stdlib.h> 19#include <string.h> 20#include <termios.h> 21 22#ifdef LOCALNAT 23#include "alias.h" 24#else 25#include <alias.h> 26#endif 27 28#include "layer.h" 29#include "proto.h" 30#include "defs.h" 31#include "command.h" 32#include "log.h" 33#include "nat_cmd.h" 34#include "descriptor.h" 35#include "prompt.h" 36#include "timer.h" 37#include "fsm.h" 38#include "slcompress.h" 39#include "throughput.h" 40#include "iplist.h" 41#include "mbuf.h" 42#include "lqr.h" 43#include "hdlc.h" 44#include "ipcp.h" 45#include "lcp.h" 46#include "ccp.h" 47#include "link.h" 48#include "mp.h" 49#include "filter.h" 50#ifndef NORADIUS 51#include "radius.h" 52#endif 53#include "bundle.h" 54 55 56#define NAT_EXTRABUF (13) 57 58static int StrToAddr(const char *, struct in_addr *); 59static int StrToPortRange(const char *, u_short *, u_short *, const char *); 60static int StrToAddrAndPort(const char *, struct in_addr *, u_short *, 61 u_short *, const char *); 62 63static void 64lowhigh(u_short *a, u_short *b) 65{ 66 if (a > b) { 67 u_short c; 68 69 c = *b; 70 *b = *a; 71 *a = c; 72 } 73} 74 75int 76nat_RedirectPort(struct cmdargs const *arg) 77{ 78 if (!arg->bundle->NatEnabled) { 79 prompt_Printf(arg->prompt, "Alias not enabled\n"); 80 return 1; 81 } else if (arg->argc == arg->argn + 3 || arg->argc == arg->argn + 4) { 82 char proto_constant; 83 const char *proto; 84 struct in_addr localaddr; 85 u_short hlocalport, llocalport; 86 struct in_addr aliasaddr; 87 u_short haliasport, laliasport; 88 struct in_addr remoteaddr; 89 u_short hremoteport, lremoteport; 90 struct alias_link *link; 91 int error; 92 93 proto = arg->argv[arg->argn]; 94 if (strcmp(proto, "tcp") == 0) { 95 proto_constant = IPPROTO_TCP; 96 } else if (strcmp(proto, "udp") == 0) { 97 proto_constant = IPPROTO_UDP; 98 } else { 99 prompt_Printf(arg->prompt, "port redirect: protocol must be" 100 " tcp or udp\n"); 101 return -1; 102 } 103 104 error = StrToAddrAndPort(arg->argv[arg->argn+1], &localaddr, &llocalport, 105 &hlocalport, proto); 106 if (error) { 107 prompt_Printf(arg->prompt, "nat port: error reading localaddr:port\n"); 108 return -1; 109 } 110 111 error = StrToPortRange(arg->argv[arg->argn+2], &laliasport, &haliasport, 112 proto); 113 if (error) { 114 prompt_Printf(arg->prompt, "nat port: error reading alias port\n"); 115 return -1; 116 } 117 aliasaddr.s_addr = INADDR_ANY; 118 119 if (arg->argc == arg->argn + 4) { 120 error = StrToAddrAndPort(arg->argv[arg->argn+3], &remoteaddr, 121 &lremoteport, &hremoteport, proto); 122 if (error) { 123 prompt_Printf(arg->prompt, "nat port: error reading " 124 "remoteaddr:port\n"); 125 return -1; 126 } 127 } else { 128 remoteaddr.s_addr = INADDR_ANY; 129 lremoteport = hremoteport = 0; 130 } 131 132 lowhigh(&llocalport, &hlocalport); 133 lowhigh(&laliasport, &haliasport); 134 lowhigh(&lremoteport, &hremoteport); 135 136 if (haliasport - laliasport != hlocalport - llocalport) { 137 prompt_Printf(arg->prompt, "nat port: local & alias port ranges " 138 "are not equal\n"); 139 return -1; 140 } 141 142 if (hremoteport && hremoteport - lremoteport != hlocalport - llocalport) { 143 prompt_Printf(arg->prompt, "nat port: local & remote port ranges " 144 "are not equal\n"); 145 return -1; 146 } 147 148 while (laliasport <= haliasport) { 149 link = PacketAliasRedirectPort(localaddr, htons(llocalport), 150 remoteaddr, htons(lremoteport), 151 aliasaddr, htons(laliasport), 152 proto_constant); 153 154 if (link == NULL) { 155 prompt_Printf(arg->prompt, "nat port: %d: error %d\n", laliasport, 156 error); 157 return 1; 158 } 159 llocalport++; 160 laliasport++; 161 if (hremoteport) 162 lremoteport++; 163 } 164 165 return 0; 166 } 167 168 return -1; 169} 170 171 172int 173nat_RedirectAddr(struct cmdargs const *arg) 174{ 175 if (!arg->bundle->NatEnabled) { 176 prompt_Printf(arg->prompt, "nat not enabled\n"); 177 return 1; 178 } else if (arg->argc == arg->argn+2) { 179 int error; 180 struct in_addr localaddr, aliasaddr; 181 struct alias_link *link; 182 183 error = StrToAddr(arg->argv[arg->argn], &localaddr); 184 if (error) { 185 prompt_Printf(arg->prompt, "address redirect: invalid local address\n"); 186 return 1; 187 } 188 error = StrToAddr(arg->argv[arg->argn+1], &aliasaddr); 189 if (error) { 190 prompt_Printf(arg->prompt, "address redirect: invalid alias address\n"); 191 prompt_Printf(arg->prompt, "Usage: nat %s %s\n", arg->cmd->name, 192 arg->cmd->syntax); 193 return 1; 194 } 195 link = PacketAliasRedirectAddr(localaddr, aliasaddr); 196 if (link == NULL) { 197 prompt_Printf(arg->prompt, "address redirect: packet aliasing" 198 " engine error\n"); 199 prompt_Printf(arg->prompt, "Usage: nat %s %s\n", arg->cmd->name, 200 arg->cmd->syntax); 201 } 202 } else 203 return -1; 204 205 return 0; 206} 207 208 209static int 210StrToAddr(const char *str, struct in_addr *addr) 211{ 212 struct hostent *hp; 213 214 if (inet_aton(str, addr)) 215 return 0; 216 217 hp = gethostbyname(str); 218 if (!hp) { 219 log_Printf(LogWARN, "StrToAddr: Unknown host %s.\n", str); 220 return -1; 221 } 222 *addr = *((struct in_addr *) hp->h_addr); 223 return 0; 224} 225 226 227static int 228StrToPort(const char *str, u_short *port, const char *proto) 229{ 230 struct servent *sp; 231 char *end; 232 233 *port = strtol(str, &end, 10); 234 if (*end != '\0') { 235 sp = getservbyname(str, proto); 236 if (sp == NULL) { 237 log_Printf(LogWARN, "StrToAddr: Unknown port or service %s/%s.\n", 238 str, proto); 239 return -1; 240 } 241 *port = ntohs(sp->s_port); 242 } 243 244 return 0; 245} 246 247static int 248StrToPortRange(const char *str, u_short *low, u_short *high, const char *proto) 249{ 250 char *minus; 251 int res; 252 253 minus = strchr(str, '-'); 254 if (minus) 255 *minus = '\0'; /* Cheat the const-ness ! */ 256 257 res = StrToPort(str, low, proto); 258 259 if (minus) 260 *minus = '-'; /* Cheat the const-ness ! */ 261 262 if (res == 0) { 263 if (minus) 264 res = StrToPort(minus + 1, high, proto); 265 else 266 *high = *low; 267 } 268 269 return res; 270} 271 272static int 273StrToAddrAndPort(const char *str, struct in_addr *addr, u_short *low, 274 u_short *high, const char *proto) 275{ 276 char *colon; 277 int res; 278 279 colon = strchr(str, ':'); 280 if (!colon) { 281 log_Printf(LogWARN, "StrToAddrAndPort: %s is missing port number.\n", str); 282 return -1; 283 } 284 285 *colon = '\0'; /* Cheat the const-ness ! */ 286 res = StrToAddr(str, addr); 287 *colon = ':'; /* Cheat the const-ness ! */ 288 if (res != 0) 289 return -1; 290 291 return StrToPortRange(colon + 1, low, high, proto); 292} 293 294int 295nat_ProxyRule(struct cmdargs const *arg) 296{ 297 char cmd[LINE_LEN]; 298 int f, pos; 299 size_t len; 300 301 if (arg->argn >= arg->argc) 302 return -1; 303 304 for (f = arg->argn, pos = 0; f < arg->argc; f++) { 305 len = strlen(arg->argv[f]); 306 if (sizeof cmd - pos < len + (f ? 1 : 0)) 307 break; 308 if (f) 309 cmd[pos++] = ' '; 310 strcpy(cmd + pos, arg->argv[f]); 311 pos += len; 312 } 313 314 return PacketAliasProxyRule(cmd); 315} 316 317int 318nat_Pptp(struct cmdargs const *arg) 319{ 320 struct in_addr addr; 321 322 if (arg->argc == arg->argn) { 323 addr.s_addr = INADDR_NONE; 324 PacketAliasPptp(addr); 325 return 0; 326 } 327 328 if (arg->argc != arg->argn + 1) 329 return -1; 330 331 addr = GetIpAddr(arg->argv[arg->argn]); 332 if (addr.s_addr == INADDR_NONE) { 333 log_Printf(LogWARN, "%s: invalid address\n", arg->argv[arg->argn]); 334 return 1; 335 } 336 337 PacketAliasPptp(addr); 338 return 0; 339} 340 341static struct mbuf * 342nat_LayerPush(struct bundle *bundle, struct link *l, struct mbuf *bp, 343 int pri, u_short *proto) 344{ 345 if (!bundle->NatEnabled || *proto != PROTO_IP) 346 return bp; 347 348 log_Printf(LogDEBUG, "nat_LayerPush: PROTO_IP -> PROTO_IP\n"); 349 m_settype(bp, MB_NATOUT); 350 /* Ensure there's a bit of extra buffer for the NAT code... */ 351 bp = m_pullup(m_append(bp, NULL, NAT_EXTRABUF)); 352 PacketAliasOut(MBUF_CTOP(bp), bp->m_len); 353 bp->m_len = ntohs(((struct ip *)MBUF_CTOP(bp))->ip_len); 354 355 return bp; 356} 357 358static struct mbuf * 359nat_LayerPull(struct bundle *bundle, struct link *l, struct mbuf *bp, 360 u_short *proto) 361{ 362 struct ip *pip, *piip; 363 int ret, len; 364 struct mbuf **last; 365 char *fptr; 366 367 if (!bundle->NatEnabled || *proto != PROTO_IP) 368 return bp; 369 370 log_Printf(LogDEBUG, "nat_LayerPull: PROTO_IP -> PROTO_IP\n"); 371 m_settype(bp, MB_NATIN); 372 bp = m_pullup(bp); 373 pip = (struct ip *)MBUF_CTOP(bp); 374 piip = (struct ip *)((char *)pip + (pip->ip_hl << 2)); 375 376 if (pip->ip_p == IPPROTO_IGMP || 377 (pip->ip_p == IPPROTO_IPIP && IN_CLASSD(ntohl(piip->ip_dst.s_addr)))) 378 return bp; 379 380 /* Ensure there's a bit of extra buffer for the NAT code... */ 381 bp = m_pullup(m_append(bp, NULL, NAT_EXTRABUF)); 382 ret = PacketAliasIn(MBUF_CTOP(bp), bp->m_len); 383 384 bp->m_len = ntohs(pip->ip_len); 385 if (bp->m_len > MAX_MRU) { 386 log_Printf(LogWARN, "nat_LayerPull: Problem with IP header length (%lu)\n", 387 (unsigned long)bp->m_len); 388 m_freem(bp); 389 return NULL; 390 } 391 392 switch (ret) { 393 case PKT_ALIAS_OK: 394 break; 395 396 case PKT_ALIAS_UNRESOLVED_FRAGMENT: 397 /* Save the data for later */ 398 fptr = malloc(bp->m_len); 399 bp = mbuf_Read(bp, fptr, bp->m_len); 400 PacketAliasSaveFragment(fptr); 401 break; 402 403 case PKT_ALIAS_FOUND_HEADER_FRAGMENT: 404 /* Fetch all the saved fragments and chain them on the end of `bp' */ 405 last = &bp->m_nextpkt; 406 while ((fptr = PacketAliasGetFragment(MBUF_CTOP(bp))) != NULL) { 407 PacketAliasFragmentIn(MBUF_CTOP(bp), fptr); 408 len = ntohs(((struct ip *)fptr)->ip_len); 409 *last = m_get(len, MB_NATIN); 410 memcpy(MBUF_CTOP(*last), fptr, len); 411 free(fptr); 412 last = &(*last)->m_nextpkt; 413 } 414 break; 415 416 default: 417 m_freem(bp); 418 bp = NULL; 419 break; 420 } 421 422 return bp; 423} 424 425struct layer natlayer = 426 { LAYER_NAT, "nat", nat_LayerPush, nat_LayerPull }; 427