xref: /netbsd-src/external/ibm-public/postfix/dist/src/util/inet_addr_list.c (revision e89934bbf778a6d6d6894877c4da59d0c7835b0f)
1 /*	$NetBSD: inet_addr_list.c,v 1.2 2017/02/14 01:16:49 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 
inet_addr_list_init(INET_ADDR_LIST * list)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 
inet_addr_list_append(INET_ADDR_LIST * list,struct sockaddr * addr)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 
inet_addr_list_comp(const void * a,const void * b)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 
inet_addr_list_uniq(INET_ADDR_LIST * list)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 
inet_addr_list_free(INET_ADDR_LIST * list)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 
inet_addr_list_print(INET_ADDR_LIST * list)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 
main(int argc,char ** argv)169 int     main(int argc, char **argv)
170 {
171     INET_ADDR_LIST list;
172     INET_PROTO_INFO *proto_info;
173 
174     proto_info = inet_proto_init(argv[0], INET_PROTO_NAME_ALL);
175     inet_addr_list_init(&list);
176     while (--argc && *++argv)
177 	if (inet_addr_host(&list, *argv) == 0)
178 	    msg_fatal("host not found: %s", *argv);
179     msg_info("list before sort/uniq");
180     inet_addr_list_print(&list);
181     inet_addr_list_uniq(&list);
182     msg_info("list after sort/uniq");
183     inet_addr_list_print(&list);
184     inet_addr_list_free(&list);
185     return (0);
186 }
187 
188 #endif
189