xref: /freebsd/usr.sbin/ppp/ip.c (revision 11afcc8f9f96d657b8e6f7547c02c1957331fc96)
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.48 1998/06/27 23:48:45 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 
68 static 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 
75 static const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" };
76 
77 static int
78 PortMatch(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  */
95 static int
96 FilterCheck(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
225 static void
226 IcmpError(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  */
242 int
243 PacketCheck(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 
374 void
375 ip_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 
494 static struct mqueue IpOutputQueues[PRI_FAST + 1];
495 
496 void
497 ip_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 
506 int
507 ip_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 
518 int
519 ip_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         if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY))
536           bundle_StartIdleTimer(bundle);
537 	vj_SendFrame(l, bp, bundle);
538         ipcp_AddOutOctets(&bundle->ncp.ipcp, cnt);
539 	return 1;
540       }
541     }
542 
543   return 0;
544 }
545