├── .gitignore ├── README.md ├── COPYRIGHT ├── Makefile ├── wrapsrv.1 ├── wrapsrv.docbook ├── list.h ├── wrapsrv.c └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | wrapsrv 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DNS SRV record command line wrapper 2 | ----------------------------------- 3 | 4 | wrapsrv adds support for connecting to a network service based on DNS SRV 5 | record lookups to commands that do not support the DNS SRV record. wrapsrv 6 | implements the weighted priority client connection algorithm in [RFC 7 | 2782](http://tools.ietf.org/html/rfc2782). The specified command line will 8 | be invoked one or more times with %h and %p sequences in the command line 9 | substituted for the hostname and port elements of the selected SRV record. 10 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009-2014 by Farsight Security, Inc. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | WARN = -Wall -Wextra -Werror 3 | CFLAGS = -O2 -g $(WARN) 4 | INCLUDE = 5 | LDFLAGS = -lresolv 6 | DESTDIR ?= 7 | PREFIX = /usr/local 8 | 9 | BINDIR ?= $(DESTDIR)$(PREFIX)/bin 10 | MANDIR ?= $(DESTDIR)$(PREFIX)/share/man/man1 11 | 12 | BIN = wrapsrv 13 | MAN = wrapsrv.1 14 | SRC = wrapsrv.c 15 | 16 | all: $(BIN) $(DOC) 17 | 18 | $(BIN): $(SRC) 19 | $(CC) $(CFLAGS) -o $@ $(SRC) $(INCLUDE) $(LDFLAGS) 20 | 21 | $(MAN): wrapsrv.docbook 22 | docbook2x-man $< 23 | 24 | clean: 25 | rm -f $(BIN) 26 | 27 | install: $(BIN) 28 | mkdir -p $(BINDIR) 29 | mkdir -p $(MANDIR) 30 | install -m 0755 $(BIN) $(BINDIR) 31 | install -m 0644 $(MAN) $(MANDIR) 32 | 33 | .PHONY: all clean install 34 | -------------------------------------------------------------------------------- /wrapsrv.1: -------------------------------------------------------------------------------- 1 | '\" -*- coding: us-ascii -*- 2 | .if \n(.g .ds T< \\FC 3 | .if \n(.g .ds T> \\F[\n[.fam]] 4 | .de URL 5 | \\$2 \(la\\$1\(ra\\$3 6 | .. 7 | .if \n(.g .mso www.tmac 8 | .TH wrapsrv 1 "13 December 2013" "" "" 9 | .SH NAME 10 | wrapsrv \- DNS SRV record command line wrapper 11 | .SH SYNOPSIS 12 | 'nh 13 | .fi 14 | .ad l 15 | \fBwrapsrv\fR \kx 16 | .if (\nx>(\n(.l/2)) .nr x (\n(.l/5) 17 | 'in \n(.iu+\nxu 18 | [\fISRVNAME\fR] [\fICOMMAND\fR] [\fIOPTION\fR]\&... 19 | 'in \n(.iu-\nxu 20 | .ad b 21 | 'hy 22 | .SH DESCRIPTION 23 | \fBwrapsrv\fR adds support for connecting to a 24 | network service based on DNS SRV record lookups to commands that 25 | do not support the DNS SRV record. \fBwrapsrv\fR 26 | implements the weighted priority client connection algorithm in 27 | RFC 2782. The specified command line will be invoked one or more 28 | times with \fI%h\fR and 29 | \fI%p\fR sequences in the command line 30 | substituted for the hostname and port elements of the selected SRV 31 | record. The command line invoked must exit and return 0 after a 32 | successful connection or exit and return non-zero if the 33 | connection fails. \fBwrapsrv\fR will itself exit with 34 | the return code of the last command line invocation, or it may 35 | exit with a non-zero return code if the DNS SRV record lookup 36 | fails for any reason. 37 | -------------------------------------------------------------------------------- /wrapsrv.docbook: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | wrapsrv 8 | 1 9 | 10 | 11 | 12 | wrapsrv 13 | DNS SRV record command line wrapper 14 | 15 | 16 | 17 | 18 | wrapsrv 19 | SRVNAME 20 | COMMAND 21 | OPTION 22 | 23 | 24 | 25 | 26 | DESCRIPTION 27 | 28 | wrapsrv adds support for connecting to a 29 | network service based on DNS SRV record lookups to commands that 30 | do not support the DNS SRV record. wrapsrv 31 | implements the weighted priority client connection algorithm in 32 | RFC 2782. The specified command line will be invoked one or more 33 | times with %h and 34 | %p sequences in the command line 35 | substituted for the hostname and port elements of the selected SRV 36 | record. The command line invoked must exit and return 0 after a 37 | successful connection or exit and return non-zero if the 38 | connection fails. wrapsrv will itself exit with 39 | the return code of the last command line invocation, or it may 40 | exit with a non-zero return code if the DNS SRV record lookup 41 | fails for any reason. 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /list.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2004, 2006, 2007 Internet Systems Consortium, Inc. ("ISC") 3 | * Copyright (C) 1997-2002 Internet Software Consortium. 4 | * 5 | * Permission to use, copy, modify, and/or distribute this software for any 6 | * purpose with or without fee is hereby granted, provided that the above 7 | * copyright notice and this permission notice appear in all copies. 8 | * 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 | * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 | * PERFORMANCE OF THIS SOFTWARE. 16 | */ 17 | 18 | #ifndef ISC_LIST_H 19 | #define ISC_LIST_H 1 20 | 21 | #define ISC_INSIST(x) assert(x) 22 | #define ISC_LINK_INSIST(x) assert(x) 23 | 24 | #define ISC_LIST(type) struct { type *head, *tail; } 25 | #define ISC_LIST_INIT(list) \ 26 | do { (list).head = NULL; (list).tail = NULL; } while (0) 27 | 28 | #define ISC_LINK(type) struct { type *prev, *next; } 29 | #define ISC_LINK_INIT_TYPE(elt, link, type) \ 30 | do { \ 31 | (elt)->link.prev = (type *)(-1); \ 32 | (elt)->link.next = (type *)(-1); \ 33 | } while (0) 34 | #define ISC_LINK_INIT(elt, link) \ 35 | ISC_LINK_INIT_TYPE(elt, link, void) 36 | #define ISC_LINK_LINKED(elt, link) ((void *)((elt)->link.prev) != (void *)(-1)) 37 | 38 | #define ISC_LIST_HEAD(list) ((list).head) 39 | #define ISC_LIST_TAIL(list) ((list).tail) 40 | #define ISC_LIST_EMPTY(list) ((list.head) == NULL ? 1 : 0) 41 | 42 | #define __ISC_LIST_PREPENDUNSAFE(list, elt, link) \ 43 | do { \ 44 | if ((list).head != NULL) \ 45 | (list).head->link.prev = (elt); \ 46 | else \ 47 | (list).tail = (elt); \ 48 | (elt)->link.prev = NULL; \ 49 | (elt)->link.next = (list).head; \ 50 | (list).head = (elt); \ 51 | } while (0) 52 | 53 | #define ISC_LIST_PREPEND(list, elt, link) \ 54 | do { \ 55 | ISC_LINK_INSIST(!ISC_LINK_LINKED(elt, link)); \ 56 | __ISC_LIST_PREPENDUNSAFE(list, elt, link); \ 57 | } while (0) 58 | 59 | #define ISC_LIST_INITANDPREPEND(list, elt, link) \ 60 | __ISC_LIST_PREPENDUNSAFE(list, elt, link) 61 | 62 | #define __ISC_LIST_APPENDUNSAFE(list, elt, link) \ 63 | do { \ 64 | if ((list).tail != NULL) \ 65 | (list).tail->link.next = (elt); \ 66 | else \ 67 | (list).head = (elt); \ 68 | (elt)->link.prev = (list).tail; \ 69 | (elt)->link.next = NULL; \ 70 | (list).tail = (elt); \ 71 | } while (0) 72 | 73 | #define ISC_LIST_APPEND(list, elt, link) \ 74 | do { \ 75 | ISC_LINK_INSIST(!ISC_LINK_LINKED(elt, link)); \ 76 | __ISC_LIST_APPENDUNSAFE(list, elt, link); \ 77 | } while (0) 78 | 79 | #define ISC_LIST_INITANDAPPEND(list, elt, link) \ 80 | __ISC_LIST_APPENDUNSAFE(list, elt, link) 81 | 82 | #define __ISC_LIST_UNLINKUNSAFE_TYPE(list, elt, link, type) \ 83 | do { \ 84 | if ((elt)->link.next != NULL) \ 85 | (elt)->link.next->link.prev = (elt)->link.prev; \ 86 | else { \ 87 | ISC_INSIST((list).tail == (elt)); \ 88 | (list).tail = (elt)->link.prev; \ 89 | } \ 90 | if ((elt)->link.prev != NULL) \ 91 | (elt)->link.prev->link.next = (elt)->link.next; \ 92 | else { \ 93 | ISC_INSIST((list).head == (elt)); \ 94 | (list).head = (elt)->link.next; \ 95 | } \ 96 | (elt)->link.prev = (type *)(-1); \ 97 | (elt)->link.next = (type *)(-1); \ 98 | } while (0) 99 | 100 | #define __ISC_LIST_UNLINKUNSAFE(list, elt, link) \ 101 | __ISC_LIST_UNLINKUNSAFE_TYPE(list, elt, link, void) 102 | 103 | #define ISC_LIST_UNLINK_TYPE(list, elt, link, type) \ 104 | do { \ 105 | ISC_LINK_INSIST(ISC_LINK_LINKED(elt, link)); \ 106 | __ISC_LIST_UNLINKUNSAFE_TYPE(list, elt, link, type); \ 107 | } while (0) 108 | #define ISC_LIST_UNLINK(list, elt, link) \ 109 | ISC_LIST_UNLINK_TYPE(list, elt, link, void) 110 | 111 | #define ISC_LIST_PREV(elt, link) ((elt)->link.prev) 112 | #define ISC_LIST_NEXT(elt, link) ((elt)->link.next) 113 | 114 | #define __ISC_LIST_INSERTBEFOREUNSAFE(list, before, elt, link) \ 115 | do { \ 116 | if ((before)->link.prev == NULL) \ 117 | ISC_LIST_PREPEND(list, elt, link); \ 118 | else { \ 119 | (elt)->link.prev = (before)->link.prev; \ 120 | (before)->link.prev = (elt); \ 121 | (elt)->link.prev->link.next = (elt); \ 122 | (elt)->link.next = (before); \ 123 | } \ 124 | } while (0) 125 | 126 | #define ISC_LIST_INSERTBEFORE(list, before, elt, link) \ 127 | do { \ 128 | ISC_LINK_INSIST(ISC_LINK_LINKED(before, link)); \ 129 | ISC_LINK_INSIST(!ISC_LINK_LINKED(elt, link)); \ 130 | __ISC_LIST_INSERTBEFOREUNSAFE(list, before, elt, link); \ 131 | } while (0) 132 | 133 | #define __ISC_LIST_INSERTAFTERUNSAFE(list, after, elt, link) \ 134 | do { \ 135 | if ((after)->link.next == NULL) \ 136 | ISC_LIST_APPEND(list, elt, link); \ 137 | else { \ 138 | (elt)->link.next = (after)->link.next; \ 139 | (after)->link.next = (elt); \ 140 | (elt)->link.next->link.prev = (elt); \ 141 | (elt)->link.prev = (after); \ 142 | } \ 143 | } while (0) 144 | 145 | #define ISC_LIST_INSERTAFTER(list, after, elt, link) \ 146 | do { \ 147 | ISC_LINK_INSIST(ISC_LINK_LINKED(after, link)); \ 148 | ISC_LINK_INSIST(!ISC_LINK_LINKED(elt, link)); \ 149 | __ISC_LIST_INSERTAFTERUNSAFE(list, after, elt, link); \ 150 | } while (0) 151 | 152 | #define ISC_LIST_APPENDLIST(list1, list2, link) \ 153 | do { \ 154 | if (ISC_LIST_EMPTY(list1)) \ 155 | (list1) = (list2); \ 156 | else if (!ISC_LIST_EMPTY(list2)) { \ 157 | (list1).tail->link.next = (list2).head; \ 158 | (list2).head->link.prev = (list1).tail; \ 159 | (list1).tail = (list2).tail; \ 160 | } \ 161 | (list2).head = NULL; \ 162 | (list2).tail = NULL; \ 163 | } while (0) 164 | 165 | #define ISC_LIST_ENQUEUE(list, elt, link) ISC_LIST_APPEND(list, elt, link) 166 | #define __ISC_LIST_ENQUEUEUNSAFE(list, elt, link) \ 167 | __ISC_LIST_APPENDUNSAFE(list, elt, link) 168 | #define ISC_LIST_DEQUEUE(list, elt, link) \ 169 | ISC_LIST_UNLINK_TYPE(list, elt, link, void) 170 | #define ISC_LIST_DEQUEUE_TYPE(list, elt, link, type) \ 171 | ISC_LIST_UNLINK_TYPE(list, elt, link, type) 172 | #define __ISC_LIST_DEQUEUEUNSAFE(list, elt, link) \ 173 | __ISC_LIST_UNLINKUNSAFE_TYPE(list, elt, link, void) 174 | #define __ISC_LIST_DEQUEUEUNSAFE_TYPE(list, elt, link, type) \ 175 | __ISC_LIST_UNLINKUNSAFE_TYPE(list, elt, link, type) 176 | 177 | #endif /* ISC_LIST_H */ 178 | -------------------------------------------------------------------------------- /wrapsrv.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009, 2011, 2014 by Farsight Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* Import. */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "list.h" 37 | 38 | #ifndef NS_MAXMSG 39 | #define NS_MAXMSG 65535 40 | #endif 41 | 42 | /* Data types. */ 43 | 44 | struct srv { 45 | ISC_LINK(struct srv) link; 46 | char *tname; 47 | uint16_t weight; 48 | uint16_t port; 49 | }; 50 | 51 | struct srv_prio { 52 | ISC_LINK(struct srv_prio) link; 53 | ISC_LIST(struct srv) srv_list; 54 | uint16_t prio; 55 | }; 56 | 57 | typedef ISC_LIST(struct srv) srv_list; 58 | typedef ISC_LIST(struct srv_prio) srv_prio_list; 59 | 60 | /* Globals. */ 61 | 62 | static srv_prio_list prio_list; 63 | 64 | /* Forward. */ 65 | 66 | static char *subst_cmd(struct srv *, const char *); 67 | static char *target_name(const unsigned char *); 68 | static int do_cmd(struct srv *, int, char **); 69 | static struct srv *next_tuple(void); 70 | static void free_tuples(void); 71 | static void insert_tuple(char *, uint16_t, uint16_t, uint16_t); 72 | static void parse_answer_section(ns_msg *); 73 | static void usage(void); 74 | 75 | #ifdef DEBUG 76 | static void print_tuples(void); 77 | #endif 78 | 79 | /* Functions. */ 80 | 81 | static struct srv * 82 | next_tuple(void) { 83 | struct srv_prio *pe; 84 | struct srv *se; 85 | uint16_t rnd; 86 | unsigned csum = 0; 87 | unsigned wsum = 0; 88 | 89 | pe = ISC_LIST_HEAD(prio_list); 90 | if (pe == NULL) 91 | return (NULL); 92 | 93 | for (se = ISC_LIST_HEAD(pe->srv_list); 94 | se != NULL; 95 | se = ISC_LIST_NEXT(se, link)) 96 | { 97 | wsum += se->weight; 98 | } 99 | 100 | rnd = random() % (wsum + 1); 101 | 102 | for (se = ISC_LIST_HEAD(pe->srv_list); 103 | se != NULL; 104 | se = ISC_LIST_NEXT(se, link)) 105 | { 106 | csum += se->weight; 107 | 108 | if (csum >= rnd) { 109 | ISC_LIST_UNLINK(pe->srv_list, se, link); 110 | break; 111 | } 112 | } 113 | 114 | if (se == NULL) { 115 | ISC_LIST_UNLINK(prio_list, pe, link); 116 | free(pe); 117 | return (next_tuple()); 118 | } 119 | 120 | #ifdef DEBUG 121 | fprintf(stderr, "rnd=%hu -> prio=%hu weight=%hu port=%hu tname=%s\n", 122 | rnd, pe->prio, se->weight, se->port, se->tname); 123 | #endif 124 | 125 | return (se); 126 | } 127 | 128 | static void 129 | free_tuples(void) { 130 | struct srv_prio *pe, *pe_next; 131 | struct srv *se, *se_next; 132 | 133 | pe = ISC_LIST_HEAD(prio_list); 134 | while (pe != NULL) { 135 | pe_next = ISC_LIST_NEXT(pe, link); 136 | ISC_LIST_UNLINK(prio_list, pe, link); 137 | 138 | se = ISC_LIST_HEAD(pe->srv_list); 139 | while (se != NULL) { 140 | se_next = ISC_LIST_NEXT(se, link); 141 | ISC_LIST_UNLINK(pe->srv_list, se, link); 142 | free(se->tname); 143 | free(se); 144 | se = se_next; 145 | } 146 | 147 | free(pe); 148 | pe = pe_next; 149 | } 150 | } 151 | 152 | static void 153 | insert_tuple(char *tname, uint16_t prio, uint16_t weight, uint16_t port) { 154 | struct srv_prio *pe; 155 | struct srv *se; 156 | 157 | for (pe = ISC_LIST_HEAD(prio_list); 158 | pe != NULL; 159 | pe = ISC_LIST_NEXT(pe, link)) 160 | { 161 | if (pe->prio == prio) 162 | break; 163 | } 164 | 165 | if (pe == NULL) { 166 | struct srv_prio *piter; 167 | 168 | pe = malloc(sizeof(*pe)); 169 | assert(pe != NULL); 170 | 171 | ISC_LINK_INIT(pe, link); 172 | ISC_LIST_INIT(pe->srv_list); 173 | pe->prio = prio; 174 | 175 | for (piter = ISC_LIST_HEAD(prio_list); 176 | piter != NULL; 177 | piter = ISC_LIST_NEXT(piter, link)) 178 | { 179 | assert(piter->prio != prio); 180 | 181 | if (piter->prio > prio) { 182 | ISC_LIST_INSERTBEFORE(prio_list, piter, pe, link); 183 | break; 184 | } 185 | } 186 | 187 | if (piter == NULL) 188 | ISC_LIST_APPEND(prio_list, pe, link); 189 | } 190 | 191 | se = malloc(sizeof(*se)); 192 | assert(se != NULL); 193 | 194 | ISC_LINK_INIT(se, link); 195 | se->tname = tname; 196 | se->weight = weight; 197 | se->port = port; 198 | 199 | ISC_LIST_APPEND(pe->srv_list, se, link); 200 | } 201 | 202 | #ifdef DEBUG 203 | static void 204 | print_tuples(void) { 205 | struct srv_prio *pe; 206 | struct srv *se; 207 | 208 | for (pe = ISC_LIST_HEAD(prio_list); 209 | pe != NULL; 210 | pe = ISC_LIST_NEXT(pe, link)) 211 | { 212 | fprintf(stderr, "prio=%hu\n", pe->prio); 213 | for (se = ISC_LIST_HEAD(pe->srv_list); 214 | se != NULL; 215 | se = ISC_LIST_NEXT(se, link)) 216 | { 217 | fprintf(stderr, "\tweight=%hu port=%hu tname=%s\n", 218 | se->weight, se->port, se->tname); 219 | } 220 | } 221 | } 222 | #endif 223 | 224 | static char * 225 | target_name(const unsigned char *target) { 226 | char buf[NS_MAXDNAME]; 227 | 228 | if (ns_name_ntop(target, buf, sizeof buf) == -1) { 229 | perror("ns_name_ntop"); 230 | exit(EXIT_FAILURE); 231 | } 232 | return (strdup(buf)); 233 | } 234 | 235 | static void 236 | parse_answer_section(ns_msg *msg) { 237 | int rrnum, rrmax; 238 | ns_rr rr; 239 | uint16_t prio, weight, port, len; 240 | const unsigned char *rdata; 241 | char *tname; 242 | 243 | rrmax = ns_msg_count(*msg, ns_s_an); 244 | for (rrnum = 0; rrnum < rrmax; rrnum++) { 245 | if (ns_parserr(msg, ns_s_an, rrnum, &rr)) { 246 | perror("ns_parserr"); 247 | exit(EXIT_FAILURE); 248 | } 249 | if (ns_rr_type(rr) == ns_t_srv) { 250 | len = ns_rr_rdlen(rr); 251 | rdata = ns_rr_rdata(rr); 252 | if (len > 3U * NS_INT16SZ) { 253 | NS_GET16(prio, rdata); 254 | NS_GET16(weight, rdata); 255 | NS_GET16(port, rdata); 256 | len -= 3U * NS_INT16SZ; 257 | tname = target_name(rdata); 258 | insert_tuple(tname, prio, weight, port); 259 | } 260 | } 261 | } 262 | } 263 | 264 | static char * 265 | subst_cmd(struct srv *se, const char *cmd) { 266 | char *q, *str; 267 | const char *p = cmd; 268 | int ch; 269 | int n_host = 0; 270 | int n_port = 0; 271 | size_t bufsz; 272 | size_t len_tname; 273 | 274 | len_tname = strlen(se->tname); 275 | 276 | while ((ch = *p++) != '\0') { 277 | if (ch == '%' && *p == 'h') 278 | n_host++; 279 | if (ch == '%' && *p == 'p') 280 | n_port++; 281 | } 282 | 283 | bufsz = strlen(cmd) + 1; 284 | bufsz -= 2 * (n_host + n_port); /* '%h' and '%p' */ 285 | bufsz += 5 * n_port; /* '%h' -> uint16_t */ 286 | bufsz += (strlen(se->tname) + 1) * n_host; 287 | 288 | str = calloc(1, bufsz); 289 | assert(str != NULL); 290 | 291 | p = cmd; 292 | q = str; 293 | while ((ch = *p++) != '\0') { 294 | if (ch == '%' && *p == 'h') { 295 | strcpy(q, se->tname); 296 | q += len_tname; 297 | p++; 298 | } else if (ch == '%' && *p == 'p') { 299 | q += sprintf(q, "%hu", se->port); 300 | p++; 301 | } else { 302 | *q++ = ch; 303 | } 304 | } 305 | 306 | return (str); 307 | } 308 | 309 | static int 310 | do_cmd(struct srv *se, int argc, char **argv) { 311 | char *cmd, *scmd, *p; 312 | int i, rc; 313 | size_t bufsz = 2; 314 | 315 | for (i = 2; i < argc; i++) { 316 | bufsz += 1; 317 | bufsz += strlen(argv[i]); 318 | } 319 | 320 | p = cmd = malloc(bufsz); 321 | assert(cmd != NULL); 322 | 323 | for (i = 2; i < argc; i++) { 324 | strcpy(p, argv[i]); 325 | p += strlen(argv[i]); 326 | if (i != argc - 1) { 327 | *p++ = ' '; 328 | } 329 | } 330 | 331 | scmd = subst_cmd(se, cmd); 332 | free(cmd); 333 | 334 | #ifdef DEBUG 335 | fprintf(stderr, "scmd='%s'\n", scmd); 336 | #endif 337 | 338 | rc = system(scmd); 339 | rc = WEXITSTATUS(rc); 340 | 341 | free(scmd); 342 | free(se->tname); 343 | free(se); 344 | 345 | #ifdef DEBUG 346 | fprintf(stderr, "rc=%i\n", rc); 347 | #endif 348 | return (rc); 349 | } 350 | 351 | static void 352 | usage(void) { 353 | fprintf(stderr, "Usage: wrapsrv [OPTION]...\n"); 354 | fprintf(stderr, "%%h and %%p sequences will be converted to " 355 | "hostname and port.\n"); 356 | exit(EXIT_FAILURE); 357 | } 358 | 359 | int 360 | main(int argc, char **argv) { 361 | char *qname; 362 | ns_msg msg; 363 | int len, rc = 0; 364 | unsigned char answer[NS_MAXMSG]; 365 | unsigned rcode; 366 | struct srv *se; 367 | struct timeval tv; 368 | unsigned int seed = 0; 369 | 370 | if (argc < 3) 371 | usage(); 372 | 373 | ISC_LIST_INIT(prio_list); 374 | 375 | gettimeofday(&tv, NULL); 376 | 377 | seed ^= (unsigned int) tv.tv_usec; 378 | seed ^= (unsigned int) getpid(); 379 | 380 | srandom(seed); 381 | 382 | res_init(); 383 | 384 | qname = argv[1]; 385 | 386 | len = res_query(qname, ns_c_in, ns_t_srv, answer, sizeof answer); 387 | if (len < 0) { 388 | herror("res_query"); 389 | return (EXIT_FAILURE); 390 | } 391 | 392 | if (ns_initparse(answer, len, &msg) < 0) { 393 | perror("ns_initparse"); 394 | return (EXIT_FAILURE); 395 | } 396 | 397 | rcode = ns_msg_getflag(msg, ns_f_rcode); 398 | if (rcode != ns_r_noerror) { 399 | fprintf(stderr, "wrapsrv: query for %s returned rcode %u\n", 400 | qname, rcode); 401 | return (EXIT_FAILURE); 402 | } 403 | 404 | if (ns_msg_count(msg, ns_s_an) == 0) { 405 | fprintf(stderr, "wrapsrv: query for %s returned no answers\n", 406 | qname); 407 | return (EXIT_FAILURE); 408 | } 409 | 410 | parse_answer_section(&msg); 411 | #ifdef DEBUG 412 | print_tuples(); 413 | fprintf(stderr, "\n"); 414 | #endif 415 | 416 | while ((se = next_tuple()) != NULL) { 417 | if ((rc = do_cmd(se, argc, argv)) == 0) 418 | break; 419 | #ifdef DEBUG 420 | fprintf(stderr, "\n"); 421 | #endif 422 | } 423 | 424 | free_tuples(); 425 | 426 | return (rc); 427 | } 428 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | --------------------------------------------------------------------------------