1 /* Copyright (c) 2006-2010, UNINETT AS
2 * Copyright (c) 2010-2012, NORDUnet A/S */
3 /* See LICENSE for licensing information. */
5 #include <sys/socket.h>
6 #include <netinet/in.h>
14 #include <sys/select.h>
19 char *stringcopy(const char *s, int len) {
27 debug(DBG_ERR, "stringcopy: malloc failed");
33 void printfchars(char *prefixfmt, char *prefix, char *charfmt, char *chars, int len) {
35 unsigned char *s = (unsigned char *)chars;
37 printf(prefixfmt ? prefixfmt : "%s: ", prefix);
38 for (i = 0; i < len; i++)
39 printf(charfmt ? charfmt : "%c", s[i]);
43 void port_set(struct sockaddr *sa, uint16_t port) {
44 switch (sa->sa_family) {
46 ((struct sockaddr_in *)sa)->sin_port = htons(port);
49 ((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
54 struct sockaddr *addr_copy(struct sockaddr *in) {
55 struct sockaddr *out = NULL;
57 switch (in->sa_family) {
59 out = malloc(sizeof(struct sockaddr_in));
61 memset(out, 0, sizeof(struct sockaddr_in));
62 ((struct sockaddr_in *)out)->sin_addr = ((struct sockaddr_in *)in)->sin_addr;
66 out = malloc(sizeof(struct sockaddr_in6));
68 memset(out, 0, sizeof(struct sockaddr_in6));
69 ((struct sockaddr_in6 *)out)->sin6_addr = ((struct sockaddr_in6 *)in)->sin6_addr;
73 out->sa_family = in->sa_family;
75 out->sa_len = in->sa_len;
80 char *addr2string(struct sockaddr *addr) {
81 struct sockaddr_in6 *sa6;
82 struct sockaddr_in sa4;
83 static char addr_buf[2][INET6_ADDRSTRLEN];
86 if (addr->sa_family == AF_INET6) {
87 sa6 = (struct sockaddr_in6 *)addr;
88 if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) {
89 memset(&sa4, 0, sizeof(sa4));
90 sa4.sin_family = AF_INET;
91 sa4.sin_port = sa6->sin6_port;
92 memcpy(&sa4.sin_addr, &sa6->sin6_addr.s6_addr[12], 4);
93 addr = (struct sockaddr *)&sa4;
96 if (getnameinfo(addr, SOCKADDRP_SIZE(addr), addr_buf[i], sizeof(addr_buf[i]),
97 NULL, 0, NI_NUMERICHOST)) {
98 debug(DBG_WARN, "getnameinfo failed");
99 return "getnameinfo_failed";
104 /* Disable the "Don't Fragment" bit for UDP sockets. It is set by default, which may cause an "oversized"
105 RADIUS packet to be discarded on first attempt (due to Path MTU discovery).
108 void disable_DF_bit(int socket, struct addrinfo *res) {
109 if ((res->ai_family == AF_INET) && (res->ai_socktype == SOCK_DGRAM)) {
110 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
112 * Turn off Path MTU discovery on IPv4/UDP sockets, Linux variant.
115 debug(DBG_INFO, "disable_DF_bit: disabling DF bit (Linux variant)");
116 action = IP_PMTUDISC_DONT;
117 r = setsockopt(socket, IPPROTO_IP, IP_MTU_DISCOVER, &action, sizeof(action));
119 debug(DBG_WARN, "Failed to set IP_MTU_DISCOVER");
121 debug(DBG_INFO, "Non-Linux platform, unable to unset DF bit for UDP. You should check with tcpdump whether radsecproxy will send its UDP packets with DF bit set!");
126 int bindtoaddr(struct addrinfo *addrinfo, int family, int reuse, int v6only) {
128 struct addrinfo *res;
130 for (res = addrinfo; res; res = res->ai_next) {
131 if (family != AF_UNSPEC && family != res->ai_family)
133 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
135 debug(DBG_WARN, "bindtoaddr: socket failed");
139 disable_DF_bit(s,res);
142 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
145 setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
147 if (!bind(s, res->ai_addr, res->ai_addrlen))
149 debug(DBG_WARN, "bindtoaddr: bind failed");
155 int connectnonblocking(int s, const struct sockaddr *addr, socklen_t addrlen, struct timeval *timeout) {
156 int origflags, error = 0, r = -1;
160 origflags = fcntl(s, F_GETFL, 0);
161 fcntl(s, F_SETFL, origflags | O_NONBLOCK);
162 if (!connect(s, addr, addrlen)) {
166 if (errno != EINPROGRESS)
170 FD_SET(s, &writefds);
171 if (select(s + 1, NULL, &writefds, NULL, timeout) < 1)
175 if (!getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&error, &len) && !error)
179 fcntl(s, F_SETFL, origflags);
183 int connecttcp(struct addrinfo *addrinfo, struct addrinfo *src, uint16_t timeout) {
185 struct addrinfo *res;
190 if (addrinfo && addrinfo->ai_next && timeout > 5)
196 for (res = addrinfo; res; res = res->ai_next) {
197 s = bindtoaddr(src, res->ai_family, 1, 1);
199 debug(DBG_WARN, "connecttoserver: socket failed");
203 ? connectnonblocking(s, res->ai_addr, res->ai_addrlen, &to)
204 : connect(s, res->ai_addr, res->ai_addrlen)) == 0)
206 debug(DBG_WARN, "connecttoserver: connect failed");
213 /* Local Variables: */
214 /* c-file-style: "stroustrup" */