1/* 2 * Check decoding of SIOCGIFCONF command of ioctl syscall. 3 * 4 * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr@gmail.com> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30#include "tests.h" 31 32#include <stdbool.h> 33#include <stdio.h> 34#include <string.h> 35 36#include <arpa/inet.h> 37#include <net/if.h> 38#include <sys/ioctl.h> 39#include <sys/socket.h> 40 41#define MAX_STRLEN 1 42 43static void 44print_ifc_len(int val) 45{ 46 if (val % (int) sizeof(struct ifreq)) 47 printf("%d", val); 48 else 49 printf("%d * sizeof(struct ifreq)", 50 val / (int) sizeof(struct ifreq)); 51} 52 53static void 54print_ifconf(struct ifconf *ifc, int in_len, char *in_buf, long rc) 55{ 56 if (in_buf) { 57 printf("{ifc_len="); 58 print_ifc_len(in_len); 59 60 if (in_len != ifc->ifc_len) { 61 printf(" => "); 62 print_ifc_len(ifc->ifc_len); 63 } 64 } else { 65 printf("{ifc_len="); 66 print_ifc_len(ifc->ifc_len); 67 } 68 69 printf(", ifc_buf="); 70 71 if ((rc < 0) || !in_buf) { 72 if (in_buf) 73 printf("%p", in_buf); 74 else 75 printf("NULL"); 76 } else { 77 int i; 78 79 printf("["); 80 for (i = 0; i < (ifc->ifc_len) && 81 i < (int) (MAX_STRLEN * sizeof(struct ifreq)); 82 i += sizeof(struct ifreq)) { 83 struct ifreq *ifr = (struct ifreq *) (ifc->ifc_buf + i); 84 struct sockaddr_in *const sa_in = 85 (struct sockaddr_in *) &(ifr->ifr_addr); 86 87 if (i) 88 printf(", "); 89 printf("{ifr_name=\"%s\", ifr_addr={sa_family=AF_INET, " 90 "sin_port=htons(%u), sin_addr=inet_addr(\"%s\")}" 91 "}", ifr->ifr_name, ntohs(sa_in->sin_port), 92 inet_ntoa(sa_in->sin_addr)); 93 } 94 95 if ((size_t) (ifc->ifc_len - i) >= sizeof(struct ifreq)) 96 printf(", ..."); 97 98 printf("]"); 99 } 100 101 printf("}"); 102} 103 104static void 105gifconf_ioctl(int fd, struct ifconf *ifc, bool ifc_valid) 106{ 107 const char * errstr; 108 int in_len; 109 char *in_buf; 110 long rc; 111 112 if (ifc_valid) { 113 in_len = ifc->ifc_len; 114 in_buf = ifc->ifc_buf; 115 } 116 117 rc = ioctl(fd, SIOCGIFCONF, ifc); 118 errstr = sprintrc(rc); 119 120 printf("ioctl(%d, SIOCGIFCONF, ", fd); 121 if (ifc_valid) { 122 print_ifconf(ifc, in_len, in_buf, rc); 123 } else { 124 if (ifc) 125 printf("%p", ifc); 126 else 127 printf("NULL"); 128 } 129 130 printf(") = %s\n", errstr); 131} 132 133int 134main(int argc, char *argv[]) 135{ 136 struct ifreq *ifr = tail_alloc(2 * sizeof(*ifr)); 137 struct ifconf *ifc = tail_alloc(sizeof(*ifc)); 138 139 struct sockaddr_in addr; 140 int fd; 141 142 memset(&addr, 0, sizeof(addr)); 143 addr.sin_family = AF_INET; 144 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 145 146 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) 147 perror_msg_and_skip("socket AF_INET"); 148 149 gifconf_ioctl(fd, NULL, false); 150 gifconf_ioctl(fd, ifc + 1, false); 151 152 ifc->ifc_len = 3141592653U; 153 ifc->ifc_buf = NULL; 154 gifconf_ioctl(fd, ifc, true); 155 156 ifc->ifc_len = 0; 157 ifc->ifc_buf = (char *) (ifr + 2); 158 gifconf_ioctl(fd, ifc, true); 159 160 ifc->ifc_len = 1; 161 ifc->ifc_buf = (char *) (ifr + 1); 162 gifconf_ioctl(fd, ifc, true); 163 164 ifc->ifc_len = 1 * sizeof(*ifr); 165 ifc->ifc_buf = (char *) (ifr + 1); 166 gifconf_ioctl(fd, ifc, true); 167 168 ifc->ifc_len = 2 * sizeof(*ifr); 169 ifc->ifc_buf = (char *) (ifr + 1); 170 gifconf_ioctl(fd, ifc, true); 171 172 ifc->ifc_len = 2 * sizeof(*ifr) + 2; 173 ifc->ifc_buf = (char *) ifr; 174 gifconf_ioctl(fd, ifc, true); 175 176 ifc->ifc_len = 3 * sizeof(*ifr) + 4; 177 ifc->ifc_buf = (char *) ifr; 178 gifconf_ioctl(fd, ifc, true); 179 180 puts("+++ exited with 0 +++"); 181 return 0; 182} 183