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