00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <config.h>
00023
00024 #include <stdlib.h>
00025
00026 #include <isc/magic.h>
00027 #include <isc/mem.h>
00028 #include <isc/mutex.h>
00029 #include <isc/net.h>
00030 #include <isc/refcount.h>
00031 #include <isc/result.h>
00032 #include <isc/string.h>
00033 #include <isc/types.h>
00034 #include <isc/util.h>
00035
00036 #include <dns/types.h>
00037 #include <dns/portlist.h>
00038
00039 #define DNS_PORTLIST_MAGIC ISC_MAGIC('P','L','S','T')
00040 #define DNS_VALID_PORTLIST(p) ISC_MAGIC_VALID(p, DNS_PORTLIST_MAGIC)
00041
00042 typedef struct dns_element {
00043 in_port_t port;
00044 isc_uint16_t flags;
00045 } dns_element_t;
00046
00047 struct dns_portlist {
00048 unsigned int magic;
00049 isc_mem_t *mctx;
00050 isc_refcount_t refcount;
00051 isc_mutex_t lock;
00052 dns_element_t *list;
00053 unsigned int allocated;
00054 unsigned int active;
00055 };
00056
00057 #define DNS_PL_INET 0x0001
00058 #define DNS_PL_INET6 0x0002
00059 #define DNS_PL_ALLOCATE 16
00060
00061 static int
00062 compare(const void *arg1, const void *arg2) {
00063 const dns_element_t *e1 = (const dns_element_t *)arg1;
00064 const dns_element_t *e2 = (const dns_element_t *)arg2;
00065
00066 if (e1->port < e2->port)
00067 return (-1);
00068 if (e1->port > e2->port)
00069 return (1);
00070 return (0);
00071 }
00072
00073 isc_result_t
00074 dns_portlist_create(isc_mem_t *mctx, dns_portlist_t **portlistp) {
00075 dns_portlist_t *portlist;
00076 isc_result_t result;
00077
00078 REQUIRE(portlistp != NULL && *portlistp == NULL);
00079
00080 portlist = isc_mem_get(mctx, sizeof(*portlist));
00081 if (portlist == NULL)
00082 return (ISC_R_NOMEMORY);
00083 result = isc_mutex_init(&portlist->lock);
00084 if (result != ISC_R_SUCCESS) {
00085 isc_mem_put(mctx, portlist, sizeof(*portlist));
00086 return (result);
00087 }
00088 result = isc_refcount_init(&portlist->refcount, 1);
00089 if (result != ISC_R_SUCCESS) {
00090 DESTROYLOCK(&portlist->lock);
00091 isc_mem_put(mctx, portlist, sizeof(*portlist));
00092 return (result);
00093 }
00094 portlist->list = NULL;
00095 portlist->allocated = 0;
00096 portlist->active = 0;
00097 portlist->mctx = NULL;
00098 isc_mem_attach(mctx, &portlist->mctx);
00099 portlist->magic = DNS_PORTLIST_MAGIC;
00100 *portlistp = portlist;
00101 return (ISC_R_SUCCESS);
00102 }
00103
00104 static dns_element_t *
00105 find_port(dns_element_t *list, unsigned int len, in_port_t port) {
00106 unsigned int xtry = len / 2;
00107 unsigned int min = 0;
00108 unsigned int max = len - 1;
00109 unsigned int last = len;
00110
00111 for (;;) {
00112 if (list[xtry].port == port)
00113 return (&list[xtry]);
00114 if (port > list[xtry].port) {
00115 if (xtry == max)
00116 break;
00117 min = xtry;
00118 xtry = xtry + (max - xtry + 1) / 2;
00119 INSIST(xtry <= max);
00120 if (xtry == last)
00121 break;
00122 last = min;
00123 } else {
00124 if (xtry == min)
00125 break;
00126 max = xtry;
00127 xtry = xtry - (xtry - min + 1) / 2;
00128 INSIST(xtry >= min);
00129 if (xtry == last)
00130 break;
00131 last = max;
00132 }
00133 }
00134 return (NULL);
00135 }
00136
00137 isc_result_t
00138 dns_portlist_add(dns_portlist_t *portlist, int af, in_port_t port) {
00139 dns_element_t *el;
00140 isc_result_t result;
00141
00142 REQUIRE(DNS_VALID_PORTLIST(portlist));
00143 REQUIRE(af == AF_INET || af == AF_INET6);
00144
00145 LOCK(&portlist->lock);
00146 if (portlist->active != 0) {
00147 el = find_port(portlist->list, portlist->active, port);
00148 if (el != NULL) {
00149 if (af == AF_INET)
00150 el->flags |= DNS_PL_INET;
00151 else
00152 el->flags |= DNS_PL_INET6;
00153 result = ISC_R_SUCCESS;
00154 goto unlock;
00155 }
00156 }
00157
00158 if (portlist->allocated <= portlist->active) {
00159 unsigned int allocated;
00160 allocated = portlist->allocated + DNS_PL_ALLOCATE;
00161 el = isc_mem_get(portlist->mctx, sizeof(*el) * allocated);
00162 if (el == NULL) {
00163 result = ISC_R_NOMEMORY;
00164 goto unlock;
00165 }
00166 if (portlist->list != NULL) {
00167 memmove(el, portlist->list,
00168 portlist->allocated * sizeof(*el));
00169 isc_mem_put(portlist->mctx, portlist->list,
00170 portlist->allocated * sizeof(*el));
00171 }
00172 portlist->list = el;
00173 portlist->allocated = allocated;
00174 }
00175 portlist->list[portlist->active].port = port;
00176 if (af == AF_INET)
00177 portlist->list[portlist->active].flags = DNS_PL_INET;
00178 else
00179 portlist->list[portlist->active].flags = DNS_PL_INET6;
00180 portlist->active++;
00181 qsort(portlist->list, portlist->active, sizeof(*el), compare);
00182 result = ISC_R_SUCCESS;
00183 unlock:
00184 UNLOCK(&portlist->lock);
00185 return (result);
00186 }
00187
00188 void
00189 dns_portlist_remove(dns_portlist_t *portlist, int af, in_port_t port) {
00190 dns_element_t *el;
00191
00192 REQUIRE(DNS_VALID_PORTLIST(portlist));
00193 REQUIRE(af == AF_INET || af == AF_INET6);
00194
00195 LOCK(&portlist->lock);
00196 if (portlist->active != 0) {
00197 el = find_port(portlist->list, portlist->active, port);
00198 if (el != NULL) {
00199 if (af == AF_INET)
00200 el->flags &= ~DNS_PL_INET;
00201 else
00202 el->flags &= ~DNS_PL_INET6;
00203 if (el->flags == 0) {
00204 *el = portlist->list[portlist->active];
00205 portlist->active--;
00206 qsort(portlist->list, portlist->active,
00207 sizeof(*el), compare);
00208 }
00209 }
00210 }
00211 UNLOCK(&portlist->lock);
00212 }
00213
00214 isc_boolean_t
00215 dns_portlist_match(dns_portlist_t *portlist, int af, in_port_t port) {
00216 dns_element_t *el;
00217 isc_boolean_t result = ISC_FALSE;
00218
00219 REQUIRE(DNS_VALID_PORTLIST(portlist));
00220 REQUIRE(af == AF_INET || af == AF_INET6);
00221 LOCK(&portlist->lock);
00222 if (portlist->active != 0) {
00223 el = find_port(portlist->list, portlist->active, port);
00224 if (el != NULL) {
00225 if (af == AF_INET && (el->flags & DNS_PL_INET) != 0)
00226 result = ISC_TRUE;
00227 if (af == AF_INET6 && (el->flags & DNS_PL_INET6) != 0)
00228 result = ISC_TRUE;
00229 }
00230 }
00231 UNLOCK(&portlist->lock);
00232 return (result);
00233 }
00234
00235 void
00236 dns_portlist_attach(dns_portlist_t *portlist, dns_portlist_t **portlistp) {
00237
00238 REQUIRE(DNS_VALID_PORTLIST(portlist));
00239 REQUIRE(portlistp != NULL && *portlistp == NULL);
00240
00241 isc_refcount_increment(&portlist->refcount, NULL);
00242 *portlistp = portlist;
00243 }
00244
00245 void
00246 dns_portlist_detach(dns_portlist_t **portlistp) {
00247 dns_portlist_t *portlist;
00248 unsigned int count;
00249
00250 REQUIRE(portlistp != NULL);
00251 portlist = *portlistp;
00252 REQUIRE(DNS_VALID_PORTLIST(portlist));
00253 *portlistp = NULL;
00254 isc_refcount_decrement(&portlist->refcount, &count);
00255 if (count == 0) {
00256 portlist->magic = 0;
00257 isc_refcount_destroy(&portlist->refcount);
00258 if (portlist->list != NULL)
00259 isc_mem_put(portlist->mctx, portlist->list,
00260 portlist->allocated *
00261 sizeof(*portlist->list));
00262 DESTROYLOCK(&portlist->lock);
00263 isc_mem_putanddetach(&portlist->mctx, portlist,
00264 sizeof(*portlist));
00265 }
00266 }