[PATCH net-next 06/11] selftests: net: cmsg_sender: support icmp and raw sockets

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Support sending fake ICMP(v6) messages and UDP via RAW sockets.

Signed-off-by: Jakub Kicinski <kuba@xxxxxxxxxx>
---
 tools/testing/selftests/net/cmsg_sender.c | 64 +++++++++++++++++++----
 1 file changed, 55 insertions(+), 9 deletions(-)

diff --git a/tools/testing/selftests/net/cmsg_sender.c b/tools/testing/selftests/net/cmsg_sender.c
index 4528ae638aea..edb8c427c7cb 100644
--- a/tools/testing/selftests/net/cmsg_sender.c
+++ b/tools/testing/selftests/net/cmsg_sender.c
@@ -7,7 +7,10 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <linux/icmp.h>
+#include <linux/icmpv6.h>
 #include <linux/types.h>
+#include <linux/udp.h>
 #include <sys/socket.h>
 
 enum {
@@ -27,7 +30,9 @@ struct options {
 	const char *host;
 	const char *service;
 	struct {
+		unsigned int family;
 		unsigned int type;
+		unsigned int proto;
 	} sock;
 	struct {
 		bool ena;
@@ -35,7 +40,9 @@ struct options {
 	} mark;
 } opt = {
 	.sock = {
+		.family	= AF_UNSPEC,
 		.type	= SOCK_DGRAM,
+		.proto	= IPPROTO_UDP,
 	},
 };
 
@@ -44,6 +51,10 @@ static void __attribute__((noreturn)) cs_usage(const char *bin)
 	printf("Usage: %s [opts] <dst host> <dst port / service>\n", bin);
 	printf("Options:\n"
 	       "\t\t-s      Silent send() failures\n"
+	       "\t\t-4/-6   Force IPv4 / IPv6 only\n"
+	       "\t\t-p prot Socket protocol\n"
+	       "\t\t        (u = UDP (default); i = ICMP; r = RAW)\n"
+	       "\n"
 	       "\t\t-m val  Set SO_MARK with given value\n"
 	       "");
 	exit(ERN_HELP);
@@ -53,11 +64,29 @@ static void cs_parse_args(int argc, char *argv[])
 {
 	char o;
 
-	while ((o = getopt(argc, argv, "sm:")) != -1) {
+	while ((o = getopt(argc, argv, "46sp:m:")) != -1) {
 		switch (o) {
 		case 's':
 			opt.silent_send = true;
 			break;
+		case '4':
+			opt.sock.family = AF_INET;
+			break;
+		case '6':
+			opt.sock.family = AF_INET6;
+			break;
+		case 'p':
+			if (*optarg == 'u' || *optarg == 'U') {
+				opt.sock.proto = IPPROTO_UDP;
+			} else if (*optarg == 'i' || *optarg == 'I') {
+				opt.sock.proto = IPPROTO_ICMP;
+			} else if (*optarg == 'r') {
+				opt.sock.type = SOCK_RAW;
+			} else {
+				printf("Error: unknown protocol: %s\n", optarg);
+				cs_usage(argv[0]);
+			}
+			break;
 		case 'm':
 			opt.mark.ena = true;
 			opt.mark.val = atoi(optarg);
@@ -101,6 +130,7 @@ cs_write_cmsg(struct msghdr *msg, char *cbuf, size_t cbuf_sz)
 
 int main(int argc, char *argv[])
 {
+	char buf[] = "blablablabla";
 	struct addrinfo hints, *ai;
 	struct iovec iov[1];
 	struct msghdr msg;
@@ -111,26 +141,42 @@ int main(int argc, char *argv[])
 	cs_parse_args(argc, argv);
 
 	memset(&hints, 0, sizeof(hints));
-	hints.ai_family = AF_UNSPEC;
-	hints.ai_socktype = opt.sock.type;
+	hints.ai_family = opt.sock.family;
 
 	ai = NULL;
 	err = getaddrinfo(opt.host, opt.service, &hints, &ai);
 	if (err) {
-		fprintf(stderr, "Can't resolve address [%s]:%s: %s\n",
-			opt.host, opt.service, strerror(errno));
+		fprintf(stderr, "Can't resolve address [%s]:%s\n",
+			opt.host, opt.service);
 		return ERN_SOCK_CREATE;
 	}
 
-	fd = socket(ai->ai_family, SOCK_DGRAM, IPPROTO_UDP);
+	if (ai->ai_family == AF_INET6 && opt.sock.proto == IPPROTO_ICMP)
+		opt.sock.proto = IPPROTO_ICMPV6;
+
+	fd = socket(ai->ai_family, opt.sock.type, opt.sock.proto);
 	if (fd < 0) {
 		fprintf(stderr, "Can't open socket: %s\n", strerror(errno));
 		freeaddrinfo(ai);
 		return ERN_RESOLVE;
 	}
 
-	iov[0].iov_base = "bla";
-	iov[0].iov_len = 4;
+	if (opt.sock.proto == IPPROTO_ICMP) {
+		buf[0] = ICMP_ECHO;
+		buf[1] = 0;
+	} else if (opt.sock.proto == IPPROTO_ICMPV6) {
+		buf[0] = ICMPV6_ECHO_REQUEST;
+		buf[1] = 0;
+	} else if (opt.sock.type == SOCK_RAW) {
+		struct udphdr hdr = { 1, 2, htons(sizeof(buf)), 0 };
+		struct sockaddr_in6 *sin6 = (void *)ai->ai_addr;;
+
+		memcpy(buf, &hdr, sizeof(hdr));
+		sin6->sin6_port = htons(opt.sock.proto);
+	}
+
+	iov[0].iov_base = buf;
+	iov[0].iov_len = sizeof(buf);
 
 	memset(&msg, 0, sizeof(msg));
 	msg.msg_name = ai->ai_addr;
@@ -145,7 +191,7 @@ int main(int argc, char *argv[])
 		if (!opt.silent_send)
 			fprintf(stderr, "send failed: %s\n", strerror(errno));
 		err = ERN_SEND;
-	} else if (err != 4) {
+	} else if (err != sizeof(buf)) {
 		fprintf(stderr, "short send\n");
 		err = ERN_SEND_SHORT;
 	} else {
-- 
2.34.1




[Index of Archives]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Share Photos]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux