nat_cmd.c revision 47061
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 * $Id: alias_cmd.c,v 1.24 1999/05/08 11:05:59 brian Exp $ 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 __FreeBSD__ 23#include <alias.h> 24#else 25#include "alias.h" 26#endif 27#include "layer.h" 28#include "proto.h" 29#include "defs.h" 30#include "command.h" 31#include "log.h" 32#include "alias_cmd.h" 33#include "descriptor.h" 34#include "prompt.h" 35#include "timer.h" 36#include "fsm.h" 37#include "slcompress.h" 38#include "throughput.h" 39#include "iplist.h" 40#include "mbuf.h" 41#include "lqr.h" 42#include "hdlc.h" 43#include "ipcp.h" 44#include "lcp.h" 45#include "ccp.h" 46#include "link.h" 47#include "mp.h" 48#include "filter.h" 49#ifndef NORADIUS 50#include "radius.h" 51#endif 52#include "bundle.h" 53 54 55static int StrToAddr(const char *, struct in_addr *); 56static int StrToPortRange(const char *, u_short *, u_short *, const char *); 57static int StrToAddrAndPort(const char *, struct in_addr *, u_short *, 58 u_short *, const char *); 59 60 61int 62alias_RedirectPort(struct cmdargs const *arg) 63{ 64 if (!arg->bundle->AliasEnabled) { 65 prompt_Printf(arg->prompt, "Alias not enabled\n"); 66 return 1; 67 } else if (arg->argc == arg->argn + 3) { 68 char proto_constant; 69 const char *proto; 70 u_short hlocalport; 71 u_short llocalport; 72 u_short haliasport; 73 u_short laliasport; 74 u_short port; 75 int error; 76 struct in_addr local_addr; 77 struct in_addr null_addr; 78 struct alias_link *link; 79 80 proto = arg->argv[arg->argn]; 81 if (strcmp(proto, "tcp") == 0) { 82 proto_constant = IPPROTO_TCP; 83 } else if (strcmp(proto, "udp") == 0) { 84 proto_constant = IPPROTO_UDP; 85 } else { 86 prompt_Printf(arg->prompt, "port redirect: protocol must be" 87 " tcp or udp\n"); 88 return -1; 89 } 90 91 error = StrToAddrAndPort(arg->argv[arg->argn+1], &local_addr, &llocalport, 92 &hlocalport, proto); 93 if (error) { 94 prompt_Printf(arg->prompt, "alias port: error reading localaddr:port\n"); 95 return -1; 96 } 97 error = StrToPortRange(arg->argv[arg->argn+2], &laliasport, &haliasport, 98 proto); 99 if (error) { 100 prompt_Printf(arg->prompt, "alias port: error reading alias port\n"); 101 return -1; 102 } 103 null_addr.s_addr = INADDR_ANY; 104 105 if (llocalport > hlocalport) { 106 port = llocalport; 107 llocalport = hlocalport; 108 hlocalport = port; 109 } 110 111 if (laliasport > haliasport) { 112 port = laliasport; 113 laliasport = haliasport; 114 haliasport = port; 115 } 116 117 if (haliasport - laliasport != hlocalport - llocalport) { 118 prompt_Printf(arg->prompt, "alias port: Port ranges must be equal\n"); 119 return -1; 120 } 121 122 for (port = laliasport; port <= haliasport; port++) { 123 link = PacketAliasRedirectPort(local_addr, 124 htons(llocalport + (port - laliasport)), 125 null_addr, 0, null_addr, htons(port), 126 proto_constant); 127 128 if (link == NULL) { 129 prompt_Printf(arg->prompt, "alias port: %d: error %d\n", port, error); 130 return 1; 131 } 132 } 133 } else 134 return -1; 135 136 return 0; 137} 138 139 140int 141alias_RedirectAddr(struct cmdargs const *arg) 142{ 143 if (!arg->bundle->AliasEnabled) { 144 prompt_Printf(arg->prompt, "alias not enabled\n"); 145 return 1; 146 } else if (arg->argc == arg->argn+2) { 147 int error; 148 struct in_addr local_addr; 149 struct in_addr alias_addr; 150 struct alias_link *link; 151 152 error = StrToAddr(arg->argv[arg->argn], &local_addr); 153 if (error) { 154 prompt_Printf(arg->prompt, "address redirect: invalid local address\n"); 155 return 1; 156 } 157 error = StrToAddr(arg->argv[arg->argn+1], &alias_addr); 158 if (error) { 159 prompt_Printf(arg->prompt, "address redirect: invalid alias address\n"); 160 prompt_Printf(arg->prompt, "Usage: alias %s %s\n", arg->cmd->name, 161 arg->cmd->syntax); 162 return 1; 163 } 164 link = PacketAliasRedirectAddr(local_addr, alias_addr); 165 if (link == NULL) { 166 prompt_Printf(arg->prompt, "address redirect: packet aliasing" 167 " engine error\n"); 168 prompt_Printf(arg->prompt, "Usage: alias %s %s\n", arg->cmd->name, 169 arg->cmd->syntax); 170 } 171 } else 172 return -1; 173 174 return 0; 175} 176 177 178static int 179StrToAddr(const char *str, struct in_addr *addr) 180{ 181 struct hostent *hp; 182 183 if (inet_aton(str, addr)) 184 return 0; 185 186 hp = gethostbyname(str); 187 if (!hp) { 188 log_Printf(LogWARN, "StrToAddr: Unknown host %s.\n", str); 189 return -1; 190 } 191 *addr = *((struct in_addr *) hp->h_addr); 192 return 0; 193} 194 195 196static int 197StrToPort(const char *str, u_short *port, const char *proto) 198{ 199 struct servent *sp; 200 char *end; 201 202 *port = strtol(str, &end, 10); 203 if (*end != '\0') { 204 sp = getservbyname(str, proto); 205 if (sp == NULL) { 206 log_Printf(LogWARN, "StrToAddr: Unknown port or service %s/%s.\n", 207 str, proto); 208 return -1; 209 } 210 *port = ntohs(sp->s_port); 211 } 212 213 return 0; 214} 215 216static int 217StrToPortRange(const char *str, u_short *low, u_short *high, const char *proto) 218{ 219 char *minus; 220 int res; 221 222 minus = strchr(str, '-'); 223 if (minus) 224 *minus = '\0'; /* Cheat the const-ness ! */ 225 226 res = StrToPort(str, low, proto); 227 228 if (minus) 229 *minus = '-'; /* Cheat the const-ness ! */ 230 231 if (res == 0) { 232 if (minus) 233 res = StrToPort(minus + 1, high, proto); 234 else 235 *high = *low; 236 } 237 238 return res; 239} 240 241static int 242StrToAddrAndPort(const char *str, struct in_addr *addr, u_short *low, 243 u_short *high, const char *proto) 244{ 245 char *colon; 246 int res; 247 248 colon = strchr(str, ':'); 249 if (!colon) { 250 log_Printf(LogWARN, "StrToAddrAndPort: %s is missing port number.\n", str); 251 return -1; 252 } 253 254 *colon = '\0'; /* Cheat the const-ness ! */ 255 res = StrToAddr(str, addr); 256 *colon = ':'; /* Cheat the const-ness ! */ 257 if (res != 0) 258 return -1; 259 260 return StrToPortRange(colon + 1, low, high, proto); 261} 262 263int 264alias_ProxyRule(struct cmdargs const *arg) 265{ 266 char cmd[LINE_LEN]; 267 int f, pos; 268 size_t len; 269 270 if (arg->argn >= arg->argc) 271 return -1; 272 273 for (f = arg->argn, pos = 0; f < arg->argc; f++) { 274 len = strlen(arg->argv[f]); 275 if (sizeof cmd - pos < len + (f ? 1 : 0)) 276 break; 277 if (f) 278 cmd[pos++] = ' '; 279 strcpy(cmd + pos, arg->argv[f]); 280 pos += len; 281 } 282 283 return PacketAliasProxyRule(cmd); 284} 285 286int 287alias_Pptp(struct cmdargs const *arg) 288{ 289 struct in_addr addr; 290 291 if (arg->argc == arg->argn) { 292 addr.s_addr = INADDR_NONE; 293 PacketAliasPptp(addr); 294 return 0; 295 } 296 297 if (arg->argc != arg->argn + 1) 298 return -1; 299 300 addr = GetIpAddr(arg->argv[arg->argn]); 301 if (addr.s_addr == INADDR_NONE) { 302 log_Printf(LogWARN, "%s: invalid address\n", arg->argv[arg->argn]); 303 return 1; 304 } 305 306 PacketAliasPptp(addr); 307 return 0; 308} 309 310static struct mbuf * 311alias_PadMbuf(struct mbuf *bp, int type) 312{ 313 struct mbuf **last; 314 int len; 315 316 for (last = &bp, len = 0; *last != NULL; last = &(*last)->next) 317 len += (*last)->cnt; 318 319 len = MAX_MRU - len; 320 *last = mbuf_Alloc(len, type); 321 322 return bp; 323} 324 325static struct mbuf * 326alias_LayerPush(struct bundle *bundle, struct link *l, struct mbuf *bp, 327 int pri, u_short *proto) 328{ 329 if (!bundle->AliasEnabled || *proto != PROTO_IP) 330 return bp; 331 332 log_Printf(LogDEBUG, "alias_LayerPush: PROTO_IP -> PROTO_IP\n"); 333 bp = mbuf_Contiguous(alias_PadMbuf(bp, MB_IPQ)); 334 PacketAliasOut(MBUF_CTOP(bp), bp->cnt); 335 bp->cnt = ntohs(((struct ip *)MBUF_CTOP(bp))->ip_len); 336 337 return bp; 338} 339 340static struct mbuf * 341alias_LayerPull(struct bundle *bundle, struct link *l, struct mbuf *bp, 342 u_short *proto) 343{ 344 struct ip *pip, *piip; 345 int ret; 346 struct mbuf **last; 347 char *fptr; 348 349 if (!bundle->AliasEnabled || *proto != PROTO_IP) 350 return bp; 351 352 log_Printf(LogDEBUG, "alias_LayerPull: PROTO_IP -> PROTO_IP\n"); 353 bp = mbuf_Contiguous(alias_PadMbuf(bp, MB_IPIN)); 354 pip = (struct ip *)MBUF_CTOP(bp); 355 piip = (struct ip *)((char *)pip + (pip->ip_hl << 2)); 356 357 if (pip->ip_p == IPPROTO_IGMP || 358 (pip->ip_p == IPPROTO_IPIP && IN_CLASSD(ntohl(piip->ip_dst.s_addr)))) 359 return bp; 360 361 ret = PacketAliasIn(MBUF_CTOP(bp), bp->cnt); 362 363 bp->cnt = ntohs(pip->ip_len); 364 if (bp->cnt > MAX_MRU) { 365 log_Printf(LogWARN, "alias_LayerPull: Problem with IP header length\n"); 366 mbuf_Free(bp); 367 return NULL; 368 } 369 370 switch (ret) { 371 case PKT_ALIAS_OK: 372 break; 373 374 case PKT_ALIAS_UNRESOLVED_FRAGMENT: 375 /* Save the data for later */ 376 fptr = malloc(bp->cnt); 377 mbuf_Read(bp, fptr, bp->cnt); 378 PacketAliasSaveFragment(fptr); 379 break; 380 381 case PKT_ALIAS_FOUND_HEADER_FRAGMENT: 382 /* Fetch all the saved fragments and chain them on the end of `bp' */ 383 last = &bp->pnext; 384 while ((fptr = PacketAliasGetFragment(MBUF_CTOP(bp))) != NULL) { 385 PacketAliasFragmentIn(MBUF_CTOP(bp), fptr); 386 *last = mbuf_Alloc(ntohs(((struct ip *)fptr)->ip_len), MB_IPIN); 387 memcpy(MBUF_CTOP(*last), fptr, (*last)->cnt); 388 free(fptr); 389 last = &(*last)->pnext; 390 } 391 break; 392 393 default: 394 mbuf_Free(bp); 395 bp = NULL; 396 break; 397 } 398 399 return bp; 400} 401 402struct layer aliaslayer = 403 { LAYER_ALIAS, "alias", alias_LayerPush, alias_LayerPull }; 404