1 /* Copyright (c) 2007-2009, UNINETT AS */
2 /* See LICENSE for licensing information. */
4 #include <sys/socket.h>
5 #include <netinet/in.h>
13 #include <sys/select.h>
18 char *stringcopy(const char *s, int len) {
26 debug(DBG_ERR, "stringcopy: malloc failed");
32 void printfchars(char *prefixfmt, char *prefix, char *charfmt, char *chars, int len) {
34 unsigned char *s = (unsigned char *)chars;
36 printf(prefixfmt ? prefixfmt : "%s: ", prefix);
37 for (i = 0; i < len; i++)
38 printf(charfmt ? charfmt : "%c", s[i]);
42 void port_set(struct sockaddr *sa, uint16_t port) {
43 switch (sa->sa_family) {
45 ((struct sockaddr_in *)sa)->sin_port = htons(port);
48 ((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
53 struct sockaddr *addr_copy(struct sockaddr *in) {
54 struct sockaddr *out = NULL;
56 switch (in->sa_family) {
58 out = malloc(sizeof(struct sockaddr_in));
60 memset(out, 0, sizeof(struct sockaddr_in));
61 ((struct sockaddr_in *)out)->sin_addr = ((struct sockaddr_in *)in)->sin_addr;
65 out = malloc(sizeof(struct sockaddr_in6));
67 memset(out, 0, sizeof(struct sockaddr_in6));
68 ((struct sockaddr_in6 *)out)->sin6_addr = ((struct sockaddr_in6 *)in)->sin6_addr;
72 out->sa_family = in->sa_family;
74 out->sa_len = in->sa_len;
79 char *addr2string(struct sockaddr *addr) {
80 struct sockaddr_in6 *sa6;
81 struct sockaddr_in sa4;
82 static char addr_buf[2][INET6_ADDRSTRLEN];
85 if (addr->sa_family == AF_INET6) {
86 sa6 = (struct sockaddr_in6 *)addr;
87 if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) {
88 memset(&sa4, 0, sizeof(sa4));
89 sa4.sin_family = AF_INET;
90 sa4.sin_port = sa6->sin6_port;
91 memcpy(&sa4.sin_addr, &sa6->sin6_addr.s6_addr[12], 4);
92 addr = (struct sockaddr *)&sa4;
95 if (getnameinfo(addr, SOCKADDRP_SIZE(addr), addr_buf[i], sizeof(addr_buf[i]),
96 NULL, 0, NI_NUMERICHOST)) {
97 debug(DBG_WARN, "getnameinfo failed");
98 return "getnameinfo_failed";
103 /* Disable the "Don't Fragment" bit for UDP sockets. It is set by default, which may cause an "oversized"
104 RADIUS packet to be discarded on first attempt (due to Path MTU discovery).
107 void disable_DF_bit(int socket, struct addrinfo *res) {
108 if ((res->ai_family == AF_INET) && (res->ai_socktype == SOCK_DGRAM)) {
109 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
111 * Turn off Path MTU discovery on IPv4/UDP sockets, Linux variant.
114 debug(DBG_INFO, "disable_DF_bit: disabling DF bit (Linux variant)");
115 action = IP_PMTUDISC_DONT;
116 r = setsockopt(socket, IPPROTO_IP, IP_MTU_DISCOVER, &action, sizeof(action));
118 debug(DBG_WARN, "Failed to set IP_MTU_DISCOVER");
120 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!");
125 int bindtoaddr(struct addrinfo *addrinfo, int family, int reuse, int v6only) {
127 struct addrinfo *res;
129 for (res = addrinfo; res; res = res->ai_next) {
130 if (family != AF_UNSPEC && family != res->ai_family)
132 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
134 debug(DBG_WARN, "bindtoaddr: socket failed");
138 disable_DF_bit(s,res);
141 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
144 setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
146 if (!bind(s, res->ai_addr, res->ai_addrlen))
148 debug(DBG_WARN, "bindtoaddr: bind failed");
154 int connectnonblocking(int s, const struct sockaddr *addr, socklen_t addrlen, struct timeval *timeout) {
155 int origflags, error = 0, r = -1;
159 origflags = fcntl(s, F_GETFL, 0);
160 fcntl(s, F_SETFL, origflags | O_NONBLOCK);
161 if (!connect(s, addr, addrlen)) {
165 if (errno != EINPROGRESS)
169 FD_SET(s, &writefds);
170 if (select(s + 1, NULL, &writefds, NULL, timeout) < 1)
174 if (!getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&error, &len) && !error)
178 fcntl(s, F_SETFL, origflags);
182 int connecttcp(struct addrinfo *addrinfo, struct addrinfo *src, uint16_t timeout) {
184 struct addrinfo *res;
189 if (addrinfo && addrinfo->ai_next && timeout > 5)
195 for (res = addrinfo; res; res = res->ai_next) {
196 s = bindtoaddr(src, res->ai_family, 1, 1);
198 debug(DBG_WARN, "connecttoserver: socket failed");
202 ? connectnonblocking(s, res->ai_addr, res->ai_addrlen, &to)
203 : connect(s, res->ai_addr, res->ai_addrlen)) == 0)
205 debug(DBG_WARN, "connecttoserver: connect failed");
212 /* Local Variables: */
213 /* c-file-style: "stroustrup" */