2 * Copyright (C) 2006-2008 Stig Venaas <venaas@uninett.no>
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.
9 #include <sys/socket.h>
10 #include <netinet/in.h>
18 #include <sys/select.h>
23 char *stringcopy(const char *s, int len) {
31 debug(DBG_ERR, "stringcopy: malloc failed");
37 void printfchars(char *prefixfmt, char *prefix, char *charfmt, char *chars, int len) {
39 unsigned char *s = (unsigned char *)chars;
41 printf(prefixfmt ? prefixfmt : "%s: ", prefix);
42 for (i = 0; i < len; i++)
43 printf(charfmt ? charfmt : "%c", s[i]);
47 void port_set(struct sockaddr *sa, uint16_t port) {
48 switch (sa->sa_family) {
50 ((struct sockaddr_in *)sa)->sin_port = htons(port);
53 ((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
58 struct sockaddr *addr_copy(struct sockaddr *in) {
59 struct sockaddr *out = NULL;
61 switch (in->sa_family) {
63 out = malloc(sizeof(struct sockaddr_in));
65 memset(out, 0, sizeof(struct sockaddr_in));
66 ((struct sockaddr_in *)out)->sin_addr = ((struct sockaddr_in *)in)->sin_addr;
70 out = malloc(sizeof(struct sockaddr_in6));
72 memset(out, 0, sizeof(struct sockaddr_in6));
73 ((struct sockaddr_in6 *)out)->sin6_addr = ((struct sockaddr_in6 *)in)->sin6_addr;
77 out->sa_family = in->sa_family;
79 out->sa_len = in->sa_len;
84 char *addr2string(struct sockaddr *addr) {
85 struct sockaddr_in6 *sa6;
86 struct sockaddr_in sa4;
87 static char addr_buf[2][INET6_ADDRSTRLEN];
90 if (addr->sa_family == AF_INET6) {
91 sa6 = (struct sockaddr_in6 *)addr;
92 if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) {
93 memset(&sa4, 0, sizeof(sa4));
94 sa4.sin_family = AF_INET;
95 sa4.sin_port = sa6->sin6_port;
96 memcpy(&sa4.sin_addr, &sa6->sin6_addr.s6_addr[12], 4);
97 addr = (struct sockaddr *)&sa4;
100 if (getnameinfo(addr, SOCKADDRP_SIZE(addr), addr_buf[i], sizeof(addr_buf[i]),
101 NULL, 0, NI_NUMERICHOST)) {
102 debug(DBG_WARN, "getnameinfo failed");
103 return "getnameinfo_failed";
110 int connectport(int type, char *host, char *port) {
111 struct addrinfo hints, *res0, *res;
114 memset(&hints, 0, sizeof(hints));
115 hints.ai_socktype = type;
116 hints.ai_family = AF_UNSPEC;
118 if (getaddrinfo(host, port, &hints, &res0) != 0) {
119 debug(DBG_ERR, "connectport: can't resolve host %s port %s", host, port);
123 for (res = res0; res; res = res->ai_next) {
124 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
126 debug(DBG_WARN, "connectport: socket failed");
129 if (connect(s, res->ai_addr, res->ai_addrlen) == 0)
131 debug(DBG_WARN, "connectport: connect failed");
140 /* Disable the "Don't Fragment" bit for UDP sockets. It is set by default, which may cause an "oversized"
141 RADIUS packet to be discarded on first attempt (due to Path MTU discovery).
144 void disable_DF_bit(int socket, struct addrinfo *res) {
145 if ((res->ai_family == AF_INET) && (res->ai_socktype == SOCK_DGRAM)) {
146 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
148 * Turn off Path MTU discovery on IPv4/UDP sockets, Linux variant.
151 debug(DBG_INFO, "disable_DF_bit: disabling DF bit (Linux variant)");
152 action = IP_PMTUDISC_DONT;
153 r = setsockopt(socket, IPPROTO_IP, IP_MTU_DISCOVER, &action, sizeof(action));
155 debug(DBG_WARN, "Failed to set IP_MTU_DISCOVER");
157 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!");
162 int bindtoaddr(struct addrinfo *addrinfo, int family, int reuse, int v6only) {
164 struct addrinfo *res;
166 for (res = addrinfo; res; res = res->ai_next) {
167 if (family != AF_UNSPEC && family != res->ai_family)
169 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
171 debug(DBG_WARN, "bindtoaddr: socket failed");
175 disable_DF_bit(s,res);
178 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
181 setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
183 if (!bind(s, res->ai_addr, res->ai_addrlen))
185 debug(DBG_WARN, "bindtoaddr: bind failed");
191 int connectnonblocking(int s, const struct sockaddr *addr, socklen_t addrlen, struct timeval *timeout) {
192 int origflags, error = 0, r = -1;
196 origflags = fcntl(s, F_GETFL, 0);
197 fcntl(s, F_SETFL, origflags | O_NONBLOCK);
198 if (!connect(s, addr, addrlen)) {
202 if (errno != EINPROGRESS)
206 FD_SET(s, &writefds);
207 if (select(s + 1, NULL, &writefds, NULL, timeout) < 1)
211 if (!getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&error, &len) && !error)
215 fcntl(s, F_SETFL, origflags);
219 int connecttcp(struct addrinfo *addrinfo, struct addrinfo *src, uint16_t timeout) {
221 struct addrinfo *res;
226 if (addrinfo && addrinfo->ai_next && timeout > 5)
232 for (res = addrinfo; res; res = res->ai_next) {
233 s = bindtoaddr(src, res->ai_family, 1, 1);
235 debug(DBG_WARN, "connecttoserver: socket failed");
239 ? connectnonblocking(s, res->ai_addr, res->ai_addrlen, &to)
240 : connect(s, res->ai_addr, res->ai_addrlen)) == 0)
242 debug(DBG_WARN, "connecttoserver: connect failed");