From 59b8f81283e755bf55b85ef7024572ebf5b56425 Mon Sep 17 00:00:00 2001 From: Chuck Wilson Date: Sun, 24 Dec 2017 00:10:14 -0500 Subject: [PATCH] [FEATURE] Support for Source-Specific Multicast (#802) * Support for Source-Specific Multicast * fixing whitespace issues * updating changelog --- docs/CHANGES.TXT | 4 +++ src/GUI/popups.c | 2 +- src/lib_ccx/ccx_common_option.c | 1 + src/lib_ccx/ccx_common_option.h | 1 + src/lib_ccx/ccx_demuxer.c | 2 +- src/lib_ccx/networking.c | 56 ++++++++++++++++++++++++++++++--- src/lib_ccx/networking.h | 2 +- src/lib_ccx/params.c | 19 ++++++++++- src/lib_ccx/params_dump.c | 4 ++- 9 files changed, 81 insertions(+), 10 deletions(-) diff --git a/docs/CHANGES.TXT b/docs/CHANGES.TXT index be91bdc7..13e8a26f 100644 --- a/docs/CHANGES.TXT +++ b/docs/CHANGES.TXT @@ -1,3 +1,7 @@ +0.87 +----------------- +- New: Support for source-specific multicast. + 0.86 ----------------- - New: Added a histogram in one-minute increments of the number of lines in a subtitle. diff --git a/src/GUI/popups.c b/src/GUI/popups.c index 4cc98643..8176d422 100644 --- a/src/GUI/popups.c +++ b/src/GUI/popups.c @@ -48,7 +48,7 @@ void draw_network_popup(struct nk_context *ctx, struct network_popup *network_se nk_label(ctx, "UDP:", NK_TEXT_CENTERED); nk_layout_row_static(ctx, 20, 200, 2); nk_label(ctx, "Hostname/IPv4 Address:", NK_TEXT_LEFT); - nk_edit_string(ctx, NK_EDIT_SIMPLE, network_settings->udp_ipv4, &network_settings->udp_ipv4_len, 25, nk_filter_default); + nk_edit_string(ctx, NK_EDIT_SIMPLE, network_settings->udp_ipv4, &network_settings->udp_ipv4_len, 50, nk_filter_default); nk_layout_row(ctx, NK_DYNAMIC, 21, 3, udp_tcp_ratio); nk_spacing(ctx, 1); diff --git a/src/lib_ccx/ccx_common_option.c b/src/lib_ccx/ccx_common_option.c index aac8dc4b..d68406a3 100644 --- a/src/lib_ccx/ccx_common_option.c +++ b/src/lib_ccx/ccx_common_option.c @@ -90,6 +90,7 @@ void init_options (struct ccx_s_options *options) options->debug_mask=CCX_DMT_GENERIC_NOTICES; // dbg_print will use this mask to print or ignore different types options->debug_mask_on_debug=CCX_DMT_VERBOSE; // If we're using temp_debug to enable/disable debug "live", this is the mask when temp_debug=1 /* Networking */ + options->udpsrc = NULL; options->udpaddr = NULL; options->udpport=0; // Non-zero => Listen for UDP packets on this port, no files. options->send_to_srv = 0; diff --git a/src/lib_ccx/ccx_common_option.h b/src/lib_ccx/ccx_common_option.h index 3cf803cb..9ebf826f 100644 --- a/src/lib_ccx/ccx_common_option.h +++ b/src/lib_ccx/ccx_common_option.h @@ -157,6 +157,7 @@ struct ccx_s_options // Options from user parameters LLONG debug_mask; // dbg_print will use this mask to print or ignore different types LLONG debug_mask_on_debug; // If we're using temp_debug to enable/disable debug "live", this is the mask when temp_debug=1 /* Networking */ + char *udpsrc; char *udpaddr; unsigned udpport; // Non-zero => Listen for UDP packets on this port, no files. char *tcpport; diff --git a/src/lib_ccx/ccx_demuxer.c b/src/lib_ccx/ccx_demuxer.c index c4079d3e..94bb27c7 100644 --- a/src/lib_ccx/ccx_demuxer.c +++ b/src/lib_ccx/ccx_demuxer.c @@ -78,7 +78,7 @@ static int ccx_demuxer_open(struct ccx_demuxer *ctx, const char *file) return -1; } - ctx->infd = start_upd_srv(ccx_options.udpaddr, ccx_options.udpport); + ctx->infd = start_upd_srv(ccx_options.udpsrc, ccx_options.udpaddr, ccx_options.udpport); if(ctx->infd < 0) { print_error(ccx_options.gui_mode_reports,"socket() failed."); diff --git a/src/lib_ccx/networking.c b/src/lib_ccx/networking.c index cafc9ee5..da0c1ce7 100644 --- a/src/lib_ccx/networking.c +++ b/src/lib_ccx/networking.c @@ -927,10 +927,28 @@ ssize_t read_byte(int fd, char *ch) return readn(fd, ch, 1); } -int start_upd_srv(const char *addr_str, unsigned port) +int start_upd_srv(const char *src_str, const char *addr_str, unsigned port) { init_sockets(); + in_addr_t src; + if (src_str != NULL) + { + struct hostent *host = gethostbyname(src_str); + if (NULL == host) + { + fatal(EXIT_MALFORMED_PARAMETER, "Cannot look up udp network address: %s\n", + src_str); + } + else if (host->h_addrtype != AF_INET) + { + fatal(EXIT_MALFORMED_PARAMETER, "No support for non-IPv4 network addresses: %s\n", + src_str); + } + + src = ntohl(((struct in_addr *)host->h_addr_list[0])->s_addr); + } + in_addr_t addr; if (addr_str != NULL) { @@ -1000,10 +1018,23 @@ int start_upd_srv(const char *addr_str, unsigned port) } if (IN_MULTICAST(addr)) { - struct ip_mreq group; - group.imr_multiaddr.s_addr = htonl(addr); - group.imr_interface.s_addr = htonl(INADDR_ANY); - if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&group, sizeof(group)) < 0) + int setsockopt_return = 0; + if (src_str != NULL) { + struct ip_mreq_source multicast_req; + multicast_req.imr_sourceaddr.s_addr = htonl(src); + multicast_req.imr_multiaddr.s_addr = htonl(addr); + multicast_req.imr_interface.s_addr = htonl(INADDR_ANY); + setsockopt_return = setsockopt(sockfd, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, (char *)&multicast_req, sizeof(multicast_req)); + } + else + { + struct ip_mreq multicast_req; + multicast_req.imr_multiaddr.s_addr = htonl(addr); + multicast_req.imr_interface.s_addr = htonl(INADDR_ANY); + setsockopt_return = setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&multicast_req, sizeof(multicast_req)); + } + + if (setsockopt_return < 0) { #if _WIN32 wprintf(L"setsockopt() error: %ld\n", WSAGetLastError()); @@ -1019,6 +1050,21 @@ int start_upd_srv(const char *addr_str, unsigned port) { mprint("\rReading from UDP socket %u\n", port); } + else if (src_str != NULL) + { + struct in_addr source; + struct in_addr group; + char src_ip[15]; + char addr_ip[15]; + source.s_addr = htonl(src); + memset(src_ip, 0, sizeof(char) * 15); + memcpy(src_ip, inet_ntoa(source), sizeof(src_ip)); + group.s_addr = htonl(addr); + memset(addr_ip, 0, sizeof(char) * 15); + memcpy(addr_ip, inet_ntoa(group), sizeof(addr_ip)); + + mprint("\rReading from UDP socket %s@%s:%u\n", src_ip, addr_ip, port); + } else { struct in_addr in; diff --git a/src/lib_ccx/networking.h b/src/lib_ccx/networking.h index 290fe7cd..06c40dff 100644 --- a/src/lib_ccx/networking.h +++ b/src/lib_ccx/networking.h @@ -23,6 +23,6 @@ int net_tcp_read(int socket, void *buffer, size_t length); int start_tcp_srv(const char *port, const char *pwd); -int start_upd_srv(const char *addr, unsigned port); +int start_upd_srv(const char *src, const char *addr, unsigned port); #endif /* end of include guard: NETWORKING_H */ diff --git a/src/lib_ccx/params.c b/src/lib_ccx/params.c index b16db023..a3818a46 100644 --- a/src/lib_ccx/params.c +++ b/src/lib_ccx/params.c @@ -335,6 +335,10 @@ void print_usage (void) mprint (" port) instead of reading a file. Host can be a\n"); mprint (" hostname or IPv4 address. If host is not specified\n"); mprint (" then listens on the local host.\n\n"); + mprint (" -udp [src@host:]port: Read the input via UDP (listening in the specified\n"); + mprint (" port) instead of reading a file. Host and src can be a\n"); + mprint (" hostname or IPv4 address. If host is not specified\n"); + mprint (" then listens on the local host.\n\n"); mprint (" -sendto host[:port]: Sends data in BIN format to the server\n"); mprint (" according to the CCExtractor's protocol over\n"); mprint (" TCP. For IPv6 use [address]:port\n"); @@ -2220,8 +2224,21 @@ int parse_parameters (struct ccx_s_options *opt, int argc, char *argv[]) /* Network stuff */ if (strcmp (argv[i],"-udp")==0 && iudpsrc = argv[i + 1]; + opt->udpaddr = at + 1; + opt->udpport = atoi_hex(colon + 1); + } + else if (colon) { *colon = '\0'; opt->udpaddr = argv[i + 1]; diff --git a/src/lib_ccx/params_dump.c b/src/lib_ccx/params_dump.c index 3c81e787..f6f3850e 100644 --- a/src/lib_ccx/params_dump.c +++ b/src/lib_ccx/params_dump.c @@ -18,7 +18,9 @@ void params_dump(struct lib_ccx_ctx *ctx) mprint ("stdin"); break; case CCX_DS_NETWORK: - if (ccx_options.udpaddr == NULL) + if (ccx_options.udpsrc != NULL) + mprint ("Network, %s@%s:%d", ccx_options.udpsrc, ccx_options.udpaddr, ccx_options.udpport); + else if (ccx_options.udpaddr == NULL) mprint ("Network, UDP/%u",ccx_options.udpport); else {