/* * Copyright (c) 1993-1997,2004 Rinet Corp., Novosibirsk, Russia * * Redistribution and use in source forms, with and without modification, * are permitted provided that this entire comment appears intact. * Redistribution in binary form may occur without any restrictions. * * THIS SOFTWARE IS PROVIDED ``AS IS'' WITHOUT ANY WARRANTIES OF ANY KIND. */ #ifdef HAVE_CONFIG_H #include #endif #ifdef HAVE_HAS_COLORS #ifdef HAVE_SLCURSES #include #elif HAVE_NCURSES #include #else #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "colormask.h" #include "trafshow.h" #include "netstat.h" #ifdef DEBUG #include "show_stat.h" /* just for hdr2str() */ #endif /* mask entry */ struct cm_entry { struct internet_header in_hdr; int src_mask; /* source ip address mask */ int dst_mask; /* destination ip address mask */ short pair; /* color-pair */ int attr; /* video attributes; bold, blink, etc */ }; static struct cm_entry *color_mask = NULL; static int n_masks = 0; static int n_pairs = 0; static const char *rc_file = 0; static int rc_line; /* SLcurses can't handle attributes as well; so hack it */ #ifdef HAVE_SLCURSES static void slang_init_pair(short pair, short fc, short bc, int at) { SLtt_set_color_object(pair, ((fc | (bc << 8)) << 8) | at); } static int slang_pair_content(short pair, short *fc, short *bc) { int attr; SLtt_Char_Type at; at = SLtt_get_color_object(pair); attr = at & (A_BOLD | A_BLINK); at &= ~(A_BOLD | A_BLINK); at >>= 8; *fc = at & 0xff; *bc = (at >> 8) & 0xff; return attr; } #endif /* HAVE_SLCURSES */ static short findpair(short f, short b, int a) { int i; short f1 = -1, b1 = -1; struct cm_entry *cm; for (cm = color_mask, i = 0; cm != NULL && i < n_masks-1; cm++, i++) { #ifdef HAVE_SLCURSES int a1 = slang_pair_content(cm->pair, &f1, &b1); if (f1 >= COLORS) f1 = -1; if (b1 >= COLORS) b1 = -1; if (f == f1 && b == b1 && a == a1) return cm->pair; #else pair_content(cm->pair, &f1, &b1); if (f1 >= COLORS) f1 = -1; if (b1 >= COLORS) b1 = -1; if (f == f1 && b == b1) return cm->pair; #endif } return 0; } static int add_colormask(const char *s, struct cm_entry *m) { int i, attr = 0; short fc, bc; char f[100], *b; static char *ctab[8] = { "black", "red", "green", "yellow", "blue", "magenta", "cyan", "white" }; #ifdef HAVE_USE_DEFAULT_COLORS static short fc_def = -1, bc_def = -1; #else static short fc_def = COLOR_WHITE, bc_def = COLOR_BLACK; #endif if ((b = strchr(strcpy(f, s), ':')) != NULL) *b++ = '\0'; if (*f) { for (i = 0; i < 8; i++) if (!strcasecmp(ctab[i], f)) break; if (i < 8) fc = i; else { fc = atoi(f); if (fc < 1 || fc > COLORS) { fprintf(stderr, "%s: line %d: Unknown color `%s'\n", rc_file, rc_line, f); return -1; } } if (isupper((int)*f)) attr |= A_BOLD; } else fc = fc_def; if (b && *b) { for (i = 0; i < 8; i++) if (!strcasecmp(ctab[i], b)) break; if (i < 8) bc = i; else { bc = atoi(b); if (bc < 1 || bc > COLORS) { fprintf(stderr, "%s: line %d: Unknown color `%s'\n", rc_file, rc_line, b); return -1; } } if (isupper((int)*b)) attr |= A_BLINK; } else bc = bc_def; if (m != NULL) { if ((color_mask = realloc(color_mask, ++n_masks * sizeof(struct cm_entry))) == NULL) { fprintf(stderr, "add_colormask: realloc: Out of memory?\n"); return -1; } if ((m->pair = findpair(fc, bc, attr)) == 0) { if (++n_pairs < COLOR_PAIRS-1) { #ifdef HAVE_SLCURSES slang_init_pair(n_pairs, fc, bc, attr); #else init_pair(n_pairs, fc, bc); #endif } else { fprintf(stderr, "%s: line %d: Max %d color-pairs can be used\n", rc_file, rc_line, COLOR_PAIRS-1); return -1; } m->pair = n_pairs; } m->attr = attr; memcpy(color_mask + (n_masks-1), m, sizeof(struct cm_entry)); } else { /* default colors */ #ifdef HAVE_SLCURSES slang_init_pair(0, fc, bc, attr); #else #ifdef HAVE_BKGD init_pair(COLOR_PAIRS-1, fc, bc); bkgd(COLOR_PAIR(COLOR_PAIRS-1) | attr); #elif HAVE_WBKGD init_pair(COLOR_PAIRS-1, fc, bc); wbkgd(stdscr, COLOR_PAIR(COLOR_PAIRS-1) | attr); #else /* assume the color-pair 0 is background for whole screen */ init_pair(0, fc, bc); #endif #endif fc_def = fc; bc_def = bc; } return 0; } static int is_any(const char *s) { if (!s || !*s) return 0; return (!strcmp(s, "*") || !strcasecmp(s, "any") || !strcasecmp(s, "all")); } static int is_number(const char *s) { if (!s || !*s) return 0; for (; *s; s++) { if (!isdigit((int)*s)) return 0; } return 1; } static char * str2proto(const char *str, int *proto) { int num; struct protoent *pe; if (is_any(str)) { *proto = 0; return ""; } if (is_number(str)) { num = atoi(str); if (num > 0 && num <= 0xff) { if ((pe = getprotobynumber(num)) != 0) { *proto = pe->p_proto; return pe->p_name; } *proto = num; return ""; } } if ((pe = getprotobyname(str)) != 0) { *proto = pe->p_proto; return pe->p_name; } fprintf(stderr, "%s: line %d: Unknown protocol `%s'\n", rc_file, rc_line, str); return 0; } static int str2port(const char *str, const char *proto) { int num; struct servent *se; if (is_any(str)) return 0; num = atoi(str); if (num > 0 && num <= 0xffff) return htons((u_int16_t)num); if ((se = getservbyname(str, (proto && *proto) ? proto : 0)) != 0) return se->s_port; if (proto && *proto) { fprintf(stderr, "%s: line %d: Unknown port `%s' at protocol `%s'\n", rc_file, rc_line, str, proto); } else { fprintf(stderr, "%s: line %d: Unknown port `%s'\n", rc_file, rc_line, str); } return -1; } static int str2addr(const char *str, const char *proto, struct ip_address *addr, int *mask) { int op, ver = 0; char buf[256], *cp, *mp, *pp; if (proto && !strcasecmp(proto, "IPv6")) { #ifdef INET6 ver = 6; #else fprintf(stderr, "%s: line %d: IPv6 is unsupported at this system\n", rc_file, rc_line); return -1; #endif } cp = strcpy(buf, str); if ((mp = strchr(cp, '/')) != 0) { *mp++ = '\0'; cp = mp; } if ((pp = strchr(cp, ',')) != 0) { *pp++ = '\0'; } if (mp && !is_number(mp)) { fprintf(stderr, "%s: line %d: %s: Mask must be number of bits\n", rc_file, rc_line, mp); return -1; } if (!is_any(buf)) { op = 0; #ifdef INET6 if (ver == 6 || strchr(buf, ':')) { ver = 6; op = inet_pton(AF_INET6, buf, &addr->ip6_addr); if (op < 0) { fprintf(stderr, "%s: line %d: %s: %s\n", rc_file, rc_line, buf, strerror(errno)); return -1; } } #endif if (!op) { ver = 4; op = inet_pton(AF_INET, buf, &addr->ip_addr); if (op < 0) { fprintf(stderr, "%s: line %d: %s: %s\n", rc_file, rc_line, buf, strerror(errno)); return -1; } } if (!op) { struct hostent *he; if ((he = gethostbyname(buf)) == 0) { fprintf(stderr, "%s: line %d: %s: Unknown host\n", rc_file, rc_line, buf); return -1; } if (he->h_addrtype == AF_INET) { ver = 4; memcpy(&addr->ip_addr, he->h_addr, MIN(sizeof(addr->ip_addr), he->h_length)); } #ifdef INET6 else if (he->h_addrtype == AF_INET6) { ver = 6; memcpy(&addr->ip6_addr, he->h_addr, MIN(sizeof(addr->ip6_addr), he->h_length)); } #endif else { fprintf(stderr, "%s: line %d: %s: Unknown address family\n", rc_file, rc_line, buf); return -1; } } } if (pp) { if ((op = str2port(pp, proto)) == -1) return -1; addr->ip_port = op; } if (mask) { if (mp) { op = atoi(mp); if (op < 8 || op > 128) { fprintf(stderr, "%s: line %d: %d: Wrong mask\n", rc_file, rc_line, op); return -1; } *mask = op; } else *mask = 0; } return ver; } int init_colormask() { FILE *fp; int num; struct cm_entry me, *cm; char *cp, buf[1024]; char s1[256], s2[256], s3[256], s4[256]; if (rc_file) { free((char *)rc_file); rc_file = 0; } if (!color_conf) { if ((cp = getenv("HOME")) != 0) { (void)strcpy(buf, cp); (void)strcat(buf, "/"); } else buf[0] = '\0'; (void)strcat(buf, "."); (void)strcat(buf, progname); if ((fp = fopen(buf, "r")) == NULL) { (void)strcpy(buf, "/etc/"); (void)strcat(buf, progname); if ((fp = fopen(buf, "r")) == NULL) return 0; } rc_file = strdup(buf); } else { if ((fp = fopen(color_conf, "r")) == NULL) { fprintf(stderr, "%s: %s\n", color_conf, strerror(errno)); return -1; } rc_file = strdup(color_conf); } if (!rc_file) { fprintf(stderr, "init_colormask: strdup: Out of memory?\n"); (void)fclose(fp); return -1; } rc_line = 0; cm = &me; #ifdef HAVE_USE_DEFAULT_COLORS use_default_colors(); #endif while (fgets(buf, sizeof(buf), fp) != NULL) { rc_line++; if (buf[0] == '\n' || buf[0] == '#') continue; if ((cp = strchr(buf, '#')) != NULL) { *cp++ = '\n'; *cp = '\0'; } memset(cm, 0, sizeof(struct cm_entry)); num = sscanf(buf, "%s %s %s %s\n", s1, s2, s3, s4); if (num == 2) { if (strcasecmp(s1, "default")) { if ((cp = strchr(s1, '/')) != 0) { *cp++ = '\0'; if ((cp = str2proto(cp, &num)) == 0) { (void)fclose(fp); return -1; } cm->in_hdr.proto = num; } if ((num = str2port(s1, cp)) == -1) { (void)fclose(fp); return -1; } cm->in_hdr.src.ip_port = num; cm->in_hdr.dst.ip_port = 0; if (add_colormask(s2, cm) < 0) { (void)fclose(fp); return -1; } cm->in_hdr.src.ip_port = 0; cm->in_hdr.dst.ip_port = num; if (add_colormask(s2, cm) < 0) { (void)fclose(fp); return -1; } } else if (add_colormask(s2, 0) < 0) { (void)fclose(fp); return -1; } } else if (num == 3) { num = str2addr(s1, 0, &cm->in_hdr.src, &cm->src_mask); if (num == -1) { (void)fclose(fp); return -1; } cm->in_hdr.ver = num; num = str2addr(s2, 0, &cm->in_hdr.dst, &cm->dst_mask); if (num == -1) { (void)fclose(fp); return -1; } if (!cm->in_hdr.ver) { cm->in_hdr.ver = num; } else if (num && num != cm->in_hdr.ver) { fprintf(stderr, "%s: line %d: Addresses family mismatch\n", rc_file, rc_line); (void)fclose(fp); return -1; } if (add_colormask(s3, cm) < 0) { (void)fclose(fp); return -1; } } else if (num == 4) { if ((cp = str2proto(s1, &num)) == 0) { (void)fclose(fp); return -1; } cm->in_hdr.proto = num; num = str2addr(s2, cp, &cm->in_hdr.src, &cm->src_mask); if (num == -1) { (void)fclose(fp); return -1; } cm->in_hdr.ver = num; num = str2addr(s3, cp, &cm->in_hdr.dst, &cm->dst_mask); if (num == -1) { (void)fclose(fp); return -1; } if (!cm->in_hdr.ver) { cm->in_hdr.ver = num; } else if (num && num != cm->in_hdr.ver) { fprintf(stderr, "%s: line %d: Addresses family mismatch\n", rc_file, rc_line); (void)fclose(fp); return -1; } if (add_colormask(s4, cm) < 0) { (void)fclose(fp); return -1; } } else { fprintf(stderr, "%s: line %d: Bad format\n", rc_file, rc_line); (void)fclose(fp); return -1; } } (void)fclose(fp); #ifdef DEBUG for (cm = color_mask, num = 0; cm && num < n_masks; cm++, num++) { struct netstat_header nh; memset(&nh, 0, sizeof(nh)); nh.in_hdr = cm->in_hdr; hdr2str(&nh, s1, sizeof(s1), s2, sizeof(s2), s3, sizeof(s3)); fprintf(stderr, "%d:", num+1); fprintf(stderr, " proto=%s", s3); fprintf(stderr, " src=%s", s1); fprintf(stderr, " src_mask=%d", cm->src_mask); fprintf(stderr, " dst=%s", s2); fprintf(stderr, " dst_mask=%d", cm->dst_mask); fprintf(stderr, " color_pair=%d\r\n", (int)cm->pair); } fflush(stderr); pause(); #endif return n_masks; } static u_int32_t netmask(int bits) { register u_int32_t mask = 0; int i; for (i = 0; i < bits; i++) { mask >>= 1; mask |= 0x80000000L; } return (u_int32_t)htonl(mask); } int colormask(nh) const struct netstat_header *nh; { /* sanity check */ if (!nh) return A_NORMAL; if (nh->in_hdr.ver) { register const struct cm_entry *cm; int i; for (cm = color_mask, i = 0; cm && i < n_masks; cm++, i++) { /* IP version */ if (cm->in_hdr.ver) { if (nh->in_hdr.ver != cm->in_hdr.ver) continue; } /* IP protocol */ if (cm->in_hdr.proto) { if (nh->in_hdr.proto != cm->in_hdr.proto) continue; } /* IP source address */ if (cm->in_hdr.src.ip_addr.s_addr) { if (cm->src_mask) { u_int32_t mask = netmask(cm->src_mask); if ((nh->in_hdr.src.ip_addr.s_addr & mask) ^ (cm->in_hdr.src.ip_addr.s_addr & mask)) continue; } else if (nh->in_hdr.src.ip_addr.s_addr != cm->in_hdr.src.ip_addr.s_addr) continue; } /* IP source port */ if (cm->in_hdr.src.ip_port) { if (nh->in_hdr.src.ip_port != cm->in_hdr.src.ip_port) continue; } /* IP destination address */ if (cm->in_hdr.dst.ip_addr.s_addr) { if (cm->dst_mask) { u_int32_t mask = netmask(cm->dst_mask); if ((nh->in_hdr.dst.ip_addr.s_addr & mask) ^ (cm->in_hdr.dst.ip_addr.s_addr & mask)) continue; } else if (nh->in_hdr.dst.ip_addr.s_addr != cm->in_hdr.dst.ip_addr.s_addr) continue; } /* IP destination port */ if (cm->in_hdr.dst.ip_port) { if (nh->in_hdr.dst.ip_port != cm->in_hdr.dst.ip_port) continue; } #ifdef HAVE_SLCURSES return (COLOR_PAIR(cm->pair)); #else return (COLOR_PAIR(cm->pair) | cm->attr); #endif } } return A_NORMAL; } #endif /* HAVE_HAS_COLORS */