Репозиторий Sisyphus
Последнее обновление: 1 октября 2023 | Пакетов: 18631 | Посещений: 37536160
en ru br
Репозитории ALT

Группа :: Сети/Прочее
Пакет: nc6

 Главная   Изменения   Спек   Патчи   Sources   Загрузить   Gear   Bugs and FR  Repocop 

Патч: 02_multicast.diff
Скачать


Fix for multicast addresses in UDP mode
--- a/docs/nc6.1.in
+++ b/docs/nc6.1.in
@@ -117,6 +117,11 @@
 .I \--no-reuseaddr
 Disables the SO_REUSEADDR socket option (this is only useful in listen mode).
 .TP 13
+.I \-T, \--ttl=TTL
+Set's the IP TTL of the packets leaving (this is only useful in connect mode).
+This is mainly useful for multicast, otherwise packets will often leave with
+the OS default of 1, making it rarely useful.
+.TP 13
 .I \--nru=BYTES
 Set the miNimum Receive Unit for the remote endpoint (network receives).  Note
 that this does not mean that every network read will get the specified number
--- a/src/afindep.c
+++ b/src/afindep.c
@@ -64,6 +64,9 @@
 	struct addrinfo *res = NULL, *ptr;
 	bool connect_attempted = false;
 	char name_buf[AI_STR_SIZE];
+	const connection_attributes_t *attrs =
+		*((const connection_attributes_t **)hdata);
+	int on;
 
 	/* make sure arguments are valid and preconditions are respected */
 	assert(hints != NULL);
@@ -90,6 +93,23 @@
 		/* only accept results we can handle */
 		if (skip_address(ptr) == true) continue;
 
+		if (ptr->ai_socktype == SOCK_STREAM) {
+			if (ptr->ai_family == PF_INET) {
+				if (IN_MULTICAST(ntohl(((struct sockaddr_in *)(ptr->ai_addr))->sin_addr.s_addr))) {
+					warning("socket type STREAM and multicast bad, udp only!");
+					return -1;
+				}
+			}
+#ifdef ENABLE_IPV6
+			else if (ptr->ai_family == PF_INET6) {
+				if (IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)(ptr->ai_addr))->sin6_addr)) {
+					warning("socket type STREAM and multicast bad, udp only!");
+					return -1;
+				}
+			}
+#endif
+		}
+
 		/* we are going to try to connect to this address */
 		connect_attempted = true;
 
@@ -182,6 +202,28 @@
 			freeaddrinfo(src_res);
 		}
 
+		/* setup the ttl */
+		if ((on = ca_ttl(attrs)) > -1) {
+			if ( ptr->ai_family == PF_INET ) {
+				if (IN_MULTICAST(ntohl(((struct sockaddr_in *)(ptr->ai_addr))->sin_addr.s_addr))) {
+					setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &on, sizeof(on));
+				}
+				else {
+					setsockopt(fd, SOL_IP, IP_TTL, &on, sizeof(on));
+				}
+			}
+#ifdef ENABLE_IPV6
+			else if ( ptr->ai_family == PF_INET6 ) {
+				if (IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)(ptr->ai_addr))->sin6_addr)) {
+					setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_HOPS, &on, sizeof(on));
+				}
+				else {
+					setsockopt(fd, SOL_IPV6, IPV6_UNICAST_HOPS, &on, sizeof(on));
+				}
+			}
+#endif
+		}
+
 		/* attempt the connection */
 		err = connect_with_timeout(fd,
 				ptr->ai_addr, ptr->ai_addrlen, timeout);
@@ -250,7 +292,10 @@
 {
 	int nfd, i, fd, err, maxfd = -1;
 	struct addrinfo *res = NULL, *ptr;
+	int off = 0;
+	struct ip_mreq mreq;
 #ifdef ENABLE_IPV6
+	struct ipv6_mreq mreq6;
 	bool set_ipv6_only = false;
 	bool bound_ipv6_any = false;
 #endif
@@ -327,7 +372,24 @@
 
 		/* only accept results we can handle */
 		if (skip_address(ptr) == true) continue;
-		
+
+		if (ptr->ai_socktype == SOCK_STREAM) {
+			if (ptr->ai_family == PF_INET) {
+				if (IN_MULTICAST(ntohl(((struct sockaddr_in *)(ptr->ai_addr))->sin_addr.s_addr))) {
+					warning("socket type STREAM and multicast bad, udp only!");
+					return -1;
+				}
+			}
+#ifdef ENABLE_IPV6
+			else if (ptr->ai_family == PF_INET6) {
+				if (IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)(ptr->ai_addr))->sin6_addr)) {
+					warning("socket type STREAM and multicast bad, udp only!");
+					return -1;
+				}
+			}
+#endif
+		}
+
 		/* create the socket */
 		fd = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
 		if (fd < 0) {
@@ -414,6 +476,27 @@
 		FD_SET(fd, &accept_fdset);
 		maxfd = MAX(maxfd, fd);
 		nfd++;
+
+		if (ptr->ai_family == PF_INET) {
+			if (IN_MULTICAST(ntohl(((struct sockaddr_in *)(ptr->ai_addr))->sin_addr.s_addr))) {
+				memset(&mreq, 0, sizeof(mreq));
+				mreq.imr_multiaddr = ((struct sockaddr_in *)(ptr->ai_addr))->sin_addr;
+				mreq.imr_interface.s_addr = INADDR_ANY;
+				setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
+				setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &off, sizeof(off));
+			}
+		}
+#ifdef ENABLE_IPV6
+		else if (ptr->ai_family == PF_INET6) {
+			if (IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)(ptr->ai_addr))->sin6_addr)) {
+				memset(&mreq6, 0, sizeof(mreq6));
+				mreq6.ipv6mr_multiaddr = ((struct sockaddr_in6 *)(ptr->ai_addr))->sin6_addr;
+				mreq6.ipv6mr_interface = 0;
+				setsockopt(fd, SOL_IPV6, IPV6_JOIN_GROUP, &mreq6, sizeof(mreq));
+				setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_LOOP, &off, sizeof(off));
+			}
+		}
+#endif
 	}
 
 	freeaddrinfo(res);
--- a/src/connection.h
+++ b/src/connection.h
@@ -56,6 +56,7 @@
 	sock_protocol_t protocol;
 	address_t remote_address;
 	address_t local_address;
+	int ttl;
 	int flags;
 	size_t buffer_size;
 	size_t remote_mtu;
@@ -104,6 +105,9 @@
 #define ca_set_flag(CA, FLG)		((CA)->flags |=  (FLG))
 #define ca_clear_flag(CA, FLG)		((CA)->flags &= ~(FLG))
 
+#define ca_ttl(CA)			((CA)->ttl)
+#define ca_set_ttl(CA, SZ)		((CA)->ttl = (SZ))
+
 #define ca_buffer_size(CA)		((CA)->buffer_size)
 #define ca_set_buffer_size(CA, SZ)	((CA)->buffer_size = (SZ))
 
--- a/src/parser.c
+++ b/src/parser.c
@@ -109,7 +109,9 @@
 	{"bluetooth",           no_argument,        NULL, 'b'},
 #define OPT_SCO			24
 	{"sco",			no_argument,        NULL,  0 },
-#define OPT_MAX			25
+#define OPT_TTL			25
+	{"ttl",                 required_argument,  NULL, 'T'},
+#define OPT_MAX			26
 	{0, 0, 0, 0}
 };
 
@@ -142,6 +144,7 @@
 	int remote_hold_timeout = 0;
 	int remote_mtu = 0;
 	int remote_nru = 0;
+	int ttl = -1;
 	int buffer_size = 0;
 	int sndbuf_size = 0;
 	int rcvbuf_size = 0;
@@ -160,7 +163,7 @@
 	_verbosity_level = 0;
 
 	/* option recognition loop */
-	while ((c = getopt_long(argc, argv, "46be:hlnp:q:s:uvw:xX",
+	while ((c = getopt_long(argc, argv, "46be:T:hlnp:q:s:uvw:xX",
 	                        long_options, &option_index)) >= 0)
 	{
  		switch (c) {
@@ -296,6 +299,14 @@
 		case 'X':	
 			rev_file_transfer = true;
 			break;
+		case 'T':
+			assert(optarg != NULL);
+			if (safe_atoi(optarg, &ttl))
+				fatal(_("invalid argument to "
+				      "--ttl"));
+			if (ttl < -1 || ttl > 255 )
+				fatal(_("ttl can only be set between 0 to 255"));
+			break;
 		case '?':
 			print_usage(stderr);
 			exit(EXIT_FAILURE);
@@ -446,6 +457,11 @@
 			fatal(_("--continuous option "
 			      "must be used with --exec"));
 		}
+
+		if (ttl != -1) {
+			warning(_("setting ttl in listen mode "
+			      "is meaningless, ignoring"));
+		}
 	} else {
 		/* check port has been specified (except with sco) */
 		if (remote_address.address == NULL || 
@@ -508,11 +524,12 @@
 	if (set_local_hold_timeout == true)
 		ca_set_local_hold_timeout(attrs, local_hold_timeout);
 	
-	/* setup mtu, nru, and buffer sizes if they were specified */
+	/* setup mtu, nru, ttl, and buffer sizes if they were specified */
 	if (remote_mtu > 0)
 		ca_set_remote_MTU(attrs, remote_mtu);
 	if (remote_nru > 0)
 		ca_set_remote_NRU(attrs, remote_nru);
+	ca_set_ttl(attrs, ttl);
 	if (buffer_size > 0)
 		ca_set_buffer_size(attrs, buffer_size);
 	if (sndbuf_size > 0)
@@ -603,6 +620,7 @@
 	fprintf(fp, " -x, --transfer         %s\n", _("File transfer mode"));
 	fprintf(fp, " -X, --rev-transfer     %s\n",
 	              _("File transfer mode (reverse direction)"));
+	fprintf(fp, " -T, --ttl=TTL          %s\n", _("TTL of outgoing IP packet"));
 	fprintf(fp, "\n");
 }
 
 
дизайн и разработка: Vladimir Lettiev aka crux © 2004-2005, Andrew Avramenko aka liks © 2007-2008
текущий майнтейнер: Michael Shigorin