Logo Search packages:      
Sourcecode: netdiag version File versions

colormask.c

/*
 *    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 <config.h>
#endif

#ifdef      HAVE_HAS_COLORS

#ifdef      HAVE_SLCURSES
#include <slcurses.h>
#elif HAVE_NCURSES
#include <ncurses.h>
#else
#include <curses.h>
#endif
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <netdb.h>
#include <errno.h>

#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 */

Generated by  Doxygen 1.6.0   Back to index