📄 softflowd.c
字号:
if (ft->flows_expired != 0) { fprintf(out, "Expired flow statistics: minimum average maximum\n"); fprintf(out, " Flow bytes: %12.0f %12.0f %12.0f\n", ft->octets.min, ft->octets.mean, ft->octets.max); fprintf(out, " Flow packets: %12.0f %12.0f %12.0f\n", ft->packets.min, ft->packets.mean, ft->packets.max); fprintf(out, " Duration: %12.2fs %12.2fs %12.2fs\n", ft->duration.min, ft->duration.mean, ft->duration.max); fprintf(out, "\n"); fprintf(out, "Expired flow reasons:\n"); fprintf(out, " tcp = %9llu tcp.rst = %9llu tcp.fin = %9llu\n", ft->expired_tcp, ft->expired_tcp_rst, ft->expired_tcp_fin); fprintf(out, " udp = %9llu icmp = %9llu general = %9llu\n", ft->expired_udp, ft->expired_icmp, ft->expired_general); fprintf(out, " maxlife = %9llu\n", ft->expired_maxlife); fprintf(out, " over 2Gb = %9llu\n", ft->expired_overbytes); fprintf(out, " maxflows = %9llu\n", ft->expired_maxflows); fprintf(out, " flushed = %9llu\n", ft->expired_flush); fprintf(out, "\n"); fprintf(out, "Per-protocol statistics: Octets Packets Avg Life Max Life\n"); for(i = 0; i < 256; i++) { if (ft->packets_pp[i]) { pe = getprotobynumber(i); snprintf(proto, sizeof(proto), "%s (%d)", pe != NULL ? pe->p_name : "Unknown", i); fprintf(out, " %17s: %14llu %12llu %8.2fs %10.2fs\n", proto, ft->octets_pp[i], ft->packets_pp[i], ft->duration_pp[i].mean, ft->duration_pp[i].max); } } } return (0);}static voiddump_flows(struct FLOWTRACK *ft, FILE *out){ struct EXPIRY *expiry; time_t now; now = time(NULL); EXPIRY_FOREACH(expiry, EXPIRIES, &ft->expiries) { fprintf(out, "ACTIVE %s\n", format_flow(expiry->flow)); if ((long int) expiry->expires_at - now < 0) { fprintf(out, "EXPIRY EVENT for flow %llu now%s\n", expiry->flow->flow_seq, expiry->expires_at == 0 ? " (FORCED)": ""); } else { fprintf(out, "EXPIRY EVENT for flow %llu in %ld seconds\n", expiry->flow->flow_seq, (long int) expiry->expires_at - now); } fprintf(out, "\n"); }}/* * Figure out how many bytes to skip from front of packet to get past * datalink headers. If pkt is specified, also check whether determine * whether or not it is one that we are interested in (IPv4 or IPv6 for now) * * Returns number of bytes to skip or -1 to indicate that entire * packet should be skipped */static int datalink_check(int linktype, const u_int8_t *pkt, u_int32_t caplen, int *af){ int i, j; u_int32_t frametype; static const struct DATALINK *dl = NULL; /* Try to cache last used linktype */ if (dl == NULL || dl->dlt != linktype) { for (i = 0; lt[i].dlt != linktype && lt[i].dlt != -1; i++) ; dl = <[i]; } if (dl->dlt == -1 || pkt == NULL) return (dl->dlt); if (caplen <= dl->skiplen) return (-1); /* Suck out the frametype */ frametype = 0; if (dl->ft_is_be) { for (j = 0; j < dl->ft_len; j++) { frametype <<= 8; frametype |= pkt[j + dl->ft_off]; } } else { for (j = dl->ft_len - 1; j >= 0 ; j--) { frametype <<= 8; frametype |= pkt[j + dl->ft_off]; } } frametype &= dl->ft_mask; if (frametype == dl->ft_v4) *af = AF_INET; else if (frametype == dl->ft_v6) *af = AF_INET6; else return (-1); return (dl->skiplen);}/* * Per-packet callback function from libpcap. Pass the packet (if it is IP) * sans datalink headers to process_packet. */static voidflow_cb(u_char *user_data, const struct pcap_pkthdr* phdr, const u_char *pkt){ int s, af; struct CB_CTXT *cb_ctxt = (struct CB_CTXT *)user_data; struct timeval tv; s = datalink_check(cb_ctxt->linktype, pkt, phdr->caplen, &af); if (s < 0 || (!cb_ctxt->want_v6 && af == AF_INET6)) { cb_ctxt->ft->non_ip_packets++; } else { tv.tv_sec = phdr->ts.tv_sec; tv.tv_usec = phdr->ts.tv_usec; if (process_packet(cb_ctxt->ft, pkt + s, af, phdr->caplen - s, phdr->len - s, &tv) == PP_MALLOC_FAIL) cb_ctxt->fatal = 1; }}static voidprint_timeouts(struct FLOWTRACK *ft, FILE *out){ fprintf(out, " TCP timeout: %ds\n", ft->tcp_timeout); fprintf(out, " TCP post-RST timeout: %ds\n", ft->tcp_rst_timeout); fprintf(out, " TCP post-FIN timeout: %ds\n", ft->tcp_fin_timeout); fprintf(out, " UDP timeout: %ds\n", ft->udp_timeout); fprintf(out, " ICMP timeout: %ds\n", ft->icmp_timeout); fprintf(out, " General timeout: %ds\n", ft->general_timeout); fprintf(out, " Maximum lifetime: %ds\n", ft->maximum_lifetime); fprintf(out, " Expiry interval: %ds\n", ft->expiry_interval);}static intaccept_control(int lsock, struct NETFLOW_TARGET *target, struct FLOWTRACK *ft, pcap_t *pcap, int *exit_request, int *stop_collection_flag){ unsigned char buf[64], *p; FILE *ctlf; int fd, ret; if ((fd = accept(lsock, NULL, NULL)) == -1) { logit(LOG_ERR, "ctl accept: %s - exiting", strerror(errno)); return(-1); } if ((ctlf = fdopen(fd, "r+")) == NULL) { logit(LOG_ERR, "fdopen: %s - exiting\n", strerror(errno)); close(fd); return (-1); } setlinebuf(ctlf); if (fgets(buf, sizeof(buf), ctlf) == NULL) { logit(LOG_ERR, "Control socket yielded no data"); return (0); } if ((p = strchr(buf, '\n')) != NULL) *p = '\0'; if (verbose_flag) logit(LOG_DEBUG, "Control socket \"%s\"", buf); /* XXX - use dispatch table */ ret = -1; if (strcmp(buf, "help") == 0) { fprintf(ctlf, "Valid control words are:\n"); fprintf(ctlf, "\tdebug+ debug- delete-all dump-flows exit " "expire-all\n"); fprintf(ctlf, "\tshutdown start-gather statistics stop-gather " "timeouts\n"); fprintf(ctlf, "\tsend-template\n"); ret = 0; } else if (strcmp(buf, "shutdown") == 0) { fprintf(ctlf, "softflowd[%u]: Shutting down gracefully...\n", getpid()); graceful_shutdown_request = 1; ret = 1; } else if (strcmp(buf, "exit") == 0) { fprintf(ctlf, "softflowd[%u]: Exiting now...\n", getpid()); *exit_request = 1; ret = 1; } else if (strcmp(buf, "expire-all") == 0) { netflow9_resend_template(); fprintf(ctlf, "softflowd[%u]: Expired %d flows.\n", getpid(), check_expired(ft, target, CE_EXPIRE_ALL)); ret = 0; } else if (strcmp(buf, "send-template") == 0) { netflow9_resend_template(); fprintf(ctlf, "softflowd[%u]: Template will be sent at " "next flow export\n", getpid()); ret = 0; } else if (strcmp(buf, "delete-all") == 0) { fprintf(ctlf, "softflowd[%u]: Deleted %d flows.\n", getpid(), delete_all_flows(ft)); ret = 0; } else if (strcmp(buf, "statistics") == 0) { fprintf(ctlf, "softflowd[%u]: Accumulated statistics:\n", getpid()); statistics(ft, ctlf, pcap); ret = 0; } else if (strcmp(buf, "debug+") == 0) { fprintf(ctlf, "softflowd[%u]: Debug level increased.\n", getpid()); verbose_flag = 1; ret = 0; } else if (strcmp(buf, "debug-") == 0) { fprintf(ctlf, "softflowd[%u]: Debug level decreased.\n", getpid()); verbose_flag = 0; ret = 0; } else if (strcmp(buf, "stop-gather") == 0) { fprintf(ctlf, "softflowd[%u]: Data collection stopped.\n", getpid()); *stop_collection_flag = 1; ret = 0; } else if (strcmp(buf, "start-gather") == 0) { fprintf(ctlf, "softflowd[%u]: Data collection resumed.\n", getpid()); *stop_collection_flag = 0; ret = 0; } else if (strcmp(buf, "dump-flows") == 0) { fprintf(ctlf, "softflowd[%u]: Dumping flow data:\n", getpid()); dump_flows(ft, ctlf); ret = 0; } else if (strcmp(buf, "timeouts") == 0) { fprintf(ctlf, "softflowd[%u]: Printing timeouts:\n", getpid()); print_timeouts(ft, ctlf); ret = 0; } else { fprintf(ctlf, "Unknown control commmand \"%s\"\n", buf); ret = 0; } fclose(ctlf); close(fd); return (ret);}static intconnsock(struct sockaddr_storage *addr, socklen_t len, int hoplimit){ int s; unsigned int h6; unsigned char h4; struct sockaddr_in *in4 = (struct sockaddr_in *)addr; struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)addr; if ((s = socket(addr->ss_family, SOCK_DGRAM, 0)) == -1) { fprintf(stderr, "socket() error: %s\n", strerror(errno)); exit(1); } if (connect(s, (struct sockaddr*)addr, len) == -1) { fprintf(stderr, "connect() error: %s\n", strerror(errno)); exit(1); } switch (addr->ss_family) { case AF_INET: /* Default to link-local TTL for multicast addresses */ if (hoplimit == -1 && IN_MULTICAST(in4->sin_addr.s_addr)) hoplimit = 1; if (hoplimit == -1) break; h4 = hoplimit; if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &h4, sizeof(h4)) == -1) { fprintf(stderr, "setsockopt(IP_MULTICAST_TTL, " "%u): %s\n", h4, strerror(errno)); exit(1); } break; case AF_INET6: /* Default to link-local hoplimit for multicast addresses */ if (hoplimit == -1 && IN6_IS_ADDR_MULTICAST(&in6->sin6_addr)) hoplimit = 1; if (hoplimit == -1) break; h6 = hoplimit; if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &h6, sizeof(h6)) == -1) { fprintf(stderr, "setsockopt(IPV6_MULTICAST_HOPS, %u): " "%s\n", h6, strerror(errno)); exit(1); } } return(s);}static int unix_listener(const char *path){ struct sockaddr_un addr; socklen_t addrlen; int s; memset(&addr, '\0', sizeof(addr)); addr.sun_family = AF_UNIX; if (strlcpy(addr.sun_path, path, sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) { fprintf(stderr, "control socket path too long\n"); exit(1); } addr.sun_path[sizeof(addr.sun_path) - 1] = '\0'; addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(path) + 1;#ifdef SOCK_HAS_LEN addr.sun_len = addrlen;#endif if ((s = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { fprintf(stderr, "unix domain socket() error: %s\n", strerror(errno)); exit(1); } unlink(path); if (bind(s, (struct sockaddr*)&addr, addrlen) == -1) { fprintf(stderr, "unix domain bind(\"%s\") error: %s\n", addr.sun_path, strerror(errno)); exit(1); } if (listen(s, 64) == -1) { fprintf(stderr, "unix domain listen() error: %s\n", strerror(errno)); exit(1); } return (s);}static voidsetup_packet_capture(struct pcap **pcap, int *linktype, char *dev, char *capfile, char *bpf_prog, int need_v6){ char ebuf[PCAP_ERRBUF_SIZE]; struct bpf_program prog_c; u_int32_t bpf_mask, bpf_net; /* Open pcap */ if (dev != NULL) { if ((*pcap = pcap_open_live(dev, need_v6 ? LIBPCAP_SNAPLEN_V6 : LIBPCAP_SNAPLEN_V4, 1, 0, ebuf)) == NULL) { fprintf(stderr, "pcap_open_live: %s\n", ebuf); exit(1); } if (pcap_lookupnet(dev, &bpf_net, &bpf_mask, ebuf) == -1) bpf_net = bpf_mask = 0; } else { if ((*pcap = pcap_open_offline(capfile, ebuf)) == NULL) { fprintf(stderr, "pcap_open_offline(%s): %s\n", capfile, ebuf); exit(1); } bpf_net = bpf_mask = 0; } *linktype = pcap_datalink(*pcap); if (datalink_check(*linktype, NULL, 0, NULL) == -1) { fprintf(stderr, "Unsupported datalink type %d\n", *linktype); exit(1); } /* Attach BPF filter, if specified */ if (bpf_prog != NULL) { if (pcap_compile(*pcap, &prog_c, bpf_prog, 1, bpf_mask) == -1) { fprintf(stderr, "pcap_compile(\"%s\"): %s\n", bpf_prog, pcap_geterr(*pcap)); exit(1); } if (pcap_setfilter(*pcap, &prog_c) == -1) { fprintf(stderr, "pcap_setfilter: %s\n", pcap_geterr(*pcap)); exit(1); } }#ifdef BIOCLOCK /* * If we are reading from an device (not a file), then * lock the underlying BPF device to prevent changes in the * unprivileged child */ if (dev != NULL && ioctl(pcap_fileno(*pcap), BIOCLOCK) < 0) { fprintf(stderr, "ioctl(BIOCLOCK) failed: %s\n", strerror(errno)); exit(1); }#endif}static voidinit_flowtrack(struct FLOWTRACK *ft){ /* Set up flow-tracking structure */ memset(ft, '\0', sizeof(*ft)); ft->next_flow_seq = 1; FLOW_INIT(&ft->flows); EXPIRY_INIT(&ft->expiries); ft->track_level = TRACK_FULL; ft->tcp_timeout = DEFAULT_TCP_TIMEOUT; ft->tcp_rst_timeout = DEFAULT_TCP_RST_TIMEOUT; ft->tcp_fin_timeout = DEFAULT_TCP_FIN_TIMEOUT; ft->udp_timeout = DEFAULT_UDP_TIMEOUT; ft->icmp_timeout = DEFAULT_ICMP_TIMEOUT; ft->general_timeout = DEFAULT_GENERAL_TIMEOUT; ft->maximum_lifetime = DEFAULT_MAXIMUM_LIFETIME; ft->expiry_interval = DEFAULT_EXPIRY_INTERVAL;}static char *argv_join(int argc, char **argv){ int i; size_t ret_len; char *ret; ret_len = 0; ret = NULL; for (i = 0; i < argc; i++) { ret_len += strlen(argv[i]); if ((ret = realloc(ret, ret_len + 2)) == NULL) { fprintf(stderr, "Memory allocation failed.\n"); exit(1); } if (i == 0) ret[0] = '\0'; else { ret_len++; /* Make room for ' ' */ strlcat(ret, " ", ret_len + 1); } strlcat(ret, argv[i], ret_len + 1); } return (ret);}/* Display commandline usage information */static voidusage(void){ fprintf(stderr, "Usage: %s [options] [bpf_program]\n", PROGNAME); fprintf(stderr, "This is %s version %s. Valid commandline options:\n", PROGNAME, PROGVER); fprintf(stderr, " -i interface Specify interface to listen on\n"); fprintf(stderr, " -r pcap_file Specify packet capture file to read\n"); fprintf(stderr, " -t timeout=time Specify named timeout\n"); fprintf(stderr, " -m max_flows Specify maximum number of flows to track (default %d)\n", DEFAULT_MAX_FLOWS); 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, " -v 1|5|9 NetFlow export packet version\n"); fprintf(stderr, " -L hoplimit Set TTL/hoplimit for export datagrams\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -