diff -u2 -r softflowd-0.8.orig/common.h softflowd-0.8/common.h --- softflowd-0.8.orig/common.h Wed Oct 30 13:21:14 2002 +++ softflowd-0.8/common.h Tue Jun 3 14:38:10 2003 @@ -32,4 +32,5 @@ #include #include +#include #include @@ -40,4 +41,10 @@ #include #include +#include +#ifdef HAVE_NET_ETHERNET_H +#include +#else +#include +#endif #include diff -u2 -r softflowd-0.8.orig/softflowd.8 softflowd-0.8/softflowd.8 --- softflowd-0.8.orig/softflowd.8 Thu Oct 31 10:48:02 2002 +++ softflowd-0.8/softflowd.8 Tue Jun 24 11:33:56 2003 @@ -40,4 +40,7 @@ .Op Fl p Ar pidfile .Op Fl c Ar ctl_sock +.Op Fl x Ar ifindex +.Op Fl M Ar mac_addr +.Op Fl b Ar src_ip .Op bpf_program .Sh DESCRIPTION @@ -129,5 +132,5 @@ Specify an alternate location for the remote control socket in daemon mode. Default is -.Pa /var/run/softflowd.pid +.Pa /var/run/softflowd.ctl .It Fl m Ar max_flows Specifies the maximum number of flow to concurrently track. If this limit @@ -159,4 +162,12 @@ .Fl d flag and turns on additional debugging output. +.It Fl x Ar ifindex +Set the ifindex for the interface. +May be omitted if softflowd can autodetect it (under linux). +.It Fl M Ar mac-addr +Set the mac-address for the interface. +May be omitted if softflowd can autodetect it (under linux). +.It Fl b Ar src-ip +Set the source IP-address for flow packets. .It Fl h Displays commandline usage information. diff -u2 -r softflowd-0.8.orig/softflowd.c softflowd-0.8/softflowd.c --- softflowd-0.8.orig/softflowd.c Thu Oct 31 10:48:12 2002 +++ softflowd-0.8/softflowd.c Tue Jun 24 11:38:10 2003 @@ -109,5 +109,8 @@ unsigned int num_flows; /* # of active flows */ u_int64_t next_flow_seq; /* Next flow ID */ - + + unsigned short ifindex; /* interface index */ + unsigned char mymac[ETHER_ADDR_LEN]; + /* Flow timeouts */ int tcp_timeout; /* Open TCP connections */ @@ -174,4 +177,5 @@ u_int32_t addr[2]; /* Endpoint addresses */ u_int16_t port[2]; /* Endpoint ports */ + u_int16_t iface[2]; /* Endpoint interfaces */ u_int8_t tcp_flags[2]; /* Cumulative OR of flags */ u_int8_t protocol; /* Protocol */ @@ -238,4 +242,117 @@ (NF1_MAXFLOWS * sizeof(struct NF1_FLOW))) +#ifdef DLT_LINUX_SLL +struct sll_header { + u_int16_t sll_pkttype; /* packet type */ + u_int16_t sll_hatype; /* link-layer address type */ + u_int16_t sll_halen; /* link-layer address length */ + u_int8_t sll_addr[8]; /* link-layer address */ + u_int16_t sll_protocol; /* protocol */ +}; +#endif + +#if defined(__linux__) +#define get_ifindex(iface) if_nametoindex(iface) +#elif defined(SIOCGIFINDEX) +static short get_ifindex(const char *iface) +{ + struct ifreq ifr; + int rc = 0; + int fd = socket(PF_INET, SOCK_DGRAM, 0); + if (fd < 0) return 0; + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, iface); + if (ioctl(fd, SIOCGIFINDEX, &ifr) == 0) + rc = ifr.ifr_ifindex; + close(fd); + return rc; +} +#elif defined(SIOCGIFGENERIC) +static short get_ifindex(const char *iface) +{ + struct ifreq ifr; + int rc = 0; + int fd = socket(PF_INET, SOCK_DGRAM, 0); + if (fd < 0) return 0; + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, iface); + if (ioctl(fd, SIOCGIFGENERIC, &ifr) == 0) + rc = ifr.ifr_ifindex; + close(fd); + return rc; +} +#else +#define get_ifindex(iface) 0 +#endif + +#if defined(SIOCGIFHWADDR) +static int get_mac(const char *iface, unsigned char *mac) +{ + struct ifreq ifr; + int rc = 0; + int fd = socket(PF_INET, SOCK_DGRAM, 0); + if (fd < 0) return -1; + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, iface); + if (ioctl(fd, SIOCGIFHWADDR, &ifr) == 0 && + ifr.ifr_hwaddr.sa_family == 1 /* ARPHRD_ETHER */) + memcpy(mac, ifr.ifr_hwaddr.sa_data, ETHER_ADDR_LEN); + else rc = -1; + close(fd); + return rc; +} +#elif defined(SIOCGIFPHYS) +static int get_mac(const char *iface, unsigned char *mac) +{ + struct ifreq ifr; + int rc = 0; + int fd = socket(PF_INET, SOCK_DGRAM, 0); + if (fd < 0) return -1; + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, iface); + if (ioctl(fd, SIOCGIFPHYS, &ifr) == 0 && + ifr.ifr_hwaddr.sa_family == 1 /* ARPHRD_ETHER */) + memcpy(mac, ifr.ifr_hwaddr.sa_data, ETHER_ADDR_LEN); + else rc = -1; + close(fd); + return rc; +} +#else +#define get_mac(iface, mac) 0 +#endif + +static int parse_macaddr(char *str, unsigned char *mac) +{ + unsigned short int m[6]; + + if (sscanf(str,"%hx:%hx:%hx:%hx:%hx:%hx",m,m+1,m+2,m+3,m+4,m+5) == 6) { + if (((m[0]|m[1]|m[2]|m[3]|m[4]|m[5]) & 0xff00) != 0) + return -1; + mac[0] = (unsigned char)m[0]; + mac[1] = (unsigned char)m[1]; + mac[2] = (unsigned char)m[2]; + mac[3] = (unsigned char)m[3]; + mac[4] = (unsigned char)m[4]; + mac[5] = (unsigned char)m[5]; + return 0; + } + if (sscanf(str, "%04hx.%04hx.%04hx", m, m+1, m+2) != 3) + return -1; +#if 0 + m[0] = htons(m[0]); + m[1] = htons(m[1]); + m[2] = htons(m[2]); + memcpy(mac, m, 6); +#else + mac[0] = (unsigned char)(m[0]>>8); + mac[1] = (unsigned char)m[0]; + mac[2] = (unsigned char)(m[1]>>8); + mac[3] = (unsigned char)m[1]; + mac[4] = (unsigned char)(m[2]>>8); + mac[5] = (unsigned char)m[2]; +#endif + return 0; +} + /* Signal handlers */ static void sighand_graceful_shutdown(int signum) @@ -335,8 +452,9 @@ snprintf(buf, sizeof(buf), - "seq:%llu %s:%hu <> %s:%hu proto:%u octets>:%u packets>:%u octets<:%u packets<:%u start:%s.%03ld finish:%s.%03ld tcp>:%02x tcp<:%02x", + "seq:%llu %s:%hu <> %s:%hu proto:%u iface:%hu<>%hu octets>:%u packets>:%u octets<:%u packets<:%u start:%s.%03ld finish:%s.%03ld tcp>:%02x tcp<:%02x", flow->flow_seq, addr1, ntohs(flow->port[0]), addr2, ntohs(flow->port[1]), (int)flow->protocol, + ntohs(flow->iface[0]), ntohs(flow->iface[1]), flow->octets[0], flow->packets[0], flow->octets[1], flow->packets[1], @@ -374,5 +492,5 @@ static int packet_to_flowrec(struct FLOW *flow, const u_int8_t *pkt, - const size_t caplen, const size_t len) + const size_t caplen, const size_t len, const int out, const short ifindex) { const struct ip *ip = (const struct ip *)pkt; @@ -396,4 +514,10 @@ flow->octets[ndx] = len; flow->packets[ndx] = 1; + if (out & ~1) + flow->iface[0] = flow->iface[1] = 0; + else { + flow->iface[out ^ ndx] = ifindex; + flow->iface[out ^ ndx ^ 1] = 0; + } switch (ip->ip_p) { @@ -495,5 +619,5 @@ process_packet(struct FLOWTRACK *ft, const u_int8_t *pkt, const u_int32_t caplen, const u_int32_t len, - const struct timeval *received_time) + const struct timeval *received_time, const int out) { struct FLOW tmp, *flow; @@ -502,5 +626,5 @@ /* Convert the IP packet to a flow identity */ - if (packet_to_flowrec(&tmp, pkt, caplen, len) == -1) { + if (packet_to_flowrec(&tmp, pkt, caplen, len, out, ft->ifindex) == -1) { ft->bad_packets++; return (PP_BAD_PACKET); @@ -625,4 +749,6 @@ syslog(LOG_DEBUG, "Flow %d of %d 0>1", i, num_flows); #endif + flw->if_index_in = flows[i]->iface[0]; + flw->if_index_out = flows[i]->iface[1]; flw->src_ip = flows[i]->addr[0]; flw->dest_ip = flows[i]->addr[1]; @@ -646,4 +772,6 @@ syslog(LOG_DEBUG, "Flow %d of %d 1<0", i, num_flows); #endif + flw->if_index_in = flows[i]->iface[1]; + flw->if_index_out = flows[i]->iface[0]; flw->src_ip = flows[i]->addr[1]; flw->dest_ip = flows[i]->addr[0]; @@ -1022,4 +1150,9 @@ skiplen = 4; break; +#ifdef DLT_LINUX_SLL + case DLT_LINUX_SLL: + skiplen = 16; + break; +#endif default: skiplen = -1; @@ -1051,8 +1184,14 @@ #ifdef DLT_LOOP case DLT_LOOP: -#endif if (ntohl(*(const u_int32_t*)pkt) != AF_INET) skiplen = -1; break; +#endif +#ifdef DLT_LINUX_SLL + case DLT_LINUX_SLL: + if (htons(*(const u_int16_t*)(pkt + 14)) != 0x0800) + skiplen = -1; + break; +#endif case DLT_RAW: /* XXX: untested */ @@ -1076,11 +1215,30 @@ int s; struct CB_CTXT *cb_ctxt = (struct CB_CTXT *)user_data; + int out = -1; if ((s = datalink_skip(cb_ctxt->linktype, pkt, phdr->caplen)) == -1) { cb_ctxt->ft->non_ip_packets++; } else { + /* detect direction */ + if (cb_ctxt->linktype == DLT_EN10MB) { + const struct ether_header *eth_hdr; + eth_hdr = (const struct ether_header*)pkt; + if (memcmp(eth_hdr->ether_shost, cb_ctxt->ft->mymac, ETHER_ADDR_LEN) == 0) + out = 1; + else if (memcmp(eth_hdr->ether_dhost, cb_ctxt->ft->mymac, ETHER_ADDR_LEN) == 0) + out = 0; +#ifdef DLT_LINUX_SLL + } else if (cb_ctxt->linktype == DLT_LINUX_SLL) { + const struct sll_header *sll_hdr; + sll_hdr = (const struct sll_header*)pkt; + if (sll_hdr->sll_pkttype == 4) // LINUX_SLL_OUTGOING + out = 1; + else if (sll_hdr->sll_pkttype == 0) // LINUX_SLL_HOST + out = 0; +#endif + } if (process_packet(cb_ctxt->ft, pkt + s, phdr->caplen - s, phdr->len - s, - (const struct timeval *)&phdr->ts) == PP_MALLOC_FAIL) + (const struct timeval *)&phdr->ts, out) == PP_MALLOC_FAIL) cb_ctxt->fatal = 1; } @@ -1142,5 +1300,5 @@ static int -connsock(struct sockaddr_in *addr) +connsock(struct sockaddr_in *addr, struct in_addr *bindaddr) { int s; @@ -1151,4 +1309,17 @@ exit(1); } + if (bindaddr != INADDR_ANY) { + struct sockaddr_in bind_addr; + memset(&bind_addr, 0, sizeof(bind_addr)); +#ifdef SOCK_HAS_LEN + bind_addr.sin_len = sizeof(bind_addr); +#endif + memcpy(&bind_addr.sin_addr, bindaddr, sizeof(*bindaddr)); + bind_addr.sin_family = AF_INET; + if (bind(s,(struct sockaddr*)&bind_addr,sizeof(bind_addr))==-1){ + fprintf(stderr, "bind() error: %s\n", strerror(errno)); + exit(1); + } + } if (connect(s, (struct sockaddr*)addr, sizeof(*addr)) == -1) { fprintf(stderr, "connect() error: %s\n", @@ -1260,4 +1431,6 @@ ft->general_timeout = DEFAULT_GENERAL_TIMEOUT; ft->maximum_lifetime = DEFAULT_MAXIMUM_LIFETIME; + ft->ifindex = 0; + memset(ft->mymac, 0, ETHER_ADDR_LEN); } @@ -1313,7 +1486,10 @@ fprintf(stderr, " -n host:port Send Cisco NetFlow(tm)-compatible packets to host:port\n"); fprintf(stderr, " -p pidfile Record pid in specified file (default: %s)\n", DEFAULT_PIDFILE); - fprintf(stderr, " -c pidfile Location of control socket (default: %s)\n", DEFAULT_CTLSOCK); + fprintf(stderr, " -c ctlfile Location of control socket (default: %s)\n", DEFAULT_CTLSOCK); fprintf(stderr, " -d Don't daemonise\n"); fprintf(stderr, " -D Debug mode: don't daemonise + verbosity\n"); + fprintf(stderr, " -x num Set ifindex for the interface\n"); + fprintf(stderr, " -M mac-addr Specify mac-address for the interface\n"); + fprintf(stderr, " -b src-ip Specify source IP for flow packets\n"); fprintf(stderr, " -h Display this help\n"); fprintf(stderr, "\n"); @@ -1416,4 +1592,5 @@ struct sockaddr_in dest; time_t next_expiry_check; + struct in_addr *bindaddr; memset(&dest, '\0', sizeof(dest)); @@ -1421,4 +1598,5 @@ dest.sin_len = sizeof(dest); #endif + bindaddr = INADDR_ANY; init_flowtrack(&flowtrack); @@ -1431,5 +1609,5 @@ ctlsock_path = DEFAULT_CTLSOCK; dontfork_flag = 0; - while ((ch = getopt(argc, argv, "hdDi:r:f:t:n:m:p:c:")) != -1) { + while ((ch = getopt(argc, argv, "hdDi:r:f:t:n:m:p:c:x:M:b:")) != -1) { switch (ch) { case 'h': @@ -1484,4 +1662,17 @@ ctlsock_path = optarg; break; + case 'x': + flowtrack.ifindex = htons((short)atoi(optarg)); + break; + case 'M': + parse_macaddr(optarg, flowtrack.mymac); + break; + case 'b': + if (inet_aton(optarg, bindaddr) == 0) { + fprintf(stderr, "Invalid bind address %s\n\n", optarg); + usage(); + exit(1); + } + break; default: fprintf(stderr, "Invalid commandline option.\n"); @@ -1505,5 +1696,5 @@ /* Netflow send socket */ if (dest.sin_family != 0) - nfsock = connsock(&dest); /* Will exit on fail */ + nfsock = connsock(&dest, bindaddr); /* Will exit on fail */ /* Control socket */ @@ -1532,5 +1723,19 @@ } - syslog(LOG_NOTICE, "%s v%s starting data collection", PROGNAME, PROGVER); + syslog(LOG_NOTICE, "%s v%s starting data collection", PROGNAME,PROGVER); + + if (capfile == NULL) { + if (flowtrack.ifindex == 0) { + flowtrack.ifindex = htons(get_ifindex(dev)); + syslog(LOG_NOTICE, "IfIndex for %s is %hd", dev, ntohs(flowtrack.ifindex)); + } + if (linktype == DLT_EN10MB && + memcmp(&flowtrack.mymac, "\0\0\0\0\0\0", 6) == 0) { + if (get_mac(dev, flowtrack.mymac) == 0) + syslog(LOG_NOTICE, "MacAddr on %s is %02x%02x.%02x%02x.%02x%02x", dev, flowtrack.mymac[0], flowtrack.mymac[1], flowtrack.mymac[2], flowtrack.mymac[3], flowtrack.mymac[4], flowtrack.mymac[5]); + else + syslog(LOG_NOTICE, "Can't get mac-address for %s", dev); + } + } /* Main processing loop */