ip.c revision 35449
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.39 1998/03/13 01:36:09 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
438      if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
439	while ((fptr = VarPacketAliasGetFragment(tun.data)) != NULL) {
440	  VarPacketAliasFragmentIn(tun.data, fptr);
441	  nb = ntohs(((struct ip *) fptr)->ip_len);
442          frag = (struct tun_data *)
443	    ((char *)fptr - sizeof tun + sizeof tun.data);
444          nb += sizeof tun - sizeof tun.data;
445	  nw = write(tun_out, frag, nb);
446	  if (nw != nb) {
447            if (nw == -1)
448	      LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb,
449                        strerror(errno));
450            else
451	      LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
452          }
453	  free(frag);
454	}
455      }
456    } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) {
457      nb = ntohs(((struct ip *) tun.data)->ip_len);
458      nb += sizeof tun - sizeof tun.data;
459      frag = (struct tun_data *)malloc(nb);
460      if (frag == NULL)
461	LogPrintf(LogALERT, "IpInput: Cannot allocate memory for fragment\n");
462      else {
463        tun_fill_header(*frag, AF_INET);
464	memcpy(frag->data, tun.data, nb - sizeof tun + sizeof tun.data);
465	VarPacketAliasSaveFragment(frag->data);
466      }
467    }
468  } else
469#endif /* #ifndef NOALIAS */
470  {			/* no aliasing */
471    if (PacketCheck(tun.data, nb, FL_IN) < 0) {
472      pfree(bp);
473      return;
474    }
475    IpcpAddInOctets(nb);
476    nb += sizeof tun - sizeof tun.data;
477    nw = write(tun_out, &tun, nb);
478    if (nw != nb) {
479      if (nw == -1)
480	LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, strerror(errno));
481      else
482        LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
483    }
484  }
485  pfree(bp);
486
487  RestartIdleTimer();
488}
489
490static struct mqueue IpOutputQueues[PRI_FAST + 1];
491
492void
493IpEnqueue(int pri, char *ptr, int count)
494{
495  struct mbuf *bp;
496
497  bp = mballoc(count, MB_IPQ);
498  memcpy(MBUF_CTOP(bp), ptr, count);
499  Enqueue(&IpOutputQueues[pri], bp);
500}
501
502#if 0
503int
504IsIpEnqueued()
505{
506  struct mqueue *queue;
507  int exist = 0;
508
509  for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) {
510    if (queue->qlen > 0) {
511      exist = 1;
512      break;
513    }
514  }
515  return (exist);
516}
517#endif
518
519void
520IpStartOutput()
521{
522  struct mqueue *queue;
523  struct mbuf *bp;
524  int cnt;
525
526  if (IpcpFsm.state != ST_OPENED)
527    return;
528  for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) {
529    if (queue->top) {
530      bp = Dequeue(queue);
531      if (bp) {
532	cnt = plength(bp);
533	SendPppFrame(bp);
534	RestartIdleTimer();
535        IpcpAddOutOctets(cnt);
536	break;
537      }
538    }
539  }
540}
541