]>
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) | |
87 | theL()<<Logger::Warning<<"Warning: IP_FREEBIND setsockopt failed: "<<strerror(errno)<<endl; | |
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) |
fec7dd5a SS |
93 | theL()<<Logger::Warning<<"Warning: IP_BINDANY setsockopt failed: "<<strerror(errno)<<endl; |
94 | #endif | |
95 | #ifdef IPV6_BINDANY | |
96 | if (af == AF_INET6) | |
97 | if (setsockopt(sock, IPPROTO_IPV6, IPV6_BINDANY, &one, sizeof(one)) < 0) | |
98 | theL()<<Logger::Warning<<"Warning: IPV6_BINDANY setsockopt failed: "<<strerror(errno)<<endl; | |
99 | #endif | |
100 | #ifdef SO_BINDANY | |
101 | if (setsockopt(sock, SOL_SOCKET, SO_BINDANY, &one, sizeof(one)) < 0) | |
102 | theL()<<Logger::Warning<<"Warning: SO_BINDANY setsockopt failed: "<<strerror(errno)<<endl; | |
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 KM |
126 | // Drops the program's group privileges. |
127 | void Utility::dropGroupPrivs( int uid, int gid ) | |
12c86877 BH |
128 | { |
129 | if(gid) { | |
130 | if(setgid(gid)<0) { | |
ad1bb608 | 131 | theL()<<Logger::Critical<<"Unable to set effective group id to "<<gid<<": "<<stringerror()<<endl; |
12c86877 BH |
132 | exit(1); |
133 | } | |
134 | else | |
ad1bb608 | 135 | theL()<<Logger::Info<<"Set effective group id to "<<gid<<endl; |
12c86877 | 136 | |
cee857b0 KM |
137 | struct passwd *pw=getpwuid(uid); |
138 | if(!pw) { | |
139 | theL()<<Logger::Warning<<"Unable to determine user name for uid "<<uid<<endl; | |
140 | if (setgroups(0, NULL)<0) { | |
141 | theL()<<Logger::Critical<<"Unable to drop supplementary gids: "<<stringerror()<<endl; | |
142 | exit(1); | |
143 | } | |
144 | } else { | |
145 | if (initgroups(pw->pw_name, gid)<0) { | |
146 | theL()<<Logger::Critical<<"Unable to set supplementary groups: "<<stringerror()<<endl; | |
147 | exit(1); | |
148 | } | |
fe97f596 | 149 | } |
12c86877 | 150 | } |
f1d6a7ce KM |
151 | } |
152 | ||
12c86877 | 153 | |
f1d6a7ce KM |
154 | // Drops the program's user privileges. |
155 | void Utility::dropUserPrivs( int uid ) | |
156 | { | |
12c86877 BH |
157 | if(uid) { |
158 | if(setuid(uid)<0) { | |
ad1bb608 | 159 | theL()<<Logger::Critical<<"Unable to set effective user id to "<<uid<<": "<<stringerror()<<endl; |
12c86877 BH |
160 | exit(1); |
161 | } | |
162 | else | |
ad1bb608 | 163 | theL()<<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 | ||
181 | ||
12c86877 | 182 | |
12c86877 BH |
183 | // Retrieves a gid using a groupname. |
184 | int Utility::makeGidNumeric(const string &group) | |
185 | { | |
186 | int newgid; | |
187 | if(!(newgid=atoi(group.c_str()))) { | |
d0c0ae3a | 188 | errno=0; |
12c86877 BH |
189 | struct group *gr=getgrnam(group.c_str()); |
190 | if(!gr) { | |
d0c0ae3a | 191 | theL()<<Logger::Critical<<"Unable to look up gid of group '"<<group<<"': "<< (errno ? strerror(errno) : "not found") <<endl; |
12c86877 BH |
192 | exit(1); |
193 | } | |
194 | newgid=gr->gr_gid; | |
195 | } | |
196 | return newgid; | |
197 | } | |
198 | ||
199 | ||
200 | // Retrieves an uid using a username. | |
201 | int Utility::makeUidNumeric(const string &username) | |
202 | { | |
203 | int newuid; | |
204 | if(!(newuid=atoi(username.c_str()))) { | |
205 | struct passwd *pw=getpwnam(username.c_str()); | |
206 | if(!pw) { | |
d0c0ae3a | 207 | theL()<<Logger::Critical<<"Unable to look up uid of user '"<<username<<"': "<< (errno ? strerror(errno) : "not found") <<endl; |
12c86877 BH |
208 | exit(1); |
209 | } | |
210 | newuid=pw->pw_uid; | |
211 | } | |
212 | return newuid; | |
213 | } | |
214 | ||
896e5153 | 215 | |
12c86877 BH |
216 | // Returns a random number. |
217 | long int Utility::random( void ) | |
218 | { | |
219 | return rand(); | |
220 | } | |
221 | ||
222 | // Sets the random seed. | |
223 | void Utility::srandom( unsigned int seed ) | |
224 | { | |
225 | ::srandom(seed); | |
226 | } | |
227 | ||
12c86877 BH |
228 | |
229 | // Writes a vector. | |
092c9cc4 | 230 | int Utility::writev(int socket, const iovec *vector, size_t count ) |
12c86877 BH |
231 | { |
232 | return ::writev(socket,vector,count); | |
233 | } | |
234 | ||
49f72da1 BH |
235 | /* this is cut and pasted from dietlibc, gratefully copied! */ |
236 | static int isleap(int year) { | |
237 | /* every fourth year is a leap year except for century years that are | |
238 | * not divisible by 400. */ | |
239 | return (!(year%4) && ((year%100) || !(year%400))); | |
240 | } | |
241 | ||
242 | time_t Utility::timegm(struct tm *const t) | |
243 | { | |
244 | const static short spm[13] = /* days per month -- nonleap! */ | |
245 | { 0, | |
246 | (31), | |
247 | (31+28), | |
248 | (31+28+31), | |
249 | (31+28+31+30), | |
250 | (31+28+31+30+31), | |
251 | (31+28+31+30+31+30), | |
252 | (31+28+31+30+31+30+31), | |
253 | (31+28+31+30+31+30+31+31), | |
254 | (31+28+31+30+31+30+31+31+30), | |
255 | (31+28+31+30+31+30+31+31+30+31), | |
256 | (31+28+31+30+31+30+31+31+30+31+30), | |
257 | (31+28+31+30+31+30+31+31+30+31+30+31), | |
258 | }; | |
259 | ||
260 | time_t day; | |
261 | time_t i; | |
262 | time_t years = t->tm_year - 70; | |
263 | ||
264 | if (t->tm_sec>60) { t->tm_min += t->tm_sec/60; t->tm_sec%=60; } | |
265 | if (t->tm_min>60) { t->tm_hour += t->tm_min/60; t->tm_min%=60; } | |
266 | if (t->tm_hour>60) { t->tm_mday += t->tm_hour/60; t->tm_hour%=60; } | |
813b1d93 | 267 | if (t->tm_mon>11) { t->tm_year += t->tm_mon/12; t->tm_mon%=12; } |
49f72da1 BH |
268 | |
269 | while (t->tm_mday>spm[1+t->tm_mon]) { | |
270 | if (t->tm_mon==1 && isleap(t->tm_year+1900)) { | |
271 | if (t->tm_mon==31+29) break; | |
272 | --t->tm_mday; | |
273 | } | |
274 | t->tm_mday-=spm[t->tm_mon]; | |
275 | ++t->tm_mon; | |
276 | if (t->tm_mon>11) { t->tm_mon=0; ++t->tm_year; } | |
277 | } | |
278 | ||
279 | if (t->tm_year < 70) | |
280 | return (time_t) -1; | |
281 | /* Days since 1970 is 365 * number of years + number of leap years since 1970 */ | |
282 | day = years * 365 + (years + 1) / 4; | |
283 | ||
7c696097 | 284 | /* After 2100 we have to subtract 3 leap years for every 400 years |
49f72da1 | 285 | This is not intuitive. Most mktime implementations do not support |
1f6c983f | 286 | dates after 2059, anyway, so we might leave this out for its |
49f72da1 BH |
287 | bloat. */ |
288 | if ((years -= 131) >= 0) { | |
289 | years /= 100; | |
290 | day -= (years >> 2) * 3 + 1; | |
291 | if ((years &= 3) == 3) years--; | |
292 | day -= years; | |
293 | } | |
294 | ||
295 | day += t->tm_yday = spm [t->tm_mon] + t->tm_mday-1 + ( isleap (t->tm_year+1900) & (t->tm_mon > 1) ); | |
296 | ||
297 | /* day is now the number of days since 'Jan 1 1970' */ | |
298 | i = 7; | |
299 | t->tm_wday = (day + 4) % i; /* Sunday=0, Monday=1, ..., Saturday=6 */ | |
300 | ||
301 | i = 24; | |
302 | day *= i; | |
303 | i = 60; | |
304 | return ((day + t->tm_hour) * i + t->tm_min) * i + t->tm_sec; | |
305 | } | |
306 |