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