1: /*
2: * Copyright (c) 1993-1997,2004 Rinet Corp., Novosibirsk, Russia
3: *
4: * Redistribution and use in source forms, with and without modification,
5: * are permitted provided that this entire comment appears intact.
6: * Redistribution in binary form may occur without any restrictions.
7: *
8: * THIS SOFTWARE IS PROVIDED ``AS IS'' WITHOUT ANY WARRANTIES OF ANY KIND.
9: */
10:
11: #ifdef HAVE_CONFIG_H
12: #include <config.h>
13: #endif
14:
15: #ifdef HAVE_HAS_COLORS
16:
17: #ifdef HAVE_SLCURSES
18: #include <slcurses.h>
19: #elif HAVE_NCURSES
20: #include <ncurses.h>
21: #else
22: #include <curses.h>
23: #endif
24: #include <sys/param.h>
25: #include <sys/types.h>
26: #include <sys/socket.h>
27: #include <netinet/in.h>
28: #include <arpa/inet.h>
29: #include <stdio.h>
30: #include <stdlib.h>
31: #include <string.h>
32: #include <unistd.h>
33: #include <ctype.h>
34: #include <netdb.h>
35: #include <errno.h>
36:
37: #include "colormask.h"
38: #include "trafshow.h"
39: #include "netstat.h"
40: #ifdef DEBUG
41: #include "show_stat.h" /* just for hdr2str() */
42: #endif
43:
44: /* mask entry */
45: struct cm_entry {
46: struct internet_header in_hdr;
47: int src_mask; /* source ip address mask */
48: int dst_mask; /* destination ip address mask */
49:
50: short pair; /* color-pair */
51: int attr; /* video attributes; bold, blink, etc */
52: };
53:
54: static struct cm_entry *color_mask = NULL;
55: static int n_masks = 0;
56: static int n_pairs = 0;
57: static const char *rc_file = 0;
58: static int rc_line;
59:
60: /* SLcurses can't handle attributes as well; so hack it */
61: #ifdef HAVE_SLCURSES
62: static void
63: slang_init_pair(short pair, short fc, short bc, int at)
64: {
65: SLtt_set_color_object(pair, ((fc | (bc << 8)) << 8) | at);
66: }
67:
68: static int
69: slang_pair_content(short pair, short *fc, short *bc)
70: {
71: int attr;
72: SLtt_Char_Type at;
73:
74: at = SLtt_get_color_object(pair);
75: attr = at & (A_BOLD | A_BLINK);
76: at &= ~(A_BOLD | A_BLINK);
77: at >>= 8;
78: *fc = at & 0xff;
79: *bc = (at >> 8) & 0xff;
80:
81: return attr;
82: }
83: #endif /* HAVE_SLCURSES */
84:
85: static short
86: findpair(short f, short b, int a)
87: {
88: int i;
89: short f1 = -1, b1 = -1;
90: struct cm_entry *cm;
91:
92: for (cm = color_mask, i = 0; cm != NULL && i < n_masks-1; cm++, i++) {
93: #ifdef HAVE_SLCURSES
94: int a1 = slang_pair_content(cm->pair, &f1, &b1);
95: if (f1 >= COLORS) f1 = -1;
96: if (b1 >= COLORS) b1 = -1;
97: if (f == f1 && b == b1 && a == a1) return cm->pair;
98: #else
99: pair_content(cm->pair, &f1, &b1);
100: if (f1 >= COLORS) f1 = -1;
101: if (b1 >= COLORS) b1 = -1;
102: if (f == f1 && b == b1) return cm->pair;
103: #endif
104: }
105: return 0;
106: }
107:
108: static int
109: add_colormask(const char *s, struct cm_entry *m)
110: {
111: int i, attr = 0;
112: short fc, bc;
113: char f[100], *b;
114: static char *ctab[8] = { "black", "red", "green", "yellow",
115: "blue", "magenta", "cyan", "white" };
116: #ifdef HAVE_USE_DEFAULT_COLORS
117: static short fc_def = -1, bc_def = -1;
118: #else
119: static short fc_def = COLOR_WHITE, bc_def = COLOR_BLACK;
120: #endif
121:
122: if ((b = strchr(strcpy(f, s), ':')) != NULL) *b++ = '\0';
123:
124: if (*f) {
125: for (i = 0; i < 8; i++)
126: if (!strcasecmp(ctab[i], f)) break;
127: if (i < 8) fc = i;
128: else {
129: fc = atoi(f);
130: if (fc < 1 || fc > COLORS) {
131: fprintf(stderr, "%s: line %d: Unknown color `%s'\n",
132: rc_file, rc_line, f);
133: return -1;
134: }
135: }
136: if (isupper((int)*f)) attr |= A_BOLD;
137: } else fc = fc_def;
138:
139: if (b && *b) {
140: for (i = 0; i < 8; i++)
141: if (!strcasecmp(ctab[i], b)) break;
142: if (i < 8) bc = i;
143: else {
144: bc = atoi(b);
145: if (bc < 1 || bc > COLORS) {
146: fprintf(stderr, "%s: line %d: Unknown color `%s'\n",
147: rc_file, rc_line, b);
148: return -1;
149: }
150: }
151: if (isupper((int)*b)) attr |= A_BLINK;
152: } else bc = bc_def;
153:
154: if (m != NULL) {
155: if ((color_mask = realloc(color_mask, ++n_masks * sizeof(struct cm_entry))) == NULL) {
156: fprintf(stderr, "add_colormask: realloc: Out of memory?\n");
157: return -1;
158: }
159: if ((m->pair = findpair(fc, bc, attr)) == 0) {
160: if (++n_pairs < COLOR_PAIRS-1) {
161: #ifdef HAVE_SLCURSES
162: slang_init_pair(n_pairs, fc, bc, attr);
163: #else
164: init_pair(n_pairs, fc, bc);
165: #endif
166: } else {
167: fprintf(stderr, "%s: line %d: Max %d color-pairs can be used\n",
168: rc_file, rc_line, COLOR_PAIRS-1);
169: return -1;
170: }
171: m->pair = n_pairs;
172: }
173: m->attr = attr;
174: memcpy(color_mask + (n_masks-1), m, sizeof(struct cm_entry));
175: } else { /* default colors */
176: #ifdef HAVE_SLCURSES
177: slang_init_pair(0, fc, bc, attr);
178: #else
179: #ifdef HAVE_BKGD
180: init_pair(COLOR_PAIRS-1, fc, bc);
181: bkgd(COLOR_PAIR(COLOR_PAIRS-1) | attr);
182: #elif HAVE_WBKGD
183: init_pair(COLOR_PAIRS-1, fc, bc);
184: wbkgd(stdscr, COLOR_PAIR(COLOR_PAIRS-1) | attr);
185: #else /* assume the color-pair 0 is background for whole screen */
186: init_pair(0, fc, bc);
187: #endif
188: #endif
189: fc_def = fc;
190: bc_def = bc;
191: }
192: return 0;
193: }
194:
195: static int
196: is_any(const char *s)
197: {
198: if (!s || !*s) return 0;
199: return (!strcmp(s, "*") || !strcasecmp(s, "any") || !strcasecmp(s, "all"));
200: }
201:
202: static int
203: is_number(const char *s)
204: {
205: if (!s || !*s) return 0;
206: for (; *s; s++) {
207: if (!isdigit((int)*s)) return 0;
208: }
209: return 1;
210: }
211:
212: static char *
213: str2proto(const char *str, int *proto)
214: {
215: int num;
216: struct protoent *pe;
217:
218: if (is_any(str)) {
219: *proto = 0;
220: return "";
221: }
222: if (is_number(str)) {
223: num = atoi(str);
224: if (num > 0 && num <= 0xff) {
225: if ((pe = getprotobynumber(num)) != 0) {
226: *proto = pe->p_proto;
227: return pe->p_name;
228: }
229: *proto = num;
230: return "";
231: }
232: }
233: if ((pe = getprotobyname(str)) != 0) {
234: *proto = pe->p_proto;
235: return pe->p_name;
236: }
237: fprintf(stderr, "%s: line %d: Unknown protocol `%s'\n",
238: rc_file, rc_line, str);
239: return 0;
240: }
241:
242: static int
243: str2port(const char *str, const char *proto)
244: {
245: int num;
246: struct servent *se;
247:
248: if (is_any(str))
249: return 0;
250:
251: num = atoi(str);
252: if (num > 0 && num <= 0xffff)
253: return htons((u_int16_t)num);
254:
255: if ((se = getservbyname(str, (proto && *proto) ? proto : 0)) != 0)
256: return se->s_port;
257:
258: if (proto && *proto) {
259: fprintf(stderr, "%s: line %d: Unknown port `%s' at protocol `%s'\n",
260: rc_file, rc_line, str, proto);
261: } else {
262: fprintf(stderr, "%s: line %d: Unknown port `%s'\n",
263: rc_file, rc_line, str);
264: }
265: return -1;
266: }
267:
268: static int
269: str2addr(const char *str, const char *proto, struct ip_address *addr, int *mask)
270: {
271: int op, ver = 0;
272: char buf[256], *cp, *mp, *pp;
273:
274: if (proto && !strcasecmp(proto, "IPv6")) {
275: #ifdef INET6
276: ver = 6;
277: #else
278: fprintf(stderr, "%s: line %d: IPv6 is unsupported at this system\n",
279: rc_file, rc_line);
280: return -1;
281: #endif
282: }
283: cp = strcpy(buf, str);
284: if ((mp = strchr(cp, '/')) != 0) {
285: *mp++ = '\0';
286: cp = mp;
287: }
288: if ((pp = strchr(cp, ',')) != 0) {
289: *pp++ = '\0';
290: }
291: if (mp && !is_number(mp)) {
292: fprintf(stderr, "%s: line %d: %s: Mask must be number of bits\n",
293: rc_file, rc_line, mp);
294: return -1;
295: }
296: if (!is_any(buf)) {
297: op = 0;
298: #ifdef INET6
299: if (ver == 6 || strchr(buf, ':')) {
300: ver = 6;
301: op = inet_pton(AF_INET6, buf, &addr->ip6_addr);
302: if (op < 0) {
303: fprintf(stderr, "%s: line %d: %s: %s\n",
304: rc_file, rc_line, buf, strerror(errno));
305: return -1;
306: }
307: }
308: #endif
309: if (!op) {
310: ver = 4;
311: op = inet_pton(AF_INET, buf, &addr->ip_addr);
312: if (op < 0) {
313: fprintf(stderr, "%s: line %d: %s: %s\n",
314: rc_file, rc_line, buf, strerror(errno));
315: return -1;
316: }
317: }
318: if (!op) {
319: struct hostent *he;
320: if ((he = gethostbyname(buf)) == 0) {
321: fprintf(stderr, "%s: line %d: %s: Unknown host\n",
322: rc_file, rc_line, buf);
323: return -1;
324: }
325: if (he->h_addrtype == AF_INET) {
326: ver = 4;
327: memcpy(&addr->ip_addr, he->h_addr,
328: MIN(sizeof(addr->ip_addr), he->h_length));
329: }
330: #ifdef INET6
331: else if (he->h_addrtype == AF_INET6) {
332: ver = 6;
333: memcpy(&addr->ip6_addr, he->h_addr,
334: MIN(sizeof(addr->ip6_addr), he->h_length));
335: }
336: #endif
337: else {
338: fprintf(stderr, "%s: line %d: %s: Unknown address family\n",
339: rc_file, rc_line, buf);
340: return -1;
341: }
342: }
343: }
344: if (pp) {
345: if ((op = str2port(pp, proto)) == -1)
346: return -1;
347: addr->ip_port = op;
348: }
349: if (mask) {
350: if (mp) {
351: op = atoi(mp);
352: if (op < 8 || op > 128) {
353: fprintf(stderr, "%s: line %d: %d: Wrong mask\n",
354: rc_file, rc_line, op);
355: return -1;
356: }
357: *mask = op;
358: } else *mask = 0;
359: }
360: return ver;
361: }
362:
363: int
364: init_colormask()
365: {
366: FILE *fp;
367: int num;
368: struct cm_entry me, *cm;
369: char *cp, buf[1024];
370: char s1[256], s2[256], s3[256], s4[256];
371:
372: if (rc_file) {
373: free((char *)rc_file);
374: rc_file = 0;
375: }
376: if (!color_conf) {
377: if ((cp = getenv("HOME")) != 0) {
378: (void)strcpy(buf, cp);
379: (void)strcat(buf, "/");
380: } else buf[0] = '\0';
381: (void)strcat(buf, ".");
382: (void)strcat(buf, progname);
383: if ((fp = fopen(buf, "r")) == NULL) {
384: (void)strcpy(buf, "/etc/");
385: (void)strcat(buf, progname);
386: if ((fp = fopen(buf, "r")) == NULL) return 0;
387: }
388: rc_file = strdup(buf);
389: } else {
390: if ((fp = fopen(color_conf, "r")) == NULL) {
391: fprintf(stderr, "%s: %s\n", color_conf, strerror(errno));
392: return -1;
393: }
394: rc_file = strdup(color_conf);
395: }
396: if (!rc_file) {
397: fprintf(stderr, "init_colormask: strdup: Out of memory?\n");
398: (void)fclose(fp);
399: return -1;
400: }
401: rc_line = 0;
402: cm = &me;
403:
404: #ifdef HAVE_USE_DEFAULT_COLORS
405: use_default_colors();
406: #endif
407: while (fgets(buf, sizeof(buf), fp) != NULL) {
408: rc_line++;
409: if (buf[0] == '\n' || buf[0] == '#') continue;
410: if ((cp = strchr(buf, '#')) != NULL) {
411: *cp++ = '\n';
412: *cp = '\0';
413: }
414: memset(cm, 0, sizeof(struct cm_entry));
415: num = sscanf(buf, "%s %s %s %s\n", s1, s2, s3, s4);
416: if (num == 2) {
417: if (strcasecmp(s1, "default")) {
418: if ((cp = strchr(s1, '/')) != 0) {
419: *cp++ = '\0';
420: if ((cp = str2proto(cp, &num)) == 0) {
421: (void)fclose(fp);
422: return -1;
423: }
424: cm->in_hdr.proto = num;
425: }
426: if ((num = str2port(s1, cp)) == -1) {
427: (void)fclose(fp);
428: return -1;
429: }
430: cm->in_hdr.src.ip_port = num;
431: cm->in_hdr.dst.ip_port = 0;
432: if (add_colormask(s2, cm) < 0) {
433: (void)fclose(fp);
434: return -1;
435: }
436: cm->in_hdr.src.ip_port = 0;
437: cm->in_hdr.dst.ip_port = num;
438: if (add_colormask(s2, cm) < 0) {
439: (void)fclose(fp);
440: return -1;
441: }
442: } else if (add_colormask(s2, 0) < 0) {
443: (void)fclose(fp);
444: return -1;
445: }
446: } else if (num == 3) {
447: num = str2addr(s1, 0, &cm->in_hdr.src, &cm->src_mask);
448: if (num == -1) {
449: (void)fclose(fp);
450: return -1;
451: }
452: cm->in_hdr.ver = num;
453: num = str2addr(s2, 0, &cm->in_hdr.dst, &cm->dst_mask);
454: if (num == -1) {
455: (void)fclose(fp);
456: return -1;
457: }
458: if (!cm->in_hdr.ver) {
459: cm->in_hdr.ver = num;
460: } else if (num && num != cm->in_hdr.ver) {
461: fprintf(stderr, "%s: line %d: Addresses family mismatch\n",
462: rc_file, rc_line);
463: (void)fclose(fp);
464: return -1;
465: }
466: if (add_colormask(s3, cm) < 0) {
467: (void)fclose(fp);
468: return -1;
469: }
470: } else if (num == 4) {
471: if ((cp = str2proto(s1, &num)) == 0) {
472: (void)fclose(fp);
473: return -1;
474: }
475: cm->in_hdr.proto = num;
476: num = str2addr(s2, cp, &cm->in_hdr.src, &cm->src_mask);
477: if (num == -1) {
478: (void)fclose(fp);
479: return -1;
480: }
481: cm->in_hdr.ver = num;
482: num = str2addr(s3, cp, &cm->in_hdr.dst, &cm->dst_mask);
483: if (num == -1) {
484: (void)fclose(fp);
485: return -1;
486: }
487: if (!cm->in_hdr.ver) {
488: cm->in_hdr.ver = num;
489: } else if (num && num != cm->in_hdr.ver) {
490: fprintf(stderr, "%s: line %d: Addresses family mismatch\n",
491: rc_file, rc_line);
492: (void)fclose(fp);
493: return -1;
494: }
495: if (add_colormask(s4, cm) < 0) {
496: (void)fclose(fp);
497: return -1;
498: }
499: } else {
500: fprintf(stderr, "%s: line %d: Bad format\n",
501: rc_file, rc_line);
502: (void)fclose(fp);
503: return -1;
504: }
505: }
506: (void)fclose(fp);
507: #ifdef DEBUG
508: for (cm = color_mask, num = 0; cm && num < n_masks; cm++, num++) {
509: struct netstat_header nh;
510: memset(&nh, 0, sizeof(nh));
511: nh.in_hdr = cm->in_hdr;
512: hdr2str(&nh, s1, sizeof(s1), s2, sizeof(s2), s3, sizeof(s3));
513: fprintf(stderr, "%d:", num+1);
514: fprintf(stderr, " proto=%s", s3);
515: fprintf(stderr, " src=%s", s1);
516: fprintf(stderr, " src_mask=%d", cm->src_mask);
517: fprintf(stderr, " dst=%s", s2);
518: fprintf(stderr, " dst_mask=%d", cm->dst_mask);
519: fprintf(stderr, " color_pair=%d\r\n", (int)cm->pair);
520: }
521: fflush(stderr);
522: pause();
523: #endif
524: return n_masks;
525: }
526:
527: static u_int32_t
528: netmask(int bits)
529: {
530: register u_int32_t mask = 0;
531: int i;
532: for (i = 0; i < bits; i++) {
533: mask >>= 1;
534: mask |= 0x80000000L;
535: }
536: return (u_int32_t)htonl(mask);
537: }
538:
539: int
540: colormask(nh)
541: const struct netstat_header *nh;
542: {
543: /* sanity check */
544: if (!nh) return A_NORMAL;
545:
546: if (nh->in_hdr.ver) {
547: register const struct cm_entry *cm;
548: int i;
549: for (cm = color_mask, i = 0; cm && i < n_masks; cm++, i++) {
550: /* IP version */
551: if (cm->in_hdr.ver) {
552: if (nh->in_hdr.ver != cm->in_hdr.ver)
553: continue;
554: }
555: /* IP protocol */
556: if (cm->in_hdr.proto) {
557: if (nh->in_hdr.proto != cm->in_hdr.proto)
558: continue;
559: }
560: /* IP source address */
561: if (cm->in_hdr.src.ip_addr.s_addr) {
562: if (cm->src_mask) {
563: u_int32_t mask = netmask(cm->src_mask);
564: if ((nh->in_hdr.src.ip_addr.s_addr & mask) ^
565: (cm->in_hdr.src.ip_addr.s_addr & mask))
566: continue;
567: } else if (nh->in_hdr.src.ip_addr.s_addr !=
568: cm->in_hdr.src.ip_addr.s_addr)
569: continue;
570: }
571: /* IP source port */
572: if (cm->in_hdr.src.ip_port) {
573: if (nh->in_hdr.src.ip_port != cm->in_hdr.src.ip_port)
574: continue;
575: }
576: /* IP destination address */
577: if (cm->in_hdr.dst.ip_addr.s_addr) {
578: if (cm->dst_mask) {
579: u_int32_t mask = netmask(cm->dst_mask);
580: if ((nh->in_hdr.dst.ip_addr.s_addr & mask) ^
581: (cm->in_hdr.dst.ip_addr.s_addr & mask))
582: continue;
583: } else if (nh->in_hdr.dst.ip_addr.s_addr !=
584: cm->in_hdr.dst.ip_addr.s_addr)
585: continue;
586: }
587: /* IP destination port */
588: if (cm->in_hdr.dst.ip_port) {
589: if (nh->in_hdr.dst.ip_port != cm->in_hdr.dst.ip_port)
590: continue;
591: }
592: #ifdef HAVE_SLCURSES
593: return (COLOR_PAIR(cm->pair));
594: #else
595: return (COLOR_PAIR(cm->pair) | cm->attr);
596: #endif
597: }
598: }
599:
600: return A_NORMAL;
601: }
602:
603: #endif /* HAVE_HAS_COLORS */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>