ip.c revision 31343
1/*
2 *		PPP IP Protocol Interface
3 *
4 *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5 *
6 *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7 *
8 * Redistribution and use in source and binary forms are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by the Internet Initiative Japan.  The name of the
14 * IIJ may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 *
20 * $Id: ip.c,v 1.31 1997/11/18 14:52:04 brian Exp $
21 *
22 *	TODO:
23 *		o Return ICMP message for filterd packet
24 *		  and optionaly record it into log.
25 */
26#include <sys/param.h>
27#include <sys/time.h>
28#include <sys/select.h>
29#include <sys/socket.h>
30#include <netinet/in.h>
31#include <netinet/in_systm.h>
32#include <netinet/ip.h>
33#include <netinet/ip_icmp.h>
34#include <netinet/udp.h>
35#include <netinet/tcp.h>
36#include <arpa/inet.h>
37#include <net/if.h>
38#ifdef __FreeBSD__
39#include <net/if_var.h>
40#endif
41#include <net/if_tun.h>
42
43#ifndef NOALIAS
44#include <alias.h>
45#endif
46#include <errno.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <string.h>
50#include <termios.h>
51#include <unistd.h>
52
53#include "command.h"
54#include "mbuf.h"
55#include "log.h"
56#include "defs.h"
57#include "timer.h"
58#include "fsm.h"
59#include "lcpproto.h"
60#include "hdlc.h"
61#include "loadalias.h"
62#include "vars.h"
63#include "filter.h"
64#include "os.h"
65#include "ipcp.h"
66#include "vjcomp.h"
67#include "lcp.h"
68#include "modem.h"
69#include "tun.h"
70#include "ip.h"
71
72static struct pppTimer IdleTimer;
73
74static void
75IdleTimeout(void *v)
76{
77  LogPrintf(LogPHASE, "Idle timer expired.\n");
78  reconnect(RECON_FALSE);
79  LcpClose();
80}
81
82/*
83 *  Start Idle timer. If timeout is reached, we call LcpClose() to
84 *  close LCP and link.
85 */
86void
87StartIdleTimer()
88{
89  if (!(mode & (MODE_DEDICATED | MODE_DDIAL))) {
90    StopTimer(&IdleTimer);
91    IdleTimer.func = IdleTimeout;
92    IdleTimer.load = VarIdleTimeout * SECTICKS;
93    IdleTimer.state = TIMER_STOPPED;
94    StartTimer(&IdleTimer);
95  }
96}
97
98void
99UpdateIdleTimer()
100{
101  if (OsLinkIsUp())
102    StartIdleTimer();
103}
104
105void
106StopIdleTimer()
107{
108  StopTimer(&IdleTimer);
109}
110
111/*
112 *  If any IP layer traffic is detected, refresh IdleTimer.
113 */
114static void
115RestartIdleTimer(void)
116{
117  if (!(mode & (MODE_DEDICATED | MODE_DDIAL)) && ipKeepAlive) {
118    StartTimer(&IdleTimer);
119    ipIdleSecs = 0;
120  }
121}
122
123static const u_short interactive_ports[32] = {
124  544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
125  0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543,
126};
127
128#define	INTERACTIVE(p)	(interactive_ports[(p) & 0x1F] == (p))
129
130static const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" };
131
132static const char *Direction[] = {"INP", "OUT", "OUT", "IN/OUT"};
133static struct filterent *Filters[] = {ifilters, ofilters, dfilters, afilters};
134
135static int
136PortMatch(int op, u_short pport, u_short rport)
137{
138  switch (op) {
139    case OP_EQ:
140    return (pport == rport);
141  case OP_GT:
142    return (pport > rport);
143  case OP_LT:
144    return (pport < rport);
145  default:
146    return (0);
147  }
148}
149
150/*
151 *  Check a packet against with defined filters
152 */
153static int
154FilterCheck(struct ip * pip, int direction)
155{
156  struct filterent *fp = Filters[direction];
157  int gotinfo, cproto, estab, n;
158  struct tcphdr *th;
159  struct udphdr *uh;
160  struct icmp *ih;
161  char *ptop;
162  u_short sport, dport;
163
164  if (fp->action) {
165    cproto = gotinfo = estab = 0;
166    sport = dport = 0;
167    for (n = 0; n < MAXFILTERS; n++) {
168      if (fp->action) {
169	/* permit fragments on in and out filter */
170	if ((direction == FL_IN || direction == FL_OUT) &&
171	    (ntohs(pip->ip_off) & IP_OFFMASK) != 0) {
172	  return (A_PERMIT);
173	}
174	LogPrintf(LogDEBUG, "rule = %d\n", n);
175	if ((pip->ip_src.s_addr & fp->smask.s_addr) ==
176	    (fp->saddr.s_addr & fp->smask.s_addr) &&
177	    (pip->ip_dst.s_addr & fp->dmask.s_addr) ==
178	    (fp->daddr.s_addr & fp->dmask.s_addr)) {
179	  if (fp->proto) {
180	    if (!gotinfo) {
181	      ptop = (char *) pip + (pip->ip_hl << 2);
182
183	      switch (pip->ip_p) {
184	      case IPPROTO_ICMP:
185		cproto = P_ICMP;
186		ih = (struct icmp *) ptop;
187		sport = ih->icmp_type;
188		estab = 1;
189		break;
190	      case IPPROTO_UDP:
191		cproto = P_UDP;
192		uh = (struct udphdr *) ptop;
193		sport = ntohs(uh->uh_sport);
194		dport = ntohs(uh->uh_dport);
195		estab = 1;
196		break;
197	      case IPPROTO_TCP:
198		cproto = P_TCP;
199		th = (struct tcphdr *) ptop;
200		sport = ntohs(th->th_sport);
201		dport = ntohs(th->th_dport);
202		estab = (th->th_flags & TH_ACK);
203		if (estab == 0)
204		  LogPrintf(LogDEBUG, "flag = %02x, sport = %d, dport = %d\n",
205			    th->th_flags, sport, dport);
206		break;
207	      default:
208		return (A_DENY);/* We'll block unknown type of packet */
209	      }
210	      gotinfo = 1;
211	      LogPrintf(LogDEBUG, "dir = %d, proto = %d, srcop = %d,"
212			" dstop = %d, estab = %d\n", direction, cproto,
213			fp->opt.srcop, fp->opt.dstop, estab);
214	    }
215	    LogPrintf(LogDEBUG, "check0: rule = %d, proto = %d, sport = %d,"
216		      " dport = %d\n", n, cproto, sport, dport);
217	    LogPrintf(LogDEBUG, "check0: action = %d\n", fp->action);
218
219	    if (cproto == fp->proto) {
220	      if ((fp->opt.srcop == OP_NONE ||
221		   PortMatch(fp->opt.srcop, sport, fp->opt.srcport))
222		  &&
223		  (fp->opt.dstop == OP_NONE ||
224		   PortMatch(fp->opt.dstop, dport, fp->opt.dstport))
225		  &&
226		  (fp->opt.estab == 0 || estab)) {
227		return (fp->action);
228	      }
229	    }
230	  } else {
231	    /* Address is mached. Make a decision. */
232	    LogPrintf(LogDEBUG, "check1: action = %d\n", fp->action);
233	    return (fp->action);
234	  }
235	}
236      }
237      fp++;
238    }
239    return (A_DENY);		/* No rule is mached. Deny this packet */
240  }
241  return (A_PERMIT);		/* No rule is given. Permit this packet */
242}
243
244static void
245IcmpError(struct ip * pip, int code)
246{
247#ifdef notdef
248  struct mbuf *bp;
249
250  if (pip->ip_p != IPPROTO_ICMP) {
251    bp = mballoc(cnt, MB_IPIN);
252    memcpy(MBUF_CTOP(bp), ptr, cnt);
253    SendPppFrame(bp);
254    RestartIdleTimer();
255    IpcpAddOutOctets(cnt);
256  }
257#endif
258}
259
260/*
261 *  For debugging aid.
262 */
263int
264PacketCheck(char *cp, int nb, int direction)
265{
266  struct ip *pip;
267  struct tcphdr *th;
268  struct udphdr *uh;
269  struct icmp *icmph;
270  char *ptop;
271  int mask, len, n;
272  int pri = PRI_NORMAL;
273  int logit, loglen;
274  static char logbuf[200];
275
276  logit = LogIsKept(LogTCPIP);
277  loglen = 0;
278
279  pip = (struct ip *) cp;
280
281  if (logit && loglen < sizeof logbuf) {
282    snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ",
283	     Direction[direction]);
284    loglen += strlen(logbuf + loglen);
285  }
286  ptop = (cp + (pip->ip_hl << 2));
287
288  switch (pip->ip_p) {
289  case IPPROTO_ICMP:
290    if (logit && loglen < sizeof logbuf) {
291      icmph = (struct icmp *) ptop;
292      snprintf(logbuf + loglen, sizeof logbuf - loglen,
293	     "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
294      loglen += strlen(logbuf + loglen);
295      snprintf(logbuf + loglen, sizeof logbuf - loglen,
296	       "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
297      loglen += strlen(logbuf + loglen);
298    }
299    break;
300  case IPPROTO_UDP:
301    if (logit && loglen < sizeof logbuf) {
302      uh = (struct udphdr *) ptop;
303      snprintf(logbuf + loglen, sizeof logbuf - loglen,
304	   "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
305      loglen += strlen(logbuf + loglen);
306      snprintf(logbuf + loglen, sizeof logbuf - loglen,
307	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
308      loglen += strlen(logbuf + loglen);
309    }
310    break;
311  case IPPROTO_TCP:
312    th = (struct tcphdr *) ptop;
313    if (pip->ip_tos == IPTOS_LOWDELAY)
314      pri = PRI_FAST;
315    else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
316      if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
317	pri = PRI_FAST;
318    }
319    if (logit && loglen < sizeof logbuf) {
320      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
321      snprintf(logbuf + loglen, sizeof logbuf - loglen,
322	   "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
323      loglen += strlen(logbuf + loglen);
324      snprintf(logbuf + loglen, sizeof logbuf - loglen,
325	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
326      loglen += strlen(logbuf + loglen);
327      n = 0;
328      for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
329	if (th->th_flags & mask) {
330	  snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
331	  loglen += strlen(logbuf + loglen);
332	}
333	n++;
334      }
335      snprintf(logbuf + loglen, sizeof logbuf - loglen,
336	       "  seq:%x  ack:%x (%d/%d)",
337	       ntohl(th->th_seq), ntohl(th->th_ack), len, nb);
338      loglen += strlen(logbuf + loglen);
339      if ((th->th_flags & TH_SYN) && nb > 40) {
340	u_short *sp;
341
342	ptop += 20;
343	sp = (u_short *) ptop;
344	if (ntohs(sp[0]) == 0x0204) {
345	  snprintf(logbuf + loglen, sizeof logbuf - loglen,
346		   " MSS = %d", ntohs(sp[1]));
347	  loglen += strlen(logbuf + loglen);
348	}
349      }
350    }
351    break;
352  }
353
354  if ((FilterCheck(pip, direction) & A_DENY)) {
355    if (logit)
356      LogPrintf(LogTCPIP, "%s - BLOCKED\n", logbuf);
357    if (direction == 0)
358      IcmpError(pip, pri);
359    return (-1);
360  } else {
361    if (FilterCheck(pip, FL_KEEP) & A_DENY) {	/* Check Keep Alive filter */
362      if (logit)
363        LogPrintf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
364      ipKeepAlive = 0;
365    } else {
366      if (logit)
367        LogPrintf(LogTCPIP, "%s\n", logbuf);
368      ipKeepAlive = 1;
369    }
370    return (pri);
371  }
372}
373
374void
375IpInput(struct mbuf * bp)
376{				/* IN: Pointer to IP pakcet */
377  u_char *cp;
378  struct mbuf *wp;
379  int nb, nw;
380  struct tun_data tun;
381
382  tun_fill_header(tun, AF_INET);
383  cp = tun.data;
384  nb = 0;
385  for (wp = bp; wp; wp = wp->next) {	/* Copy to contiguous region */
386    memcpy(cp, MBUF_CTOP(wp), wp->cnt);
387    cp += wp->cnt;
388    nb += wp->cnt;
389  }
390
391#ifndef NOALIAS
392  if (mode & MODE_ALIAS) {
393    struct tun_data *frag;
394    int iresult;
395    char *fptr;
396
397    iresult = VarPacketAliasIn(tun.data, sizeof tun.data);
398    nb = ntohs(((struct ip *) tun.data)->ip_len);
399
400    if (nb > MAX_MRU) {
401      LogPrintf(LogERROR, "IpInput: Problem with IP header length\n");
402      pfree(bp);
403      return;
404    }
405    if (iresult == PKT_ALIAS_OK
406	|| iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
407      if (PacketCheck(tun.data, nb, FL_IN) < 0) {
408	pfree(bp);
409	return;
410      }
411      IpcpAddInOctets(nb);
412
413      nb = ntohs(((struct ip *) tun.data)->ip_len);
414      nb += sizeof(tun)-sizeof(tun.data);
415      nw = write(tun_out, &tun, nb);
416      if (nw != nb)
417        if (nw == -1)
418	  LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb,
419                    strerror(errno));
420        else
421	  LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
422
423      if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
424	while ((fptr = VarPacketAliasGetFragment(tun.data)) != NULL) {
425	  VarPacketAliasFragmentIn(tun.data, fptr);
426	  nb = ntohs(((struct ip *) fptr)->ip_len);
427          frag = (struct tun_data *)((char *)fptr-sizeof(tun)+sizeof(tun.data));
428          nb += sizeof(tun)-sizeof(tun.data);
429	  nw = write(tun_out, frag, nb);
430	  if (nw != nb)
431            if (nw == -1)
432	      LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb,
433                        strerror(errno));
434            else
435	      LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
436	  free(frag);
437	}
438      }
439    } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) {
440      nb = ntohs(((struct ip *) tun.data)->ip_len);
441      nb += sizeof(tun)-sizeof(tun.data);
442      frag = (struct tun_data *)malloc(nb);
443      if (frag == NULL)
444	LogPrintf(LogALERT, "IpInput: Cannot allocate memory for fragment\n");
445      else {
446        tun_fill_header(*frag, AF_INET);
447	memcpy(frag->data, tun.data, nb-sizeof(tun)+sizeof(tun.data));
448	VarPacketAliasSaveFragment(frag->data);
449      }
450    }
451  } else
452#endif /* #ifndef NOALIAS */
453  {			/* no aliasing */
454    if (PacketCheck(tun.data, nb, FL_IN) < 0) {
455      pfree(bp);
456      return;
457    }
458    IpcpAddInOctets(nb);
459    nb += sizeof(tun)-sizeof(tun.data);
460    nw = write(tun_out, &tun, nb);
461    if (nw != nb)
462      if (nw == -1)
463	LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, strerror(errno));
464      else
465        LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
466  }
467  pfree(bp);
468
469  RestartIdleTimer();
470}
471
472static struct mqueue IpOutputQueues[PRI_FAST + 1];
473
474void
475IpEnqueue(int pri, char *ptr, int count)
476{
477  struct mbuf *bp;
478
479  bp = mballoc(count, MB_IPQ);
480  memcpy(MBUF_CTOP(bp), ptr, count);
481  Enqueue(&IpOutputQueues[pri], bp);
482}
483
484#if 0
485int
486IsIpEnqueued()
487{
488  struct mqueue *queue;
489  int exist = 0;
490
491  for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) {
492    if (queue->qlen > 0) {
493      exist = 1;
494      break;
495    }
496  }
497  return (exist);
498}
499#endif
500
501void
502IpStartOutput()
503{
504  struct mqueue *queue;
505  struct mbuf *bp;
506  int cnt;
507
508  if (IpcpFsm.state != ST_OPENED)
509    return;
510  for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) {
511    if (queue->top) {
512      bp = Dequeue(queue);
513      if (bp) {
514	cnt = plength(bp);
515	SendPppFrame(bp);
516	RestartIdleTimer();
517        IpcpAddOutOctets(cnt);
518	break;
519      }
520    }
521  }
522}
523