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