]>
Commit | Line | Data |
---|---|---|
12c86877 | 1 | /* |
6edbf68a PL |
2 | * This file is part of PowerDNS or dnsdist. |
3 | * Copyright -- PowerDNS.COM B.V. and its contributors | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of version 2 of the GNU General Public License as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * In addition, for the avoidance of any doubt, permission is granted to | |
10 | * link this program with OpenSSL and to (re)distribute the binaries | |
11 | * produced as the result of such linking. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
21 | */ | |
870a0fe4 AT |
22 | #ifdef HAVE_CONFIG_H |
23 | #include "config.h" | |
24 | #endif | |
12c86877 BH |
25 | #include "utility.hh" |
26 | #include <cstring> | |
27 | #include <fcntl.h> | |
28 | #include <unistd.h> | |
29 | #include <stdlib.h> | |
5c409fa2 | 30 | #include "pdnsexception.hh" |
12c86877 BH |
31 | #include "logger.hh" |
32 | #include "misc.hh" | |
33 | #include <pwd.h> | |
34 | #include <grp.h> | |
35 | #include <sys/types.h> | |
c7c7edb5 | 36 | #include <sys/select.h> |
12c86877 | 37 | |
1258abe0 BH |
38 | #ifdef NEED_INET_NTOP_PROTO |
39 | extern "C" { | |
40 | const char *inet_ntop(int af, const void *src, char *dst, size_t cnt); | |
41 | } | |
42 | #endif | |
43 | ||
44 | ||
10f4eea8 | 45 | #include "namespaces.hh" |
12c86877 | 46 | |
12c86877 | 47 | |
c7c7edb5 IM |
48 | // Connects to socket with timeout |
49 | int Utility::timed_connect( Utility::sock_t sock, | |
50 | const sockaddr *addr, | |
51 | Utility::socklen_t sockaddr_size, | |
52 | int timeout_sec, | |
53 | int timeout_usec ) | |
54 | { | |
55 | fd_set set; | |
56 | struct timeval timeout; | |
57 | int ret; | |
58 | ||
59 | timeout.tv_sec = timeout_sec; | |
60 | timeout.tv_usec = timeout_usec; | |
61 | ||
62 | FD_ZERO(&set); | |
63 | FD_SET(sock, &set); | |
64 | ||
65 | setNonBlocking(sock); | |
66 | ||
67 | if ((ret = connect (sock, addr, sockaddr_size)) < 0) { | |
68 | if (errno != EINPROGRESS) | |
69 | return ret; | |
70 | } | |
71 | ||
72 | ret = select(sock + 1, NULL, &set, NULL, &timeout); | |
73 | setBlocking(sock); | |
74 | ||
75 | return ret; | |
76 | } | |
77 | ||
12c86877 | 78 | |
42c235e5 | 79 | |
fec7dd5a SS |
80 | void Utility::setBindAny(int af, sock_t sock) |
81 | { | |
27eb476b | 82 | const int one = 1; |
fec7dd5a | 83 | |
27eb476b | 84 | (void) one; // avoids 'unused var' warning on systems that have none of the defines checked below |
fec7dd5a SS |
85 | #ifdef IP_FREEBIND |
86 | if (setsockopt(sock, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) < 0) | |
e6a9dde5 | 87 | g_log<<Logger::Warning<<"Warning: IP_FREEBIND setsockopt failed: "<<strerror(errno)<<endl; |
fec7dd5a SS |
88 | #endif |
89 | ||
90 | #ifdef IP_BINDANY | |
91 | if (af == AF_INET) | |
4355c3ea | 92 | if (setsockopt(sock, IPPROTO_IP, IP_BINDANY, &one, sizeof(one)) < 0) |
e6a9dde5 | 93 | g_log<<Logger::Warning<<"Warning: IP_BINDANY setsockopt failed: "<<strerror(errno)<<endl; |
fec7dd5a SS |
94 | #endif |
95 | #ifdef IPV6_BINDANY | |
96 | if (af == AF_INET6) | |
97 | if (setsockopt(sock, IPPROTO_IPV6, IPV6_BINDANY, &one, sizeof(one)) < 0) | |
e6a9dde5 | 98 | g_log<<Logger::Warning<<"Warning: IPV6_BINDANY setsockopt failed: "<<strerror(errno)<<endl; |
fec7dd5a SS |
99 | #endif |
100 | #ifdef SO_BINDANY | |
101 | if (setsockopt(sock, SOL_SOCKET, SO_BINDANY, &one, sizeof(one)) < 0) | |
e6a9dde5 | 102 | g_log<<Logger::Warning<<"Warning: SO_BINDANY setsockopt failed: "<<strerror(errno)<<endl; |
fec7dd5a SS |
103 | #endif |
104 | } | |
105 | ||
12c86877 BH |
106 | const char *Utility::inet_ntop(int af, const char *src, char *dst, size_t size) |
107 | { | |
1258abe0 | 108 | return ::inet_ntop(af,src,dst,size); |
12c86877 BH |
109 | } |
110 | ||
111 | unsigned int Utility::sleep(unsigned int sec) | |
112 | { | |
113 | return ::sleep(sec); | |
114 | } | |
115 | ||
116 | void Utility::usleep(unsigned long usec) | |
117 | { | |
22cc5a36 AT |
118 | struct timespec ts; |
119 | ts.tv_sec = usec / 1000000; | |
120 | ts.tv_nsec = (usec % 1000000) * 1000; | |
121 | // POSIX.1 recommends using nanosleep instead of usleep | |
122 | ::nanosleep(&ts, NULL); | |
12c86877 BH |
123 | } |
124 | ||
125 | ||
f1d6a7ce | 126 | // Drops the program's group privileges. |
76ba685e | 127 | void Utility::dropGroupPrivs( uid_t uid, gid_t gid ) |
12c86877 | 128 | { |
6c7848b3 | 129 | if(gid && gid != getegid()) { |
12c86877 | 130 | if(setgid(gid)<0) { |
e6a9dde5 | 131 | g_log<<Logger::Critical<<"Unable to set effective group id to "<<gid<<": "<<stringerror()<<endl; |
12c86877 BH |
132 | exit(1); |
133 | } | |
134 | else | |
e6a9dde5 | 135 | g_log<<Logger::Info<<"Set effective group id to "<<gid<<endl; |
12c86877 | 136 | |
cee857b0 KM |
137 | struct passwd *pw=getpwuid(uid); |
138 | if(!pw) { | |
e6a9dde5 | 139 | g_log<<Logger::Warning<<"Unable to determine user name for uid "<<uid<<endl; |
cee857b0 | 140 | if (setgroups(0, NULL)<0) { |
e6a9dde5 | 141 | g_log<<Logger::Critical<<"Unable to drop supplementary gids: "<<stringerror()<<endl; |
cee857b0 KM |
142 | exit(1); |
143 | } | |
144 | } else { | |
145 | if (initgroups(pw->pw_name, gid)<0) { | |
e6a9dde5 | 146 | g_log<<Logger::Critical<<"Unable to set supplementary groups: "<<stringerror()<<endl; |
cee857b0 KM |
147 | exit(1); |
148 | } | |
fe97f596 | 149 | } |
12c86877 | 150 | } |
f1d6a7ce KM |
151 | } |
152 | ||
12c86877 | 153 | |
f1d6a7ce | 154 | // Drops the program's user privileges. |
76ba685e | 155 | void Utility::dropUserPrivs( uid_t uid ) |
f1d6a7ce | 156 | { |
6c7848b3 | 157 | if(uid && uid != geteuid()) { |
12c86877 | 158 | if(setuid(uid)<0) { |
84cbd0dc | 159 | g_log<<Logger::Critical<<"Unable to set effective user id to "<<uid<<": "<<stringerror()<<endl; |
12c86877 BH |
160 | exit(1); |
161 | } | |
162 | else | |
e6a9dde5 | 163 | g_log<<Logger::Info<<"Set effective user id to "<<uid<<endl; |
12c86877 BH |
164 | } |
165 | } | |
166 | ||
167 | ||
168 | // Returns the current process id. | |
169 | Utility::pid_t Utility::getpid( void ) | |
170 | { | |
171 | return ::getpid(); | |
172 | } | |
173 | ||
174 | ||
175 | // Returns the current time. | |
176 | int Utility::gettimeofday( struct timeval *tv, void *tz ) | |
177 | { | |
178 | return ::gettimeofday(tv,0); | |
179 | } | |
180 | ||
8342eb4f | 181 | // Sets the random seed. |
b51ef4f9 | 182 | void Utility::srandom(void) |
8342eb4f | 183 | { |
b51ef4f9 OM |
184 | struct timeval tv; |
185 | gettimeofday(&tv, 0); | |
186 | ::srandom(tv.tv_sec ^ tv.tv_usec ^ getpid()); | |
8342eb4f | 187 | } |
896e5153 | 188 | |
12c86877 | 189 | // Writes a vector. |
092c9cc4 | 190 | int Utility::writev(int socket, const iovec *vector, size_t count ) |
12c86877 BH |
191 | { |
192 | return ::writev(socket,vector,count); | |
193 | } | |
194 | ||
49f72da1 BH |
195 | /* this is cut and pasted from dietlibc, gratefully copied! */ |
196 | static int isleap(int year) { | |
197 | /* every fourth year is a leap year except for century years that are | |
198 | * not divisible by 400. */ | |
199 | return (!(year%4) && ((year%100) || !(year%400))); | |
200 | } | |
201 | ||
202 | time_t Utility::timegm(struct tm *const t) | |
203 | { | |
204 | const static short spm[13] = /* days per month -- nonleap! */ | |
205 | { 0, | |
206 | (31), | |
207 | (31+28), | |
208 | (31+28+31), | |
209 | (31+28+31+30), | |
210 | (31+28+31+30+31), | |
211 | (31+28+31+30+31+30), | |
212 | (31+28+31+30+31+30+31), | |
213 | (31+28+31+30+31+30+31+31), | |
214 | (31+28+31+30+31+30+31+31+30), | |
215 | (31+28+31+30+31+30+31+31+30+31), | |
216 | (31+28+31+30+31+30+31+31+30+31+30), | |
217 | (31+28+31+30+31+30+31+31+30+31+30+31), | |
218 | }; | |
219 | ||
220 | time_t day; | |
221 | time_t i; | |
222 | time_t years = t->tm_year - 70; | |
223 | ||
224 | if (t->tm_sec>60) { t->tm_min += t->tm_sec/60; t->tm_sec%=60; } | |
225 | if (t->tm_min>60) { t->tm_hour += t->tm_min/60; t->tm_min%=60; } | |
226 | if (t->tm_hour>60) { t->tm_mday += t->tm_hour/60; t->tm_hour%=60; } | |
813b1d93 | 227 | if (t->tm_mon>11) { t->tm_year += t->tm_mon/12; t->tm_mon%=12; } |
49f72da1 BH |
228 | |
229 | while (t->tm_mday>spm[1+t->tm_mon]) { | |
230 | if (t->tm_mon==1 && isleap(t->tm_year+1900)) { | |
231 | if (t->tm_mon==31+29) break; | |
232 | --t->tm_mday; | |
233 | } | |
234 | t->tm_mday-=spm[t->tm_mon]; | |
235 | ++t->tm_mon; | |
236 | if (t->tm_mon>11) { t->tm_mon=0; ++t->tm_year; } | |
237 | } | |
238 | ||
239 | if (t->tm_year < 70) | |
240 | return (time_t) -1; | |
241 | /* Days since 1970 is 365 * number of years + number of leap years since 1970 */ | |
242 | day = years * 365 + (years + 1) / 4; | |
243 | ||
7c696097 | 244 | /* After 2100 we have to subtract 3 leap years for every 400 years |
49f72da1 | 245 | This is not intuitive. Most mktime implementations do not support |
1f6c983f | 246 | dates after 2059, anyway, so we might leave this out for its |
49f72da1 BH |
247 | bloat. */ |
248 | if ((years -= 131) >= 0) { | |
249 | years /= 100; | |
250 | day -= (years >> 2) * 3 + 1; | |
251 | if ((years &= 3) == 3) years--; | |
252 | day -= years; | |
253 | } | |
254 | ||
255 | day += t->tm_yday = spm [t->tm_mon] + t->tm_mday-1 + ( isleap (t->tm_year+1900) & (t->tm_mon > 1) ); | |
256 | ||
257 | /* day is now the number of days since 'Jan 1 1970' */ | |
258 | i = 7; | |
259 | t->tm_wday = (day + 4) % i; /* Sunday=0, Monday=1, ..., Saturday=6 */ | |
260 | ||
261 | i = 24; | |
262 | day *= i; | |
263 | i = 60; | |
264 | return ((day + t->tm_hour) * i + t->tm_min) * i + t->tm_sec; | |
265 | } | |
266 |