364 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			364 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * Copyright (c) 2017-2018 The strace developers.
 | |
|  * All rights reserved.
 | |
|  *
 | |
|  * Redistribution and use in source and binary forms, with or without
 | |
|  * modification, are permitted provided that the following conditions
 | |
|  * are met:
 | |
|  * 1. Redistributions of source code must retain the above copyright
 | |
|  *    notice, this list of conditions and the following disclaimer.
 | |
|  * 2. Redistributions in binary form must reproduce the above copyright
 | |
|  *    notice, this list of conditions and the following disclaimer in the
 | |
|  *    documentation and/or other materials provided with the distribution.
 | |
|  * 3. The name of the author may not be used to endorse or promote products
 | |
|  *    derived from this software without specific prior written permission.
 | |
|  *
 | |
|  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 | |
|  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | |
|  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 | |
|  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 | |
|  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | |
|  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | |
|  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | |
|  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | |
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | |
|  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
|  */
 | |
| 
 | |
| #include "tests.h"
 | |
| #include "print_fields.h"
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <stdint.h>
 | |
| #include <string.h>
 | |
| #include <sys/socket.h>
 | |
| #include "netlink.h"
 | |
| #include <linux/rtnetlink.h>
 | |
| 
 | |
| static void
 | |
| init_nlattr(struct nlattr *const nla,
 | |
| 	    const uint16_t nla_len,
 | |
| 	    const uint16_t nla_type,
 | |
| 	    const void *const src,
 | |
| 	    const size_t n)
 | |
| {
 | |
| 	SET_STRUCT(struct nlattr, nla,
 | |
| 		.nla_len = nla_len,
 | |
| 		.nla_type = nla_type,
 | |
| 	);
 | |
| 
 | |
| 	memcpy(RTA_DATA(nla), src, n);
 | |
| }
 | |
| 
 | |
| static void
 | |
| print_nlattr(const unsigned int nla_len, const char *const nla_type, bool add_data)
 | |
| {
 | |
| 	printf(", %s{{nla_len=%u, nla_type=%s}, ",
 | |
| 	       add_data ? "[" : "", nla_len, nla_type);
 | |
| }
 | |
| 
 | |
| #define TEST_NLATTR_EX_(fd_, nlh0_, hdrlen_,				\
 | |
| 		     init_msg_, print_msg_,				\
 | |
| 		     nla_type_, nla_type_str_,				\
 | |
| 		     nla_data_len_, nla_total_len_,			\
 | |
| 		     src_, slen_, ...)					\
 | |
| 	do {								\
 | |
| 		struct nlmsghdr *const nlh =				\
 | |
| 			(nlh0_) - (NLA_HDRLEN + (slen_));		\
 | |
| 		struct nlattr *const TEST_NLATTR_nla =			\
 | |
| 			NLMSG_ATTR(nlh, (hdrlen_));			\
 | |
| 		const unsigned int nla_len =				\
 | |
| 			NLA_HDRLEN + (nla_data_len_);			\
 | |
| 		const unsigned int msg_len =				\
 | |
| 			NLMSG_SPACE(hdrlen_) + NLA_HDRLEN + (nla_total_len_); \
 | |
| 									\
 | |
| 		(init_msg_)(nlh, msg_len);				\
 | |
| 		init_nlattr(TEST_NLATTR_nla, nla_len, (nla_type_),	\
 | |
| 			   (src_), (slen_));				\
 | |
| 									\
 | |
| 		const char *const errstr =				\
 | |
| 			sprintrc(sendto((fd_), nlh, msg_len,		\
 | |
| 					MSG_DONTWAIT, NULL, 0));	\
 | |
| 									\
 | |
| 		printf("sendto(%d, {", (fd_));				\
 | |
| 		(print_msg_)(msg_len);					\
 | |
| 		print_nlattr(nla_len, (nla_type_str_),			\
 | |
| 			     (nla_total_len_) > (nla_data_len_));	\
 | |
| 									\
 | |
| 		{ __VA_ARGS__; }					\
 | |
| 									\
 | |
| 		if ((nla_total_len_) > (nla_data_len_))			\
 | |
| 			printf("]");					\
 | |
| 									\
 | |
| 		printf("}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",		\
 | |
| 		       msg_len, errstr);				\
 | |
| 	} while (0)
 | |
| 
 | |
| #define TEST_NLATTR_(fd_, nlh0_, hdrlen_,				\
 | |
| 		     init_msg_, print_msg_,				\
 | |
| 		     nla_type_, nla_type_str_,				\
 | |
| 		     nla_data_len_, src_, slen_, ...)			\
 | |
| 	TEST_NLATTR_EX_((fd_), (nlh0_), (hdrlen_),			\
 | |
| 			(init_msg_), (print_msg_),			\
 | |
| 			(nla_type_), (nla_type_str_),			\
 | |
| 			(nla_data_len_), (nla_data_len_),		\
 | |
| 			(src_), (slen_), __VA_ARGS__)
 | |
| 
 | |
| #define TEST_NLATTR(fd_, nlh0_, hdrlen_,				\
 | |
| 		    init_msg_, print_msg_,				\
 | |
| 		    nla_type_,						\
 | |
| 		    nla_data_len_, src_, slen_, ...)			\
 | |
| 	TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),				\
 | |
| 		(init_msg_), (print_msg_),				\
 | |
| 		(nla_type_), #nla_type_,				\
 | |
| 		(nla_data_len_), (src_), (slen_), __VA_ARGS__)
 | |
| 
 | |
| #define TEST_NLATTR_OBJECT_EX_(fd_, nlh0_, hdrlen_,			\
 | |
| 			       init_msg_, print_msg_,			\
 | |
| 			       nla_type_, nla_type_str_,		\
 | |
| 			       pattern_, obj_, fallback_func, ...)	\
 | |
| 	do {								\
 | |
| 		const unsigned int plen =				\
 | |
| 			sizeof(obj_) - 1 > DEFAULT_STRLEN		\
 | |
| 			? DEFAULT_STRLEN : (int) sizeof(obj_) - 1;	\
 | |
| 		/* len < sizeof(obj_) */				\
 | |
| 		if (plen > 0)						\
 | |
| 			TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),		\
 | |
| 				(init_msg_), (print_msg_),		\
 | |
| 				(nla_type_), (nla_type_str_),		\
 | |
| 				plen, (pattern_), plen,			\
 | |
| 				(fallback_func)((pattern_), plen));	\
 | |
| 		/* short read of sizeof(obj_) */			\
 | |
| 		TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),			\
 | |
| 			(init_msg_), (print_msg_),			\
 | |
| 			(nla_type_), (nla_type_str_),			\
 | |
| 			sizeof(obj_),					\
 | |
| 			(pattern_), sizeof(obj_) - 1,			\
 | |
| 			printf("%p",					\
 | |
| 			       RTA_DATA(NLMSG_ATTR(nlh, (hdrlen_)))));	\
 | |
| 		/* sizeof(obj_) */					\
 | |
| 		TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),			\
 | |
| 			(init_msg_), (print_msg_),			\
 | |
| 			(nla_type_), (nla_type_str_),			\
 | |
| 			sizeof(obj_),					\
 | |
| 			&(obj_), sizeof(obj_),				\
 | |
| 			__VA_ARGS__);					\
 | |
| 	} while (0)
 | |
| 
 | |
| #define TEST_NLATTR_OBJECT_EX(fd_, nlh0_, hdrlen_,			\
 | |
| 			      init_msg_, print_msg_,			\
 | |
| 			      nla_type_,				\
 | |
| 			      pattern_, obj_, fallback_func, ...)	\
 | |
| 	TEST_NLATTR_OBJECT_EX_((fd_), (nlh0_), (hdrlen_),		\
 | |
| 			       (init_msg_), (print_msg_),		\
 | |
| 			       (nla_type_), #nla_type_,			\
 | |
| 			       (pattern_), (obj_), (fallback_func),	\
 | |
| 			       __VA_ARGS__)
 | |
| 
 | |
| #define TEST_NLATTR_OBJECT(fd_, nlh0_, hdrlen_,				\
 | |
| 			   init_msg_, print_msg_,			\
 | |
| 			   nla_type_, pattern_, obj_, ...)		\
 | |
| 	TEST_NLATTR_OBJECT_EX_((fd_), (nlh0_), (hdrlen_),		\
 | |
| 			       (init_msg_), (print_msg_),		\
 | |
| 			       (nla_type_), #nla_type_,			\
 | |
| 			       (pattern_), (obj_), print_quoted_hex,	\
 | |
| 			       __VA_ARGS__)
 | |
| 
 | |
| #define TEST_NLATTR_ARRAY(fd_, nlh0_, hdrlen_,				\
 | |
| 			  init_msg_, print_msg_,			\
 | |
| 			  nla_type_, pattern_, obj_, print_elem_)	\
 | |
| 	do {								\
 | |
| 		const unsigned int plen =				\
 | |
| 			sizeof((obj_)[0]) - 1 > DEFAULT_STRLEN		\
 | |
| 			? DEFAULT_STRLEN : (int) sizeof((obj_)[0]) - 1;	\
 | |
| 		/* len < sizeof((obj_)[0]) */				\
 | |
| 		TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),			\
 | |
| 			(init_msg_), (print_msg_),			\
 | |
| 			(nla_type_), #nla_type_,			\
 | |
| 			plen, (pattern_), plen,				\
 | |
| 			print_quoted_hex((pattern_), plen));		\
 | |
| 		/* sizeof((obj_)[0]) < len < sizeof(obj_) */		\
 | |
| 		TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),			\
 | |
| 			(init_msg_), (print_msg_),			\
 | |
| 			(nla_type_), #nla_type_,			\
 | |
| 			sizeof(obj_) - 1,				\
 | |
| 			&(obj_), sizeof(obj_) - 1,			\
 | |
| 			printf("[");					\
 | |
| 			size_t i;					\
 | |
| 			for (i = 0; i < ARRAY_SIZE(obj_) - 1; ++i) {	\
 | |
| 				if (i) printf(", ");			\
 | |
| 				(print_elem_)(&(obj_)[i], i);		\
 | |
| 			}						\
 | |
| 			printf("]"));					\
 | |
| 		/* short read of sizeof(obj_) */			\
 | |
| 		TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),			\
 | |
| 			(init_msg_), (print_msg_),			\
 | |
| 			(nla_type_), #nla_type_,			\
 | |
| 			sizeof(obj_),					\
 | |
| 			&(obj_), sizeof(obj_) - 1,			\
 | |
| 			printf("[");					\
 | |
| 			size_t i;					\
 | |
| 			for (i = 0; i < ARRAY_SIZE(obj_) - 1; ++i) {	\
 | |
| 				if (i) printf(", ");			\
 | |
| 				(print_elem_)(&(obj_)[i], i);		\
 | |
| 			}						\
 | |
| 			printf(", ... /* %p */]",			\
 | |
| 			       RTA_DATA(NLMSG_ATTR(nlh, (hdrlen_)))	\
 | |
| 			        + sizeof(obj_) - sizeof((obj_)[0])));	\
 | |
| 		/* sizeof(obj_) */					\
 | |
| 		TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),			\
 | |
| 			(init_msg_), (print_msg_),			\
 | |
| 			(nla_type_), #nla_type_,			\
 | |
| 			sizeof(obj_),					\
 | |
| 			&(obj_), sizeof(obj_),				\
 | |
| 			printf("[");					\
 | |
| 			size_t i;					\
 | |
| 			for (i = 0; i < ARRAY_SIZE(obj_); ++i) {	\
 | |
| 				if (i) printf(", ");			\
 | |
| 				(print_elem_)(&(obj_)[i], i);		\
 | |
| 			}						\
 | |
| 			printf("]"));					\
 | |
| 	} while (0)
 | |
| 
 | |
| #define TEST_NESTED_NLATTR_OBJECT_EX_(fd_, nlh0_, hdrlen_,		\
 | |
| 				      init_msg_, print_msg_,		\
 | |
| 				      nla_type_, nla_type_str_,		\
 | |
| 				      pattern_, obj_, fallback_func,	\
 | |
| 				      depth_, ...)	\
 | |
| 	do {								\
 | |
| 		const unsigned int plen =				\
 | |
| 			sizeof(obj_) - 1 > DEFAULT_STRLEN		\
 | |
| 			? DEFAULT_STRLEN : (int) sizeof(obj_) - 1;	\
 | |
| 		/* len < sizeof(obj_) */				\
 | |
| 		if (plen > 0)						\
 | |
| 			TEST_NLATTR_((fd_), (nlh0_) - NLA_HDRLEN * depth_, \
 | |
| 				(hdrlen_) + NLA_HDRLEN * depth_,	\
 | |
| 				(init_msg_), (print_msg_),		\
 | |
| 				(nla_type_), (nla_type_str_),		\
 | |
| 				plen, (pattern_), plen,			\
 | |
| 				(fallback_func)((pattern_), plen);	\
 | |
| 				size_t i;				\
 | |
| 				for (i = 0; i < depth_; ++i)		\
 | |
| 					printf("}"));			\
 | |
| 		/* short read of sizeof(obj_) */			\
 | |
| 		TEST_NLATTR_((fd_), (nlh0_) - NLA_HDRLEN * depth_,	\
 | |
| 			(hdrlen_) + NLA_HDRLEN * depth_,		\
 | |
| 			(init_msg_), (print_msg_),			\
 | |
| 			(nla_type_), (nla_type_str_),			\
 | |
| 			sizeof(obj_),					\
 | |
| 			(pattern_), sizeof(obj_) - 1,			\
 | |
| 			printf("%p", RTA_DATA(TEST_NLATTR_nla));	\
 | |
| 			size_t i;					\
 | |
| 			for (i = 0; i < depth_; ++i)			\
 | |
| 				printf("}"));				\
 | |
| 		/* sizeof(obj_) */					\
 | |
| 		TEST_NLATTR_((fd_), (nlh0_) - NLA_HDRLEN * depth_,	\
 | |
| 			(hdrlen_) + NLA_HDRLEN * depth_,		\
 | |
| 			(init_msg_), (print_msg_),			\
 | |
| 			(nla_type_), (nla_type_str_),			\
 | |
| 			sizeof(obj_),					\
 | |
| 			&(obj_), sizeof(obj_),				\
 | |
| 			__VA_ARGS__;					\
 | |
| 			size_t i;					\
 | |
| 			for (i = 0; i < depth_; ++i)			\
 | |
| 				printf("}"));				\
 | |
| 	} while (0)
 | |
| 
 | |
| #define TEST_NESTED_NLATTR_OBJECT_EX(fd_, nlh0_, hdrlen_,		\
 | |
| 				     init_msg_, print_msg_,		\
 | |
| 				     nla_type_, pattern_, obj_,		\
 | |
| 				     depth_, ...)			\
 | |
| 	TEST_NESTED_NLATTR_OBJECT_EX_((fd_), (nlh0_), (hdrlen_),	\
 | |
| 				      (init_msg_), (print_msg_),	\
 | |
| 				      (nla_type_), #nla_type_,		\
 | |
| 				      (pattern_), (obj_),		\
 | |
| 				      print_quoted_hex, (depth_),	\
 | |
| 				      __VA_ARGS__)
 | |
| 
 | |
| #define TEST_NESTED_NLATTR_OBJECT(fd_, nlh0_, hdrlen_,			\
 | |
| 				  init_msg_, print_msg_,		\
 | |
| 				  nla_type_, pattern_, obj_, ...)	\
 | |
| 	TEST_NESTED_NLATTR_OBJECT_EX_((fd_), (nlh0_), (hdrlen_),	\
 | |
| 				      (init_msg_), (print_msg_),	\
 | |
| 				      (nla_type_), #nla_type_,		\
 | |
| 				      (pattern_), (obj_),		\
 | |
| 				      print_quoted_hex, 1,		\
 | |
| 				      __VA_ARGS__)
 | |
| 
 | |
| #define TEST_NESTED_NLATTR_ARRAY_EX(fd_, nlh0_, hdrlen_,		\
 | |
| 				 init_msg_, print_msg_,			\
 | |
| 				 nla_type_, pattern_, obj_, depth_,	\
 | |
| 				 print_elem_)				\
 | |
| 	do {								\
 | |
| 		const unsigned int plen =				\
 | |
| 			sizeof((obj_)[0]) - 1 > DEFAULT_STRLEN		\
 | |
| 			? DEFAULT_STRLEN : (int) sizeof((obj_)[0]) - 1;	\
 | |
| 		/* len < sizeof((obj_)[0]) */				\
 | |
| 		TEST_NLATTR_((fd_), (nlh0_) - NLA_HDRLEN * depth_,	\
 | |
| 			(hdrlen_) + NLA_HDRLEN * depth_,		\
 | |
| 			(init_msg_), (print_msg_),			\
 | |
| 			(nla_type_), #nla_type_,			\
 | |
| 			plen, (pattern_), plen,				\
 | |
| 			print_quoted_hex((pattern_), plen);		\
 | |
| 			for (size_t i = 0; i < depth_; ++i)		\
 | |
| 				printf("}"));				\
 | |
| 		/* sizeof((obj_)[0]) < len < sizeof(obj_) */		\
 | |
| 		TEST_NLATTR_((fd_), (nlh0_) - NLA_HDRLEN * depth_,	\
 | |
| 			(hdrlen_) + NLA_HDRLEN * depth_,		\
 | |
| 			(init_msg_), (print_msg_),			\
 | |
| 			(nla_type_), #nla_type_,			\
 | |
| 			sizeof(obj_) - 1,				\
 | |
| 			&(obj_), sizeof(obj_) - 1,			\
 | |
| 			printf("[");					\
 | |
| 			size_t i;					\
 | |
| 			for (i = 0; i < ARRAY_SIZE(obj_) - 1; ++i) {	\
 | |
| 				if (i) printf(", ");			\
 | |
| 				(print_elem_)(&(obj_)[i], i);		\
 | |
| 			}						\
 | |
| 			printf("]");					\
 | |
| 			for (i = 0; i < depth_; ++i)			\
 | |
| 				printf("}"));				\
 | |
| 		/* short read of sizeof(obj_) */			\
 | |
| 		TEST_NLATTR_((fd_), (nlh0_) - NLA_HDRLEN * depth_,	\
 | |
| 			(hdrlen_) + NLA_HDRLEN * depth_,		\
 | |
| 			(init_msg_), (print_msg_),			\
 | |
| 			(nla_type_), #nla_type_,			\
 | |
| 			sizeof(obj_),					\
 | |
| 			&(obj_), sizeof(obj_) - 1,			\
 | |
| 			printf("[");					\
 | |
| 			size_t i;					\
 | |
| 			for (i = 0; i < ARRAY_SIZE(obj_) - 1; ++i) {	\
 | |
| 				if (i) printf(", ");			\
 | |
| 				(print_elem_)(&(obj_)[i], i);		\
 | |
| 			}						\
 | |
| 			printf(", ... /* %p */]",			\
 | |
| 			       RTA_DATA(TEST_NLATTR_nla)		\
 | |
| 			        + sizeof(obj_) - sizeof((obj_)[0]));	\
 | |
| 			for (i = 0; i < depth_; ++i)			\
 | |
| 				printf("}"));				\
 | |
| 		/* sizeof(obj_) */					\
 | |
| 		TEST_NLATTR_((fd_), (nlh0_) - NLA_HDRLEN * depth_,	\
 | |
| 			(hdrlen_) + NLA_HDRLEN * depth_,		\
 | |
| 			(init_msg_), (print_msg_),			\
 | |
| 			(nla_type_), #nla_type_,			\
 | |
| 			sizeof(obj_),					\
 | |
| 			&(obj_), sizeof(obj_),				\
 | |
| 			printf("[");					\
 | |
| 			size_t i;					\
 | |
| 			for (i = 0; i < ARRAY_SIZE(obj_); ++i) {	\
 | |
| 				if (i) printf(", ");			\
 | |
| 				(print_elem_)(&(obj_)[i], i);		\
 | |
| 			}						\
 | |
| 			printf("]");					\
 | |
| 			for (i = 0; i < depth_; ++i)			\
 | |
| 				printf("}"));				\
 | |
| 	} while (0)
 | |
| 
 | |
| #define TEST_NESTED_NLATTR_ARRAY(fd_, nlh0_, hdrlen_,			\
 | |
| 				 init_msg_, print_msg_,			\
 | |
| 				 nla_type_, pattern_, obj_, print_elem_)\
 | |
| 	TEST_NESTED_NLATTR_ARRAY_EX((fd_), (nlh0_), (hdrlen_),		\
 | |
| 				    (init_msg_), (print_msg_),		\
 | |
| 				    nla_type_, (pattern_), (obj_), 1,	\
 | |
| 				    (print_elem_))
 |