Imported Upstream version 2.7
[ossec-hids.git] / src / os_net / os_net.c
1 /* @(#) $Id: ./src/os_net/os_net.c, 2011/09/08 dcid Exp $
2  */
3
4 /* Copyright (C) 2009 Trend Micro Inc.
5  * All rights reserved.
6  *
7  * This program is a free software; you can redistribute it
8  * and/or modify it under the terms of the GNU General Public
9  * License (version 2) as published by the FSF - Free Software
10  * Foundation
11  *
12  * License details at the LICENSE file included with OSSEC or
13  * online at: http://www.ossec.net/en/licensing.html
14  */
15
16 /* OS_net Library.
17  * APIs for many network operations.
18  */
19
20
21
22
23 #include "shared.h"
24 #include "os_net.h"
25
26
27
28
29 /* Unix socket -- not for windows */
30 #ifndef WIN32
31 struct sockaddr_un n_us;
32 socklen_t us_l = sizeof(n_us);
33
34 /* UNIX SOCKET */
35 #ifndef SUN_LEN
36 #define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path)        \
37                                       + strlen ((ptr)->sun_path))
38 #endif /* Sun_LEN */
39
40 #else
41 int ENOBUFS = 0;
42 #endif /* WIN32*/
43
44
45 /* OS_Bindport v 0.2, 2005/02/11
46  * Bind a specific port
47  * v0.2: Added REUSEADDR.
48  */
49 int OS_Bindport(unsigned int _port, unsigned int _proto, char *_ip, int ipv6)
50 {
51     int ossock;
52     struct sockaddr_in server;
53
54     #ifndef WIN32
55     struct sockaddr_in6 server6;
56     #else
57     ipv6 = 0;
58     #endif
59
60
61     if(_proto == IPPROTO_UDP)
62     {
63         if((ossock = socket(ipv6 == 1?PF_INET6:PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
64         {
65             return OS_SOCKTERR;
66         }
67     }
68     else if(_proto == IPPROTO_TCP)
69     {
70         int flag = 1;
71         if((ossock = socket(ipv6 == 1?PF_INET6:PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
72         {
73             return(int)(OS_SOCKTERR);
74         }
75
76         if(setsockopt(ossock, SOL_SOCKET, SO_REUSEADDR,
77                               (char *)&flag,  sizeof(flag)) < 0)
78         {
79             return(OS_SOCKTERR);
80         }
81     }
82     else
83     {
84         return(OS_INVALID);
85     }
86
87     if(ipv6)
88     {
89         #ifndef WIN32
90         memset(&server6, 0, sizeof(server6));
91         server6.sin6_family = AF_INET6;
92         server6.sin6_port = htons( _port );
93         server6.sin6_addr = in6addr_any;
94
95
96         if(bind(ossock, (struct sockaddr *) &server6, sizeof(server6)) < 0)
97         {
98             return(OS_SOCKTERR);
99         }
100         #endif
101     }
102     else
103     {
104         memset(&server, 0, sizeof(server));
105         server.sin_family = AF_INET;
106         server.sin_port = htons( _port );
107
108
109         if((_ip == NULL)||(_ip[0] == '\0'))
110             server.sin_addr.s_addr = htonl(INADDR_ANY);
111         else
112             server.sin_addr.s_addr = inet_addr(_ip);
113
114
115         if(bind(ossock, (struct sockaddr *) &server, sizeof(server)) < 0)
116         {
117             return(OS_SOCKTERR);
118         }
119     }
120
121
122
123     if(_proto == IPPROTO_TCP)
124     {
125         if(listen(ossock, 32) < 0)
126         {
127             return(OS_SOCKTERR);
128         }
129     }
130
131
132     return(ossock);
133 }
134
135
136 /* OS_Bindporttcp v 0.1
137  * Bind a TCP port, using the OS_Bindport
138  */
139 int OS_Bindporttcp(unsigned int _port, char *_ip, int ipv6)
140 {
141     return(OS_Bindport(_port, IPPROTO_TCP, _ip, ipv6));
142 }
143
144
145 /* OS_Bindportudp v 0.1
146  * Bind a UDP port, using the OS_Bindport
147  */
148 int OS_Bindportudp(unsigned int _port, char *_ip, int ipv6)
149 {
150     return(OS_Bindport(_port, IPPROTO_UDP, _ip, ipv6));
151 }
152
153 #ifndef WIN32
154 /* OS_BindUnixDomain v0.1, 2004/07/29
155  * Bind to a Unix domain, using DGRAM sockets
156  */
157 int OS_BindUnixDomain(char * path, int mode, int max_msg_size)
158 {
159     int len;
160     int ossock = 0;
161     socklen_t optlen = sizeof(len);
162
163     /* Making sure the path isn't there */
164     unlink(path);
165
166     memset(&n_us, 0, sizeof(n_us));
167     n_us.sun_family = AF_UNIX;
168     strncpy(n_us.sun_path, path, sizeof(n_us.sun_path)-1);
169
170     if((ossock = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
171         return(OS_SOCKTERR);
172
173     if(bind(ossock, (struct sockaddr *)&n_us, SUN_LEN(&n_us)) < 0)
174     {
175         close(ossock);
176         return(OS_SOCKTERR);
177     }
178
179     /* Changing permissions */
180     chmod(path,mode);
181
182
183     /* Getting current maximum size */
184     if(getsockopt(ossock, SOL_SOCKET, SO_RCVBUF, &len, &optlen) == -1)
185         return(OS_SOCKTERR);
186
187
188     /* Setting socket opt */
189     if(len < max_msg_size)
190     {
191         len = max_msg_size;
192         setsockopt(ossock, SOL_SOCKET, SO_RCVBUF, &len, optlen);
193     }
194
195     return(ossock);
196 }
197
198 /* OS_ConnectUnixDomain v0.1, 2004/07/29
199  * Open a client Unix domain socket
200  * ("/tmp/lala-socket",0666));
201  *
202  */
203 int OS_ConnectUnixDomain(char * path, int max_msg_size)
204 {
205     int len;
206     int ossock = 0;
207     socklen_t optlen = sizeof(len);
208
209     memset(&n_us, 0, sizeof(n_us));
210
211     n_us.sun_family = AF_UNIX;
212
213     /* Setting up path */
214     strncpy(n_us.sun_path,path,sizeof(n_us.sun_path)-1);        
215
216     if((ossock = socket(AF_UNIX, SOCK_DGRAM,0)) < 0)
217         return(OS_SOCKTERR);
218
219
220     /* Connecting to the UNIX domain.
221      * We can use "send" after that
222      */
223     if(connect(ossock,(struct sockaddr *)&n_us,SUN_LEN(&n_us)) < 0)
224         return(OS_SOCKTERR);
225
226
227     /* Getting current maximum size */
228     if(getsockopt(ossock, SOL_SOCKET, SO_SNDBUF, &len, &optlen) == -1)
229         return(OS_SOCKTERR);
230
231
232     /* Setting maximum message size */
233     if(len < max_msg_size)
234     {
235         len = max_msg_size;
236         setsockopt(ossock, SOL_SOCKET, SO_SNDBUF, &len, optlen);
237     }
238
239
240     /* Returning the socket */  
241     return(ossock);
242 }
243
244
245 int OS_getsocketsize(int ossock)
246 {
247     int len = 0;
248     socklen_t optlen = sizeof(len);
249
250     /* Getting current maximum size */
251     if(getsockopt(ossock, SOL_SOCKET, SO_SNDBUF, &len, &optlen) == -1)
252         return(OS_SOCKTERR);
253
254     return(len);
255 }
256
257 #endif
258
259 /* OS_Connect v 0.1, 2004/07/21
260  * Open a TCP/UDP client socket
261  */
262 int OS_Connect(unsigned int _port, unsigned int protocol, char *_ip, int ipv6)
263 {
264     int ossock;
265     struct sockaddr_in server;
266
267     #ifndef WIN32
268     struct sockaddr_in6 server6;
269     #else
270     ipv6 = 0;
271     #endif
272
273     if(protocol == IPPROTO_TCP)
274     {
275         if((ossock = socket(ipv6 == 1?PF_INET6:PF_INET,SOCK_STREAM,IPPROTO_TCP)) < 0)
276             return(OS_SOCKTERR);
277     }
278     else if(protocol == IPPROTO_UDP)
279     {
280         if((ossock = socket(ipv6 == 1?PF_INET6:PF_INET,SOCK_DGRAM,IPPROTO_UDP)) < 0)
281             return(OS_SOCKTERR);
282     }
283     else
284         return(OS_INVALID);
285
286
287
288     #ifdef HPUX
289     {
290     int flags;
291     flags = fcntl(ossock,F_GETFL,0);
292     fcntl(ossock, F_SETFL, flags | O_NONBLOCK);
293     }
294     #endif
295
296
297
298     if((_ip == NULL)||(_ip[0] == '\0'))
299         return(OS_INVALID);
300
301
302     if(ipv6 == 1)
303     {
304         #ifndef WIN32
305         memset(&server6, 0, sizeof(server6));
306         server6.sin6_family = AF_INET6;
307         server6.sin6_port = htons( _port );
308         inet_pton(AF_INET6, _ip, &server6.sin6_addr.s6_addr);
309
310         if(connect(ossock,(struct sockaddr *)&server6, sizeof(server6)) < 0)
311             return(OS_SOCKTERR);
312         #endif
313     }
314     else
315     {
316         memset(&server, 0, sizeof(server));
317         server.sin_family = AF_INET;
318         server.sin_port = htons( _port );
319         server.sin_addr.s_addr = inet_addr(_ip);
320
321
322         if(connect(ossock,(struct sockaddr *)&server, sizeof(server)) < 0)
323             return(OS_SOCKTERR);
324     }
325
326
327     return(ossock);
328 }
329
330
331 /* OS_ConnectTCP, v0.1
332  * Open a TCP socket
333  */
334 int OS_ConnectTCP(unsigned int _port, char *_ip, int ipv6)
335 {
336     return(OS_Connect(_port, IPPROTO_TCP, _ip, ipv6));
337 }
338
339
340 /* OS_ConnectUDP, v0.1
341  * Open a UDP socket
342  */
343 int OS_ConnectUDP(unsigned int _port, char *_ip, int ipv6)
344 {
345     return(OS_Connect(_port, IPPROTO_UDP, _ip, ipv6));
346 }
347
348 /* OS_SendTCP v0.1, 2004/07/21
349  * Send a TCP packet (in a open socket)
350  */
351 int OS_SendTCP(int socket, char *msg)
352 {
353     if((send(socket, msg, strlen(msg),0)) <= 0)
354         return (OS_SOCKTERR);
355
356     return(0);
357 }
358
359 /* OS_SendTCPbySize v0.1, 2004/07/21
360  * Send a TCP packet (in a open socket) of a specific size
361  */
362 int OS_SendTCPbySize(int socket, int size, char *msg)
363 {
364     if((send(socket, msg, size, 0)) < size)
365         return (OS_SOCKTERR);
366
367     return(0);
368 }
369
370
371 /* OS_SendUDPbySize v0.1, 2004/07/21
372  * Send a UDP packet (in a open socket) of a specific size
373  */
374 int OS_SendUDPbySize(int socket, int size, char *msg)
375 {
376     int i = 0;
377
378     /* Maximum attempts is 5 */
379     while((send(socket,msg,size,0)) < 0)
380     {
381         if((errno != ENOBUFS) || (i >= 5))
382         {
383             return(OS_SOCKTERR);
384         }
385
386         i++;
387         merror("%s: INFO: Remote socket busy, waiting %d s.", __local_name, i);
388         sleep(i);
389     }
390
391     return(0);
392 }
393
394
395
396 /* OS_AcceptTCP v0.1, 2005/01/28
397  * Accept a TCP connection
398  */
399 int OS_AcceptTCP(int socket, char *srcip, int addrsize)
400 {
401     int clientsocket;
402     struct sockaddr_in _nc;
403     socklen_t _ncl;
404
405     memset(&_nc, 0, sizeof(_nc));
406     _ncl = sizeof(_nc);
407
408     if((clientsocket = accept(socket, (struct sockaddr *) &_nc,
409                     &_ncl)) < 0)
410         return(-1);     
411
412     strncpy(srcip, inet_ntoa(_nc.sin_addr),addrsize -1);
413     srcip[addrsize -1]='\0';
414
415     return(clientsocket);
416 }
417
418
419 /* OS_RecvTCP v0.1, 2004/07/21
420  * Receive a TCP packet (in a open socket)
421  */
422 char *OS_RecvTCP(int socket, int sizet)
423 {
424     char *ret;
425
426     int retsize=0;
427
428     ret = (char *) calloc((sizet), sizeof(char));
429     if(ret == NULL)
430         return(NULL);
431
432     if((retsize = recv(socket, ret, sizet-1,0)) <= 0)
433         return(NULL);
434
435     return(ret);
436 }
437
438
439 /* OS_RecvTCPBuffer v0.1, 2004/07/21
440  * Receive a TCP packet (in a open socket)
441  */
442 int OS_RecvTCPBuffer(int socket, char *buffer, int sizet)
443 {
444     int retsize = 0;
445
446     while(!retsize)
447     {
448         retsize = recv(socket, buffer, sizet -1, 0);
449         if(retsize > 0)
450         {
451             buffer[retsize] = '\0';
452             return(0);
453         }
454         return(-1);
455     }
456     return(-1);
457 }
458
459
460
461
462 /* OS_RecvUDP v 0.1, 2004/07/20
463  * Receive a UDP packet
464  */
465 char *OS_RecvUDP(int socket, int sizet)
466 {
467     char *ret;
468
469     ret = (char *) calloc((sizet), sizeof(char));
470     if(ret == NULL)
471         return(NULL);
472
473     if((recv(socket,ret,sizet-1,0))<0)
474         return(NULL);
475
476     return(ret);
477 }
478
479
480 /* OS_RecvConnUDP v0.1
481  * Receives a message from a connected UDP socket
482  */
483 int OS_RecvConnUDP(int socket, char *buffer, int buffer_size)
484 {
485     int recv_b;
486
487     recv_b = recv(socket, buffer, buffer_size, 0);
488     if(recv_b < 0)
489         return(0);
490
491     return(recv_b);
492 }
493
494
495 #ifndef WIN32
496 /* OS_RecvUnix, v0.1, 2004/07/29
497  * Receive a message using a Unix socket
498  */
499 int OS_RecvUnix(int socket, int sizet, char *ret)
500 {
501     ssize_t recvd;
502     if((recvd = recvfrom(socket, ret, sizet -1, 0,
503                          (struct sockaddr*)&n_us,&us_l)) < 0)
504         return(0);
505
506     ret[recvd] = '\0';
507     return((int)recvd);
508 }
509
510
511 /* OS_SendUnix, v0.1, 2004/07/29
512  * Send a message using a Unix socket.
513  * Returns the OS_SOCKETERR if it
514  */
515 int OS_SendUnix(int socket, char * msg, int size)
516 {
517     if(size == 0)
518         size = strlen(msg)+1;
519
520     if(send(socket, msg, size,0) < size)
521     {
522         if(errno == ENOBUFS)
523             return(OS_SOCKBUSY);
524
525         return(OS_SOCKTERR);
526     }
527
528     return(OS_SUCCESS);
529 }
530 #endif
531
532
533 /* OS_GetHost, v0.1, 2005/01/181
534  * Calls gethostbyname (tries x attempts)
535  */
536 char *OS_GetHost(char *host, int attempts)
537 {
538     int i = 0;
539     int sz;
540
541     char *ip;
542     struct hostent *h;
543
544     if(host == NULL)
545         return(NULL);
546
547     while(i <= attempts)
548     {
549         if((h = gethostbyname(host)) == NULL)
550         {
551             sleep(i++);
552             continue;
553         }
554
555         sz = strlen(inet_ntoa(*((struct in_addr *)h->h_addr)))+1;
556         if((ip = (char *) calloc(sz, sizeof(char))) == NULL)
557             return(NULL);
558
559         strncpy(ip,inet_ntoa(*((struct in_addr *)h->h_addr)), sz-1);
560
561         return(ip);
562     }
563
564     return(NULL);
565 }
566
567 /* EOF */