nat_cmd.c revision 47695
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.25 1999/05/12 09:48:39 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  mbuf_SetType(bp, type);
317  for (last = &bp, len = 0; *last != NULL; last = &(*last)->next)
318    len += (*last)->cnt;
319
320  len = MAX_MRU - len;
321  *last = mbuf_Alloc(len, type);
322
323  return bp;
324}
325
326static struct mbuf *
327alias_LayerPush(struct bundle *bundle, struct link *l, struct mbuf *bp,
328                int pri, u_short *proto)
329{
330  if (!bundle->AliasEnabled || *proto != PROTO_IP)
331    return bp;
332
333  log_Printf(LogDEBUG, "alias_LayerPush: PROTO_IP -> PROTO_IP\n");
334  bp = mbuf_Contiguous(alias_PadMbuf(bp, MB_ALIASOUT));
335  PacketAliasOut(MBUF_CTOP(bp), bp->cnt);
336  bp->cnt = ntohs(((struct ip *)MBUF_CTOP(bp))->ip_len);
337
338  return bp;
339}
340
341static struct mbuf *
342alias_LayerPull(struct bundle *bundle, struct link *l, struct mbuf *bp,
343                u_short *proto)
344{
345  struct ip *pip, *piip;
346  int ret;
347  struct mbuf **last;
348  char *fptr;
349
350  if (!bundle->AliasEnabled || *proto != PROTO_IP)
351    return bp;
352
353  log_Printf(LogDEBUG, "alias_LayerPull: PROTO_IP -> PROTO_IP\n");
354  bp = mbuf_Contiguous(alias_PadMbuf(bp, MB_ALIASIN));
355  pip = (struct ip *)MBUF_CTOP(bp);
356  piip = (struct ip *)((char *)pip + (pip->ip_hl << 2));
357
358  if (pip->ip_p == IPPROTO_IGMP ||
359      (pip->ip_p == IPPROTO_IPIP && IN_CLASSD(ntohl(piip->ip_dst.s_addr))))
360    return bp;
361
362  ret = PacketAliasIn(MBUF_CTOP(bp), bp->cnt);
363
364  bp->cnt = ntohs(pip->ip_len);
365  if (bp->cnt > MAX_MRU) {
366    log_Printf(LogWARN, "alias_LayerPull: Problem with IP header length\n");
367    mbuf_Free(bp);
368    return NULL;
369  }
370
371  switch (ret) {
372    case PKT_ALIAS_OK:
373      break;
374
375    case PKT_ALIAS_UNRESOLVED_FRAGMENT:
376      /* Save the data for later */
377      fptr = malloc(bp->cnt);
378      mbuf_Read(bp, fptr, bp->cnt);
379      PacketAliasSaveFragment(fptr);
380      break;
381
382    case PKT_ALIAS_FOUND_HEADER_FRAGMENT:
383      /* Fetch all the saved fragments and chain them on the end of `bp' */
384      last = &bp->pnext;
385      while ((fptr = PacketAliasGetFragment(MBUF_CTOP(bp))) != NULL) {
386	PacketAliasFragmentIn(MBUF_CTOP(bp), fptr);
387        *last = mbuf_Alloc(ntohs(((struct ip *)fptr)->ip_len), MB_ALIASIN);
388        memcpy(MBUF_CTOP(*last), fptr, (*last)->cnt);
389        free(fptr);
390        last = &(*last)->pnext;
391      }
392      break;
393
394    default:
395      mbuf_Free(bp);
396      bp = NULL;
397      break;
398  }
399
400  return bp;
401}
402
403struct layer aliaslayer =
404  { LAYER_ALIAS, "alias", alias_LayerPush, alias_LayerPull };
405