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;
        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)
                exit(1);
        }
 
-       if (tcp_md5sig(sd, addr, alen, args->password))
+       if (tcp_md5sig(sd, addr, alen, args))
                return -1;
 
        return 0;
        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)
        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;
 
                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);
        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)
 {
        "    -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"
                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;
        }
 
        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;