1 /* $NetBSD: inet_addr_list.c,v 1.3 2026/05/09 18:49:22 christos Exp $ */ 2 3 /*++ 4 /* NAME 5 /* inet_addr_list 3 6 /* SUMMARY 7 /* internet address list manager 8 /* SYNOPSIS 9 /* #include <inet_addr_list.h> 10 /* 11 /* void inet_addr_list_init(list) 12 /* INET_ADDR_LIST *list; 13 /* 14 /* void inet_addr_list_append(list,addr) 15 /* INET_ADDR_LIST *list; 16 /* struct sockaddr *addr; 17 /* 18 /* void inet_addr_list_uniq(list) 19 /* INET_ADDR_LIST *list; 20 /* 21 /* void inet_addr_list_free(list) 22 /* INET_ADDR_LIST *list; 23 /* DESCRIPTION 24 /* This module maintains simple lists of internet addresses. 25 /* 26 /* inet_addr_list_init() initializes a user-provided structure 27 /* so that it can be used by inet_addr_list_append() and by 28 /* inet_addr_list_free(). 29 /* 30 /* inet_addr_list_append() appends the specified address to 31 /* the specified list, extending the list on the fly. 32 /* 33 /* inet_addr_list_uniq() sorts the specified address list and 34 /* eliminates duplicates. 35 /* 36 /* inet_addr_list_free() reclaims memory used for the 37 /* specified address list. 38 /* LICENSE 39 /* .ad 40 /* .fi 41 /* The Secure Mailer license must be distributed with this software. 42 /* AUTHOR(S) 43 /* Wietse Venema 44 /* IBM T.J. Watson Research 45 /* P.O. Box 704 46 /* Yorktown Heights, NY 10598, USA 47 /*--*/ 48 49 /* System library. */ 50 51 #include <sys_defs.h> 52 #include <sys/socket.h> 53 #include <netinet/in.h> 54 #include <arpa/inet.h> 55 #include <stdlib.h> 56 #include <netdb.h> 57 58 /* Utility library. */ 59 60 #include <msg.h> 61 #include <mymalloc.h> 62 #include <myaddrinfo.h> 63 #include <sock_addr.h> 64 #include <inet_addr_list.h> 65 66 /* inet_addr_list_init - initialize internet address list */ 67 68 void inet_addr_list_init(INET_ADDR_LIST *list) 69 { 70 int init_size; 71 72 list->used = 0; 73 list->size = 0; 74 init_size = 2; 75 list->addrs = (struct sockaddr_storage *) 76 mymalloc(sizeof(*list->addrs) * init_size); 77 list->size = init_size; 78 } 79 80 /* inet_addr_list_append - append address to internet address list */ 81 82 void inet_addr_list_append(INET_ADDR_LIST *list, 83 struct sockaddr *addr) 84 { 85 const char *myname = "inet_addr_list_append"; 86 MAI_HOSTADDR_STR hostaddr; 87 int new_size; 88 89 if (msg_verbose > 1) { 90 SOCKADDR_TO_HOSTADDR(addr, SOCK_ADDR_LEN(addr), 91 &hostaddr, (MAI_SERVPORT_STR *) 0, 0); 92 msg_info("%s: %s", myname, hostaddr.buf); 93 } 94 if (list->used >= list->size) { 95 new_size = list->size * 2; 96 list->addrs = (struct sockaddr_storage *) 97 myrealloc((void *) list->addrs, sizeof(*list->addrs) * new_size); 98 list->size = new_size; 99 } 100 memcpy(list->addrs + list->used++, addr, SOCK_ADDR_LEN(addr)); 101 } 102 103 /* inet_addr_list_comp - compare addresses */ 104 105 static int inet_addr_list_comp(const void *a, const void *b) 106 { 107 108 /* 109 * In case (struct *) != (void *). 110 */ 111 return (sock_addr_cmp_addr(SOCK_ADDR_PTR(a), SOCK_ADDR_PTR(b))); 112 } 113 114 /* inet_addr_list_uniq - weed out duplicates */ 115 116 void inet_addr_list_uniq(INET_ADDR_LIST *list) 117 { 118 int n; 119 int m; 120 121 /* 122 * Put the identical members right next to each other. 123 */ 124 qsort((void *) list->addrs, list->used, 125 sizeof(list->addrs[0]), inet_addr_list_comp); 126 127 /* 128 * Nuke the duplicates. Postcondition after while loop: m is the largest 129 * index for which list->addrs[n] == list->addrs[m]. 130 */ 131 for (m = n = 0; m < list->used; m++, n++) { 132 if (m != n) 133 list->addrs[n] = list->addrs[m]; 134 while (m + 1 < list->used 135 && inet_addr_list_comp((void *) &(list->addrs[n]), 136 (void *) &(list->addrs[m + 1])) == 0) 137 m += 1; 138 } 139 list->used = n; 140 } 141 142 /* inet_addr_list_free - destroy internet address list */ 143 144 void inet_addr_list_free(INET_ADDR_LIST *list) 145 { 146 myfree((void *) list->addrs); 147 } 148 149 #ifdef TEST 150 #include <inet_proto.h> 151 152 /* 153 * Duplicate elimination needs to be tested. 154 */ 155 #include <inet_addr_host.h> 156 157 static void inet_addr_list_print(INET_ADDR_LIST *list) 158 { 159 MAI_HOSTADDR_STR hostaddr; 160 struct sockaddr_storage *sa; 161 162 for (sa = list->addrs; sa < list->addrs + list->used; sa++) { 163 SOCKADDR_TO_HOSTADDR(SOCK_ADDR_PTR(sa), SOCK_ADDR_LEN(sa), 164 &hostaddr, (MAI_SERVPORT_STR *) 0, 0); 165 msg_info("%s", hostaddr.buf); 166 } 167 } 168 169 int main(int argc, char **argv) 170 { 171 INET_ADDR_LIST list; 172 173 inet_proto_init(argv[0], INET_PROTO_NAME_ALL); 174 inet_addr_list_init(&list); 175 while (--argc && *++argv) 176 if (inet_addr_host(&list, *argv) == 0) 177 msg_fatal("host not found: %s", *argv); 178 msg_info("list before sort/uniq"); 179 inet_addr_list_print(&list); 180 inet_addr_list_uniq(&list); 181 msg_info("list after sort/uniq"); 182 inet_addr_list_print(&list); 183 inet_addr_list_free(&list); 184 return (0); 185 } 186 187 #endif 188