Various changes, see Changelog
[revinetd.git] / revinetd.c
blobdc2faf019d1feb8bf93e02f78c83fc023e5090dd
1 /*
2 * revinetd.c
4 * This file is a part of the revinetd project
6 * Revinetd is copyright (c) 2003-2008 by Steven M. Gill
7 * and distributed under the GPL.
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
22 * USA.
24 * */
26 #include "includes.h"
27 #include "revinetd.h"
28 #include "relay_agt.h"
29 #include "server.h"
30 #include "misc.h"
32 static const char cvsid[] = "$Id: revinetd.c,v 1.29 2008/08/28 03:24:59 necrotaur Exp, adapted by ThP $";
34 int
35 main(int argc, char **argv)
37 /* All variables are initialized to a known invalid value so that they
38 are not used un-initialized. To use them should trip tests or cause
39 segfaults. */
40 static struct option long_options[] = {
41 /* These options set a flag. */
42 {"help", no_argument, 0, 'h'},
43 {"daemonize", no_argument, 0, 'd'},
44 {"relay-agent", no_argument, 0, 'r'},
45 {"server", no_argument, 0, 's'},
46 {"listen-client", required_argument, 0, 'c'},
47 {"listen-relay", required_argument, 0, 'l'},
48 {"server-host", required_argument, 0, 'b'},
49 {"target-host", required_argument, 0, 't'},
50 {"verbose", no_argument, 0, 'v'},
51 {"quiet", no_argument, 0, 'q'},
52 {"keep-alive", required_argument, 0, 'k'},
53 {0, 0, 0, 0}};
54 /* getopt_long stores the option index here. */
55 int c, option_index = 0;
56 pid_t pid;
58 printf("%s - v1.0.2_p5_20200612 - Copyright (c) 2003-2008 Steven M. Gill, et al (201x, 2020)\n", *argv);
59 printf("%s is distributed under the terms of the GPL\n", *argv);
60 printf("http://revinetd.sourceforge.net\n\n");
61 exec_name = strdup(*argv);
63 init_conf();
65 while (1) {
66 c = getopt_long(argc, argv, "hdrsc:l:b:t:qvk:", long_options,
67 &option_index);
69 /* Detect the end of the options. */
70 if (c == -1)
71 break;
73 switch (c) {
74 case 0:
75 /* If this option set a flag, do nothing else now. */
76 if (long_options[option_index].flag != 0)
77 break;
78 printf("option %s", long_options[option_index].name);
79 if (optarg)
80 printf(" with arg %s", optarg);
81 printf("\n");
82 break;
84 case 'd':
85 conf.daemonize = 1;
86 conf.verbosity = VB_QUIET;
87 break;
89 case 's':
90 if (conf.server_flag == FLAG_NONE) {
91 conf.server_flag = FLAG_SERVER;
92 } else {
93 fprintf(stderr, "You can only set one mode, either Server or "
94 "Relay Agent, not both.\n\n");
95 usage();
97 break;
99 case 'r':
100 if (conf.server_flag == FLAG_NONE) {
101 conf.server_flag = FLAG_RELAY;
102 } else {
103 fprintf(stderr, "You can only set one mode, either Server or "
104 "Relay Agent, not both.\n\n");
105 usage();
107 break;
109 case 'c':
110 if (conf.server_flag == FLAG_SERVER) {
111 conf.host = strdup(optarg);
112 conf.port = parse_host_str(conf.host);
113 } else {
114 fprintf(stderr, "You must select Server mode to use -c or "
115 "--listen-client.\n\n");
116 usage();
118 break;
120 case 'l':
121 if (conf.server_flag == FLAG_SERVER) {
122 conf.host2 = strdup(optarg);
123 conf.port2 = parse_host_str(conf.host2);
124 } else {
125 fprintf(stderr, "You must select Server mode to use -l or "
126 "--listen-relay.\n\n");
127 usage();
129 break;
131 case 'b':
132 if (conf.server_flag == FLAG_RELAY) {
133 conf.host = strdup(optarg);
134 conf.port = parse_host_str(conf.host);
135 } else {
136 fprintf(stderr, "You must select Relay Agent mode to use -c "
137 "or --server-host.\n\n");
138 usage();
140 break;
142 case 't':
143 if (conf.server_flag == FLAG_RELAY) {
144 conf.host2 = strdup(optarg);
145 conf.port2 = parse_host_str(conf.host2);
146 } else {
147 fprintf(stderr, "You must select Relay Agent mode to use -t "
148 "or --target-host.\n\n");
149 usage();
151 break;
152 case 'h':
153 usage();
154 break;
156 case 'k':
157 conf.keepalive = atoi(optarg);
158 break;
160 case 'v':
161 if (conf.daemonize == 0) {
162 //conf.verbosity = VB_VERBOSE;
163 conf.verbosity++;
165 break;
167 case 'q':
168 conf.verbosity = VB_QUIET;
169 break;
171 case '?':
172 /* FALL THROUGH */
173 default:
174 usage();
178 /* Print any remaining command line arguments (not options). */
179 if (optind < argc) {
180 usage();
183 if (conf.daemonize == TRUE) {
184 pid = fork();
186 if (pid > 0) { /* parent */
187 exit(0);
188 } else if (pid < 0) { /* error */
189 perror("fork");
190 exit(1);
191 } /* child */
192 setsid();
194 close(0); close(1); close(2);
197 signal(SIGTERM, clean_exit);
198 signal(SIGINT, clean_exit);
199 signal(SIGQUIT, clean_exit);
200 signal(SIGHUP, clean_exit);
202 if (conf.server_flag == FLAG_SERVER) {
203 if (conf.port >= 0 && conf.port2 >= 0) {
204 server(conf.host, conf.port, conf.host2, conf.port2);
205 } else {
206 fprintf(stderr, "Two ports, port1 (-l and --client-port) and "
207 "port2 (-L and --ra-port) must be "
208 "provided.\n\n");
209 usage();
211 } else if (conf.server_flag == FLAG_RELAY) {
212 if (conf.host != NULL && conf.host2 != NULL) {
213 relay_agent(conf.host, conf.port, conf.host2, conf.port2);
214 } else {
215 fprintf(stderr, "Both a server (-b and --server-host) and a "
216 "target (-t and --target-host)\nmust be "
217 "specified.\n\n");
218 usage();
220 } else {
221 usage();
224 exit(0);
227 void
228 usage(void)
231 fprintf(stderr, "Usage: revinetd -s -c HOST1:PORT1 -l HOST2:PORT2 [-d]"
232 "\n"
233 " revinetd -r -b HOST1:PORT1 -t "
234 "HOST2:PORT2 [-d] [-k seconds]\n"
235 "\n"
236 "Global arguments:\n"
237 " -s --server\t\tRuns in server mode\n"
238 " -r --relay-agent\tRuns as the relay agent\n"
239 " -d --daemonize\tRuns as a daemon (implies -q)\n"
240 " -h --help\t\tPrints this message and exit\n"
241 " -q --quiet\t\tSurpress all messages\n"
242 " -v --verbose\t\tIncrease verbiosity\n"
243 "\n"
244 "Server arguments:\n"
245 " -c HOST1:PORT1 --client-port=HOST1:PORT1\tListen for a client on IP and Port\n"
246 " -l HOST2:PORT2 --ra-port=HOST2:PORT2 \tListen for a relay agent on IP and Port\n"
247 "Relay agent arguments:\n"
248 " required arguments:\n"
249 " -b HOST1:PORT1 --server-host=HOST1:PORT1\tRevinetd server "
250 "host and port\n"
251 " -t HOST2:PORT2 --target-host=HOST2:PORT2\tThe target host "
252 "and port\n\n"
253 " optional arguments:\n"
254 " -k seconds --keep-alive=seconds\tKeep-alive signal interval\n"
255 " \tdefaults to 180 seconds\n\n");
257 clean_exit(SIGQUIT);
260 void
261 clean_exit(int sig)
263 OpenSockets *open_sock;
265 /* Close all registered sockets. */
266 open_sock = conf.open_sock;
267 while (open_sock != NULL) {
268 if (shutdown(open_sock->sock, SHUT_RDWR) == -1) {
269 perror("shutdown");
271 close(open_sock->sock);
272 open_sock = open_sock->next;
275 exit(0);
278 // Adapted to search for the colon from the right. (thpi)
279 unsigned short
280 parse_host_str(char *host_str)
282 unsigned short port;
283 int j;
285 /* Skip any leading spaces. */
286 while (isspace(*host_str)) { host_str++; }
288 /* Loop through the line until we reach a ':'. Exit with errors if we
289 stumble on an illegal character. */
290 j = strlen(host_str)-1;
291 if (j < 0) return 0;
292 while (*(host_str + j) != ':') {
293 if (isspace(*(host_str + j))) {
294 *(host_str + j) = '\0'; // remove the trailing padding
296 --j;
297 if (j < 0) {
298 fprintf(stderr, "Invalid hostname format.\n");
299 usage();
303 /* Insert a NUL byte at the position of the right-most ':' to delimitate the
304 hostname. And then skip ahead one byte. */
305 *(host_str + j++) = '\0';
307 /* Grab the port. */
308 port = (unsigned short)atoi(host_str + j);
310 return port;
313 void
314 init_conf(void)
317 memset(&conf, 0, sizeof(Conf));
318 conf.port = -1;
319 conf.port2 = -1;
320 conf.verbosity = VB_NORMAL;
321 conf.keepalive = 180L;