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 { ...@@ -74,7 +74,14 @@ struct sock_args {
int use_cmsg; int use_cmsg;
const char *dev; const char *dev;
int ifindex; int ifindex;
const char *password; 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 */ /* expected addresses and device index for connection */
int expected_ifindex; int expected_ifindex;
...@@ -200,20 +207,33 @@ static void log_address(const char *desc, struct sockaddr *sa) ...@@ -200,20 +207,33 @@ static void log_address(const char *desc, struct sockaddr *sa)
fflush(stdout); 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 = strlen(args->password);
int keylen = password ? strlen(password) : 0; struct tcp_md5sig md5sig = {};
int opt = TCP_MD5SIG;
int rc; int rc;
memset(&md5sig, 0, sizeof(md5sig));
memcpy(&md5sig.tcpm_addr, addr, alen);
md5sig.tcpm_keylen = keylen; md5sig.tcpm_keylen = keylen;
memcpy(md5sig.tcpm_key, args->password, keylen);
if (keylen) if (args->prefix_len) {
memcpy(md5sig.tcpm_key, password, keylen); 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) { if (rc < 0) {
/* ENOENT is harmless. Returned when a password is cleared */ /* ENOENT is harmless. Returned when a password is cleared */
if (errno == ENOENT) if (errno == ENOENT)
...@@ -254,7 +274,7 @@ static int tcp_md5_remote(int sd, struct sock_args *args) ...@@ -254,7 +274,7 @@ static int tcp_md5_remote(int sd, struct sock_args *args)
exit(1); exit(1);
} }
if (tcp_md5sig(sd, addr, alen, args->password)) if (tcp_md5sig(sd, addr, alen, args))
return -1; return -1;
return 0; return 0;
...@@ -1313,7 +1333,7 @@ static int connectsock(void *addr, socklen_t alen, struct sock_args *args) ...@@ -1313,7 +1333,7 @@ static int connectsock(void *addr, socklen_t alen, struct sock_args *args)
if (args->type != SOCK_STREAM) if (args->type != SOCK_STREAM)
goto out; goto out;
if (args->password && tcp_md5sig(sd, addr, alen, args->password)) if (args->password && tcp_md5sig(sd, addr, alen, args))
goto err; goto err;
if (args->bind_test_only) if (args->bind_test_only)
...@@ -1405,16 +1425,18 @@ enum addr_type { ...@@ -1405,16 +1425,18 @@ enum addr_type {
ADDR_TYPE_MCAST, ADDR_TYPE_MCAST,
ADDR_TYPE_EXPECTED_LOCAL, ADDR_TYPE_EXPECTED_LOCAL,
ADDR_TYPE_EXPECTED_REMOTE, ADDR_TYPE_EXPECTED_REMOTE,
ADDR_TYPE_MD5_PREFIX,
}; };
static int convert_addr(struct sock_args *args, const char *_str, static int convert_addr(struct sock_args *args, const char *_str,
enum addr_type atype) enum addr_type atype)
{ {
int pfx_len_max = args->version == AF_INET6 ? 128 : 32;
int family = args->version; int family = args->version;
char *str, *dev, *sep;
struct in6_addr *in6; struct in6_addr *in6;
struct in_addr *in; struct in_addr *in;
const char *desc; const char *desc;
char *str, *dev;
void *addr; void *addr;
int rc = 0; int rc = 0;
...@@ -1443,6 +1465,30 @@ static int convert_addr(struct sock_args *args, const char *_str, ...@@ -1443,6 +1465,30 @@ static int convert_addr(struct sock_args *args, const char *_str,
desc = "expected remote"; desc = "expected remote";
addr = &args->expected_raddr; addr = &args->expected_raddr;
break; 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: default:
log_error("unknown address type"); log_error("unknown address type");
exit(1); exit(1);
...@@ -1522,7 +1568,7 @@ static char *random_msg(int len) ...@@ -1522,7 +1568,7 @@ static char *random_msg(int len)
return m; 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) static void print_usage(char *prog)
{ {
...@@ -1551,6 +1597,7 @@ 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 num number of times to send message\n"
"\n" "\n"
" -M password use MD5 sum protection\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" " -g grp multicast group (e.g., 239.1.1.1)\n"
" -i interactive mode (default is echo and terminate)\n" " -i interactive mode (default is echo and terminate)\n"
"\n" "\n"
...@@ -1642,6 +1689,10 @@ int main(int argc, char *argv[]) ...@@ -1642,6 +1689,10 @@ int main(int argc, char *argv[])
case 'M': case 'M':
args.password = optarg; args.password = optarg;
break; break;
case 'm':
if (convert_addr(&args, optarg, ADDR_TYPE_MD5_PREFIX) < 0)
return 1;
break;
case 'S': case 'S':
args.use_setsockopt = 1; args.use_setsockopt = 1;
break; break;
...@@ -1706,11 +1757,16 @@ int main(int argc, char *argv[]) ...@@ -1706,11 +1757,16 @@ int main(int argc, char *argv[])
} }
if (args.password && 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"); log_error("MD5 passwords apply to TCP only and require a remote ip for the password\n");
return 1; 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) { if ((args.use_setsockopt || args.use_cmsg) && !args.ifindex) {
fprintf(stderr, "Device binding not specified\n"); fprintf(stderr, "Device binding not specified\n");
return 1; 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