1 /* 2 * Check decoding of netlink protocol. 3 * 4 * Copyright (c) 2014-2017 Dmitry V. Levin <ldv (at) altlinux.org> 5 * Copyright (c) 2016 Fabien Siron <fabien.siron (at) epita.fr> 6 * Copyright (c) 2016-2018 The strace developers. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include "tests.h" 33 34 #ifdef HAVE_SYS_XATTR_H 35 36 # include <stdio.h> 37 # include <stdlib.h> 38 # include <string.h> 39 # include <unistd.h> 40 # include <sys/xattr.h> 41 # include <netinet/in.h> 42 # include "netlink.h" 43 # include <linux/sock_diag.h> 44 # include <linux/netlink_diag.h> 45 46 static void 47 send_query(const int fd) 48 { 49 static const struct req { 50 struct nlmsghdr nlh; 51 const char magic[4]; 52 } c_req = { 53 .nlh = { 54 .nlmsg_len = sizeof(struct req), 55 .nlmsg_type = NLMSG_NOOP, 56 .nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST 57 }, 58 .magic = "abcd" 59 }; 60 struct req *const req = tail_memdup(&c_req, sizeof(c_req)); 61 long rc; 62 const char *errstr; 63 64 /* zero address */ 65 rc = sendto(fd, NULL, sizeof(*req), MSG_DONTWAIT, NULL, 0); 66 printf("sendto(%d, NULL, %u, MSG_DONTWAIT, NULL, 0) = %s\n", 67 fd, (unsigned) sizeof(*req), sprintrc(rc)); 68 69 /* zero length */ 70 rc = sendto(fd, req, 0, MSG_DONTWAIT, NULL, 0); 71 printf("sendto(%d, \"\", 0, MSG_DONTWAIT, NULL, 0) = %s\n", 72 fd, sprintrc(rc)); 73 74 /* zero address and length */ 75 rc = sendto(fd, NULL, 0, MSG_DONTWAIT, NULL, 0); 76 printf("sendto(%d, NULL, 0, MSG_DONTWAIT, NULL, 0) = %s\n", 77 fd, sprintrc(rc)); 78 79 /* unfetchable struct nlmsghdr */ 80 const void *const efault = tail_alloc(sizeof(struct nlmsghdr) - 1); 81 rc = sendto(fd, efault, sizeof(struct nlmsghdr), MSG_DONTWAIT, NULL, 0); 82 printf("sendto(%d, %p, %u, MSG_DONTWAIT, NULL, 0) = %s\n", 83 fd, efault, (unsigned) sizeof(struct nlmsghdr), sprintrc(rc)); 84 85 /* whole message length < sizeof(struct nlmsghdr) */ 86 rc = sendto(fd, req->magic, sizeof(req->magic), MSG_DONTWAIT, NULL, 0); 87 printf("sendto(%d, \"\\x61\\x62\\x63\\x64\"" 88 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n", 89 fd, (unsigned) sizeof(req->magic), sprintrc(rc)); 90 91 /* a single message with some data */ 92 rc = sendto(fd, req, sizeof(*req), MSG_DONTWAIT, NULL, 0); 93 printf("sendto(%d, {{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x" 94 ", seq=0, pid=0}, \"\\x61\\x62\\x63\\x64\"}" 95 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n", 96 fd, req->nlh.nlmsg_len, NLM_F_DUMP, 97 (unsigned) sizeof(*req), sprintrc(rc)); 98 99 /* a single message without data */ 100 req->nlh.nlmsg_len = sizeof(req->nlh); 101 rc = sendto(fd, &req->nlh, sizeof(req->nlh), MSG_DONTWAIT, NULL, 0); 102 printf("sendto(%d, {len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x" 103 ", seq=0, pid=0}, %u, MSG_DONTWAIT, NULL, 0) = %s\n", 104 fd, req->nlh.nlmsg_len, NLM_F_DUMP, 105 (unsigned) sizeof(req->nlh), sprintrc(rc)); 106 107 /* nlmsg_len > whole message length */ 108 req->nlh.nlmsg_len = sizeof(*req) + 8; 109 rc = sendto(fd, req, sizeof(*req), MSG_DONTWAIT, NULL, 0); 110 printf("sendto(%d, {{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x" 111 ", seq=0, pid=0}, \"\\x61\\x62\\x63\\x64\"}" 112 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n", 113 fd, req->nlh.nlmsg_len, NLM_F_DUMP, 114 (unsigned) sizeof(*req), sprintrc(rc)); 115 116 /* nlmsg_len < sizeof(struct nlmsghdr) */ 117 req->nlh.nlmsg_len = 8; 118 rc = sendto(fd, req, sizeof(*req), MSG_DONTWAIT, NULL, 0); 119 printf("sendto(%d, {len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x" 120 ", seq=0, pid=0}, %u, MSG_DONTWAIT, NULL, 0) = %s\n", 121 fd, req->nlh.nlmsg_len, NLM_F_DUMP, 122 (unsigned) sizeof(*req), sprintrc(rc)); 123 124 /* a sequence of two nlmsg objects */ 125 struct reqs { 126 struct req req1; 127 char padding[NLMSG_ALIGN(sizeof(struct req)) - sizeof(struct req)]; 128 struct req req2; 129 }; 130 TAIL_ALLOC_OBJECT_CONST_PTR(struct reqs, reqs); 131 memcpy(&reqs->req1, &c_req, sizeof(c_req)); 132 memcpy(&reqs->req2, &c_req, sizeof(c_req)); 133 134 rc = sendto(fd, reqs, sizeof(*reqs), MSG_DONTWAIT, NULL, 0); 135 printf("sendto(%d, [{{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x" 136 ", seq=0, pid=0}, \"\\x61\\x62\\x63\\x64\"}" 137 ", {{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x" 138 ", seq=0, pid=0}, \"\\x61\\x62\\x63\\x64\"}]" 139 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n", 140 fd, reqs->req1.nlh.nlmsg_len, NLM_F_DUMP, 141 reqs->req2.nlh.nlmsg_len, NLM_F_DUMP, 142 (unsigned) sizeof(*reqs), sprintrc(rc)); 143 144 /* unfetchable second struct nlmsghdr */ 145 void *const efault2 = tail_memdup(&reqs->req1, sizeof(reqs->req1)); 146 rc = sendto(fd, efault2, sizeof(*reqs), MSG_DONTWAIT, NULL, 0); 147 printf("sendto(%d, [{{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x" 148 ", seq=0, pid=0}, \"\\x61\\x62\\x63\\x64\"}" 149 ", ... /* %p */], %u, MSG_DONTWAIT, NULL, 0) = %s\n", 150 fd, reqs->req1.nlh.nlmsg_len, NLM_F_DUMP, 151 &((struct reqs *) efault2)->req2, (unsigned) sizeof(*reqs), 152 sprintrc(rc)); 153 154 /* message length is not enough for the second struct nlmsghdr */ 155 rc = sendto(fd, reqs, sizeof(*reqs) - sizeof(req->nlh), MSG_DONTWAIT, 156 NULL, 0); 157 errstr = sprintrc(rc); 158 printf("sendto(%d, [{{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x" 159 ", seq=0, pid=0}, \"\\x61\\x62\\x63\\x64\"}, ", 160 fd, reqs->req1.nlh.nlmsg_len, NLM_F_DUMP); 161 print_quoted_hex(&reqs->req2.nlh, 162 sizeof(reqs->req2) - sizeof(req->nlh)); 163 printf("], %u, MSG_DONTWAIT, NULL, 0) = %s\n", 164 (unsigned) (sizeof(*reqs) - sizeof(req->nlh)), errstr); 165 166 /* second nlmsg_len < sizeof(struct nlmsghdr) */ 167 reqs->req2.nlh.nlmsg_len = 4; 168 rc = sendto(fd, reqs, sizeof(*reqs), MSG_DONTWAIT, NULL, 0); 169 printf("sendto(%d, [{{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x" 170 ", seq=0, pid=0}, \"\\x61\\x62\\x63\\x64\"}" 171 ", {len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x" 172 ", seq=0, pid=0}], %u, MSG_DONTWAIT, NULL, 0) = %s\n", 173 fd, reqs->req1.nlh.nlmsg_len, NLM_F_DUMP, 174 reqs->req2.nlh.nlmsg_len, NLM_F_DUMP, 175 (unsigned) sizeof(*reqs), sprintrc(rc)); 176 177 /* abbreviated output */ 178 # define ABBREV_LEN (DEFAULT_STRLEN + 1) 179 const unsigned int msg_len = sizeof(struct nlmsghdr) * ABBREV_LEN; 180 struct nlmsghdr *const msgs = tail_alloc(msg_len); 181 unsigned int i; 182 for (i = 0; i < ABBREV_LEN; ++i) { 183 msgs[i].nlmsg_len = sizeof(*msgs); 184 msgs[i].nlmsg_type = NLMSG_NOOP; 185 msgs[i].nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; 186 msgs[i].nlmsg_seq = i; 187 msgs[i].nlmsg_pid = 0; 188 } 189 190 rc = sendto(fd, msgs, msg_len, MSG_DONTWAIT, NULL, 0); 191 errstr = sprintrc(rc); 192 printf("sendto(%d, [", fd); 193 for (i = 0; i < DEFAULT_STRLEN; ++i) { 194 if (i) 195 printf(", "); 196 printf("{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x" 197 ", seq=%u, pid=0}", 198 msgs[i].nlmsg_len, NLM_F_DUMP, msgs[i].nlmsg_seq); 199 } 200 printf(", ...], %u, MSG_DONTWAIT, NULL, 0) = %s\n", msg_len, errstr); 201 } 202 203 static void 204 test_nlmsgerr(const int fd) 205 { 206 struct nlmsgerr *err; 207 struct nlmsghdr *nlh; 208 void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(*err) + 4); 209 long rc; 210 211 /* error message without enough room for the error code */ 212 nlh = nlh0; 213 nlh->nlmsg_len = NLMSG_HDRLEN + 4; 214 nlh->nlmsg_type = NLMSG_ERROR; 215 nlh->nlmsg_flags = NLM_F_REQUEST; 216 nlh->nlmsg_seq = 0; 217 nlh->nlmsg_pid = 0; 218 219 rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0); 220 printf("sendto(%d, {{len=%u, type=NLMSG_ERROR, flags=NLM_F_REQUEST" 221 ", seq=0, pid=0}, %p}, %u, MSG_DONTWAIT, NULL, 0) = %s\n", 222 fd, nlh->nlmsg_len, nlh0 + NLMSG_HDRLEN, 223 nlh->nlmsg_len, sprintrc(rc)); 224 225 nlh->nlmsg_len = NLMSG_HDRLEN + 2; 226 nlh = nlh0 - 2; 227 memmove(nlh, nlh0, sizeof(*nlh)); 228 memcpy(NLMSG_DATA(nlh), "42", 2); 229 230 rc = sendto(fd, nlh, NLMSG_HDRLEN + 2, MSG_DONTWAIT, NULL, 0); 231 printf("sendto(%d, {{len=%u, type=NLMSG_ERROR, flags=NLM_F_REQUEST" 232 ", seq=0, pid=0}, \"\\x34\\x32\"}" 233 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n", 234 fd, NLMSG_HDRLEN + 2, NLMSG_HDRLEN + 2, sprintrc(rc)); 235 236 /* error message with room for the error code only */ 237 nlh = nlh0 - sizeof(err->error); 238 nlh->nlmsg_len = NLMSG_HDRLEN + sizeof(err->error); 239 nlh->nlmsg_type = NLMSG_ERROR; 240 nlh->nlmsg_flags = NLM_F_REQUEST; 241 nlh->nlmsg_seq = 0; 242 nlh->nlmsg_pid = 0; 243 err = NLMSG_DATA(nlh); 244 err->error = 42; 245 246 rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0); 247 printf("sendto(%d, {{len=%u, type=NLMSG_ERROR, flags=NLM_F_REQUEST" 248 ", seq=0, pid=0}, {error=42}}, %u, MSG_DONTWAIT, NULL, 0)" 249 " = %s\n", fd, nlh->nlmsg_len, nlh->nlmsg_len, sprintrc(rc)); 250 251 err->error = -1; 252 253 rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0); 254 printf("sendto(%d, {{len=%u, type=NLMSG_ERROR, flags=NLM_F_REQUEST" 255 ", seq=0, pid=0}, {error=-EPERM}}, %u, MSG_DONTWAIT, NULL, 0)" 256 " = %s\n", fd, nlh->nlmsg_len, nlh->nlmsg_len, sprintrc(rc)); 257 258 err->error = -32767; 259 nlh->nlmsg_len += sizeof(err->msg.nlmsg_len); 260 261 rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0); 262 printf("sendto(%d, {{len=%u, type=NLMSG_ERROR, flags=NLM_F_REQUEST" 263 ", seq=0, pid=0}, {error=-32767, msg=%p}}" 264 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n", 265 fd, nlh->nlmsg_len, nlh0 + NLMSG_HDRLEN, 266 nlh->nlmsg_len, sprintrc(rc)); 267 268 /* error message with room for the error code and a header */ 269 nlh = nlh0 - sizeof(*err); 270 nlh->nlmsg_len = NLMSG_HDRLEN + sizeof(*err); 271 nlh->nlmsg_type = NLMSG_ERROR; 272 nlh->nlmsg_flags = NLM_F_REQUEST; 273 nlh->nlmsg_seq = 0; 274 nlh->nlmsg_pid = 0; 275 err = NLMSG_DATA(nlh); 276 err->error = -13; 277 err->msg.nlmsg_len = NLMSG_HDRLEN; 278 err->msg.nlmsg_type = NLMSG_NOOP; 279 err->msg.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; 280 err->msg.nlmsg_seq = 42; 281 err->msg.nlmsg_pid = 1234; 282 283 rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0); 284 printf("sendto(%d, {{len=%u, type=NLMSG_ERROR, flags=NLM_F_REQUEST" 285 ", seq=0, pid=0}, {error=-EACCES" 286 ", msg={len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x" 287 ", seq=%u, pid=%u}}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n", 288 fd, nlh->nlmsg_len, err->msg.nlmsg_len, NLM_F_DUMP, 289 err->msg.nlmsg_seq, err->msg.nlmsg_pid, 290 nlh->nlmsg_len, sprintrc(rc)); 291 292 /* error message with room for the error code, a header, and some data */ 293 nlh = nlh0 - sizeof(*err) - 4; 294 nlh->nlmsg_len = NLMSG_HDRLEN + sizeof(*err) + 4; 295 nlh->nlmsg_type = NLMSG_ERROR; 296 nlh->nlmsg_flags = NLM_F_REQUEST; 297 nlh->nlmsg_seq = 0; 298 nlh->nlmsg_pid = 0; 299 err = NLMSG_DATA(nlh); 300 err->error = -13; 301 err->msg.nlmsg_len = NLMSG_HDRLEN + 4; 302 err->msg.nlmsg_type = NLMSG_NOOP; 303 err->msg.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; 304 err->msg.nlmsg_seq = 421; 305 err->msg.nlmsg_pid = 12345; 306 memcpy(NLMSG_DATA(&err->msg), "abcd", 4); 307 308 rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0); 309 printf("sendto(%d, {{len=%u, type=NLMSG_ERROR, flags=NLM_F_REQUEST" 310 ", seq=0, pid=0}, {error=-EACCES" 311 ", msg={{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x" 312 ", seq=%u, pid=%u}, \"\\x61\\x62\\x63\\x64\"}}}" 313 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n", 314 fd, nlh->nlmsg_len, err->msg.nlmsg_len, NLM_F_DUMP, 315 err->msg.nlmsg_seq, err->msg.nlmsg_pid, 316 nlh->nlmsg_len, sprintrc(rc)); 317 } 318 319 static void 320 test_nlmsg_done(const int fd) 321 { 322 struct nlmsghdr *nlh; 323 const int num = 0xfacefeed; 324 void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(num)); 325 long rc; 326 327 /* NLMSG_DONE message without enough room for an integer payload */ 328 nlh = nlh0; 329 *nlh = (struct nlmsghdr) { 330 .nlmsg_len = NLMSG_HDRLEN + sizeof(num), 331 .nlmsg_type = NLMSG_DONE, 332 .nlmsg_flags = NLM_F_MULTI 333 }; 334 335 rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0); 336 printf("sendto(%d, {{len=%u, type=NLMSG_DONE, flags=NLM_F_MULTI" 337 ", seq=0, pid=0}, %p}, %u, MSG_DONTWAIT, NULL, 0) = %s\n", 338 fd, nlh->nlmsg_len, nlh0 + NLMSG_HDRLEN, 339 nlh->nlmsg_len, sprintrc(rc)); 340 341 /* NLMSG_DONE message with enough room for an oddly short payload */ 342 nlh->nlmsg_len = NLMSG_HDRLEN + 2; 343 nlh = nlh0 - 2; 344 /* Beware of unaligned access to nlh members. */ 345 memmove(nlh, nlh0, sizeof(*nlh)); 346 memcpy(NLMSG_DATA(nlh), "42", 2); 347 348 rc = sendto(fd, nlh, NLMSG_HDRLEN + 2, MSG_DONTWAIT, NULL, 0); 349 printf("sendto(%d, {{len=%u, type=NLMSG_DONE, flags=NLM_F_MULTI, seq=0" 350 ", pid=0}, \"\\x34\\x32\"}, %u, MSG_DONTWAIT, NULL, 0) = %s\n", 351 fd, NLMSG_HDRLEN + 2, NLMSG_HDRLEN + 2, sprintrc(rc)); 352 353 /* NLMSG_DONE message with enough room for an integer payload */ 354 nlh = nlh0 - sizeof(num); 355 *nlh = (struct nlmsghdr) { 356 .nlmsg_len = NLMSG_HDRLEN + sizeof(num), 357 .nlmsg_type = NLMSG_DONE, 358 .nlmsg_flags = NLM_F_MULTI 359 }; 360 memcpy(NLMSG_DATA(nlh), &num, sizeof(num)); 361 362 rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0); 363 printf("sendto(%d, {{len=%u, type=NLMSG_DONE, flags=NLM_F_MULTI" 364 ", seq=0, pid=0}, %d}, %u, MSG_DONTWAIT, NULL, 0) = %s\n", 365 fd, nlh->nlmsg_len, num, nlh->nlmsg_len, sprintrc(rc)); 366 } 367 368 #if defined NLM_F_CAPPED || defined NLM_F_ACK_TLVS 369 static void 370 test_ack_flags(const int fd) 371 { 372 long rc; 373 struct nlmsghdr nlh = { 374 .nlmsg_len = sizeof(nlh), 375 .nlmsg_type = NLMSG_ERROR, 376 }; 377 378 #ifdef NLM_F_CAPPED 379 nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CAPPED, 380 rc = sendto(fd, &nlh, sizeof(nlh), MSG_DONTWAIT, NULL, 0); 381 printf("sendto(%d, {len=%u, type=NLMSG_ERROR" 382 ", flags=NLM_F_REQUEST|NLM_F_CAPPED, seq=0, pid=0}" 383 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n", 384 fd, nlh.nlmsg_len, (unsigned) sizeof(nlh), sprintrc(rc)); 385 #endif 386 387 #ifdef NLM_F_ACK_TLVS 388 nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK_TLVS; 389 rc = sendto(fd, &nlh, sizeof(nlh), MSG_DONTWAIT, NULL, 0); 390 printf("sendto(%d, {len=%u, type=NLMSG_ERROR" 391 ", flags=NLM_F_REQUEST|NLM_F_ACK_TLVS, seq=0, pid=0}" 392 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n", 393 fd, nlh.nlmsg_len, (unsigned) sizeof(nlh), sprintrc(rc)); 394 #endif 395 396 #if defined NLM_F_CAPPED && defined NLM_F_ACK_TLVS 397 nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CAPPED | NLM_F_ACK_TLVS; 398 rc = sendto(fd, &nlh, sizeof(nlh), MSG_DONTWAIT, NULL, 0); 399 printf("sendto(%d, {len=%u, type=NLMSG_ERROR" 400 ", flags=NLM_F_REQUEST|NLM_F_CAPPED|NLM_F_ACK_TLVS, seq=0, pid=0}" 401 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n", 402 fd, nlh.nlmsg_len, (unsigned) sizeof(nlh), sprintrc(rc)); 403 #endif 404 } 405 #endif 406 407 int main(void) 408 { 409 const int fd = create_nl_socket(NETLINK_SOCK_DIAG); 410 411 char *path; 412 if (asprintf(&path, "/proc/self/fd/%u", fd) < 0) 413 perror_msg_and_fail("asprintf"); 414 char buf[256]; 415 if (getxattr(path, "system.sockprotoname", buf, sizeof(buf) - 1) < 0) 416 perror_msg_and_skip("getxattr"); 417 free(path); 418 419 send_query(fd); 420 test_nlmsgerr(fd); 421 test_nlmsg_done(fd); 422 #if defined NLM_F_CAPPED || defined NLM_F_ACK_TLVS 423 test_ack_flags(fd); 424 #endif 425 426 puts("+++ exited with 0 +++"); 427 return 0; 428 } 429 430 #else 431 432 SKIP_MAIN_UNDEFINED("HAVE_SYS_XATTR_H") 433 434 #endif 435