savecopy.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. #include "unp.h"
  2. #include <ctype.h> /* isxdigit(), etc. */
  3. #include <arpa/nameser.h>
  4. #include <resolv.h> /* res_init, _res */
  5. /* following internal flag cannot overlap with other AI_xxx flags */
  6. #define AI_CLONE 4 /* clone this entry for other socket types */
  7. struct search {
  8. const char *host; /* hostname of address string */
  9. int family; /* AF_xxx */
  10. };
  11. /* function prototypes for our own internal functions */
  12. static int ga_echeck(const char *, const char *, const struct addrinfo *);
  13. static int ga_nsearch(const char *, const struct addrinfo *,
  14. struct search *);
  15. static int ga_aistruct(struct addrinfo ***, const struct addrinfo *,
  16. void *, int);
  17. static int ga_serv(struct addrinfo *, const struct addrinfo *, const char *);
  18. static int ga_port(struct addrinfo *, int , int);
  19. static int ga_unix(const char *, struct addrinfo *, struct addrinfo **);
  20. static struct addrinfo *ga_clone(struct addrinfo *);
  21. /* globals for all functions in this file; these *must* be
  22. read-only if this function is to be reentrant */
  23. static struct addrinfo hints_default;
  24. int
  25. getaddrinfo(const char *hostname, const char *servname,
  26. const struct addrinfo *hintsp, struct addrinfo **result)
  27. {
  28. int rc, error, nsearch;
  29. char **ap;
  30. struct hostent *hptr;
  31. struct search search[3], *sptr;
  32. struct addrinfo hints, *ai, *aihead, **aipnext;
  33. /*
  34. * If we encounter an error we want to free() any dynamic memory
  35. * that we've allocated. This is our hack to simplify the code.
  36. */
  37. #define error(e) { error = (e); goto bad; }
  38. if (hintsp == NULL) {
  39. hints = hints_default; /* struct copy */
  40. hints.ai_family = AF_UNSPEC;
  41. } else
  42. hints = *hintsp; /* struct copy */
  43. /* 4first some basic error checking */
  44. if ( (rc = ga_echeck(hostname, servname, &hints)) != 0)
  45. error(rc);
  46. #ifdef UNIXDOMAIN
  47. /*
  48. * Special case Unix domain first;
  49. * remainder of function for IPv4/IPv6.
  50. */
  51. if (hostname != NULL && hostname[0] == '/' &&
  52. (servname == NULL || servname[0] == '\0'))
  53. return(ga_unix(hostname, &hints, result));
  54. if (servname != NULL && servname[0] == '/' &&
  55. (hostname == NULL || hostname[0] == '\0'))
  56. return(ga_unix(servname, &hints, result));
  57. #endif
  58. nsearch = ga_nsearch(hostname, &hints, &search[0]);
  59. aihead = NULL;
  60. aipnext = &aihead;
  61. for (sptr = &search[0]; sptr < &search[nsearch]; sptr++) {
  62. #ifdef IPV4
  63. /* 4check for an IPv4 dotted-decimal string */
  64. if (isdigit(sptr->host[0])) {
  65. struct in_addr inaddr;
  66. if (inet_pton(AF_INET, sptr->host, &inaddr) == 1) {
  67. rc = ga_aistruct(&aipnext, &hints, &inaddr, AF_INET);
  68. if (rc != 0)
  69. error(rc);
  70. continue;
  71. }
  72. }
  73. #endif
  74. #ifdef IPV6
  75. /* 4check for an IPv6 hex string */
  76. if (isxdigit(sptr->host[0]) || sptr->host[0] == ':') {
  77. struct in6_addr in6addr;
  78. if (inet_pton(AF_INET6, sptr->host, &in6addr) == 1) {
  79. rc = ga_aistruct(&aipnext, &hints, &in6addr, AF_INET6);
  80. if (rc != 0)
  81. error(rc);
  82. continue;
  83. }
  84. }
  85. #endif
  86. /* 4look up hostname */
  87. if ((_res.options & RES_INIT) == 0)
  88. res_init(); /* need this to set _res.options */
  89. if (nsearch == 2)
  90. hptr = gethostbyname2(sptr->host, sptr->family);
  91. else {
  92. #ifdef IPV6
  93. if (sptr->family == AF_INET6)
  94. _res.options |= RES_USE_INET6;
  95. else
  96. _res.options &= ~RES_USE_INET6;
  97. #endif
  98. hptr = gethostbyname(sptr->host);
  99. }
  100. if (hptr == NULL) {
  101. switch (h_errno) {
  102. case HOST_NOT_FOUND: error(EAI_NONAME);
  103. case TRY_AGAIN: error(EAI_AGAIN);
  104. case NO_RECOVERY: error(EAI_FAIL);
  105. case NO_DATA: error(EAI_NODATA);
  106. default: error(EAI_NONAME);
  107. }
  108. }
  109. /* 4check for address family mismatch if one specified */
  110. if (hints.ai_family != AF_UNSPEC && hints.ai_family != hptr->h_addrtype)
  111. error(EAI_ADDRFAMILY);
  112. /* 4create one addrinfo{} for each returned address */
  113. for (ap = hptr->h_addr_list; *ap != NULL; ap++) {
  114. if ( (ai = calloc(1, sizeof(struct addrinfo))) == NULL)
  115. error(EAI_MEMORY);
  116. *aipnext = ai;
  117. aipnext = &ai->ai_next;
  118. rc = ga_aistruct(&aipnext, &hints, *ap, hptr->h_addrtype);
  119. if (rc != 0)
  120. error(rc);
  121. }
  122. }
  123. /* "aihead" points to the first structure in the linked list */
  124. if (hostname != NULL && hostname[0] != '\0' &&
  125. hints.ai_flags & AI_CANONNAME) {
  126. aihead->ai_canonname = strdup(hptr->h_name != NULL ?
  127. hptr->h_name : search[0].host);
  128. if (aihead->ai_canonname == NULL)
  129. error(EAI_MEMORY);
  130. }
  131. /* 4now process the service name */
  132. if (servname != NULL && servname[0] != '\0') {
  133. if ( (rc = ga_serv(aihead, &hints, servname)) != 0)
  134. error(rc);
  135. }
  136. *result = aihead; /* pointer to first structure in linked list */
  137. return(0);
  138. bad:
  139. freeaddrinfo(aihead); /* free any alloc'ed memory */
  140. return(error);
  141. }
  142. /*
  143. * Basic error checking at the beginning.
  144. */
  145. static int
  146. ga_echeck(const char *hostname, const char *servname,
  147. const struct addrinfo *hintsp)
  148. {
  149. if (hintsp->ai_flags & ~(AI_PASSIVE | AI_CANONNAME))
  150. return(EAI_BADFLAGS); /* unknown flag bits */
  151. if (hostname == NULL || hostname[0] == '\0') {
  152. if (servname == NULL || servname[0] == '\0')
  153. return(EAI_NONAME); /* host or service must be specified */
  154. }
  155. switch(hintsp->ai_family) {
  156. case AF_UNSPEC:
  157. break;
  158. #ifdef IPV4
  159. case AF_INET:
  160. if (hintsp->ai_socktype != 0 &&
  161. (hintsp->ai_socktype != SOCK_STREAM &&
  162. hintsp->ai_socktype != SOCK_DGRAM &&
  163. hintsp->ai_socktype != SOCK_RAW))
  164. return(EAI_SOCKTYPE); /* invalid socket type */
  165. break;
  166. #endif
  167. #ifdef IPV6
  168. case AF_INET6:
  169. if (hintsp->ai_socktype != 0 &&
  170. (hintsp->ai_socktype != SOCK_STREAM &&
  171. hintsp->ai_socktype != SOCK_DGRAM &&
  172. hintsp->ai_socktype != SOCK_RAW))
  173. return(EAI_SOCKTYPE); /* invalid socket type */
  174. break;
  175. #endif
  176. #ifdef UNIXDOMAIN
  177. case AF_LOCAL:
  178. if (hintsp->ai_socktype != 0 &&
  179. (hintsp->ai_socktype != SOCK_STREAM &&
  180. hintsp->ai_socktype != SOCK_DGRAM))
  181. return(EAI_SOCKTYPE); /* invalid socket type */
  182. break;
  183. #endif
  184. default:
  185. return(EAI_FAMILY); /* unknown protocol family */
  186. }
  187. return(0);
  188. }
  189. /*
  190. * Set up the search[] array with the hostnames and address families
  191. * that we are to look up.
  192. */
  193. static int
  194. ga_nsearch(const char *hostname, const struct addrinfo *hintsp,
  195. struct search *search)
  196. {
  197. int nsearch = 0;
  198. if (hostname == NULL || hostname[0] == '\0') {
  199. if (hintsp->ai_flags & AI_PASSIVE) {
  200. /* 4no hostname and AI_PASSIVE: implies wildcard bind */
  201. switch (hintsp->ai_family) {
  202. #ifdef IPV4
  203. case AF_INET:
  204. search[nsearch].host = "0.0.0.0";
  205. search[nsearch].family = AF_INET;
  206. nsearch++;
  207. break;
  208. #endif
  209. #ifdef IPV6
  210. case AF_INET6:
  211. search[nsearch].host = "0::0";
  212. search[nsearch].family = AF_INET6;
  213. nsearch++;
  214. break;
  215. #endif
  216. case AF_UNSPEC:
  217. #ifdef IPV6
  218. search[nsearch].host = "0::0"; /* IPv6 first, then IPv4 */
  219. search[nsearch].family = AF_INET6;
  220. nsearch++;
  221. #endif
  222. #ifdef IPV4
  223. search[nsearch].host = "0.0.0.0";
  224. search[nsearch].family = AF_INET;
  225. nsearch++;
  226. #endif
  227. break;
  228. }
  229. } else {
  230. /* 4no host and not AI_PASSIVE: connect to local host */
  231. switch (hintsp->ai_family) {
  232. #ifdef IPV4
  233. case AF_INET:
  234. search[nsearch].host = "localhost"; /* 127.0.0.1 */
  235. search[nsearch].family = AF_INET;
  236. nsearch++;
  237. break;
  238. #endif
  239. #ifdef IPV6
  240. case AF_INET6:
  241. search[nsearch].host = "0::1";
  242. search[nsearch].family = AF_INET6;
  243. nsearch++;
  244. break;
  245. #endif
  246. case AF_UNSPEC:
  247. #ifdef IPV6
  248. search[nsearch].host = "0::1"; /* IPv6 first, then IPv4 */
  249. search[nsearch].family = AF_INET6;
  250. nsearch++;
  251. #endif
  252. #ifdef IPV4
  253. search[nsearch].host = "localhost";
  254. search[nsearch].family = AF_INET;
  255. nsearch++;
  256. #endif
  257. break;
  258. }
  259. }
  260. } else { /* host is specified */
  261. switch (hintsp->ai_family) {
  262. #ifdef IPV4
  263. case AF_INET:
  264. search[nsearch].host = hostname;
  265. search[nsearch].family = AF_INET;
  266. nsearch++;
  267. break;
  268. #endif
  269. #ifdef IPV6
  270. case AF_INET6:
  271. search[nsearch].host = hostname;
  272. search[nsearch].family = AF_INET6;
  273. nsearch++;
  274. break;
  275. #endif
  276. case AF_UNSPEC:
  277. #ifdef IPV6
  278. search[nsearch].host = hostname;
  279. search[nsearch].family = AF_INET6; /* IPv6 first */
  280. nsearch++;
  281. #endif
  282. #ifdef IPV4
  283. search[nsearch].host = hostname;
  284. search[nsearch].family = AF_INET; /* then IPv4 */
  285. nsearch++;
  286. #endif
  287. break;
  288. }
  289. }
  290. if (nsearch < 1 || nsearch > 2)
  291. err_quit("nsearch = %d", nsearch);
  292. return(nsearch);
  293. }
  294. /*
  295. * Create and fill in a addrinfo{}.
  296. */
  297. static int
  298. ga_aistruct(struct addrinfo ***paipnext, const struct addrinfo *hintsp,
  299. void *addr, int family)
  300. {
  301. struct addrinfo *ai;
  302. if ( (ai = calloc(1, sizeof(struct addrinfo))) == NULL)
  303. return(EAI_MEMORY);
  304. ai->ai_next = NULL;
  305. ai->ai_canonname = NULL;
  306. **paipnext = ai;
  307. *paipnext = &ai->ai_next;
  308. if ( (ai->ai_socktype = hintsp->ai_socktype) == 0)
  309. ai->ai_flags |= AI_CLONE;
  310. ai->ai_protocol = hintsp->ai_protocol;
  311. switch ((ai->ai_family = family)) {
  312. #ifdef IPV4
  313. case AF_INET: {
  314. struct sockaddr_in *sinptr;
  315. /* 4allocate sockaddr_in{} and fill in all but port */
  316. if ( (sinptr = calloc(1, sizeof(struct sockaddr_in))) == NULL)
  317. return(EAI_MEMORY);
  318. #ifdef HAVE_SOCKADDR_SA_LEN
  319. sinptr->sin_len = sizeof(struct sockaddr_in);
  320. #endif
  321. sinptr->sin_family = AF_INET;
  322. memcpy(&sinptr->sin_addr, addr, sizeof(struct in_addr));
  323. ai->ai_addr = (struct sockaddr *) sinptr;
  324. ai->ai_addrlen = sizeof(struct sockaddr_in);
  325. break;
  326. }
  327. #endif /* IPV4 */
  328. #ifdef IPV6
  329. /* 4allocate sockaddr_in6{} and fill in all but port */
  330. case AF_INET6: {
  331. struct sockaddr_in6 *sin6ptr;
  332. if ( (sin6ptr = calloc(1, sizeof(struct sockaddr_in6))) == NULL)
  333. return(EAI_MEMORY);
  334. #ifdef HAVE_SOCKADDR_SA_LEN
  335. sin6ptr->sin6_len = sizeof(struct sockaddr_in6);
  336. #endif
  337. sin6ptr->sin6_family = AF_INET6;
  338. memcpy(&sin6ptr->sin6_addr, addr, sizeof(struct in6_addr));
  339. ai->ai_addr = (struct sockaddr *) sin6ptr;
  340. ai->ai_addrlen = sizeof(struct sockaddr_in6);
  341. break;
  342. }
  343. #endif /* IPV6 */
  344. }
  345. return(0);
  346. }
  347. /*
  348. * This function handles the service string.
  349. */
  350. static int
  351. ga_serv(struct addrinfo *aihead, const struct addrinfo *hintsp,
  352. const char *serv)
  353. {
  354. int port, rc, nfound;
  355. struct servent *sptr;
  356. /* 4check for port number first */
  357. if (isdigit(serv[0]) && hintsp->ai_socktype != 0) {
  358. port = htons(atoi(serv));
  359. if ( (rc = ga_port(aihead, port, hintsp->ai_socktype)) == 0)
  360. return(EAI_NONAME);
  361. else if (rc < 0)
  362. return(EAI_MEMORY);
  363. else
  364. return(0);
  365. }
  366. /* 4try TCP first */
  367. nfound = 0;
  368. if (hintsp->ai_socktype == 0 || hintsp->ai_socktype == SOCK_STREAM) {
  369. if ( (sptr = getservbyname(serv, "tcp")) != NULL) {
  370. if ( (rc = ga_port(aihead, sptr->s_port, SOCK_STREAM)) < 0)
  371. return(EAI_MEMORY);
  372. nfound += rc;
  373. }
  374. }
  375. /* 4try UDP */
  376. if (hintsp->ai_socktype == 0 || hintsp->ai_socktype == SOCK_DGRAM) {
  377. if ( (sptr = getservbyname(serv, "udp")) != NULL) {
  378. if ( (rc = ga_port(aihead, sptr->s_port, SOCK_DGRAM)) < 0)
  379. return(EAI_MEMORY);
  380. nfound += rc;
  381. }
  382. }
  383. if (nfound == 0) {
  384. if (hintsp->ai_socktype == 0)
  385. return(EAI_NONAME); /* all calls to getservbyname() failed */
  386. else
  387. return(EAI_SERVICE);/* service not supported for socket type */
  388. }
  389. return(0);
  390. }
  391. /*
  392. * Go through all the addrinfo structures, checking for a match of the
  393. * socket type and filling in the socket type, and then the port number
  394. * in the corresponding socket address structures.
  395. *
  396. * The AI_CLONE flag works as follows. Consider a multihomed host with
  397. * two IP addresses and no socket type specified by the caller. After
  398. * the "host" search there are two addrinfo structures, one per IP address.
  399. * Assuming a service supported by both TCP and UDP (say the daytime
  400. * service) we need to return *four* addrinfo structures:
  401. * IP#1, SOCK_STREAM, TCP port,
  402. * IP#1, SOCK_DGRAM, UDP port,
  403. * IP#2, SOCK_STREAM, TCP port,
  404. * IP#2, SOCK_DGRAM, UDP port.
  405. * To do this, when the "host" loop creates an addrinfo structure, if the
  406. * caller has not specified a socket type (hintsp->ai_socktype == 0), the
  407. * AI_CLONE flag is set. When the following function finds an entry like
  408. * this it is handled as follows: If the entry's ai_socktype is still 0,
  409. * this is the first use of the structure, and the ai_socktype field is set.
  410. * But, if the entry's ai_socktype is nonzero, then we clone a new addrinfo
  411. * structure and set it's ai_socktype to the new value. Although we only
  412. * need two socket types today (SOCK_STREAM and SOCK_DGRAM) this algorithm
  413. * will handle any number. Also notice that Posix.1g requires all socket
  414. * types to be nonzero.
  415. */
  416. static int
  417. ga_port(struct addrinfo *aihead, int port, int socktype)
  418. /* port must be in network byte order */
  419. {
  420. int nfound = 0;
  421. struct addrinfo *ai;
  422. for (ai = aihead; ai != NULL; ai = ai->ai_next) {
  423. if (ai->ai_flags & AI_CLONE) {
  424. if (ai->ai_socktype != 0) {
  425. if ( (ai = ga_clone(ai)) == NULL)
  426. return(-1); /* memory allocation error */
  427. /* ai points to newly cloned entry, which is what we want */
  428. }
  429. } else if (ai->ai_socktype != socktype)
  430. continue; /* ignore if mismatch on socket type */
  431. ai->ai_socktype = socktype;
  432. switch (ai->ai_family) {
  433. #ifdef IPV4
  434. case AF_INET:
  435. ((struct sockaddr_in *) ai->ai_addr)->sin_port = port;
  436. nfound++;
  437. break;
  438. #endif
  439. #ifdef IPV6
  440. case AF_INET6:
  441. ((struct sockaddr_in6 *) ai->ai_addr)->sin6_port = port;
  442. nfound++;
  443. break;
  444. #endif
  445. }
  446. }
  447. return(nfound);
  448. }
  449. /*
  450. * Clone a new addrinfo structure from an existing one.
  451. */
  452. static struct addrinfo *
  453. ga_clone(struct addrinfo *ai)
  454. {
  455. struct addrinfo *new;
  456. if ( (new = calloc(1, sizeof(struct addrinfo))) == NULL)
  457. return(NULL);
  458. new->ai_next = ai->ai_next;
  459. ai->ai_next = new;
  460. new->ai_flags = 0; /* make sure AI_CLONE is off */
  461. new->ai_family = ai->ai_family;
  462. new->ai_socktype = ai->ai_socktype;
  463. new->ai_protocol = ai->ai_protocol;
  464. new->ai_canonname = NULL;
  465. new->ai_addrlen = ai->ai_addrlen;
  466. if ( (new->ai_addr = malloc(ai->ai_addrlen)) == NULL)
  467. return(NULL);
  468. memcpy(new->ai_addr, ai->ai_addr, ai->ai_addrlen);
  469. return(new);
  470. }
  471. #ifdef UNIXDOMAIN
  472. /*
  473. * Do everything for a Unix domain socket.
  474. * Only one addrinfo{} is returned.
  475. */
  476. static int
  477. ga_unix(const char *path, struct addrinfo *hintsp, struct addrinfo **result)
  478. {
  479. struct addrinfo *ai;
  480. struct sockaddr_un *unp;
  481. if (hintsp->ai_socktype == 0)
  482. return(EAI_SOCKTYPE); /* we cannot tell socket type from service */
  483. if ( (ai = calloc(1, sizeof(struct addrinfo))) == NULL)
  484. return(NULL);
  485. ai->ai_flags = 0;
  486. ai->ai_family = AF_LOCAL;
  487. ai->ai_socktype = hintsp->ai_socktype;
  488. ai->ai_protocol = 0;
  489. /* allocate and fill in a socket address structure */
  490. ai->ai_addrlen = sizeof(struct sockaddr_un);
  491. if ( (ai->ai_addr = malloc(ai->ai_addrlen)) == NULL)
  492. return(EAI_MEMORY);
  493. unp = (struct sockaddr_un *) ai->ai_addr;
  494. unp->sun_family = AF_UNIX;
  495. strncpy(unp->sun_path, path, sizeof(unp->sun_path));
  496. ai->ai_canonname = NULL; /* maybe return the i-node number :-) */
  497. ai->ai_next = NULL;
  498. *result = ai;
  499. if (hintsp->ai_flags & AI_PASSIVE)
  500. unlink(path); /* OK if this fails */
  501. return(0); /* success */
  502. }
  503. #endif /* UNIXDOMAIN */
  504. void
  505. freeaddrinfo(struct addrinfo *aihead)
  506. {
  507. struct addrinfo *ai, *ainext;
  508. for (ai = aihead; ai != NULL; ai = ainext) {
  509. if (ai->ai_addr != NULL)
  510. free(ai->ai_addr); /* the socket address structure */
  511. if (ai->ai_canonname != NULL)
  512. free(ai->ai_canonname); /* the canonical name */
  513. ainext = ai->ai_next; /* can't fetch ai_next after free() */
  514. free(ai); /* the addrinfo{} itself */
  515. }
  516. }