made it so it works with mix of dynamic and static servers for a realm
[radsecproxy.git] / util.c
1 /*
2  * Copyright (C) 2006-2008 Stig Venaas <venaas@uninett.no>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  */
8
9 #include <sys/socket.h>
10 #include <netinet/in.h>
11 #include <netdb.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <unistd.h>
16 #include <stdarg.h>
17 #include "debug.h"
18 #include "util.h"
19
20 char *stringcopy(const char *s, int len) {
21     char *r;
22     if (!s)
23         return NULL;
24     if (!len)
25         len = strlen(s);
26     r = malloc(len + 1);
27     if (!r)
28         debug(DBG_ERR, "stringcopy: malloc failed");
29     memcpy(r, s, len);
30     r[len] = '\0';
31     return r;
32 }
33
34 void printfchars(char *prefixfmt, char *prefix, char *charfmt, char *chars, int len) {
35     int i;
36     unsigned char *s = (unsigned char *)chars;
37     if (prefix)
38         printf(prefixfmt ? prefixfmt : "%s: ", prefix);
39     for (i = 0; i < len; i++)
40         printf(charfmt ? charfmt : "%c", s[i]);
41     printf("\n");
42 }
43
44 void port_set(struct sockaddr *sa, uint16_t port) {
45     switch (sa->sa_family) {
46     case AF_INET:
47         ((struct sockaddr_in *)sa)->sin_port = htons(port);
48         break;
49     case AF_INET6:
50         ((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
51         break;
52     }
53 }
54
55 struct sockaddr *addr_copy(struct sockaddr *in) {
56     struct sockaddr *out = NULL;
57     
58     switch (in->sa_family) {
59     case AF_INET:
60         out = malloc(sizeof(struct sockaddr_in));
61         if (out) {
62             memset(out, 0, sizeof(struct sockaddr_in));
63             ((struct sockaddr_in *)out)->sin_addr = ((struct sockaddr_in *)in)->sin_addr;
64         }
65         break;
66     case AF_INET6:
67         out = malloc(sizeof(struct sockaddr_in6));
68         if (out) {
69             memset(out, 0, sizeof(struct sockaddr_in6));
70             ((struct sockaddr_in6 *)out)->sin6_addr = ((struct sockaddr_in6 *)in)->sin6_addr;
71         }
72         break;
73     }
74     out->sa_family = in->sa_family;
75     return out;
76 }
77
78 char *addr2string(struct sockaddr *addr) {
79     struct sockaddr_in6 *sa6;
80     struct sockaddr_in sa4;
81     static char addr_buf[2][INET6_ADDRSTRLEN];
82     static int i = 0;
83     i = !i;
84     if (addr->sa_family == AF_INET6) {
85         sa6 = (struct sockaddr_in6 *)addr;
86         if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) {
87             memset(&sa4, 0, sizeof(sa4));
88             sa4.sin_family = AF_INET;
89             sa4.sin_port = sa6->sin6_port;
90             memcpy(&sa4.sin_addr, &sa6->sin6_addr.s6_addr[12], 4);
91             addr = (struct sockaddr *)&sa4;
92         }
93     }
94     if (getnameinfo(addr, SOCKADDRP_SIZE(addr), addr_buf[i], sizeof(addr_buf[i]),
95                     NULL, 0, NI_NUMERICHOST)) {
96         debug(DBG_WARN, "getnameinfo failed");
97         return "getnameinfo_failed";
98     }
99     return addr_buf[i];
100 }
101
102 #if 0
103 /* not in use */
104 int connectport(int type, char *host, char *port) {
105     struct addrinfo hints, *res0, *res;
106     int s = -1;
107     
108     memset(&hints, 0, sizeof(hints));
109     hints.ai_socktype = type;
110     hints.ai_family = AF_UNSPEC;
111
112     if (getaddrinfo(host, port, &hints, &res0) != 0) {
113         debug(DBG_ERR, "connectport: can't resolve host %s port %s", host, port);
114         return -1;
115     }
116
117     for (res = res0; res; res = res->ai_next) {
118         s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
119         if (s < 0) {
120             debug(DBG_WARN, "connectport: socket failed");
121             continue;
122         }
123         if (connect(s, res->ai_addr, res->ai_addrlen) == 0)
124             break;
125         debug(DBG_WARN, "connectport: connect failed");
126         close(s);
127         s = -1;
128     }
129     freeaddrinfo(res0);
130     return s;
131 }
132 #endif
133
134 int bindtoaddr(struct addrinfo *addrinfo, int family, int reuse, int v6only) {
135     int s, on = 1;
136     struct addrinfo *res;
137
138     for (res = addrinfo; res; res = res->ai_next) {
139         if (family != AF_UNSPEC && family != res->ai_family)
140             continue;
141         s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
142         if (s < 0) {
143             debug(DBG_WARN, "bindtoaddr: socket failed");
144             continue;
145         }
146         if (reuse)
147             setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
148         #ifdef IPV6_V6ONLY
149         if (v6only)
150             setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
151         #endif
152         if (!bind(s, res->ai_addr, res->ai_addrlen))
153             return s;
154         debug(DBG_WARN, "bindtoaddr: bind failed");
155         close(s);
156     }
157     return -1;
158 }
159
160 int connecttcp(struct addrinfo *addrinfo, struct addrinfo *src) {
161     int s;
162     struct addrinfo *res;
163
164     s = -1;
165     for (res = addrinfo; res; res = res->ai_next) {
166         s = bindtoaddr(src, res->ai_family, 1, 1);
167         if (s < 0) {
168             debug(DBG_WARN, "connecttoserver: socket failed");
169             continue;
170         }
171         if (connect(s, res->ai_addr, res->ai_addrlen) == 0)
172             break;
173         debug(DBG_WARN, "connecttoserver: connect failed");
174         close(s);
175         s = -1;
176     }
177     return s;
178 }