1 /*
2     ettercap -- socket handling module
3 
4     Copyright (C) ALoR & NaGA
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 
20 */
21 
22 #include <ec.h>
23 #include <ec_signals.h>
24 #include <ec_socket.h>
25 #include <ec_sleep.h>
26 
27 #ifndef OS_WINDOWS
28    #include <netdb.h>
29    #include <sys/socket.h>
30    #include <netinet/in.h>
31    #include <arpa/inet.h>
32 #endif
33 
34 #include <fcntl.h>
35 
36 /*******************************************/
37 
38 /*
39  * set or unset blocking flag on a socket
40  */
set_blocking(int s,int set)41 void set_blocking(int s, int set)
42 {
43 #ifdef OS_WINDOWS
44    u_long on = set;
45    ioctlsocket(s, FIONBIO, &on);
46 #else
47    int ret;
48 
49    /* get the current flags */
50    if ((ret = fcntl(s, F_GETFL, 0)) == -1)
51       return;
52 
53    if (set)
54       ret &= ~O_NONBLOCK;
55    else
56       ret |= O_NONBLOCK;
57 
58    /* set the flag */
59 //   fcntl (s, F_SETFL, F_SETFD, FD_CLOEXEC, ret); //this solution BREAKS the socket (ssl mitm will not work)
60    fcntl(s, F_SETFL, ret);
61 
62 #endif
63 }
64 
65 
66 /*
67  * open a socket to the specified host and port
68  */
open_socket(const char * host,u_int16 port)69 int open_socket(const char *host, u_int16 port)
70 {
71    struct addrinfo *result, *res;
72    struct addrinfo hints;
73    int sh, ret, err = 0;
74 #define TSLEEP (50*1000) /* 50 milliseconds */
75    int loops = (EC_GBL_CONF->connect_timeout * 10e5) / TSLEEP;
76    char service[5+1];
77 
78    DEBUG_MSG("open_socket -- [%s]:[%d]", host, port);
79 
80    /* convert port number to string */
81    snprintf(service, 6, "%u", port);
82 
83    /* predefine TCP as socket type and protocol */
84    memset(&hints, 0, sizeof(struct addrinfo));
85    hints.ai_socktype = SOCK_STREAM;
86 
87    /* resolve hostname */
88    if ((ret = getaddrinfo(host, service, &hints, &result)) != 0) {
89       DEBUG_MSG("unable to resolve %s using getaddrinfo(): %s",
90             host, gai_strerror(ret));
91          return -E_NOADDRESS;
92    }
93 
94    /* go though results and try to connect */
95    for (res = result; res != NULL; res = res->ai_next) {
96       /* open the socket */
97       if ( (sh = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) {
98          freeaddrinfo(result);
99          return -E_FATAL;
100       }
101 
102       /* set nonblocking socket */
103       set_blocking(sh, 0);
104 
105       do {
106          /* connect to the server */
107          ret = connect(sh, res->ai_addr, res->ai_addrlen);
108 
109          /* connect is in progress... */
110          if (ret < 0) {
111             err = GET_SOCK_ERRNO();
112             if (err == EINPROGRESS || err == EALREADY || err == EWOULDBLOCK || err == EAGAIN) {
113                /* sleep a quirk of time... */
114                DEBUG_MSG("open_socket: connect() retrying: %d", err);
115                ec_usleep(TSLEEP); /* 50000 microseconds */
116             }
117          } else {
118             /* there was an error or the connect was successful */
119             break;
120          }
121       } while(loops--);
122 
123       /* if connected we skip other addresses */
124       if (ret == 0)
125          break;
126    }
127 
128    /*
129     * we cannot recall get_sock_errno because under windows
130     * calling it twice would not return the same result
131     */
132    err = ret < 0 ? err : 0;
133 
134    /* reached the timeout */
135    if (ret < 0 && (err == EINPROGRESS || err == EALREADY || err == EAGAIN)) {
136       DEBUG_MSG("open_socket: connect() timeout: %d", err);
137       close_socket(sh);
138       freeaddrinfo(result);
139       return -E_TIMEOUT;
140    }
141 
142    /* error while connecting */
143    if (ret < 0 && err != EISCONN) {
144       DEBUG_MSG("open_socket: connect() error: %d", err);
145       close_socket(sh);
146       freeaddrinfo(result);
147       return -E_INVALID;
148    }
149 
150    DEBUG_MSG("open_socket: connect() connected.");
151 
152    /* reset the state to blocking socket */
153    set_blocking(sh, 1);
154 
155 
156    DEBUG_MSG("open_socket: %d", sh);
157    freeaddrinfo(result);
158 
159    return sh;
160 }
161 
162 /*
163  * close the given socket
164  */
close_socket(int s)165 int close_socket(int s)
166 {
167    DEBUG_MSG("close_socket: %d", s);
168 
169    /* close the socket */
170 #ifdef OS_WINDOWS
171    return closesocket(s);
172 #else
173    return close(s);
174 #endif
175 }
176 
177 
178 /*
179  * send a buffer throught the socket
180  */
socket_send(int s,const u_char * payload,size_t size)181 int socket_send(int s, const u_char *payload, size_t size)
182 {
183    /* send data to the socket */
184    return send(s, payload, size, 0);
185 }
186 
187 /*
188  * receive data from the socket
189  */
socket_recv(int sh,u_char * payload,size_t size)190 int socket_recv(int sh, u_char *payload, size_t size)
191 {
192    /* read up to size byte */
193    return recv(sh, payload, size, 0);
194 }
195 
196 
197 /* EOF */
198 
199 // vim:ts=3:expandtab
200 
201