ip.c revision 37210
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.47 1998/06/27 14:18:05 brian Exp $
21 *
22 *	TODO:
23 *		o Return ICMP message for filterd packet
24 *		  and optionaly record it into log.
25 */
26#include <sys/types.h>
27#include <sys/socket.h>
28#include <netinet/in.h>
29#include <netinet/in_systm.h>
30#include <netinet/ip.h>
31#include <netinet/ip_icmp.h>
32#include <netinet/udp.h>
33#include <netinet/tcp.h>
34#include <arpa/inet.h>
35#include <sys/un.h>
36
37#ifndef NOALIAS
38#include <alias.h>
39#endif
40#include <errno.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44#include <unistd.h>
45
46#include "mbuf.h"
47#include "log.h"
48#include "defs.h"
49#include "timer.h"
50#include "fsm.h"
51#include "lqr.h"
52#include "hdlc.h"
53#include "throughput.h"
54#include "iplist.h"
55#include "slcompress.h"
56#include "ipcp.h"
57#include "filter.h"
58#include "descriptor.h"
59#include "lcp.h"
60#include "ccp.h"
61#include "link.h"
62#include "mp.h"
63#include "bundle.h"
64#include "vjcomp.h"
65#include "tun.h"
66#include "ip.h"
67
68static const u_short interactive_ports[32] = {
69  544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
70  0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543,
71};
72
73#define	INTERACTIVE(p)	(interactive_ports[(p) & 0x1F] == (p))
74
75static const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" };
76
77static int
78PortMatch(int op, u_short pport, u_short rport)
79{
80  switch (op) {
81    case OP_EQ:
82    return (pport == rport);
83  case OP_GT:
84    return (pport > rport);
85  case OP_LT:
86    return (pport < rport);
87  default:
88    return (0);
89  }
90}
91
92/*
93 *  Check a packet against with defined filters
94 */
95static int
96FilterCheck(struct ip *pip, struct filter *filter)
97{
98  int gotinfo, cproto, estab, syn, finrst, n, len, didname;
99  struct tcphdr *th;
100  struct udphdr *uh;
101  struct icmp *ih;
102  char *ptop;
103  u_short sport, dport;
104  struct filterent *fp = filter->rule;
105  char dbuff[100];
106
107  if (fp->action) {
108    cproto = gotinfo = estab = syn = finrst = didname = 0;
109    sport = dport = 0;
110    for (n = 0; n < MAXFILTERS; n++) {
111      if (fp->action) {
112	/* permit fragments on in and out filter */
113        if (filter->fragok && (ntohs(pip->ip_off) & IP_OFFMASK) != 0)
114	  return (A_PERMIT);
115
116        if (!didname)
117          log_Printf(LogDEBUG, "%s filter:\n", filter->name);
118        didname = 1;
119
120	if ((pip->ip_src.s_addr & fp->smask.s_addr) ==
121	    (fp->saddr.s_addr & fp->smask.s_addr) &&
122	    (pip->ip_dst.s_addr & fp->dmask.s_addr) ==
123	    (fp->daddr.s_addr & fp->dmask.s_addr)) {
124	  if (fp->proto) {
125	    if (!gotinfo) {
126	      ptop = (char *) pip + (pip->ip_hl << 2);
127
128	      switch (pip->ip_p) {
129	      case IPPROTO_ICMP:
130		cproto = P_ICMP;
131		ih = (struct icmp *) ptop;
132		sport = ih->icmp_type;
133		estab = syn = finrst = -1;
134                if (log_IsKept(LogDEBUG))
135		  snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
136		break;
137	      case IPPROTO_UDP:
138	      case IPPROTO_IGMP:
139	      case IPPROTO_IPIP:
140		cproto = P_UDP;
141		uh = (struct udphdr *) ptop;
142		sport = ntohs(uh->uh_sport);
143		dport = ntohs(uh->uh_dport);
144		estab = syn = finrst = -1;
145                if (log_IsKept(LogDEBUG))
146		  snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
147                           sport, dport);
148		break;
149	      case IPPROTO_TCP:
150		cproto = P_TCP;
151		th = (struct tcphdr *) ptop;
152		sport = ntohs(th->th_sport);
153		dport = ntohs(th->th_dport);
154		estab = (th->th_flags & TH_ACK);
155		syn = (th->th_flags & TH_SYN);
156		finrst = (th->th_flags & (TH_FIN|TH_RST));
157                if (log_IsKept(LogDEBUG) && !estab)
158		  snprintf(dbuff, sizeof dbuff,
159                           "flags = %02x, sport = %d, dport = %d",
160                           th->th_flags, sport, dport);
161		break;
162	      default:
163		return (A_DENY);       /* We'll block unknown type of packet */
164	      }
165              if (log_IsKept(LogDEBUG)) {
166                if (estab != -1) {
167                  len = strlen(dbuff);
168                  snprintf(dbuff + len, sizeof dbuff - len,
169                           ", estab = %d, syn = %d, finrst = %d",
170                           estab, syn, finrst);
171                }
172	        log_Printf(LogDEBUG, " Filter: proto = %s, %s\n",
173                          filter_Proto2Nam(cproto), dbuff);
174              }
175	      gotinfo = 1;
176	    }
177            if (log_IsKept(LogDEBUG)) {
178	      if (fp->opt.srcop != OP_NONE) {
179                snprintf(dbuff, sizeof dbuff, ", src %s %d",
180                         filter_Op2Nam(fp->opt.srcop), fp->opt.srcport);
181                len = strlen(dbuff);
182              } else
183                len = 0;
184	      if (fp->opt.dstop != OP_NONE) {
185                snprintf(dbuff + len, sizeof dbuff - len,
186                         ", dst %s %d", filter_Op2Nam(fp->opt.dstop),
187                         fp->opt.dstport);
188              } else if (!len)
189                *dbuff = '\0';
190
191	      log_Printf(LogDEBUG, "  rule = %d: Address match, "
192                        "check against proto %s%s, action = %s\n",
193                        n, filter_Proto2Nam(fp->proto),
194                        dbuff, filter_Action2Nam(fp->action));
195            }
196
197	    if (cproto == fp->proto) {
198	      if ((fp->opt.srcop == OP_NONE ||
199		   PortMatch(fp->opt.srcop, sport, fp->opt.srcport)) &&
200		  (fp->opt.dstop == OP_NONE ||
201		   PortMatch(fp->opt.dstop, dport, fp->opt.dstport)) &&
202		  (fp->opt.estab == 0 || estab) &&
203		  (fp->opt.syn == 0 || syn) &&
204		  (fp->opt.finrst == 0 || finrst)) {
205		return (fp->action);
206	      }
207	    }
208	  } else {
209	    /* Address is mached. Make a decision. */
210	    log_Printf(LogDEBUG, "  rule = %d: Address match, action = %s\n", n,
211                      filter_Action2Nam(fp->action));
212	    return (fp->action);
213	  }
214	} else
215	  log_Printf(LogDEBUG, "  rule = %d: Address mismatch\n", n);
216      }
217      fp++;
218    }
219    return (A_DENY);		/* No rule is mached. Deny this packet */
220  }
221  return (A_PERMIT);		/* No rule is given. Permit this packet */
222}
223
224#ifdef notdef
225static void
226IcmpError(struct ip * pip, int code)
227{
228  struct mbuf *bp;
229
230  if (pip->ip_p != IPPROTO_ICMP) {
231    bp = mbuf_Alloc(cnt, MB_IPIN);
232    memcpy(MBUF_CTOP(bp), ptr, cnt);
233    vj_SendFrame(bp);
234    ipcp_AddOutOctets(cnt);
235  }
236}
237#endif
238
239/*
240 *  For debugging aid.
241 */
242int
243PacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter)
244{
245  struct ip *pip;
246  struct tcphdr *th;
247  struct udphdr *uh;
248  struct icmp *icmph;
249  char *ptop;
250  int mask, len, n;
251  int pri = PRI_NORMAL;
252  int logit, loglen;
253  char logbuf[200];
254
255  logit = log_IsKept(LogTCPIP) && filter->logok;
256  loglen = 0;
257
258  pip = (struct ip *) cp;
259
260  if (logit && loglen < sizeof logbuf) {
261    snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
262    loglen += strlen(logbuf + loglen);
263  }
264  ptop = (cp + (pip->ip_hl << 2));
265
266  switch (pip->ip_p) {
267  case IPPROTO_ICMP:
268    if (logit && loglen < sizeof logbuf) {
269      icmph = (struct icmp *) ptop;
270      snprintf(logbuf + loglen, sizeof logbuf - loglen,
271	     "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
272      loglen += strlen(logbuf + loglen);
273      snprintf(logbuf + loglen, sizeof logbuf - loglen,
274	       "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
275      loglen += strlen(logbuf + loglen);
276    }
277    break;
278  case IPPROTO_UDP:
279    if (logit && loglen < sizeof logbuf) {
280      uh = (struct udphdr *) ptop;
281      snprintf(logbuf + loglen, sizeof logbuf - loglen,
282	   "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
283      loglen += strlen(logbuf + loglen);
284      snprintf(logbuf + loglen, sizeof logbuf - loglen,
285	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
286      loglen += strlen(logbuf + loglen);
287    }
288    break;
289  case IPPROTO_IPIP:
290    if (logit && loglen < sizeof logbuf) {
291      uh = (struct udphdr *) ptop;
292      snprintf(logbuf + loglen, sizeof logbuf - loglen,
293	   "IPIP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
294      loglen += strlen(logbuf + loglen);
295      snprintf(logbuf + loglen, sizeof logbuf - loglen,
296	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
297      loglen += strlen(logbuf + loglen);
298    }
299    break;
300  case IPPROTO_IGMP:
301    if (logit && loglen < sizeof logbuf) {
302      uh = (struct udphdr *) ptop;
303      snprintf(logbuf + loglen, sizeof logbuf - loglen,
304	   "IGMP: %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:%lx  ack:%lx (%d/%d)",
337	       (u_long)ntohl(th->th_seq), (u_long)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, filter) & A_DENY)) {
355    if (logit)
356      log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf);
357#ifdef notdef
358    if (direction == 0)
359      IcmpError(pip, pri);
360#endif
361    return (-1);
362  } else {
363    /* Check Keep Alive filter */
364    if (logit) {
365      if (FilterCheck(pip, &bundle->filter.alive) & A_DENY)
366        log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
367      else
368        log_Printf(LogTCPIP, "%s\n", logbuf);
369    }
370    return (pri);
371  }
372}
373
374void
375ip_Input(struct bundle *bundle, struct mbuf * bp)
376{
377  u_char *cp;
378  struct mbuf *wp;
379  int nb, nw;
380  struct tun_data tun;
381  struct ip *pip = (struct ip *)tun.data;
382#ifndef NOALIAS
383  struct ip *piip = (struct ip *)((char *)pip + (pip->ip_hl << 2));
384#endif
385
386  tun_fill_header(tun, AF_INET);
387  cp = tun.data;
388  nb = 0;
389  for (wp = bp; wp; wp = wp->next) {	/* Copy to contiguous region */
390    if (sizeof tun.data - (cp - tun.data) < wp->cnt) {
391      log_Printf(LogWARN, "ip_Input: Packet too large (%d) - dropped\n",
392                mbuf_Length(bp));
393      mbuf_Free(bp);
394      return;
395    }
396    memcpy(cp, MBUF_CTOP(wp), wp->cnt);
397    cp += wp->cnt;
398    nb += wp->cnt;
399  }
400
401#ifndef NOALIAS
402  if (bundle->AliasEnabled && pip->ip_p != IPPROTO_IGMP &&
403      (pip->ip_p != IPPROTO_IPIP || !IN_CLASSD(ntohl(piip->ip_dst.s_addr)))) {
404    struct tun_data *frag;
405    int iresult;
406    char *fptr;
407
408    iresult = PacketAliasIn(tun.data, sizeof tun.data);
409    nb = ntohs(((struct ip *) tun.data)->ip_len);
410
411    if (nb > MAX_MRU) {
412      log_Printf(LogWARN, "ip_Input: Problem with IP header length\n");
413      mbuf_Free(bp);
414      return;
415    }
416    if (iresult == PKT_ALIAS_OK
417	|| iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
418      if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0) {
419	mbuf_Free(bp);
420	return;
421      }
422
423      if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY))
424        bundle_StartIdleTimer(bundle);
425
426      ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
427
428      nb = ntohs(((struct ip *) tun.data)->ip_len);
429      nb += sizeof tun - sizeof tun.data;
430      nw = write(bundle->dev.fd, &tun, nb);
431      if (nw != nb) {
432        if (nw == -1)
433	  log_Printf(LogERROR, "ip_Input: wrote %d, got %s\n", nb,
434                    strerror(errno));
435        else
436	  log_Printf(LogERROR, "ip_Input: wrote %d, got %d\n", nb, nw);
437      }
438
439      if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
440	while ((fptr = PacketAliasGetFragment(tun.data)) != NULL) {
441	  PacketAliasFragmentIn(tun.data, fptr);
442	  nb = ntohs(((struct ip *) fptr)->ip_len);
443          frag = (struct tun_data *)
444	    ((char *)fptr - sizeof tun + sizeof tun.data);
445          nb += sizeof tun - sizeof tun.data;
446	  nw = write(bundle->dev.fd, frag, nb);
447	  if (nw != nb) {
448            if (nw == -1)
449	      log_Printf(LogERROR, "ip_Input: wrote %d, got %s\n", nb,
450                        strerror(errno));
451            else
452	      log_Printf(LogERROR, "ip_Input: wrote %d, got %d\n", nb, nw);
453          }
454	  free(frag);
455	}
456      }
457    } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) {
458      nb = ntohs(((struct ip *) tun.data)->ip_len);
459      nb += sizeof tun - sizeof tun.data;
460      frag = (struct tun_data *)malloc(nb);
461      if (frag == NULL)
462	log_Printf(LogALERT, "ip_Input: Cannot allocate memory for fragment\n");
463      else {
464        tun_fill_header(*frag, AF_INET);
465	memcpy(frag->data, tun.data, nb - sizeof tun + sizeof tun.data);
466	PacketAliasSaveFragment(frag->data);
467      }
468    }
469  } else
470#endif /* #ifndef NOALIAS */
471  {			/* no aliasing */
472    if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0) {
473      mbuf_Free(bp);
474      return;
475    }
476
477    if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY))
478      bundle_StartIdleTimer(bundle);
479
480    ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
481
482    nb += sizeof tun - sizeof tun.data;
483    nw = write(bundle->dev.fd, &tun, nb);
484    if (nw != nb) {
485      if (nw == -1)
486	log_Printf(LogERROR, "ip_Input: wrote %d, got %s\n", nb, strerror(errno));
487      else
488        log_Printf(LogERROR, "ip_Input: wrote %d, got %d\n", nb, nw);
489    }
490  }
491  mbuf_Free(bp);
492}
493
494static struct mqueue IpOutputQueues[PRI_FAST + 1];
495
496void
497ip_Enqueue(int pri, char *ptr, int count)
498{
499  struct mbuf *bp;
500
501  bp = mbuf_Alloc(count, MB_IPQ);
502  memcpy(MBUF_CTOP(bp), ptr, count);
503  mbuf_Enqueue(&IpOutputQueues[pri], bp);
504}
505
506int
507ip_QueueLen()
508{
509  struct mqueue *queue;
510  int result = 0;
511
512  for (queue = &IpOutputQueues[PRI_MAX]; queue >= IpOutputQueues; queue--)
513    result += queue->qlen;
514
515  return result;
516}
517
518int
519ip_FlushPacket(struct link *l, struct bundle *bundle)
520{
521  struct mqueue *queue;
522  struct mbuf *bp;
523  int cnt;
524
525  if (bundle->ncp.ipcp.fsm.state != ST_OPENED)
526    return 0;
527
528  for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--)
529    if (queue->top) {
530      bp = mbuf_Dequeue(queue);
531      if (bp) {
532        struct ip *pip = (struct ip *)MBUF_CTOP(bp);
533
534	cnt = mbuf_Length(bp);
535	vj_SendFrame(l, bp, bundle);
536        if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY))
537          bundle_StartIdleTimer(bundle);
538        ipcp_AddOutOctets(&bundle->ncp.ipcp, cnt);
539	return 1;
540      }
541    }
542
543  return 0;
544}
545