1 /*
2 * ircio.c: A quaint little program to make irc life PING free
3 *
4 * Written By Michael Sandrof
5 *
6 * Copyright (c) 1990 Michael Sandrof.
7 * Copyright (c) 1991, 1992 Troy Rollo.
8 * Copyright (c) 1992-2014 Matthew R. Green.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include "irc.h"
36 IRCII_RCSID("@(#)$eterna: ircio.c,v 2.34 2014/07/11 09:56:27 mrg Exp $");
37
38 #include <errno.h>
39
40 #include "defs.h"
41 #include "newio.h"
42
43 #ifdef HAVE_SYS_UN_H
44 #include <sys/un.h>
45 static int connect_to_unix(char *);
46 #endif /* HAVE_SYS_UN_H */
47
48 #undef NON_BLOCKING
49
50 void new_free(char **);
51 void *new_malloc(size_t);
52 static int connect_by_number(char *, char *);
53 int main(int, char *[], char *[]);
54
55 void *
new_malloc(size_t size)56 new_malloc(size_t size)
57 {
58 void *ptr;
59
60 if ((ptr = malloc(size)) == NULL)
61 {
62 printf("-1 0\n");
63 exit(1);
64 }
65 return (ptr);
66 }
67
68 /*
69 * new_free: Why do this? Why not? Saves me a bit of trouble here and
70 * there
71 */
72 void
new_free(char ** ptr)73 new_free(char **ptr)
74 {
75 if (*ptr)
76 {
77 free(*ptr);
78 *ptr = 0;
79 }
80 }
81
82 #ifdef DEBUG
83 void
debug(int level,char * fmt,...)84 debug(int level, char *fmt, ...)
85 {
86 }
87 #endif
88
89 ssize_t
ssl_read(SslInfo * info,int fd,void * buf,size_t buflen)90 ssl_read(SslInfo *info, int fd, void *buf, size_t buflen)
91 {
92 return read(fd, buf, buflen);
93 }
94
95 /*
96 * connect_by_number Performs a connecting to socket 'service' on host
97 * 'host'. Host can be a hostname or ip-address. If 'host' is null, the
98 * local host is assumed. The parameter full_hostname will, on return,
99 * contain the expanded hostname (if possible). Note that full_hostname is a
100 * pointer to a char *, and is allocated by connect_by_numbers()
101 *
102 * Errors:
103 *
104 * -1 get service failed
105 *
106 * -2 get host failed
107 *
108 * -3 socket call failed
109 *
110 * -4 connect call failed
111 */
112 static int
connect_by_number(char * service,char * host)113 connect_by_number(char *service, char *host)
114 {
115 int s = -1, err;
116 char buf[256];
117 struct addrinfo hints, *res = 0, *res0 = 0;
118
119 if (host == NULL)
120 {
121 gethostname(buf, sizeof(buf));
122 host = buf;
123 }
124 memset(&hints, 0, sizeof hints);
125 hints.ai_flags = 0;
126 hints.ai_protocol = 0;
127 hints.ai_addrlen = 0;
128 hints.ai_canonname = NULL;
129 hints.ai_addr = NULL;
130 hints.ai_next = NULL;
131 hints.ai_socktype = SOCK_STREAM;
132 hints.ai_family = AF_UNSPEC;
133 err = getaddrinfo(host, service, &hints, &res0);
134 if (err != 0)
135 return -2;
136 for (res = res0; res; res = res->ai_next)
137 {
138 err = 0;
139 if ((s = socket(res->ai_family, res->ai_socktype,
140 res->ai_protocol)) < 0)
141 continue;
142 set_socket_options(s);
143 err = connect(s, res->ai_addr, res->ai_addrlen);
144 if (err == 0)
145 break;
146 close(s);
147 }
148 freeaddrinfo(res0);
149 if (err)
150 return -4;
151 return (s);
152 }
153
154 /*
155 * ircio: This little program connects to the server (given as arg 1) on
156 * the given port (given as arg 2). It then accepts input from stdin and
157 * sends it to that server. Likewise, it reads stuff sent from the server and
158 * sends it to stdout. Simple? Yes, it is. But wait! There's more! It
159 * also intercepts server PINGs and automatically responds to them. This
160 * frees up the process that starts ircio (such as IRCII) to pause without
161 * fear of being pooted off the net.
162 *
163 * Future enhancements: No-blocking io. It will either discard or dynamically
164 * buffer anything that would block.
165 */
166 int
main(int argc,char * argv[],char * envp[])167 main(int argc, char *argv[], char *envp[])
168 {
169 int des;
170 fd_set rd;
171 int done = 0,
172 c;
173 char *ptr,
174 lbuf[BUFSIZ + 1],
175 pong[BUFSIZ + 1];
176 #ifdef NON_BLOCKING
177 char block_buffer[BUFSIZ + 1];
178 fd_set *wd_ptr = NULL,
179 wd;
180 int wrote;
181 #endif /* NON_BLOCKING */
182
183 if (argc < 3)
184 exit(1);
185 #ifdef SOCKS
186 SOCKSinit(*argv);
187 #endif /* SOCKS */
188 #ifdef HAVE_SYS_UN_H
189 if (*argv[1] == '/')
190 des = connect_to_unix(argv[1]);
191 else
192 #endif /* HAVE_SYS_UN_H */
193 des = connect_by_number(argv[2], argv[1]);
194 if (des < 0)
195 exit(des);
196 fflush(stdout);
197
198 (void) MY_SIGNAL(SIGTERM, (sigfunc *) SIG_IGN, 0);
199 (void) MY_SIGNAL(SIGSEGV, (sigfunc *) SIG_IGN, 0);
200 (void) MY_SIGNAL(SIGBUS, (sigfunc *) SIG_IGN, 0);
201 (void) MY_SIGNAL(SIGPIPE, (sigfunc *) SIG_IGN, 0);
202 #ifdef SIGWINCH
203 (void) MY_SIGNAL(SIGWINCH, (sigfunc *) SIG_IGN, 0);
204 #endif /* SIGWINCH */
205
206 #ifdef NON_BLOCKING
207 if (fcntl(1, F_SETFL, FNDELAY))
208 exit(1);
209 #endif /* NON_BLOCKING */
210 while (!done)
211 {
212 fflush(stderr);
213 FD_ZERO(&rd);
214 FD_SET(0, &rd);
215 FD_SET(des, &rd);
216 #ifdef NON_BLOCKING
217 if (wd_ptr)
218 {
219 FD_ZERO(wd_ptr);
220 FD_SET(1, wd_ptr);
221 }
222 switch (new_select(&rd, wd_ptr, NULL))
223 {
224 #else
225 switch (new_select(&rd, NULL, NULL))
226 {
227 #endif /* NON_BLOCKING */
228 case -1:
229 case 0:
230 break;
231 default:
232 #ifdef NON_BLOCKING
233 if (wd_ptr)
234 {
235 if (FD_ISSET(1, wd_ptr))
236 {
237 c = strlen(block_buffer);
238 if ((wrote = write(1, block_buffer,
239 c)) == -1)
240 {
241 wd_ptr = &wd;
242 }
243 else if (wrote < c)
244 {
245 strcpy(block_buffer,
246 &(block_buffer[wrote]));
247 wd_ptr = &wd;
248 }
249 else
250 wd_ptr = NULL;
251 }
252 }
253 #endif /* NON_BLOCKING */
254 if (FD_ISSET(0, &rd))
255 {
256 c = dgets(UP(lbuf), BUFSIZ, 0);
257 switch (c) {
258 case -1:
259 case 0:
260 done = 1;
261 break;
262 default:
263 if (write(des, lbuf, (size_t)c) != c)
264 done = 1;
265 }
266 }
267 if (FD_ISSET(des, &rd))
268 {
269 c = dgets(UP(lbuf), BUFSIZ, des);
270 switch (c) {
271 case -1:
272 case 0:
273 done = 1;
274 break;
275 default:
276 if (strncmp(lbuf, "PING ", 5) == 0)
277 {
278 if ((ptr = (char *)
279 my_index(lbuf, ' ')) != NULL)
280 {
281 snprintf(pong, sizeof pong, "PONG user@host %s\n", ptr + 1);
282 if (write(des, pong, strlen(pong)) != strlen(pong))
283 done = 1;
284 }
285 }
286 else
287 {
288 #ifdef NON_BLOCKING
289 if ((wrote = write(1, lbuf,
290 (size_t)c)) == -1)
291 wd_ptr = &wd;
292 else if (wrote < c)
293 {
294 strcpy(block_buffer,
295 &(lbuf[wrote]));
296 wd_ptr = &wd;
297 }
298 #else
299 if (write(1, lbuf, (size_t)c) != c)
300 done = 1;
301 #endif /* NON_BLOCKING */
302 }
303 }
304 }
305 }
306 }
307 return 0;
308 }
309
310
311 #ifdef HAVE_SYS_UN_H
312 /*
313 * Connect to a UNIX domain socket. Only works for servers.
314 * submitted by Avalon for use with server 2.7.2 and beyond.
315 */
316 static int
317 connect_to_unix(char *path)
318 {
319 struct sockaddr_un un;
320 int sock;
321
322 sock = socket(AF_UNIX, SOCK_STREAM, 0);
323
324 un.sun_family = AF_UNIX;
325 strcpy(un.sun_path, path);
326 if (connect(sock, (struct sockaddr *)&un, (int)strlen(path)+2) == -1)
327 {
328 new_close(sock);
329 return -1;
330 }
331 return sock;
332 }
333 #endif /* HAVE_SYS_UN_H */
334