selftests: net: cmsg_sender: support icmp and raw sockets
Support sending fake ICMP(v6) messages and UDP via RAW sockets. Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
49b7861302
commit
de17e305a8
1 changed files with 55 additions and 9 deletions
|
@ -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 {
|
||||||
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 {
|
||||||
} 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)
|
||||||
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[])
|
||||||
{
|
{
|
||||||
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)
|
||||||
|
|
||||||
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[])
|
||||||
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[])
|
||||||
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 {
|
||||||
|
|
Loading…
Add table
Reference in a new issue