Deleted Added
sdiff udiff text old ( 50479 ) new ( 50867 )
full compact
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 * $FreeBSD: head/usr.sbin/ppp/ip.c 50479 1999-08-28 01:35:59Z peter $
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#if defined(__OpenBSD__) || defined(__NetBSD__)
28#include <sys/socket.h>
29#endif
30#include <netinet/in.h>
31#include <netinet/in_systm.h>
32#include <netinet/ip.h>
33#include <netinet/ip_icmp.h>
34#include <netinet/udp.h>
35#include <netinet/tcp.h>
36#include <arpa/inet.h>
37#include <sys/un.h>
38
39#include <errno.h>
40#include <stdio.h>
41#include <string.h>
42#include <termios.h>
43#include <unistd.h>
44
45#include "layer.h"
46#include "proto.h"
47#include "mbuf.h"
48#include "log.h"
49#include "defs.h"
50#include "timer.h"
51#include "fsm.h"
52#include "lqr.h"
53#include "hdlc.h"
54#include "throughput.h"
55#include "iplist.h"
56#include "slcompress.h"
57#include "ipcp.h"
58#include "filter.h"
59#include "descriptor.h"
60#include "lcp.h"
61#include "ccp.h"
62#include "link.h"
63#include "mp.h"
64#ifndef NORADIUS
65#include "radius.h"
66#endif
67#include "bundle.h"
68#include "tun.h"
69#include "ip.h"
70
71static const u_short interactive_ports[32] = {
72 544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
73 80, 81, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543,
74};
75
76#define INTERACTIVE(p) (interactive_ports[(p) & 0x1F] == (p))
77
78static const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" };
79
80static __inline int
81PortMatch(int op, u_short pport, u_short rport)
82{
83 switch (op) {
84 case OP_EQ:
85 return (pport == rport);
86 case OP_GT:
87 return (pport > rport);
88 case OP_LT:
89 return (pport < rport);
90 default:
91 return (0);
92 }
93}
94
95/*
96 * Check a packet against a defined filter
97 * Returns 0 to accept the packet, non-zero to drop the packet
98 *
99 * If filtering is enabled, the initial fragment of a datagram must
100 * contain the complete protocol header, and subsequent fragments
101 * must not attempt to over-write it.
102 */
103static int
104FilterCheck(const struct ip *pip, const struct filter *filter)
105{
106 int gotinfo; /* true if IP payload decoded */
107 int cproto; /* P_* protocol type if (gotinfo) */
108 int estab, syn, finrst; /* TCP state flags if (gotinfo) */
109 u_short sport, dport; /* src, dest port from packet if (gotinfo) */
110 int n; /* filter rule to process */
111 int len; /* bytes used in dbuff */
112 int didname; /* true if filter header printed */
113 int match; /* true if condition matched */
114 const struct filterent *fp = filter->rule;
115 char dbuff[100];
116
117 if (fp->f_action == A_NONE)
118 return (0); /* No rule is given. Permit this packet */
119
120 /* Deny any packet fragment that tries to over-write the header.
121 * Since we no longer have the real header available, punt on the
122 * largest normal header - 20 bytes for TCP without options, rounded
123 * up to the next possible fragment boundary. Since the smallest
124 * `legal' MTU is 576, and the smallest recommended MTU is 296, any
125 * fragmentation within this range is dubious at best */
126 len = ntohs(pip->ip_off) & IP_OFFMASK; /* fragment offset */
127 if (len > 0) { /* Not first fragment within datagram */
128 if (len < (24 >> 3)) /* don't allow fragment to over-write header */
129 return (1);
130 /* permit fragments on in and out filter */
131 return (filter->fragok);
132 }
133
134 cproto = gotinfo = estab = syn = finrst = didname = 0;
135 sport = dport = 0;
136 for (n = 0; n < MAXFILTERS; ) {
137 if (fp->f_action == A_NONE) {
138 n++;
139 fp++;
140 continue;
141 }
142
143 if (!didname) {
144 log_Printf(LogDEBUG, "%s filter:\n", filter->name);
145 didname = 1;
146 }
147
148 match = 0;
149 if (!((pip->ip_src.s_addr ^ fp->f_src.ipaddr.s_addr) &
150 fp->f_src.mask.s_addr) &&
151 !((pip->ip_dst.s_addr ^ fp->f_dst.ipaddr.s_addr) &
152 fp->f_dst.mask.s_addr)) {
153 if (fp->f_proto != P_NONE) {
154 if (!gotinfo) {
155 const char *ptop = (const char *) pip + (pip->ip_hl << 2);
156 const struct tcphdr *th;
157 const struct udphdr *uh;
158 const struct icmp *ih;
159 int datalen; /* IP datagram length */
160
161 datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
162 switch (pip->ip_p) {
163 case IPPROTO_ICMP:
164 cproto = P_ICMP;
165 if (datalen < 8) /* ICMP must be at least 8 octets */
166 return (1);
167 ih = (const struct icmp *) ptop;
168 sport = ih->icmp_type;
169 estab = syn = finrst = -1;
170 if (log_IsKept(LogDEBUG))
171 snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
172 break;
173 case IPPROTO_IGMP:
174 cproto = P_IGMP;
175 if (datalen < 8) /* IGMP uses 8-octet messages */
176 return (1);
177 estab = syn = finrst = -1;
178 sport = ntohs(0);
179 break;
180#ifdef IPPROTO_OSPFIGP
181 case IPPROTO_OSPFIGP:
182 cproto = P_OSPF;
183 if (datalen < 8) /* IGMP uses 8-octet messages */
184 return (1);
185 estab = syn = finrst = -1;
186 sport = ntohs(0);
187 break;
188#endif
189 case IPPROTO_UDP:
190 case IPPROTO_IPIP:
191 cproto = P_UDP;
192 if (datalen < 8) /* UDP header is 8 octets */
193 return (1);
194 uh = (const struct udphdr *) ptop;
195 sport = ntohs(uh->uh_sport);
196 dport = ntohs(uh->uh_dport);
197 estab = syn = finrst = -1;
198 if (log_IsKept(LogDEBUG))
199 snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
200 sport, dport);
201 break;
202 case IPPROTO_TCP:
203 cproto = P_TCP;
204 th = (const struct tcphdr *) ptop;
205 /* TCP headers are variable length. The following code
206 * ensures that the TCP header length isn't de-referenced if
207 * the datagram is too short
208 */
209 if (datalen < 20 || datalen < (th->th_off << 2))
210 return (1);
211 sport = ntohs(th->th_sport);
212 dport = ntohs(th->th_dport);
213 estab = (th->th_flags & TH_ACK);
214 syn = (th->th_flags & TH_SYN);
215 finrst = (th->th_flags & (TH_FIN|TH_RST));
216 if (log_IsKept(LogDEBUG)) {
217 if (!estab)
218 snprintf(dbuff, sizeof dbuff,
219 "flags = %02x, sport = %d, dport = %d",
220 th->th_flags, sport, dport);
221 else
222 *dbuff = '\0';
223 }
224 break;
225 default:
226 return (1); /* We'll block unknown type of packet */
227 }
228
229 if (log_IsKept(LogDEBUG)) {
230 if (estab != -1) {
231 len = strlen(dbuff);
232 snprintf(dbuff + len, sizeof dbuff - len,
233 ", estab = %d, syn = %d, finrst = %d",
234 estab, syn, finrst);
235 }
236 log_Printf(LogDEBUG, " Filter: proto = %s, %s\n",
237 filter_Proto2Nam(cproto), dbuff);
238 }
239 gotinfo = 1;
240 }
241 if (log_IsKept(LogDEBUG)) {
242 if (fp->f_srcop != OP_NONE) {
243 snprintf(dbuff, sizeof dbuff, ", src %s %d",
244 filter_Op2Nam(fp->f_srcop), fp->f_srcport);
245 len = strlen(dbuff);
246 } else
247 len = 0;
248 if (fp->f_dstop != OP_NONE) {
249 snprintf(dbuff + len, sizeof dbuff - len,
250 ", dst %s %d", filter_Op2Nam(fp->f_dstop),
251 fp->f_dstport);
252 } else if (!len)
253 *dbuff = '\0';
254
255 log_Printf(LogDEBUG, " rule = %d: Address match, "
256 "check against proto %s%s, action = %s\n",
257 n, filter_Proto2Nam(fp->f_proto),
258 dbuff, filter_Action2Nam(fp->f_action));
259 }
260
261 if (cproto == fp->f_proto) {
262 if ((fp->f_srcop == OP_NONE ||
263 PortMatch(fp->f_srcop, sport, fp->f_srcport)) &&
264 (fp->f_dstop == OP_NONE ||
265 PortMatch(fp->f_dstop, dport, fp->f_dstport)) &&
266 (fp->f_estab == 0 || estab) &&
267 (fp->f_syn == 0 || syn) &&
268 (fp->f_finrst == 0 || finrst)) {
269 match = 1;
270 }
271 }
272 } else {
273 /* Address is matched and no protocol specified. Make a decision. */
274 log_Printf(LogDEBUG, " rule = %d: Address match, action = %s\n", n,
275 filter_Action2Nam(fp->f_action));
276 match = 1;
277 }
278 } else
279 log_Printf(LogDEBUG, " rule = %d: Address mismatch\n", n);
280
281 if (match != fp->f_invert) {
282 /* Take specified action */
283 if (fp->f_action < A_NONE)
284 fp = &filter->rule[n = fp->f_action];
285 else
286 return (fp->f_action != A_PERMIT);
287 } else {
288 n++;
289 fp++;
290 }
291 }
292 return (1); /* No rule is mached. Deny this packet */
293}
294
295#ifdef notdef
296static void
297IcmpError(struct ip *pip, int code)
298{
299 struct mbuf *bp;
300
301 if (pip->ip_p != IPPROTO_ICMP) {
302 bp = mbuf_Alloc(cnt, MB_IPIN);
303 memcpy(MBUF_CTOP(bp), ptr, cnt);
304 vj_SendFrame(bp);
305 ipcp_AddOutOctets(cnt);
306 }
307}
308#endif
309
310/*
311 * For debugging aid.
312 */
313int
314PacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter)
315{
316 struct ip *pip;
317 struct tcphdr *th;
318 struct udphdr *uh;
319 struct icmp *icmph;
320 char *ptop;
321 int mask, len, n;
322 int pri = PRI_NORMAL;
323 int logit, loglen;
324 char logbuf[200];
325
326 logit = log_IsKept(LogTCPIP) && filter->logok;
327 loglen = 0;
328
329 pip = (struct ip *) cp;
330
331 if (logit && loglen < sizeof logbuf) {
332 snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
333 loglen += strlen(logbuf + loglen);
334 }
335 ptop = (cp + (pip->ip_hl << 2));
336
337 switch (pip->ip_p) {
338 case IPPROTO_ICMP:
339 if (logit && loglen < sizeof logbuf) {
340 icmph = (struct icmp *) ptop;
341 snprintf(logbuf + loglen, sizeof logbuf - loglen,
342 "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
343 loglen += strlen(logbuf + loglen);
344 snprintf(logbuf + loglen, sizeof logbuf - loglen,
345 "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
346 loglen += strlen(logbuf + loglen);
347 }
348 break;
349 case IPPROTO_UDP:
350 if (logit && loglen < sizeof logbuf) {
351 uh = (struct udphdr *) ptop;
352 snprintf(logbuf + loglen, sizeof logbuf - loglen,
353 "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
354 loglen += strlen(logbuf + loglen);
355 snprintf(logbuf + loglen, sizeof logbuf - loglen,
356 "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
357 loglen += strlen(logbuf + loglen);
358 }
359 break;
360#ifdef IPPROTO_OSPFIGP
361 case IPPROTO_OSPFIGP:
362 if (logit && loglen < sizeof logbuf) {
363 snprintf(logbuf + loglen, sizeof logbuf - loglen,
364 "OSPF: %s ---> ", inet_ntoa(pip->ip_src));
365 loglen += strlen(logbuf + loglen);
366 snprintf(logbuf + loglen, sizeof logbuf - loglen,
367 "%s", inet_ntoa(pip->ip_dst));
368 loglen += strlen(logbuf + loglen);
369 }
370 break;
371#endif
372 case IPPROTO_IPIP:
373 if (logit && loglen < sizeof logbuf) {
374 uh = (struct udphdr *) ptop;
375 snprintf(logbuf + loglen, sizeof logbuf - loglen,
376 "IPIP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
377 loglen += strlen(logbuf + loglen);
378 snprintf(logbuf + loglen, sizeof logbuf - loglen,
379 "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
380 loglen += strlen(logbuf + loglen);
381 }
382 break;
383 case IPPROTO_IGMP:
384 if (logit && loglen < sizeof logbuf) {
385 uh = (struct udphdr *) ptop;
386 snprintf(logbuf + loglen, sizeof logbuf - loglen,
387 "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
388 loglen += strlen(logbuf + loglen);
389 snprintf(logbuf + loglen, sizeof logbuf - loglen,
390 "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
391 loglen += strlen(logbuf + loglen);
392 }
393 break;
394 case IPPROTO_TCP:
395 th = (struct tcphdr *) ptop;
396 if (pip->ip_tos == IPTOS_LOWDELAY)
397 pri = PRI_FAST;
398 else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
399 if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
400 pri = PRI_FAST;
401 }
402 if (logit && loglen < sizeof logbuf) {
403 len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
404 snprintf(logbuf + loglen, sizeof logbuf - loglen,
405 "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
406 loglen += strlen(logbuf + loglen);
407 snprintf(logbuf + loglen, sizeof logbuf - loglen,
408 "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
409 loglen += strlen(logbuf + loglen);
410 n = 0;
411 for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
412 if (th->th_flags & mask) {
413 snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
414 loglen += strlen(logbuf + loglen);
415 }
416 n++;
417 }
418 snprintf(logbuf + loglen, sizeof logbuf - loglen,
419 " seq:%lx ack:%lx (%d/%d)",
420 (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb);
421 loglen += strlen(logbuf + loglen);
422 if ((th->th_flags & TH_SYN) && nb > 40) {
423 u_short *sp;
424
425 ptop += 20;
426 sp = (u_short *) ptop;
427 if (ntohs(sp[0]) == 0x0204) {
428 snprintf(logbuf + loglen, sizeof logbuf - loglen,
429 " MSS = %d", ntohs(sp[1]));
430 loglen += strlen(logbuf + loglen);
431 }
432 }
433 }
434 break;
435 }
436
437 if (FilterCheck(pip, filter)) {
438 if (logit)
439 log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf);
440#ifdef notdef
441 if (direction == 0)
442 IcmpError(pip, pri);
443#endif
444 return (-1);
445 } else {
446 /* Check Keep Alive filter */
447 if (logit) {
448 if (FilterCheck(pip, &bundle->filter.alive))
449 log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
450 else
451 log_Printf(LogTCPIP, "%s\n", logbuf);
452 }
453 return (pri);
454 }
455}
456
457struct mbuf *
458ip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
459{
460 int nb, nw;
461 struct tun_data tun;
462 struct ip *pip;
463
464 if (bundle->ncp.ipcp.fsm.state != ST_OPENED) {
465 log_Printf(LogWARN, "ip_Input: IPCP not open - packet dropped\n");
466 mbuf_Free(bp);
467 return NULL;
468 }
469
470 mbuf_SetType(bp, MB_IPIN);
471 tun_fill_header(tun, AF_INET);
472 nb = mbuf_Length(bp);
473 if (nb > sizeof tun.data) {
474 log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %d, max %d)\n",
475 l->name, nb, (int)(sizeof tun.data));
476 mbuf_Free(bp);
477 return NULL;
478 }
479 mbuf_Read(bp, tun.data, nb);
480
481 if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0)
482 return NULL;
483
484 pip = (struct ip *)tun.data;
485 if (!FilterCheck(pip, &bundle->filter.alive))
486 bundle_StartIdleTimer(bundle);
487
488 ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
489
490 nb += sizeof tun - sizeof tun.data;
491 nw = write(bundle->dev.fd, &tun, nb);
492 if (nw != nb) {
493 if (nw == -1)
494 log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %s\n",
495 l->name, nb, strerror(errno));
496 else
497 log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %d\n", l->name, nb, nw);
498 }
499
500 return NULL;
501}
502
503void
504ip_Enqueue(struct ipcp *ipcp, int pri, char *ptr, int count)
505{
506 struct mbuf *bp;
507
508 if (pri < 0 || pri > sizeof ipcp->Queue / sizeof ipcp->Queue[0])
509 log_Printf(LogERROR, "Can't store in ip queue %d\n", pri);
510 else {
511 /*
512 * We allocate an extra 6 bytes, four at the front and two at the end.
513 * This is an optimisation so that we need to do less work in
514 * mbuf_Prepend() in acf_LayerPush() and proto_LayerPush() and
515 * appending in hdlc_LayerPush().
516 */
517 bp = mbuf_Alloc(count + 6, MB_IPOUT);
518 bp->offset += 4;
519 bp->cnt -= 6;
520 memcpy(MBUF_CTOP(bp), ptr, count);
521 mbuf_Enqueue(&ipcp->Queue[pri], bp);
522 }
523}
524
525void
526ip_DeleteQueue(struct ipcp *ipcp)
527{
528 struct mqueue *queue;
529
530 for (queue = ipcp->Queue; queue < ipcp->Queue + PRI_MAX; queue++)
531 while (queue->top)
532 mbuf_Free(mbuf_Dequeue(queue));
533}
534
535int
536ip_QueueLen(struct ipcp *ipcp)
537{
538 struct mqueue *queue;
539 int result = 0;
540
541 for (queue = ipcp->Queue; queue < ipcp->Queue + PRI_MAX; queue++)
542 result += queue->qlen;
543
544 return result;
545}
546
547int
548ip_PushPacket(struct link *l, struct bundle *bundle)
549{
550 struct ipcp *ipcp = &bundle->ncp.ipcp;
551 struct mqueue *queue;
552 struct mbuf *bp;
553 struct ip *pip;
554 int cnt;
555
556 if (ipcp->fsm.state != ST_OPENED)
557 return 0;
558
559 for (queue = &ipcp->Queue[PRI_FAST]; queue >= ipcp->Queue; queue--)
560 if (queue->top) {
561 bp = mbuf_Contiguous(mbuf_Dequeue(queue));
562 cnt = mbuf_Length(bp);
563 pip = (struct ip *)MBUF_CTOP(bp);
564 if (!FilterCheck(pip, &bundle->filter.alive))
565 bundle_StartIdleTimer(bundle);
566 link_PushPacket(l, bp, bundle, PRI_NORMAL, PROTO_IP);
567 ipcp_AddOutOctets(ipcp, cnt);
568 return 1;
569 }
570
571 return 0;
572}