Commit de17e305 authored by Jakub Kicinski's avatar Jakub Kicinski Committed by David S. Miller

selftests: net: cmsg_sender: support icmp and raw sockets

Support sending fake ICMP(v6) messages and UDP via RAW sockets.
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 49b78613
...@@ -7,7 +7,10 @@ ...@@ -7,7 +7,10 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <linux/icmp.h>
#include <linux/icmpv6.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/udp.h>
#include <sys/socket.h> #include <sys/socket.h>
enum { enum {
...@@ -27,7 +30,9 @@ struct options { ...@@ -27,7 +30,9 @@ struct options {
const char *host; const char *host;
const char *service; const char *service;
struct { struct {
unsigned int family;
unsigned int type; unsigned int type;
unsigned int proto;
} sock; } sock;
struct { struct {
bool ena; bool ena;
...@@ -35,7 +40,9 @@ struct options { ...@@ -35,7 +40,9 @@ struct options {
} mark; } mark;
} opt = { } opt = {
.sock = { .sock = {
.family = AF_UNSPEC,
.type = SOCK_DGRAM, .type = SOCK_DGRAM,
.proto = IPPROTO_UDP,
}, },
}; };
...@@ -44,6 +51,10 @@ static void __attribute__((noreturn)) cs_usage(const char *bin) ...@@ -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("Usage: %s [opts] <dst host> <dst port / service>\n", bin);
printf("Options:\n" printf("Options:\n"
"\t\t-s Silent send() failures\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" "\t\t-m val Set SO_MARK with given value\n"
""); "");
exit(ERN_HELP); exit(ERN_HELP);
...@@ -53,11 +64,29 @@ static void cs_parse_args(int argc, char *argv[]) ...@@ -53,11 +64,29 @@ static void cs_parse_args(int argc, char *argv[])
{ {
char o; char o;
while ((o = getopt(argc, argv, "sm:")) != -1) { while ((o = getopt(argc, argv, "46sp:m:")) != -1) {
switch (o) { switch (o) {
case 's': case 's':
opt.silent_send = true; opt.silent_send = true;
break; 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': case 'm':
opt.mark.ena = true; opt.mark.ena = true;
opt.mark.val = atoi(optarg); opt.mark.val = atoi(optarg);
...@@ -101,6 +130,7 @@ cs_write_cmsg(struct msghdr *msg, char *cbuf, size_t cbuf_sz) ...@@ -101,6 +130,7 @@ cs_write_cmsg(struct msghdr *msg, char *cbuf, size_t cbuf_sz)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
char buf[] = "blablablabla";
struct addrinfo hints, *ai; struct addrinfo hints, *ai;
struct iovec iov[1]; struct iovec iov[1];
struct msghdr msg; struct msghdr msg;
...@@ -111,26 +141,42 @@ int main(int argc, char *argv[]) ...@@ -111,26 +141,42 @@ int main(int argc, char *argv[])
cs_parse_args(argc, argv); cs_parse_args(argc, argv);
memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; hints.ai_family = opt.sock.family;
hints.ai_socktype = opt.sock.type;
ai = NULL; ai = NULL;
err = getaddrinfo(opt.host, opt.service, &hints, &ai); err = getaddrinfo(opt.host, opt.service, &hints, &ai);
if (err) { if (err) {
fprintf(stderr, "Can't resolve address [%s]:%s: %s\n", fprintf(stderr, "Can't resolve address [%s]:%s\n",
opt.host, opt.service, strerror(errno)); opt.host, opt.service);
return ERN_SOCK_CREATE; 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) { if (fd < 0) {
fprintf(stderr, "Can't open socket: %s\n", strerror(errno)); fprintf(stderr, "Can't open socket: %s\n", strerror(errno));
freeaddrinfo(ai); freeaddrinfo(ai);
return ERN_RESOLVE; return ERN_RESOLVE;
} }
iov[0].iov_base = "bla"; if (opt.sock.proto == IPPROTO_ICMP) {
iov[0].iov_len = 4; 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)); memset(&msg, 0, sizeof(msg));
msg.msg_name = ai->ai_addr; msg.msg_name = ai->ai_addr;
...@@ -145,7 +191,7 @@ int main(int argc, char *argv[]) ...@@ -145,7 +191,7 @@ int main(int argc, char *argv[])
if (!opt.silent_send) if (!opt.silent_send)
fprintf(stderr, "send failed: %s\n", strerror(errno)); fprintf(stderr, "send failed: %s\n", strerror(errno));
err = ERN_SEND; err = ERN_SEND;
} else if (err != 4) { } else if (err != sizeof(buf)) {
fprintf(stderr, "short send\n"); fprintf(stderr, "short send\n");
err = ERN_SEND_SHORT; err = ERN_SEND_SHORT;
} else { } else {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment