Commit eb09cf03 authored by David Ahern's avatar David Ahern Committed by David S. Miller

nettest: Add support for TCP_MD5 extensions

Update nettest to implement TCP_MD5SIG_EXT for a prefix and a device.

Add a new option, -m, to specify a prefix and length to use with MD5
auth. The device option comes from the existing -d option. If either
are set and MD5 auth is requested, TCP_MD5SIG_EXT is used instead of
TCP_MD5SIG.
Signed-off-by: default avatarDavid Ahern <dsahern@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1bfb45d8
......@@ -74,7 +74,14 @@ struct sock_args {
int use_cmsg;
const char *dev;
int ifindex;
const char *password;
/* prefix for MD5 password */
union {
struct sockaddr_in v4;
struct sockaddr_in6 v6;
} md5_prefix;
unsigned int prefix_len;
/* expected addresses and device index for connection */
int expected_ifindex;
......@@ -200,20 +207,33 @@ static void log_address(const char *desc, struct sockaddr *sa)
fflush(stdout);
}
static int tcp_md5sig(int sd, void *addr, socklen_t alen, const char *password)
static int tcp_md5sig(int sd, void *addr, socklen_t alen, struct sock_args *args)
{
struct tcp_md5sig md5sig;
int keylen = password ? strlen(password) : 0;
int keylen = strlen(args->password);
struct tcp_md5sig md5sig = {};
int opt = TCP_MD5SIG;
int rc;
memset(&md5sig, 0, sizeof(md5sig));
memcpy(&md5sig.tcpm_addr, addr, alen);
md5sig.tcpm_keylen = keylen;
memcpy(md5sig.tcpm_key, args->password, keylen);
if (keylen)
memcpy(md5sig.tcpm_key, password, keylen);
if (args->prefix_len) {
opt = TCP_MD5SIG_EXT;
md5sig.tcpm_flags |= TCP_MD5SIG_FLAG_PREFIX;
md5sig.tcpm_prefixlen = args->prefix_len;
addr = &args->md5_prefix;
}
memcpy(&md5sig.tcpm_addr, addr, alen);
rc = setsockopt(sd, IPPROTO_TCP, TCP_MD5SIG, &md5sig, sizeof(md5sig));
if (args->ifindex) {
opt = TCP_MD5SIG_EXT;
md5sig.tcpm_flags |= TCP_MD5SIG_FLAG_IFINDEX;
md5sig.tcpm_ifindex = args->ifindex;
}
rc = setsockopt(sd, IPPROTO_TCP, opt, &md5sig, sizeof(md5sig));
if (rc < 0) {
/* ENOENT is harmless. Returned when a password is cleared */
if (errno == ENOENT)
......@@ -254,7 +274,7 @@ static int tcp_md5_remote(int sd, struct sock_args *args)
exit(1);
}
if (tcp_md5sig(sd, addr, alen, args->password))
if (tcp_md5sig(sd, addr, alen, args))
return -1;
return 0;
......@@ -1313,7 +1333,7 @@ static int connectsock(void *addr, socklen_t alen, struct sock_args *args)
if (args->type != SOCK_STREAM)
goto out;
if (args->password && tcp_md5sig(sd, addr, alen, args->password))
if (args->password && tcp_md5sig(sd, addr, alen, args))
goto err;
if (args->bind_test_only)
......@@ -1405,16 +1425,18 @@ enum addr_type {
ADDR_TYPE_MCAST,
ADDR_TYPE_EXPECTED_LOCAL,
ADDR_TYPE_EXPECTED_REMOTE,
ADDR_TYPE_MD5_PREFIX,
};
static int convert_addr(struct sock_args *args, const char *_str,
enum addr_type atype)
{
int pfx_len_max = args->version == AF_INET6 ? 128 : 32;
int family = args->version;
char *str, *dev, *sep;
struct in6_addr *in6;
struct in_addr *in;
const char *desc;
char *str, *dev;
void *addr;
int rc = 0;
......@@ -1443,6 +1465,30 @@ static int convert_addr(struct sock_args *args, const char *_str,
desc = "expected remote";
addr = &args->expected_raddr;
break;
case ADDR_TYPE_MD5_PREFIX:
desc = "md5 prefix";
if (family == AF_INET) {
args->md5_prefix.v4.sin_family = AF_INET;
addr = &args->md5_prefix.v4.sin_addr;
} else if (family == AF_INET6) {
args->md5_prefix.v6.sin6_family = AF_INET6;
addr = &args->md5_prefix.v6.sin6_addr;
} else
return 1;
sep = strchr(str, '/');
if (sep) {
*sep = '\0';
sep++;
if (str_to_uint(sep, 1, pfx_len_max,
&args->prefix_len) != 0) {
fprintf(stderr, "Invalid port\n");
return 1;
}
} else {
args->prefix_len = pfx_len_max;
}
break;
default:
log_error("unknown address type");
exit(1);
......@@ -1522,7 +1568,7 @@ static char *random_msg(int len)
return m;
}
#define GETOPT_STR "sr:l:p:t:g:P:DRn:M:d:SCi6L:0:1:2:Fbq"
#define GETOPT_STR "sr:l:p:t:g:P:DRn:M:m:d:SCi6L:0:1:2:Fbq"
static void print_usage(char *prog)
{
......@@ -1551,6 +1597,7 @@ static void print_usage(char *prog)
" -n num number of times to send message\n"
"\n"
" -M password use MD5 sum protection\n"
" -m prefix/len prefix and length to use for MD5 key\n"
" -g grp multicast group (e.g., 239.1.1.1)\n"
" -i interactive mode (default is echo and terminate)\n"
"\n"
......@@ -1642,6 +1689,10 @@ int main(int argc, char *argv[])
case 'M':
args.password = optarg;
break;
case 'm':
if (convert_addr(&args, optarg, ADDR_TYPE_MD5_PREFIX) < 0)
return 1;
break;
case 'S':
args.use_setsockopt = 1;
break;
......@@ -1706,11 +1757,16 @@ int main(int argc, char *argv[])
}
if (args.password &&
(!args.has_remote_ip || args.type != SOCK_STREAM)) {
((!args.has_remote_ip && !args.prefix_len) || args.type != SOCK_STREAM)) {
log_error("MD5 passwords apply to TCP only and require a remote ip for the password\n");
return 1;
}
if (args.prefix_len && !args.password) {
log_error("Prefix range for MD5 protection specified without a password\n");
return 1;
}
if ((args.use_setsockopt || args.use_cmsg) && !args.ifindex) {
fprintf(stderr, "Device binding not specified\n");
return 1;
......
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