├── .gitignore
├── CHANGES
├── Makefile
├── README.md
├── getopt.c
├── getopt.h
├── match.c
├── match.h
├── rinetd.8
├── rinetd.c
├── rinetd.dsp
├── rinetd.dsw
├── rinetd.html
├── rinetd.ncb
├── rinetd.opt
└── rinetd.plg
/.gitignore:
--------------------------------------------------------------------------------
1 | *.o
2 | *.exe
3 | rinetd
4 |
--------------------------------------------------------------------------------
/CHANGES:
--------------------------------------------------------------------------------
1 | Version 0.1: original version.
2 |
3 | Version 0.2: fixed bug when several reads are necessary
4 | on one end or the other before a write flushes them.
5 | Fixed bug which threw away data not yet sent to the
6 | other side on close, when running under Linux. Fixed
7 | associated bugs that probably affected other operating
8 | systems as well. Fixed bug causing long, perhaps
9 | indefinite pauses when a possible connection to a
10 | server socket went away before the accept() call,
11 | resulting in a blocking call.
12 |
13 | Version 0.3: fixed additional bugs relating to
14 | the code previously used only by non-Linux OSes.
15 | This should fix problems such as connections not
16 | going away when they should or connections being
17 | mysteriously closed. Most of that code is now used by
18 | Linux also, so it is likely that rinetd is much closer
19 | to bug-free on non-Linux platforms. Of course, I don't
20 | actually have any to play with it on.
21 |
22 | Version 0.4: added support for kill -1 (SIGHUP)
23 | and specification of service names instead of
24 | port numbers. Removed calls to realloc(), replacing
25 | them with code that should fail gracefully without
26 | crashing the program or breaking existing connections
27 | when another application is hogging memory.
28 |
29 | Version 0.5: added logging in both tab-delimited
30 | and web-server-style formats. No longer exits if
31 | an individual configuration file line generates
32 | an error. Added allow and deny rules. Added
33 | -c command line option to specify a configuration file.
34 |
35 | Version 0.51: fixed failure to check for an open
36 | log file before writing log entries.
37 |
38 | Version 0.52: documentation added regarding the
39 | ability to bind to all IP addresses, if desired,
40 | using the special address 0.0.0.0.
41 |
42 | Version 0.6: ported to Win32. Various compatibility
43 | fixes were made and some minor oversights without
44 | functional consequences were corrected.
45 |
46 | Version 0.61: fixed a bug in 0.6 which completely
47 | broke rinetd under Linux. Oops.
48 |
49 | Version 0.62: fixed a potential buffer overrun;
50 | prior versions failed to reallocate one of the
51 | arrays correctly when reallocating memory to
52 | accommodate more connections. Thanks to
53 | Sam Hocevar.
54 |
55 |
56 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | CFLAGS=-DLINUX -g
2 |
3 |
4 | rinetd: rinetd.o match.o
5 | $(CC) rinetd.o match.o -o rinetd
6 |
7 | install: rinetd
8 | install -m 700 rinetd /usr/sbin
9 | install -m 644 rinetd.8 /usr/man/man8
10 | clean:
11 | rm -rf *.o
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # OBSOLETE! THIS REPO IS ARCHIVED, USE [Sam Hocevar's lovely and well-maintained version](https://github.com/samhocevar/rinetd). Thanks!
2 |
3 |
Description
4 |
5 | Redirects TCP connections from one IP address and port to another. rinetd
6 | is a single-process server which handles any number of connections to
7 | the address/port pairs specified in the file /etc/rinetd.conf
.
8 | Since rinetd runs as a single process using nonblocking I/O, it is
9 | able to redirect a large number of connections without a severe
10 | impact on the machine. This makes it practical to run TCP services
11 | on machines inside an IP masquerading firewall. rinetd does not
12 | redirect FTP, because FTP requires more than one socket.
13 |
14 |
15 | rinetd is typically launched at boot time, using the following syntax:
16 |
17 |
18 | /usr/sbin/rinetd
19 |
20 |
21 | The configuration file is found in the file
22 | /etc/rinetd.conf
, unless
23 | another file is specified using the -c
command line option.
24 |
25 | Forwarding Rules
26 |
27 | Most entries in the configuration file are forwarding rules. The
28 | format of a forwarding rule is as follows:
29 |
30 |
31 | bindaddress bindport connectaddress connectport
32 |
33 | For example:
34 |
35 | 206.125.69.81 80 10.1.1.2 80
36 |
37 |
38 | Would redirect all connections to port 80 of the "real" IP address
39 | 206.125.69.81, which could be a virtual interface, through
40 | rinetd to port 80 of the address 10.1.1.2, which would typically
41 | be a machine on the inside of a firewall which has no
42 | direct routing to the outside world.
43 |
44 |
45 | Although responding on individual interfaces rather than on all
46 | interfaces is one of rinetd's primary features, sometimes it is
47 | preferable to respond on all IP addresses that belong to the server.
48 | In this situation, the special IP address 0.0.0.0
49 | can be used. For example:
50 |
51 |
52 | 0.0.0.0 23 10.1.1.2 23
53 |
54 |
55 | Would redirect all connections to port 23, for all IP addresses
56 | assigned to the server. This is the default behavior for most
57 | other programs.
58 |
59 |
60 | Service names can be specified instead of port numbers. On most systems,
61 | service names are defined in the file /etc/services.
62 |
63 |
64 | Both IP addresses and hostnames are accepted for
65 | bindaddress and connectaddress.
66 |
67 | Allow and Deny Rules
68 |
69 | Configuration files can also contain allow and deny rules.
70 |
71 |
72 | Allow rules which appear before the first forwarding rule are
73 | applied globally: if at least one global allow rule exists,
74 | and the address of a new connection does not
75 | satisfy at least one of the global allow rules, that connection
76 | is immediately rejected, regardless of any other rules.
77 |
78 |
79 | Allow rules which appear after a specific forwarding rule apply
80 | to that forwarding rule only. If at least one allow rule
81 | exists for a particular forwarding rule, and the address of a new
82 | connection does not satisfy at least one of the allow rules
83 | for that forwarding rule, that connection is immediately
84 | rejected, regardless of any other rules.
85 |
86 |
87 | Deny rules which appear before the first forwarding rule are
88 | applied globally: if the address of a new connection satisfies
89 | any of the global allow rules, that connection
90 | is immediately rejected, regardless of any other rules.
91 |
92 |
93 | Deny rules which appear after a specific forwarding rule apply
94 | to that forwarding rule only. If the address of a new
95 | connection satisfies any of the deny rules for that forwarding rule,
96 | that connection is immediately rejected, regardless of any other rules.
97 |
98 |
99 | The format of an allow rule is as follows:
100 |
101 |
102 | allow pattern
103 |
104 |
105 | Patterns can contain the following characters: 0, 1, 2, 3, 4, 5,
106 | 6, 7, 8, 9, . (period), ?, and *. The ? wildcard matches any one
107 | character. The * wildcard matches any number of characters, including
108 | zero.
109 |
110 |
111 | For example:
112 |
113 |
114 | allow 206.125.69.*
115 |
116 |
117 | This allow rule matches all IP addresses in the 206.125.69 class C domain.
118 |
119 |
120 | Host names are NOT permitted in allow and deny rules. The performance
121 | cost of looking up IP addresses to find their corresponding names
122 | is prohibitive. Since rinetd is a single process server, all other
123 | connections would be forced to pause during the address lookup.
124 |
125 | Logging
126 |
127 | rinetd is able to produce a log file in either of two formats:
128 | tab-delimited and web server-style "common log format."
129 |
130 |
131 | By default, rinetd does not produce a log file. To activate logging, add
132 | the following line to the configuration file:
133 |
134 |
135 | logfile log-file-location
136 |
137 |
138 | Example:
139 |
140 |
141 | logfile /var/log/rinetd.log
142 |
143 |
144 | By default, rinetd logs in a simple tab-delimited format containing
145 | the following information:
146 |
147 |
148 | Date and time
149 | Client address
150 |
151 | Listening host
152 |
153 | Listening port
154 |
155 | Forwarded-to host
156 |
157 | Forwarded-to port
158 |
159 | Bytes received from client
160 |
161 | Bytes sent to client
162 |
163 | Result message
164 |
165 |
166 | To activate web server-style "common log format" logging,
167 | add the following line to the configuration file:
168 |
169 |
170 | logcommon
171 |
172 | Command line options
173 |
174 | The -c command line option is used to specify an alternate
175 | configuration file.
176 |
177 |
178 | The -h command line option produces a short help message.
179 |
180 |
181 | The -v command line option displays the version number.
182 |
183 | Reinitializing rinetd
184 |
185 | The kill -1 signal (SIGHUP) can be used to cause rinetd
186 | to reload its configuration file without interrupting existing
187 | connections. Under Linux(tm) the process id
188 | is saved in the file /var/run/rinetd.pid
189 | to facilitate the kill -HUP. An alternate
190 | file name can be provided by using the pidlogfile
191 | configuration file option.
192 |
193 | Bugs
194 |
195 | The server redirected to is not able to identify the host the
196 | client really came from. This cannot be corrected; however,
197 | the log produced by rinetd provides a way to obtain this
198 | information. Under Unix, sockets would theoretically lose data when closed
199 | with SO_LINGER
turned off, but in Linux this is not the case
200 | (kernel source comments support this belief on my part). On non-Linux Unix
201 | platforms, alternate code which uses a different trick to work around
202 | blocking close()
is provided, but this code is untested.
203 |
204 |
205 | The logging is inadequate. The duration of the connection should be logged.
206 |
207 | License
208 |
209 | Copyright (c) 1997-2019 Thomas Boutell.
210 | This software is released for free use under the terms of
211 | the GNU General Public License, version 2 or higher.
212 |
213 | Thanks
214 |
215 | Thanks are due to Bill Davidsen, Libor Pechachek, Sascha Ziemann,
216 | Joel S. Noble, the Apache Group, and many others who have contributed
217 | advice, encouragement and/or source code to this and other open
218 | software projects.
219 |
220 |
--------------------------------------------------------------------------------
/getopt.c:
--------------------------------------------------------------------------------
1 | /* THIS IS HERE FOR WIN32's BENEFIT ONLY. */
2 |
3 | /* Getopt for GNU.
4 | NOTE: getopt is now part of the C library, so if you don't know what
5 | "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
6 | before changing it!
7 |
8 | Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
9 | Free Software Foundation, Inc.
10 |
11 | This program is free software; you can redistribute it and/or modify it
12 | under the terms of the GNU General Public License as published by the
13 | Free Software Foundation; either version 2, or (at your option) any
14 | later version.
15 |
16 | This program is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | GNU General Public License for more details.
20 |
21 | You should have received a copy of the GNU General Public License
22 | along with this program; if not, write to the Free Software
23 | Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
24 |
25 | #ifdef HAVE_CONFIG_H
26 | #include "config.h"
27 | #endif
28 |
29 | #ifndef __STDC__
30 | # ifndef const
31 | # define const
32 | # endif
33 | #endif
34 |
35 | /* This tells Alpha OSF/1 not to define a getopt prototype in . */
36 | #ifndef _NO_PROTO
37 | #define _NO_PROTO
38 | #endif
39 |
40 | #include
41 |
42 | /* Comment out all this code if we are using the GNU C Library, and are not
43 | actually compiling the library itself. This code is part of the GNU C
44 | Library, but also included in many other GNU distributions. Compiling
45 | and linking in this code is a waste when using the GNU C library
46 | (especially if it is a shared library). Rather than having every GNU
47 | program understand `configure --with-gnu-libc' and omit the object files,
48 | it is simpler to just do this in the source for each such file. */
49 |
50 | #if defined (_LIBC) || !defined (__GNU_LIBRARY__)
51 |
52 |
53 | /* This needs to come after some library #include
54 | to get __GNU_LIBRARY__ defined. */
55 | #ifdef __GNU_LIBRARY__
56 | /* Don't include stdlib.h for non-GNU C libraries because some of them
57 | contain conflicting prototypes for getopt. */
58 | #include
59 | #endif /* GNU C library. */
60 |
61 | /* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
62 | long-named option. Because this is not POSIX.2 compliant, it is
63 | being phased out. */
64 | /* #define GETOPT_COMPAT */
65 |
66 | /* This version of `getopt' appears to the caller like standard Unix `getopt'
67 | but it behaves differently for the user, since it allows the user
68 | to intersperse the options with the other arguments.
69 |
70 | As `getopt' works, it permutes the elements of ARGV so that,
71 | when it is done, all the options precede everything else. Thus
72 | all application programs are extended to handle flexible argument order.
73 |
74 | Setting the environment variable POSIXLY_CORRECT disables permutation.
75 | Then the behavior is completely standard.
76 |
77 | GNU application programs can use a third alternative mode in which
78 | they can distinguish the relative order of options and other arguments. */
79 |
80 | #include "getopt.h"
81 |
82 | /* For communication from `getopt' to the caller.
83 | When `getopt' finds an option that takes an argument,
84 | the argument value is returned here.
85 | Also, when `ordering' is RETURN_IN_ORDER,
86 | each non-option ARGV-element is returned here. */
87 |
88 | char *optarg = 0;
89 |
90 | /* Index in ARGV of the next element to be scanned.
91 | This is used for communication to and from the caller
92 | and for communication between successive calls to `getopt'.
93 |
94 | On entry to `getopt', zero means this is the first call; initialize.
95 |
96 | When `getopt' returns EOF, this is the index of the first of the
97 | non-option elements that the caller should itself scan.
98 |
99 | Otherwise, `optind' communicates from one call to the next
100 | how much of ARGV has been scanned so far. */
101 |
102 | /* XXX 1003.2 says this must be 1 before any call. */
103 | int optind = 0;
104 |
105 | /* The next char to be scanned in the option-element
106 | in which the last option character we returned was found.
107 | This allows us to pick up the scan where we left off.
108 |
109 | If this is zero, or a null string, it means resume the scan
110 | by advancing to the next ARGV-element. */
111 |
112 | static char *nextchar;
113 |
114 | /* Callers store zero here to inhibit the error message
115 | for unrecognized options. */
116 |
117 | int opterr = 1;
118 |
119 | /* Set to an option character which was unrecognized.
120 | This must be initialized on some systems to avoid linking in the
121 | system's own getopt implementation. */
122 |
123 | #define BAD_OPTION '\0'
124 | int optopt = BAD_OPTION;
125 |
126 | /* Describe how to deal with options that follow non-option ARGV-elements.
127 |
128 | If the caller did not specify anything,
129 | the default is REQUIRE_ORDER if the environment variable
130 | POSIXLY_CORRECT is defined, PERMUTE otherwise.
131 |
132 | REQUIRE_ORDER means don't recognize them as options;
133 | stop option processing when the first non-option is seen.
134 | This is what Unix does.
135 | This mode of operation is selected by either setting the environment
136 | variable POSIXLY_CORRECT, or using `+' as the first character
137 | of the list of option characters.
138 |
139 | PERMUTE is the default. We permute the contents of ARGV as we scan,
140 | so that eventually all the non-options are at the end. This allows options
141 | to be given in any order, even with programs that were not written to
142 | expect this.
143 |
144 | RETURN_IN_ORDER is an option available to programs that were written
145 | to expect options and other ARGV-elements in any order and that care about
146 | the ordering of the two. We describe each non-option ARGV-element
147 | as if it were the argument of an option with character code 1.
148 | Using `-' as the first character of the list of option characters
149 | selects this mode of operation.
150 |
151 | The special argument `--' forces an end of option-scanning regardless
152 | of the value of `ordering'. In the case of RETURN_IN_ORDER, only
153 | `--' can cause `getopt' to return EOF with `optind' != ARGC. */
154 |
155 | static enum
156 | {
157 | REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
158 | } ordering;
159 |
160 | #ifdef __GNU_LIBRARY__
161 | /* We want to avoid inclusion of string.h with non-GNU libraries
162 | because there are many ways it can cause trouble.
163 | On some systems, it contains special magic macros that don't work
164 | in GCC. */
165 | #include
166 | #define my_index strchr
167 | #define my_strlen strlen
168 | #else
169 |
170 | /* Avoid depending on library functions or files
171 | whose names are inconsistent. */
172 |
173 | #if __STDC__ || defined(PROTO)
174 | extern char *getenv(const char *name);
175 | extern int strcmp (const char *s1, const char *s2);
176 | extern int strncmp(const char *s1, const char *s2, int n);
177 |
178 | static int my_strlen(const char *s);
179 | static char *my_index (const char *str, int chr);
180 | #else
181 | extern char *getenv ();
182 | #endif
183 |
184 | static int
185 | my_strlen (str)
186 | const char *str;
187 | {
188 | int n = 0;
189 | while (*str++)
190 | n++;
191 | return n;
192 | }
193 |
194 | static char *
195 | my_index (str, chr)
196 | const char *str;
197 | int chr;
198 | {
199 | while (*str)
200 | {
201 | if (*str == chr)
202 | return (char *) str;
203 | str++;
204 | }
205 | return 0;
206 | }
207 |
208 | #endif /* GNU C library. */
209 |
210 | /* Handle permutation of arguments. */
211 |
212 | /* Describe the part of ARGV that contains non-options that have
213 | been skipped. `first_nonopt' is the index in ARGV of the first of them;
214 | `last_nonopt' is the index after the last of them. */
215 |
216 | static int first_nonopt;
217 | static int last_nonopt;
218 |
219 | /* Exchange two adjacent subsequences of ARGV.
220 | One subsequence is elements [first_nonopt,last_nonopt)
221 | which contains all the non-options that have been skipped so far.
222 | The other is elements [last_nonopt,optind), which contains all
223 | the options processed since those non-options were skipped.
224 |
225 | `first_nonopt' and `last_nonopt' are relocated so that they describe
226 | the new indices of the non-options in ARGV after they are moved.
227 |
228 | To perform the swap, we first reverse the order of all elements. So
229 | all options now come before all non options, but they are in the
230 | wrong order. So we put back the options and non options in original
231 | order by reversing them again. For example:
232 | original input: a b c -x -y
233 | reverse all: -y -x c b a
234 | reverse options: -x -y c b a
235 | reverse non options: -x -y a b c
236 | */
237 |
238 | #if __STDC__ || defined(PROTO)
239 | static void exchange (char **argv);
240 | #endif
241 |
242 | static void
243 | exchange (argv)
244 | char **argv;
245 | {
246 | char *temp, **first, **last;
247 |
248 | /* Reverse all the elements [first_nonopt, optind) */
249 | first = &argv[first_nonopt];
250 | last = &argv[optind-1];
251 | while (first < last) {
252 | temp = *first; *first = *last; *last = temp; first++; last--;
253 | }
254 | /* Put back the options in order */
255 | first = &argv[first_nonopt];
256 | first_nonopt += (optind - last_nonopt);
257 | last = &argv[first_nonopt - 1];
258 | while (first < last) {
259 | temp = *first; *first = *last; *last = temp; first++; last--;
260 | }
261 |
262 | /* Put back the non options in order */
263 | first = &argv[first_nonopt];
264 | last_nonopt = optind;
265 | last = &argv[last_nonopt-1];
266 | while (first < last) {
267 | temp = *first; *first = *last; *last = temp; first++; last--;
268 | }
269 | }
270 |
271 | /* Scan elements of ARGV (whose length is ARGC) for option characters
272 | given in OPTSTRING.
273 |
274 | If an element of ARGV starts with '-', and is not exactly "-" or "--",
275 | then it is an option element. The characters of this element
276 | (aside from the initial '-') are option characters. If `getopt'
277 | is called repeatedly, it returns successively each of the option characters
278 | from each of the option elements.
279 |
280 | If `getopt' finds another option character, it returns that character,
281 | updating `optind' and `nextchar' so that the next call to `getopt' can
282 | resume the scan with the following option character or ARGV-element.
283 |
284 | If there are no more option characters, `getopt' returns `EOF'.
285 | Then `optind' is the index in ARGV of the first ARGV-element
286 | that is not an option. (The ARGV-elements have been permuted
287 | so that those that are not options now come last.)
288 |
289 | OPTSTRING is a string containing the legitimate option characters.
290 | If an option character is seen that is not listed in OPTSTRING,
291 | return BAD_OPTION after printing an error message. If you set `opterr' to
292 | zero, the error message is suppressed but we still return BAD_OPTION.
293 |
294 | If a char in OPTSTRING is followed by a colon, that means it wants an arg,
295 | so the following text in the same ARGV-element, or the text of the following
296 | ARGV-element, is returned in `optarg'. Two colons mean an option that
297 | wants an optional arg; if there is text in the current ARGV-element,
298 | it is returned in `optarg', otherwise `optarg' is set to zero.
299 |
300 | If OPTSTRING starts with `-' or `+', it requests different methods of
301 | handling the non-option ARGV-elements.
302 | See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
303 |
304 | Long-named options begin with `--' instead of `-'.
305 | Their names may be abbreviated as long as the abbreviation is unique
306 | or is an exact match for some defined option. If they have an
307 | argument, it follows the option name in the same ARGV-element, separated
308 | from the option name by a `=', or else the in next ARGV-element.
309 | When `getopt' finds a long-named option, it returns 0 if that option's
310 | `flag' field is nonzero, the value of the option's `val' field
311 | if the `flag' field is zero.
312 |
313 | The elements of ARGV aren't really const, because we permute them.
314 | But we pretend they're const in the prototype to be compatible
315 | with other systems.
316 |
317 | LONGOPTS is a vector of `struct option' terminated by an
318 | element containing a name which is zero.
319 |
320 | LONGIND returns the index in LONGOPT of the long-named option found.
321 | It is only valid when a long-named option has been found by the most
322 | recent call.
323 |
324 | If LONG_ONLY is nonzero, '-' as well as '--' can introduce
325 | long-named options. */
326 |
327 | int
328 | _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
329 | int argc;
330 | char *const *argv;
331 | const char *optstring;
332 | const struct option *longopts;
333 | int *longind;
334 | int long_only;
335 | {
336 | int option_index;
337 |
338 | optarg = 0;
339 |
340 | /* Initialize the internal data when the first call is made.
341 | Start processing options with ARGV-element 1 (since ARGV-element 0
342 | is the program name); the sequence of previously skipped
343 | non-option ARGV-elements is empty. */
344 |
345 | if (optind == 0)
346 | {
347 | first_nonopt = last_nonopt = optind = 1;
348 |
349 | nextchar = NULL;
350 |
351 | /* Determine how to handle the ordering of options and nonoptions. */
352 |
353 | if (optstring[0] == '-')
354 | {
355 | ordering = RETURN_IN_ORDER;
356 | ++optstring;
357 | }
358 | else if (optstring[0] == '+')
359 | {
360 | ordering = REQUIRE_ORDER;
361 | ++optstring;
362 | }
363 | else if (getenv ("POSIXLY_CORRECT") != NULL)
364 | ordering = REQUIRE_ORDER;
365 | else
366 | ordering = PERMUTE;
367 | }
368 |
369 | if (nextchar == NULL || *nextchar == '\0')
370 | {
371 | if (ordering == PERMUTE)
372 | {
373 | /* If we have just processed some options following some non-options,
374 | exchange them so that the options come first. */
375 |
376 | if (first_nonopt != last_nonopt && last_nonopt != optind)
377 | exchange ((char **) argv);
378 | else if (last_nonopt != optind)
379 | first_nonopt = optind;
380 |
381 | /* Now skip any additional non-options
382 | and extend the range of non-options previously skipped. */
383 |
384 | while (optind < argc
385 | && (argv[optind][0] != '-' || argv[optind][1] == '\0')
386 | #ifdef GETOPT_COMPAT
387 | && (longopts == NULL
388 | || argv[optind][0] != '+' || argv[optind][1] == '\0')
389 | #endif /* GETOPT_COMPAT */
390 | )
391 | optind++;
392 | last_nonopt = optind;
393 | }
394 |
395 | /* Special ARGV-element `--' means premature end of options.
396 | Skip it like a null option,
397 | then exchange with previous non-options as if it were an option,
398 | then skip everything else like a non-option. */
399 |
400 | if (optind != argc && !strcmp (argv[optind], "--"))
401 | {
402 | optind++;
403 |
404 | if (first_nonopt != last_nonopt && last_nonopt != optind)
405 | exchange ((char **) argv);
406 | else if (first_nonopt == last_nonopt)
407 | first_nonopt = optind;
408 | last_nonopt = argc;
409 |
410 | optind = argc;
411 | }
412 |
413 | /* If we have done all the ARGV-elements, stop the scan
414 | and back over any non-options that we skipped and permuted. */
415 |
416 | if (optind == argc)
417 | {
418 | /* Set the next-arg-index to point at the non-options
419 | that we previously skipped, so the caller will digest them. */
420 | if (first_nonopt != last_nonopt)
421 | optind = first_nonopt;
422 | return EOF;
423 | }
424 |
425 | /* If we have come to a non-option and did not permute it,
426 | either stop the scan or describe it to the caller and pass it by. */
427 |
428 | if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
429 | #ifdef GETOPT_COMPAT
430 | && (longopts == NULL
431 | || argv[optind][0] != '+' || argv[optind][1] == '\0')
432 | #endif /* GETOPT_COMPAT */
433 | )
434 | {
435 | if (ordering == REQUIRE_ORDER)
436 | return EOF;
437 | optarg = argv[optind++];
438 | return 1;
439 | }
440 |
441 | /* We have found another option-ARGV-element.
442 | Start decoding its characters. */
443 |
444 | nextchar = (argv[optind] + 1
445 | + (longopts != NULL && argv[optind][1] == '-'));
446 | }
447 |
448 | if (longopts != NULL
449 | && ((argv[optind][0] == '-'
450 | && (argv[optind][1] == '-' || long_only))
451 | #ifdef GETOPT_COMPAT
452 | || argv[optind][0] == '+'
453 | #endif /* GETOPT_COMPAT */
454 | ))
455 | {
456 | const struct option *p;
457 | char *s = nextchar;
458 | int exact = 0;
459 | int ambig = 0;
460 | const struct option *pfound = NULL;
461 | int indfound = 0;
462 |
463 | while (*s && *s != '=')
464 | s++;
465 |
466 | /* Test all options for either exact match or abbreviated matches. */
467 | for (p = longopts, option_index = 0; p->name;
468 | p++, option_index++)
469 | if (!strncmp (p->name, nextchar, s - nextchar))
470 | {
471 | if (s - nextchar == my_strlen (p->name))
472 | {
473 | /* Exact match found. */
474 | pfound = p;
475 | indfound = option_index;
476 | exact = 1;
477 | break;
478 | }
479 | else if (pfound == NULL)
480 | {
481 | /* First nonexact match found. */
482 | pfound = p;
483 | indfound = option_index;
484 | }
485 | else
486 | /* Second nonexact match found. */
487 | ambig = 1;
488 | }
489 |
490 | if (ambig && !exact)
491 | {
492 | if (opterr)
493 | fprintf (stderr, "%s: option `%s' is ambiguous\n",
494 | argv[0], argv[optind]);
495 | nextchar += my_strlen (nextchar);
496 | optind++;
497 | return BAD_OPTION;
498 | }
499 |
500 | if (pfound != NULL)
501 | {
502 | option_index = indfound;
503 | optind++;
504 | if (*s)
505 | {
506 | /* Don't test has_arg with >, because some C compilers don't
507 | allow it to be used on enums. */
508 | if (pfound->has_arg)
509 | optarg = s + 1;
510 | else
511 | {
512 | if (opterr)
513 | {
514 | if (argv[optind - 1][1] == '-')
515 | /* --option */
516 | fprintf (stderr,
517 | "%s: option `--%s' doesn't allow an argument\n",
518 | argv[0], pfound->name);
519 | else
520 | /* +option or -option */
521 | fprintf (stderr,
522 | "%s: option `%c%s' doesn't allow an argument\n",
523 | argv[0], argv[optind - 1][0], pfound->name);
524 | }
525 | nextchar += my_strlen (nextchar);
526 | return BAD_OPTION;
527 | }
528 | }
529 | else if (pfound->has_arg == 1)
530 | {
531 | if (optind < argc)
532 | optarg = argv[optind++];
533 | else
534 | {
535 | if (opterr)
536 | fprintf (stderr, "%s: option `%s' requires an argument\n",
537 | argv[0], argv[optind - 1]);
538 | nextchar += my_strlen (nextchar);
539 | return optstring[0] == ':' ? ':' : BAD_OPTION;
540 | }
541 | }
542 | nextchar += my_strlen (nextchar);
543 | if (longind != NULL)
544 | *longind = option_index;
545 | if (pfound->flag)
546 | {
547 | *(pfound->flag) = pfound->val;
548 | return 0;
549 | }
550 | return pfound->val;
551 | }
552 | /* Can't find it as a long option. If this is not getopt_long_only,
553 | or the option starts with '--' or is not a valid short
554 | option, then it's an error.
555 | Otherwise interpret it as a short option. */
556 | if (!long_only || argv[optind][1] == '-'
557 | #ifdef GETOPT_COMPAT
558 | || argv[optind][0] == '+'
559 | #endif /* GETOPT_COMPAT */
560 | || my_index (optstring, *nextchar) == NULL)
561 | {
562 | if (opterr)
563 | {
564 | if (argv[optind][1] == '-')
565 | /* --option */
566 | fprintf (stderr, "%s: unrecognized option `--%s'\n",
567 | argv[0], nextchar);
568 | else
569 | /* +option or -option */
570 | fprintf (stderr, "%s: unrecognized option `%c%s'\n",
571 | argv[0], argv[optind][0], nextchar);
572 | }
573 | nextchar = (char *) "";
574 | optind++;
575 | return BAD_OPTION;
576 | }
577 | }
578 |
579 | /* Look at and handle the next option-character. */
580 |
581 | {
582 | char c = *nextchar++;
583 | char *temp = my_index (optstring, c);
584 |
585 | /* Increment `optind' when we start to process its last character. */
586 | if (*nextchar == '\0')
587 | ++optind;
588 |
589 | if (temp == NULL || c == ':')
590 | {
591 | if (opterr)
592 | {
593 | #if 0
594 | if (c < 040 || c >= 0177)
595 | fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
596 | argv[0], c);
597 | else
598 | fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
599 | #else
600 | /* 1003.2 specifies the format of this message. */
601 | fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
602 | #endif
603 | }
604 | optopt = c;
605 | return BAD_OPTION;
606 | }
607 | if (temp[1] == ':')
608 | {
609 | if (temp[2] == ':')
610 | {
611 | /* This is an option that accepts an argument optionally. */
612 | if (*nextchar != '\0')
613 | {
614 | optarg = nextchar;
615 | optind++;
616 | }
617 | else
618 | optarg = 0;
619 | nextchar = NULL;
620 | }
621 | else
622 | {
623 | /* This is an option that requires an argument. */
624 | if (*nextchar != '\0')
625 | {
626 | optarg = nextchar;
627 | /* If we end this ARGV-element by taking the rest as an arg,
628 | we must advance to the next element now. */
629 | optind++;
630 | }
631 | else if (optind == argc)
632 | {
633 | if (opterr)
634 | {
635 | #if 0
636 | fprintf (stderr, "%s: option `-%c' requires an argument\n",
637 | argv[0], c);
638 | #else
639 | /* 1003.2 specifies the format of this message. */
640 | fprintf (stderr, "%s: option requires an argument -- %c\n",
641 | argv[0], c);
642 | #endif
643 | }
644 | optopt = c;
645 | if (optstring[0] == ':')
646 | c = ':';
647 | else
648 | c = BAD_OPTION;
649 | }
650 | else
651 | /* We already incremented `optind' once;
652 | increment it again when taking next ARGV-elt as argument. */
653 | optarg = argv[optind++];
654 | nextchar = NULL;
655 | }
656 | }
657 | return c;
658 | }
659 | }
660 |
661 | int
662 | getopt (argc, argv, optstring)
663 | int argc;
664 | char *const *argv;
665 | const char *optstring;
666 | {
667 | return _getopt_internal (argc, argv, optstring,
668 | (const struct option *) 0,
669 | (int *) 0,
670 | 0);
671 | }
672 |
673 | int
674 | getopt_long (argc, argv, options, long_options, opt_index)
675 | int argc;
676 | char *const *argv;
677 | const char *options;
678 | const struct option *long_options;
679 | int *opt_index;
680 | {
681 | return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
682 | }
683 |
684 | #endif /* _LIBC or not __GNU_LIBRARY__. */
685 |
686 | #ifdef TEST
687 |
688 | /* Compile with -DTEST to make an executable for use in testing
689 | the above definition of `getopt'. */
690 |
691 | int
692 | main (argc, argv)
693 | int argc;
694 | char **argv;
695 | {
696 | int c;
697 | int digit_optind = 0;
698 |
699 | while (1)
700 | {
701 | int this_option_optind = optind ? optind : 1;
702 |
703 | c = getopt (argc, argv, "abc:d:0123456789");
704 | if (c == EOF)
705 | break;
706 |
707 | switch (c)
708 | {
709 | case '0':
710 | case '1':
711 | case '2':
712 | case '3':
713 | case '4':
714 | case '5':
715 | case '6':
716 | case '7':
717 | case '8':
718 | case '9':
719 | if (digit_optind != 0 && digit_optind != this_option_optind)
720 | printf ("digits occur in two different argv-elements.\n");
721 | digit_optind = this_option_optind;
722 | printf ("option %c\n", c);
723 | break;
724 |
725 | case 'a':
726 | printf ("option a\n");
727 | break;
728 |
729 | case 'b':
730 | printf ("option b\n");
731 | break;
732 |
733 | case 'c':
734 | printf ("option c with value `%s'\n", optarg);
735 | break;
736 |
737 | case BAD_OPTION:
738 | break;
739 |
740 | default:
741 | printf ("?? getopt returned character code 0%o ??\n", c);
742 | }
743 | }
744 |
745 | if (optind < argc)
746 | {
747 | printf ("non-option ARGV-elements: ");
748 | while (optind < argc)
749 | printf ("%s ", argv[optind++]);
750 | printf ("\n");
751 | }
752 |
753 | exit (0);
754 | }
755 |
756 | #endif /* TEST */
757 |
--------------------------------------------------------------------------------
/getopt.h:
--------------------------------------------------------------------------------
1 | /* THIS IS HERE FOR WIN32's BENEFIT ONLY. */
2 |
3 | /* Declarations for getopt.
4 | Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
5 |
6 | This program is free software; you can redistribute it and/or modify it
7 | under the terms of the GNU General Public License as published by the
8 | Free Software Foundation; either version 2, or (at your option) any
9 | 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
19 |
20 | #ifndef _GETOPT_H
21 | #define _GETOPT_H 1
22 |
23 | #ifdef __cplusplus
24 | extern "C" {
25 | #endif
26 |
27 | /* For communication from `getopt' to the caller.
28 | When `getopt' finds an option that takes an argument,
29 | the argument value is returned here.
30 | Also, when `ordering' is RETURN_IN_ORDER,
31 | each non-option ARGV-element is returned here. */
32 |
33 | extern char *optarg;
34 |
35 | /* Index in ARGV of the next element to be scanned.
36 | This is used for communication to and from the caller
37 | and for communication between successive calls to `getopt'.
38 |
39 | On entry to `getopt', zero means this is the first call; initialize.
40 |
41 | When `getopt' returns EOF, this is the index of the first of the
42 | non-option elements that the caller should itself scan.
43 |
44 | Otherwise, `optind' communicates from one call to the next
45 | how much of ARGV has been scanned so far. */
46 |
47 | extern int optind;
48 |
49 | /* Callers store zero here to inhibit the error message `getopt' prints
50 | for unrecognized options. */
51 |
52 | extern int opterr;
53 |
54 | /* Set to an option character which was unrecognized. */
55 |
56 | extern int optopt;
57 |
58 | /* Describe the long-named options requested by the application.
59 | The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
60 | of `struct option' terminated by an element containing a name which is
61 | zero.
62 |
63 | The field `has_arg' is:
64 | no_argument (or 0) if the option does not take an argument,
65 | required_argument (or 1) if the option requires an argument,
66 | optional_argument (or 2) if the option takes an optional argument.
67 |
68 | If the field `flag' is not NULL, it points to a variable that is set
69 | to the value given in the field `val' when the option is found, but
70 | left unchanged if the option is not found.
71 |
72 | To have a long-named option do something other than set an `int' to
73 | a compiled-in constant, such as set a value from `optarg', set the
74 | option's `flag' field to zero and its `val' field to a nonzero
75 | value (the equivalent single-letter option character, if there is
76 | one). For long options that have a zero `flag' field, `getopt'
77 | returns the contents of the `val' field. */
78 |
79 | struct option
80 | {
81 | #if __STDC__
82 | const char *name;
83 | #else
84 | char *name;
85 | #endif
86 | /* has_arg can't be an enum because some compilers complain about
87 | type mismatches in all the code that assumes it is an int. */
88 | int has_arg;
89 | int *flag;
90 | int val;
91 | };
92 |
93 | /* Names for the values of the `has_arg' field of `struct option'. */
94 |
95 | #define no_argument 0
96 | #define required_argument 1
97 | #define optional_argument 2
98 |
99 | #if __STDC__ || defined(PROTO)
100 | #if defined(__GNU_LIBRARY__)
101 | /* Many other libraries have conflicting prototypes for getopt, with
102 | differences in the consts, in stdlib.h. To avoid compilation
103 | errors, only prototype getopt for the GNU C library. */
104 | extern int getopt (int argc, char *const *argv, const char *shortopts);
105 | #endif /* not __GNU_LIBRARY__ */
106 | extern int getopt_long (int argc, char *const *argv, const char *shortopts,
107 | const struct option *longopts, int *longind);
108 | extern int getopt_long_only (int argc, char *const *argv,
109 | const char *shortopts,
110 | const struct option *longopts, int *longind);
111 |
112 | /* Internal only. Users should not call this directly. */
113 | extern int _getopt_internal (int argc, char *const *argv,
114 | const char *shortopts,
115 | const struct option *longopts, int *longind,
116 | int long_only);
117 | #else /* not __STDC__ */
118 | extern int getopt ();
119 | extern int getopt_long ();
120 | extern int getopt_long_only ();
121 |
122 | extern int _getopt_internal ();
123 | #endif /* not __STDC__ */
124 |
125 | #ifdef __cplusplus
126 | }
127 | #endif
128 |
129 | #endif /* _GETOPT_H */
130 |
--------------------------------------------------------------------------------
/match.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include "match.h"
4 |
5 | int match(char *sorig, char *p)
6 | {
7 | return matchBody(sorig, p, 0);
8 | }
9 |
10 | int matchNoCase(char *sorig, char *p)
11 | {
12 | return matchBody(sorig, p, 1);
13 | }
14 |
15 | #define CASE(x) (nocase ? tolower(x) : (x))
16 |
17 | int matchBody(char *sorig, char *p, int nocase)
18 | {
19 | static int dummy = 0;
20 | /* Algorithm:
21 |
22 | Word separator: *. End-of-string
23 | is considered to be a word constituent.
24 | ? is similarly considered to be a specialized
25 | word constituent.
26 |
27 | Match the word to the current position in s.
28 | Empty words automatically succeed.
29 |
30 | If the word matches s, and the word
31 | and s contain end-of-string at that
32 | point, return success.
33 |
34 | \ escapes the next character, including \ itself (6.0).
35 |
36 | For each *:
37 |
38 | Find the next occurrence of the next word
39 | and advance beyond it in both p and s.
40 | If the next word ends in end-of-string
41 | and is found successfully, return success,
42 | otherwise advance past the *.
43 |
44 | If the word is not found, return failure.
45 |
46 | If the next word is empty, advance past the *.
47 |
48 | Behavior of ?: advance one character in s and p.
49 |
50 | Addendum: consider the | character to be a logical OR
51 | separating distinct patterns. */
52 |
53 | char *s = sorig;
54 | int escaped = 0;
55 | if (strstr(p, "WS-0000")) {
56 | if (strstr(s, "ws_ftp_pro.html")) {
57 | dummy = 1;
58 | }
59 | }
60 | while (1) {
61 | char *word;
62 | int wordLen;
63 | int wordPos;
64 | if (escaped) {
65 | /* This is like the default case,
66 | except that | doesn't end the pattern. */
67 | escaped = 0;
68 | if ((*s == '\0') && (*p == '\0')) {
69 | return 1;
70 | }
71 | if (CASE(*p) != CASE(*s)) {
72 | goto nextPattern;
73 | }
74 | p++;
75 | s++;
76 | continue;
77 | }
78 | switch(*p) {
79 | case '\\':
80 | /* Escape the next character. */
81 | escaped = 1;
82 | p++;
83 | continue;
84 | case '*':
85 | /* Find the next occurrence of the next word
86 | and advance beyond it in both p and s.
87 | If the next word ends in end-of-string
88 | and is found successfully, return success,
89 | otherwise advance past the *.
90 |
91 | If the word is not found, return failure.
92 |
93 | If the next word is empty, advance. */
94 | p++;
95 | wordLen = 0;
96 | word = p;
97 | while (1) {
98 | if ((*p) == '*') {
99 | break;
100 | }
101 | wordLen++;
102 | if ((*p == '\0') || (*p == '|')) {
103 | break;
104 | }
105 | p++;
106 | }
107 | wordPos = 0;
108 | while (1) {
109 | if (wordPos == wordLen) {
110 | if ((*p == '\0') || (*p == '|')) {
111 | return 1;
112 | }
113 | break;
114 | }
115 | if ((((CASE(*s)) == CASE(word[wordPos])) ||
116 | ((*s == '\0') &&
117 | (word[wordPos] == '|'))) ||
118 | (((*s != '\0') && (*s != '|')) &&
119 | (word[wordPos] == '?')))
120 | {
121 | wordPos++;
122 | s++;
123 | } else {
124 | s -= wordPos;
125 | if (!(*s)) {
126 | goto nextPattern;
127 | }
128 | s++;
129 | wordPos = 0;
130 | }
131 | }
132 | break;
133 | case '?':
134 | p++;
135 | s++;
136 | break;
137 | default:
138 | if ((*s == '\0') && ((*p == '\0') ||
139 | (*p == '|'))) {
140 | return 1;
141 | }
142 | if (CASE(*p) != CASE(*s)) {
143 | goto nextPattern;
144 | }
145 | p++;
146 | s++;
147 | break;
148 | }
149 | continue;
150 | nextPattern:
151 | while (1) {
152 | if (*p == '\0') {
153 | return 0;
154 | }
155 | if (*p == '|') {
156 | p++;
157 | s = sorig;
158 | break;
159 | }
160 | p++;
161 | }
162 | }
163 | }
164 |
165 | #ifdef TEST_MATCH
166 |
167 | #include
168 | #include
169 | #include
170 |
171 | int main(int argc, char *argv[])
172 | {
173 | char s[1024];
174 | if (argc != 2) {
175 | fprintf(stderr, "Usage: match pattern\n");
176 | return 1;
177 | }
178 | while (1) {
179 | if (!fgets(s, sizeof(s), stdin)) {
180 | break;
181 | }
182 | while (isspace(s[strlen(s) - 1])) {
183 | s[strlen(s) - 1] = '\0';
184 | }
185 | printf("%s --> %s\n", s, argv[1]);
186 | if (match(s, argv[1])) {
187 | printf("Match\n");
188 | } else {
189 | printf("No Match\n");
190 | }
191 | }
192 | }
193 |
194 | #endif /* TEST_MATCH */
195 |
196 |
--------------------------------------------------------------------------------
/match.h:
--------------------------------------------------------------------------------
1 | #ifndef MATCH_H
2 | #define MATCH_H 1
3 |
4 | extern int match(char *s, char *p);
5 | extern int matchNoCase(char *s, char *p);
6 | extern int matchBody(char *s, char *p, int nocase);
7 |
8 | #endif /* MATCH_H */
9 |
10 |
--------------------------------------------------------------------------------
/rinetd.8:
--------------------------------------------------------------------------------
1 | .\" Copyright (c) 1997, 1998, 1999, Thomas Boutell and Boutell.Com, Inc.
2 | .\" This software is released for free use under the terms of
3 | .\" the GNU Public License, version 2 or higher.
4 | .\"
5 | .Dd February 18, 1999
6 | .Dt RINETD 8
7 | .Os LINUX
8 | .Sh NAME
9 | .Nm rinetd
10 | .Nd internet
11 | .Dq redirection server
12 | .Sh SYNOPSIS
13 | .Nm /usr/sbin/rinetd
14 | .Sh VERSION
15 | Version 0.62, 04/14/2003.
16 | .Sh DESCRIPTION
17 | .Nm rinetd
18 | redirects TCP connections from one IP address and port to another. rinetd
19 | is a single-process server which handles any number of connections to
20 | the address/port pairs specified in the file /etc/rinetd.conf.
21 | Since rinetd runs as a single process using nonblocking I/O, it is
22 | able to redirect a large number of connections without a severe
23 | impact on the machine. This makes it practical to run TCP services
24 | on machines inside an IP masquerading firewall. rinetd does not
25 | redirect FTP, because FTP requires more than one socket.
26 | .Pp
27 | rinetd is typically launched at boot time, using the following syntax:
28 | .Pp
29 | /usr/sbin/rinetd
30 | .Pp
31 | The configuration file is found in the file /etc/rinetd.conf, unless
32 | another file is specified using the -c command line option.
33 | .Sh FORWARDING RULES
34 | Most entries in the configuration file are forwarding rules. The
35 | format of a forwarding rule is as follows:
36 | .Pp
37 | bindaddress bindport connectaddress connectport
38 | .Pp
39 | For example:
40 | .Pp
41 | 206.125.69.81 80 10.1.1.2 80
42 | .Pp
43 | Would redirect all connections to port 80 of the "real" IP address
44 | 206.125.69.81, which could be a virtual interface, through
45 | rinetd to port 80 of the address 10.1.1.2, which would typically
46 | be a machine on the inside of a firewall which has no
47 | direct routing to the outside world.
48 | .Pp
49 | Although responding on individual interfaces rather than on all
50 | interfaces is one of rinetd's primary features, sometimes it is
51 | preferable to respond on all IP addresses that belong to the server.
52 | In this situation, the special IP address 0.0.0.0
53 | can be used. For example:
54 | .Pp
55 | 0.0.0.0 23 10.1.1.2 23
56 | .Pp
57 | Would redirect all connections to port 23, for all IP addresses
58 | assigned to the server. This is the default behavior for most
59 | other programs.
60 | .Pp
61 | Service names can be specified instead of port numbers. On most systems,
62 | service names are defined in the file /etc/services.
63 | .Pp
64 | Both IP addresses and hostnames are accepted for
65 | bindaddress and connectaddress.
66 | .Pp
67 | .Sh ALLOW AND DENY RULES
68 | Configuration files can also contain allow and deny rules.
69 | .Pp
70 | Allow rules which appear before the first forwarding rule are
71 | applied globally: if at least one global allow rule exists,
72 | and the address of a new connection does not
73 | satisfy at least one of the global allow rules, that connection
74 | is immediately rejected, regardless of any other rules.
75 | .Pp
76 | Allow rules which appear after a specific forwarding rule apply
77 | to that forwarding rule only. If at least one allow rule
78 | exists for a particular forwarding rule, and the address of a new
79 | connection does not satisfy at least one of the allow rules
80 | for that forwarding rule, that connection is immediately
81 | rejected, regardless of any other rules.
82 | .Pp
83 | Deny rules which appear before the first forwarding rule are
84 | applied globally: if the address of a new connection satisfies
85 | any of the global allow rules, that connection
86 | is immediately rejected, regardless of any other rules.
87 | .Pp
88 | Deny rules which appear after a specific forwarding rule apply
89 | to that forwarding rule only. If the address of a new
90 | connection satisfies any of the deny rules for that forwarding rule,
91 | that connection is immediately rejected, regardless of any other rules.
92 | .Pp
93 | The format of an allow rule is as follows:
94 | .Pp
95 | allow pattern
96 | .Pp
97 | Patterns can contain the following characters: 0, 1, 2, 3, 4, 5,
98 | 6, 7, 8, 9, . (period), ?, and *. The ? wildcard matches any one
99 | character. The * wildcard matches any number of characters, including
100 | zero.
101 | .Pp
102 | For example:
103 | .Pp
104 | allow 206.125.69.*
105 | .Pp
106 | This allow rule matches all IP addresses in the 206.125.69 class C domain.
107 | .Pp
108 | Host names are NOT permitted in allow and deny rules. The performance
109 | cost of looking up IP addresses to find their corresponding names
110 | is prohibitive. Since rinetd is a single process server, all other
111 | connections would be forced to pause during the address lookup.
112 | .Pp
113 | .Sh LOGGING
114 | rinetd is able to produce a log file in either of two formats:
115 | tab-delimited and web server-style "common log format."
116 | .Pp
117 | By default, rinetd does not produce a log file. To activate logging, add
118 | the following line to the configuration file:
119 | .Pp
120 | logfile log-file-location
121 | .Pp
122 | Example: logfile /var/log/rinetd.log
123 | .Pp
124 | By default, rinetd logs in a simple tab-delimited format containing
125 | the following information:
126 | .Pp
127 | Date and time
128 | .Pp
129 | Client address
130 | .Pp
131 | Listening host
132 | .Pp
133 | Listening port
134 | .Pp
135 | Forwarded-to host
136 | .Pp
137 | Forwarded-to port
138 | .Pp
139 | Bytes received from client
140 | .Pp
141 | Bytes sent to client
142 | .Pp
143 | Result message
144 | .Pp
145 | To activate web server-style "common log format" logging,
146 | add the following line to the configuration file:
147 | .Pp
148 | logcommon
149 | .Sh COMMAND LINE OPTIONS
150 | The -c command line option is used to specify an alternate
151 | configuration file.
152 | .Pp
153 | The -h command line option produces a short help message.
154 | .Pp
155 | The -v command line option displays the version number.
156 | .Sh REINITIALIZING RINETD
157 | The kill -1 signal (SIGHUP) can be used to cause rinetd
158 | to reload its configuration file without interrupting existing
159 | connections.
160 | Under Linux\(tm the process id is saved in the file \fI/var/run/rinetd.pid\fR
161 | to facilitate the kill -HUP. An alternate
162 | filename can be provided by using the pidlogfile
163 | configuration file option.
164 |
165 | .Sh LIMITATIONS
166 | rinetd redirects TCP connections only. There is
167 | no support for UDP. rinetd only redirects protocols which
168 | use a single TCP socket. This rules out FTP.
169 | .Sh BUGS
170 | The server redirected to is not able to identify the host the
171 | client really came from. This cannot be corrected; however,
172 | the log produced by rinetd provides a way to obtain this
173 | information. Under Unix, Sockets would theoretically lose data when closed
174 | with SO_LINGER turned off, but in Linux this is not the case (kernel
175 | source comments support this belief on my part). On non-Linux Unix platforms,
176 | alternate code which uses a different trick to work around blocking close()
177 | is provided, but this code is untested. The logging is inadequate.
178 | The duration of each connection should be logged.
179 | .Sh LICENSE
180 | Copyright (c) 1997, 1998, 1999, Thomas Boutell and Boutell.Com, Inc.
181 | This software is released for free use under the terms of
182 | the GNU Public License, version 2 or higher. NO WARRANTY
183 | IS EXPRESSED OR IMPLIED. USE THIS SOFTWARE AT YOUR OWN RISK.
184 | .Sh THANKS
185 | Thanks are due to Bill Davidsen, Libor Pechachek, Sascha Ziemann, the
186 | Apache Group, and many others who have contributed advice
187 | and/or source code to this and other free software projects.
188 |
--------------------------------------------------------------------------------
/rinetd.c:
--------------------------------------------------------------------------------
1 | #define VERSION "0.62"
2 |
3 | #ifdef WIN32
4 | #include
5 | #include
6 | #include "getopt.h"
7 | #else
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #define INVALID_SOCKET (-1)
16 | #include
17 | #endif /* WIN32 */
18 |
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 |
27 | #ifndef WIN32
28 | /* Windows sockets compatibility defines */
29 | #define INVALID_SOCKET (-1)
30 | #define SOCKET_ERROR (-1)
31 | int closesocket(int s);
32 |
33 | int closesocket(int s) {
34 | return close(s);
35 | }
36 | #define ioctlsocket ioctl
37 | #define MAKEWORD(a, b)
38 | #define WSAStartup(a, b) (0)
39 | #define WSACleanup()
40 | #ifdef __MAC__
41 | /* The constants for these are a little screwy in the prelinked
42 | MSL GUSI lib and we can't rebuild it, so roll with it */
43 | #define WSAEWOULDBLOCK EWOULDBLOCK
44 | #define WSAEAGAIN EAGAIN
45 | #define WSAEINPROGRESS EINPROGRESS
46 | #else
47 | #define WSAEWOULDBLOCK EWOULDBLOCK
48 | #define WSAEAGAIN EAGAIN
49 | #define WSAEINPROGRESS EINPROGRESS
50 | #endif /* __MAC__ */
51 | #define WSAEINTR EINTR
52 | #define SOCKET int
53 | #define GetLastError() (errno)
54 | typedef struct {
55 | int dummy;
56 | } WSADATA;
57 |
58 | void Sleep(long ms);
59 |
60 | void Sleep(long ms)
61 | {
62 | struct timeval tv;
63 | tv.tv_sec = ms / 1000;
64 | tv.tv_usec = ms * 1000;
65 | select(0, 0, 0, 0, &tv);
66 | }
67 | #else
68 | /* WIN32 doesn't really have WSAEAGAIN */
69 | #ifndef WSAEAGAIN
70 | #define WSAEAGAIN WSAEWOULDBLOCK
71 | #endif
72 | #endif /* WIN32 */
73 |
74 | #ifndef TRUE
75 | #define TRUE 1
76 | #endif
77 |
78 | #ifndef FALSE
79 | #define FALSE 0
80 | #endif
81 |
82 | #ifdef DEBUG
83 | #define PERROR perror
84 | #else
85 | #define PERROR(x)
86 | #endif /* DEBUG */
87 |
88 | /* We've got to get FIONBIO from somewhere. Try the Solaris location
89 | if it isn't defined yet by the above includes. */
90 | #ifndef FIONBIO
91 | #include
92 | #endif /* FIONBIO */
93 |
94 | #include "match.h"
95 |
96 | SOCKET *seFds = 0;
97 | /* In network order, for network purposes */
98 | struct in_addr *seLocalAddrs = 0;
99 | unsigned short *seLocalPorts = 0;
100 | /* In ASCII and local byte order, for logging purposes */
101 | char **seFromHosts;
102 | int *seFromPorts;
103 | char **seToHosts;
104 | int *seToPorts;
105 |
106 | /* Offsets into list of allow and deny rules. Any rules
107 | prior to globalAllowRules and globalDenyRules are global rules. */
108 |
109 | int *seAllowRules = 0;
110 | int *seAllowRulesTotal = 0;
111 | int globalAllowRules = 0;
112 | int *seDenyRules = 0;
113 | int *seDenyRulesTotal = 0;
114 | int globalDenyRules = 0;
115 |
116 | SOCKET *reFds = 0;
117 | SOCKET *loFds = 0;
118 | unsigned char *reAddresses = 0;
119 | int *coInputRPos = 0;
120 | int *coInputWPos = 0;
121 | int *coOutputRPos = 0;
122 | int *coOutputWPos = 0;
123 | int *coClosed = 0;
124 | int *coClosing = 0;
125 | int *reClosed = 0;
126 | int *loClosed = 0;
127 | int *coBytesInput = 0;
128 | int *coBytesOutput = 0;
129 | int *coLog = 0;
130 | int *coSe = 0;
131 | char **coInput = 0;
132 | char **coOutput = 0;
133 | char **allowRules = 0;
134 | char **denyRules = 0;
135 | int *denyRulesFor = 0;
136 | int seTotal = 0;
137 | int coTotal = 0;
138 | int allowRulesTotal = 0;
139 | int denyRulesTotal = 0;
140 | int maxfd = 0;
141 | char *logFileName = 0;
142 | char *pidLogFileName = 0;
143 | int logFormatCommon = 0;
144 | FILE *logFile = 0;
145 |
146 | /* If 'newsize' bytes can be allocated, *data is set to point
147 | to them, the previous data is copied, and 1 is returned.
148 | If 'size' bytes cannot be allocated, *data is UNCHANGED,
149 | and 0 is returned. */
150 |
151 | #define SAFE_REALLOC(x, y, z) safeRealloc((void **) (x), (y), (z))
152 |
153 | int safeRealloc(void **data, int oldsize, int newsize);
154 |
155 | /*
156 | se: (se)rver sockets
157 | re: (re)mote sockets
158 | lo: (lo)cal sockets (being redirected to)
159 | co: connections
160 | */
161 |
162 | #define bufferSpace 1024
163 |
164 | void readConfiguration();
165 |
166 | /* Signal handlers */
167 | void plumber(int s);
168 | void hup(int s);
169 | void term(int s);
170 |
171 | void initArrays(void);
172 | void RegisterPID(void);
173 |
174 | void selectLoop(void);
175 |
176 | void log(int i, int coSe, int result);
177 |
178 | int getAddress(char *host, struct in_addr *iaddr);
179 |
180 | char *logMessages[] = {
181 | "done-local-closed",
182 | "done-remote-closed",
183 | "accept-failed -",
184 | 0,
185 | "local-socket-failed -",
186 | 0,
187 | "local-bind-failed -",
188 | 0,
189 | "local-connect-failed -",
190 | 0,
191 | "not-allowed",
192 | 0,
193 | "denied",
194 | 0
195 | };
196 |
197 | #define logDone 0
198 | #define logAcceptFailed 2
199 | #define logLocalSocketFailed 4
200 | #define logLocalBindFailed 6
201 | #define logLocalConnectFailed 8
202 | #define logNotAllowed 10
203 | #define logDenied 12
204 |
205 | #define logLocalClosedFirst 0
206 | #define logRemoteClosedFirst 1
207 |
208 | /* Option parsing */
209 |
210 | typedef struct _rinetd_options RinetdOptions;
211 | struct _rinetd_options
212 | {
213 | char *conf_file;
214 | };
215 |
216 | RinetdOptions options = {
217 | "/etc/rinetd.conf"
218 | };
219 |
220 | int readArgs (int argc,
221 | char **argv,
222 | RinetdOptions *options);
223 |
224 | int main(int argc, char *argv[])
225 | {
226 | WSADATA wsaData;
227 | int result = WSAStartup(MAKEWORD(1, 1), &wsaData);
228 | if (result != 0) {
229 | fprintf(stderr, "Your computer was not connected "
230 | "to the Internet at the time that "
231 | "this program was launched, or you "
232 | "do not have a 32-bit "
233 | "connection to the Internet.");
234 | exit(1);
235 | }
236 | readArgs(argc, argv, &options);
237 | #ifndef WIN32
238 | #ifndef DEBUG
239 | if (!fork()) {
240 | if (!fork()) {
241 | #endif /* DEBUG */
242 | signal(SIGPIPE, plumber);
243 | signal(SIGHUP, hup);
244 | #endif /* WIN32 */
245 | signal(SIGTERM, term);
246 | initArrays();
247 | readConfiguration();
248 | RegisterPID();
249 | selectLoop();
250 | #ifndef WIN32
251 | #ifndef DEBUG
252 | } else {
253 | exit(0);
254 | }
255 | } else {
256 | exit(0);
257 | }
258 | #endif /* DEBUG */
259 | #endif /* WIN32 */
260 | return 0;
261 | }
262 |
263 | int getConfLine(FILE *in, char *line, int space, int *lnum);
264 |
265 | int patternBad(char *pattern);
266 |
267 | void readConfiguration(void)
268 | {
269 | FILE *in;
270 | char line[16384];
271 | int lnum = 0;
272 | int i;
273 | int ai;
274 | int di;
275 | if (seFds) {
276 | /* Close existing server sockets. */
277 | for (i = 0; (i < seTotal); i++) {
278 | if (seFds[i] != -1) {
279 | closesocket(seFds[i]);
280 | free(seFromHosts[i]);
281 | free(seToHosts[i]);
282 | }
283 | }
284 | /* Free memory associated with previous set. */
285 | free(seFds);
286 | free(seLocalAddrs);
287 | free(seLocalPorts);
288 | free(seFromHosts);
289 | free(seFromPorts);
290 | free(seToHosts);
291 | free(seToPorts);
292 | free(seAllowRules);
293 | free(seDenyRules);
294 | free(seAllowRulesTotal);
295 | free(seDenyRulesTotal);
296 | }
297 | seTotal = 0;
298 | if (allowRules) {
299 | /* Forget existing allow rules. */
300 | for (i = 0; (i < allowRulesTotal); i++) {
301 | free(allowRules[i]);
302 | }
303 | /* Free memory associated with previous set. */
304 | free(allowRules);
305 | globalAllowRules = 0;
306 | }
307 | allowRulesTotal = 0;
308 | if (denyRules) {
309 | /* Forget existing deny rules. */
310 | for (i = 0; (i < denyRulesTotal); i++) {
311 | free(denyRules[i]);
312 | }
313 | /* Free memory associated with previous set. */
314 | free(denyRules);
315 | globalDenyRules = 0;
316 | }
317 | denyRulesTotal = 0;
318 | if (logFileName) {
319 | free(logFileName);
320 | logFileName = 0;
321 | }
322 | if (pidLogFileName) {
323 | free(pidLogFileName);
324 | pidLogFileName = 0;
325 | }
326 | /* 1. Count the non-comment lines of each type and
327 | allocate space for the data. */
328 | in = fopen(options.conf_file, "r");
329 | if (!in) {
330 | fprintf(stderr, "rinetd: can't open %s\n", options.conf_file);
331 | exit(1);
332 | }
333 | while (1) {
334 | char *t = 0;
335 | if (!getConfLine(in, line, sizeof(line), &lnum)) {
336 | break;
337 | }
338 | t = strtok(line, " \t\r\n");
339 | if (!strcmp(t, "logfile")) {
340 | continue;
341 | } else if (!strcmp(t, "pidlogfile")) {
342 | continue;
343 | } else if (!strcmp(t, "logcommon")) {
344 | continue;
345 | } else if (!strcmp(t, "allow")) {
346 | allowRulesTotal++;
347 | } else if (!strcmp(t, "deny")) {
348 | denyRulesTotal++;
349 | } else {
350 | /* A regular forwarding rule */
351 | seTotal++;
352 | }
353 | }
354 | fclose(in);
355 | seFds = (SOCKET *) malloc(sizeof(int) * seTotal);
356 | if (!seFds) {
357 | goto lowMemory;
358 | }
359 | seLocalAddrs = (struct in_addr *) malloc(sizeof(struct in_addr) *
360 | seTotal);
361 | if (!seLocalAddrs) {
362 | goto lowMemory;
363 | }
364 | seLocalPorts = (unsigned short *)
365 | malloc(sizeof(unsigned short) * seTotal);
366 | if (!seLocalPorts) {
367 | goto lowMemory;
368 | }
369 | seFromHosts = (char **)
370 | malloc(sizeof(char *) * seTotal);
371 | if (!seFromHosts) {
372 | goto lowMemory;
373 | }
374 | seFromPorts = (int *)
375 | malloc(sizeof(int) * seTotal);
376 | if (!seFromPorts) {
377 | goto lowMemory;
378 | }
379 | seToHosts = (char **)
380 | malloc(sizeof(char *) * seTotal);
381 | if (!seToHosts) {
382 | goto lowMemory;
383 | }
384 | seToPorts = (int *)
385 | malloc(sizeof(int) * seTotal);
386 | if (!seToPorts) {
387 | goto lowMemory;
388 | }
389 | allowRules = (char **)
390 | malloc(sizeof(char *) * allowRulesTotal);
391 | if (!allowRules) {
392 | goto lowMemory;
393 | }
394 | denyRules = (char **)
395 | malloc(sizeof(char *) * denyRulesTotal);
396 | if (!denyRules) {
397 | goto lowMemory;
398 | }
399 | seAllowRules = (int *)
400 | malloc(sizeof(int) * seTotal);
401 | if (!seAllowRules) {
402 | goto lowMemory;
403 | }
404 | seAllowRulesTotal = (int *)
405 | malloc(sizeof(int) * seTotal);
406 | if (!seAllowRulesTotal) {
407 | goto lowMemory;
408 | }
409 | seDenyRules = (int *)
410 | malloc(sizeof(int) * seTotal);
411 | if (!seDenyRules) {
412 | goto lowMemory;
413 | }
414 | seDenyRulesTotal = (int *)
415 | malloc(sizeof(int) * seTotal);
416 | if (!seDenyRulesTotal) {
417 | goto lowMemory;
418 | }
419 | /* 2. Make a second pass to configure them. */
420 | i = 0;
421 | ai = 0;
422 | di = 0;
423 | lnum = 0;
424 | in = fopen(options.conf_file, "r");
425 | if (!in) {
426 | goto lowMemory;
427 | }
428 | if (seTotal > 0) {
429 | seAllowRulesTotal[i] = 0;
430 | seDenyRulesTotal[i] = 0;
431 | }
432 | while (1) {
433 | char *bindAddress;
434 | unsigned short bindPort;
435 | char *connectAddress;
436 | char *bindPortS;
437 | char *connectPortS;
438 | unsigned short connectPort;
439 | struct in_addr iaddr;
440 | struct sockaddr_in saddr;
441 | struct servent *service;
442 | int j;
443 | if (!getConfLine(in, line, sizeof(line), &lnum)) {
444 | break;
445 | }
446 | bindAddress = strtok(line, " \t\r\n");
447 | if (!bindAddress) {
448 | fprintf(stderr, "rinetd: no bind address specified "
449 | "on line %d.\n", lnum);
450 | continue;
451 | }
452 | if (!strcmp(bindAddress, "allow")) {
453 | char *pattern = strtok(0, " \t\r\n");
454 | if (!pattern) {
455 | fprintf(stderr, "rinetd: nothing to allow "
456 | "specified on line %d.\n", lnum);
457 | continue;
458 | }
459 | if (patternBad(pattern)) {
460 | fprintf(stderr, "rinetd: illegal allow or "
461 | "deny pattern. Only digits, ., and\n"
462 | "the ? and * wild cards are allowed. "
463 | "For performance reasons, rinetd\n"
464 | "does not look up complete "
465 | "host names.\n");
466 | continue;
467 | }
468 |
469 | allowRules[ai] = malloc(strlen(pattern) + 1);
470 | if (!allowRules[ai]) {
471 | goto lowMemory;
472 | }
473 | strcpy(allowRules[ai], pattern);
474 | if (i > 0) {
475 | if (seAllowRulesTotal[i - 1] == 0) {
476 | seAllowRules[i - 1] = ai;
477 | }
478 | seAllowRulesTotal[i - 1]++;
479 | } else {
480 | globalAllowRules++;
481 | }
482 | ai++;
483 | } else if (!strcmp(bindAddress, "deny")) {
484 | char *pattern = strtok(0, " \t\r\n");
485 | if (!pattern) {
486 | fprintf(stderr, "rinetd: nothing to deny "
487 | "specified on line %d.\n", lnum);
488 | continue;
489 | }
490 | denyRules[di] = malloc(strlen(pattern) + 1);
491 | if (!denyRules[di]) {
492 | goto lowMemory;
493 | }
494 | strcpy(denyRules[di], pattern);
495 | if (i > 0) {
496 | if (seDenyRulesTotal[i - 1] == 0) {
497 | seDenyRules[i - 1] = di;
498 | }
499 | seDenyRulesTotal[i - 1]++;
500 | } else {
501 | globalDenyRules++;
502 | }
503 | di++;
504 | } else if (!strcmp(bindAddress, "logfile")) {
505 | char *nt = strtok(0, " \t\r\n");
506 | if (!nt) {
507 | fprintf(stderr, "rinetd: no log file name "
508 | "specified on line %d.\n", lnum);
509 | continue;
510 | }
511 | logFileName = malloc(strlen(nt) + 1);
512 | if (!logFileName) {
513 | goto lowMemory;
514 | }
515 | strcpy(logFileName, nt);
516 | } else if (!strcmp(bindAddress, "pidlogfile")) {
517 | char *nt = strtok(0, " \t\r\n");
518 | if (!nt) {
519 | fprintf(stderr, "rinetd: no PID log file name "
520 | "specified on line %d.\n", lnum);
521 | continue;
522 | }
523 | pidLogFileName = malloc(strlen(nt) + 1);
524 | if (!pidLogFileName) {
525 | goto lowMemory;
526 | }
527 | strcpy(pidLogFileName, nt);
528 | } else if (!strcmp(bindAddress, "logcommon")) {
529 | logFormatCommon = 1;
530 | } else {
531 | /* A regular forwarding rule. */
532 | bindPortS = strtok(0, " \t\r\n");
533 | if (!bindPortS) {
534 | fprintf(stderr, "rinetd: no bind port "
535 | "specified on line %d.\n", lnum);
536 | continue;
537 | }
538 | service = getservbyname(bindPortS, "tcp");
539 | if (service) {
540 | bindPort = ntohs(service->s_port);
541 | } else {
542 | bindPort = atoi(bindPortS);
543 | }
544 | if ((bindPort == 0) || (bindPort >= 65536)) {
545 | fprintf(stderr, "rinetd: bind port missing "
546 | "or out of range on line %d.\n", lnum);
547 | continue;
548 | }
549 | connectAddress = strtok(0, " \t\r\n");
550 | if (!connectAddress) {
551 | fprintf(stderr, "rinetd: no connect address "
552 | "specified on line %d.\n", lnum);
553 | continue;
554 | }
555 | connectPortS = strtok(0, " \t\r\n");
556 | if (!connectPortS) {
557 | fprintf(stderr, "rinetd: no connect port "
558 | "specified on line %d.\n", lnum);
559 | continue;
560 | }
561 | service = getservbyname(connectPortS, "tcp");
562 | if (service) {
563 | connectPort = ntohs(service->s_port);
564 | } else {
565 | connectPort = atoi(connectPortS);
566 | }
567 | if ((connectPort == 0) || (connectPort >= 65536)) {
568 | fprintf(stderr, "rinetd: bind port missing "
569 | "or out of range on line %d.\n", lnum);
570 | continue;
571 | }
572 | /* Turn all of this stuff into reasonable addresses */
573 | if (!getAddress(bindAddress, &iaddr)) {
574 | fprintf(stderr, "rinetd: host %s could not be "
575 | "resolved on line %d.\n",
576 | bindAddress, lnum);
577 | continue;
578 | }
579 | /* Make a server socket */
580 | seFds[i] = socket(PF_INET, SOCK_STREAM, 0);
581 | if (seFds[i] == INVALID_SOCKET) {
582 | fprintf(stderr, "rinetd: couldn't create "
583 | "server socket!\n");
584 | seFds[i] = -1;
585 | continue;
586 | }
587 | #ifndef WIN32
588 | if (seFds[i] > maxfd) {
589 | maxfd = seFds[i];
590 | }
591 | #endif
592 | saddr.sin_family = AF_INET;
593 | memcpy(&saddr.sin_addr, &iaddr, sizeof(iaddr));
594 | saddr.sin_port = htons(bindPort);
595 | j = 1;
596 | setsockopt(seFds[i], SOL_SOCKET, SO_REUSEADDR,
597 | (const char *) &j, sizeof(j));
598 | if (bind(seFds[i], (struct sockaddr *)
599 | &saddr, sizeof(saddr)) == SOCKET_ERROR)
600 | {
601 | /* Warn -- don't exit. */
602 | fprintf(stderr, "rinetd: couldn't bind to "
603 | "address %s port %d\n",
604 | bindAddress, bindPort);
605 | closesocket(seFds[i]);
606 | seFds[i] = INVALID_SOCKET;
607 | continue;
608 | }
609 | if (listen(seFds[i], 5) == SOCKET_ERROR) {
610 | /* Warn -- don't exit. */
611 | fprintf(stderr, "rinetd: couldn't listen to "
612 | "address %s port %d\n",
613 | bindAddress, bindPort);
614 | closesocket(seFds[i]);
615 | seFds[i] = INVALID_SOCKET;
616 | continue;
617 | }
618 | ioctlsocket(seFds[i], FIONBIO, &j);
619 | if (!getAddress(connectAddress, &iaddr)) {
620 | /* Warn -- don't exit. */
621 | fprintf(stderr, "rinetd: host %s could not be "
622 | "resolved on line %d.\n",
623 | bindAddress, lnum);
624 | closesocket(seFds[i]);
625 | seFds[i] = INVALID_SOCKET;
626 | continue;
627 | }
628 | seLocalAddrs[i] = iaddr;
629 | seLocalPorts[i] = htons(connectPort);
630 | seFromHosts[i] = malloc(strlen(bindAddress) + 1);
631 | if (!seFromHosts[i]) {
632 | goto lowMemory;
633 | }
634 | strcpy(seFromHosts[i], bindAddress);
635 | seFromPorts[i] = bindPort;
636 | seToHosts[i] = malloc(strlen(connectAddress) + 1);
637 | if (!seToHosts[i]) {
638 | goto lowMemory;
639 | }
640 | strcpy(seToHosts[i], connectAddress);
641 | seToPorts[i] = connectPort;
642 | i++;
643 | if (i < seTotal) {
644 | seAllowRulesTotal[i] = 0;
645 | seDenyRulesTotal[i] = 0;
646 | }
647 | }
648 | }
649 | if (i maxfd) {
1026 | maxfd = nfd;
1027 | }
1028 | #endif /* WIN32 */
1029 | j = 1;
1030 | ioctlsocket(nfd, FIONBIO, &j);
1031 | j = 0;
1032 | #ifndef WIN32
1033 | setsockopt(nfd, SOL_SOCKET, SO_LINGER, &j, sizeof(j));
1034 | #endif
1035 | for (j = 0; (j < coTotal); j++) {
1036 | if (coClosed[j]) {
1037 | index = j;
1038 | break;
1039 | }
1040 | }
1041 | if (index == -1) {
1042 | o = coTotal;
1043 | coTotal *= 2;
1044 | if (!SAFE_REALLOC(&reFds, sizeof(int) * o,
1045 | sizeof(SOCKET) * coTotal))
1046 | {
1047 | goto shortage;
1048 | }
1049 | if (!SAFE_REALLOC(&loFds, sizeof(int) * o,
1050 | sizeof(SOCKET) * coTotal))
1051 | {
1052 | goto shortage;
1053 | }
1054 | if (!SAFE_REALLOC(&coInputRPos,
1055 | sizeof(int) * o, sizeof(int) * coTotal))
1056 | {
1057 | goto shortage;
1058 | }
1059 | if (!SAFE_REALLOC(&coInputWPos,
1060 | sizeof(int) * o, sizeof(int) * coTotal))
1061 | {
1062 | goto shortage;
1063 | }
1064 | if (!SAFE_REALLOC(&coOutputRPos,
1065 | sizeof(int) * o, sizeof(int) * coTotal))
1066 | {
1067 | goto shortage;
1068 | }
1069 | if (!SAFE_REALLOC(&coOutputWPos, sizeof(int) * o,
1070 | sizeof(int) * coTotal))
1071 | {
1072 | goto shortage;
1073 | }
1074 | if (!SAFE_REALLOC(&coClosed, sizeof(int) * o,
1075 | sizeof(int) * coTotal))
1076 | {
1077 | goto shortage;
1078 | }
1079 | if (!SAFE_REALLOC(&coClosing, sizeof(int) * o,
1080 | sizeof(int) * coTotal))
1081 | {
1082 | goto shortage;
1083 | }
1084 | if (!SAFE_REALLOC(&reClosed, sizeof(int) * o,
1085 | sizeof(int) * coTotal))
1086 | {
1087 | goto shortage;
1088 | }
1089 | if (!SAFE_REALLOC(&loClosed, sizeof(int) * o,
1090 | sizeof(int) * coTotal))
1091 | {
1092 | goto shortage;
1093 | }
1094 | if (!SAFE_REALLOC(&coLog, sizeof(int) * o,
1095 | sizeof(int) * coTotal))
1096 | {
1097 | goto shortage;
1098 | }
1099 | if (!SAFE_REALLOC(&coSe, sizeof(int) * o,
1100 | sizeof(int) * coTotal))
1101 | {
1102 | goto shortage;
1103 | }
1104 | if (!SAFE_REALLOC(&coBytesInput, sizeof(int) * o,
1105 | sizeof(int) * coTotal))
1106 | {
1107 | goto shortage;
1108 | }
1109 | if (!SAFE_REALLOC(&reAddresses, 4 * o,
1110 | 4 * coTotal))
1111 | {
1112 | goto shortage;
1113 | }
1114 | if (!SAFE_REALLOC(&coBytesOutput, sizeof(int) * o,
1115 | sizeof(int) * coTotal))
1116 | {
1117 | goto shortage;
1118 | }
1119 | if (!SAFE_REALLOC(&coInput, sizeof(char *) * o,
1120 | sizeof(char *) * coTotal))
1121 | {
1122 | goto shortage;
1123 | }
1124 | if (!SAFE_REALLOC(&coOutput, sizeof(char *) * o,
1125 | sizeof(char *) * coTotal))
1126 | {
1127 | goto shortage;
1128 | }
1129 | for (j = o; (j < coTotal); j++) {
1130 | coClosed[j] = 1;
1131 | coInput[j] = (char *)
1132 | malloc(sizeof(char) * bufferSpace);
1133 | if (!coInput[j]) {
1134 | int k;
1135 | for (k = o; (k < j); k++) {
1136 | free(coInput[k]);
1137 | free(coOutput[k]);
1138 | }
1139 | goto shortage;
1140 | }
1141 | coOutput[j] = (char *)
1142 | malloc(sizeof(char) * bufferSpace);
1143 | if (!coOutput[j]) {
1144 | int k;
1145 | free(coInput[j]);
1146 | for (k = o; (k < j); k++) {
1147 | free(coInput[k]);
1148 | free(coOutput[k]);
1149 | }
1150 | goto shortage;
1151 | }
1152 | }
1153 | index = o;
1154 | }
1155 | coInputRPos[index] = 0;
1156 | coInputWPos[index] = 0;
1157 | coOutputRPos[index] = 0;
1158 | coOutputWPos[index] = 0;
1159 | coClosed[index] = 0;
1160 | coClosing[index] = 0;
1161 | reClosed[index] = 0;
1162 | loClosed[index] = 0;
1163 | reFds[index] = nfd;
1164 | coBytesInput[index] = 0;
1165 | coBytesOutput[index] = 0;
1166 | coLog[index] = 0;
1167 | coSe[index] = i;
1168 | sin = (struct sockaddr_in *) &addr;
1169 | memcpy(address, &(sin->sin_addr.s_addr), 4);
1170 | memcpy(reAddresses + index * 4, address, 4);
1171 | /* Now, do we want to accept this connection?
1172 | Format it for comparison to a pattern. */
1173 | sprintf(addressText, "%d.%d.%d.%d",
1174 | address[0], address[1], address[2], address[3]);
1175 | /* 1. Check global allow rules. If there are no
1176 | global allow rules, it's presumed OK at
1177 | this step. If there are any, and it doesn't
1178 | match at least one, kick it out. */
1179 | if (globalAllowRules) {
1180 | int good = 0;
1181 | for (j = 0; (j < globalAllowRules); j++) {
1182 | if (match(addressText, allowRules[j])) {
1183 | good = 1;
1184 | break;
1185 | }
1186 | }
1187 | if (!good) {
1188 | refuse(index, logNotAllowed);
1189 | return;
1190 | }
1191 | }
1192 | /* 2. Check global deny rules. If it matches
1193 | any of the global deny rules, kick it out. */
1194 | if (globalDenyRules) {
1195 | for (j = 0; (j < globalDenyRules); j++) {
1196 | if (match(addressText, denyRules[j])) {
1197 | refuse(index, logDenied);
1198 | }
1199 | }
1200 | }
1201 | /* 3. Check allow rules specific to this forwarding rule.
1202 | If there are none, it's OK. If there are any,
1203 | it must match at least one. */
1204 | if (seAllowRulesTotal[i]) {
1205 | int good = 0;
1206 | for (j = 0; (j < seAllowRulesTotal[i]); j++) {
1207 | if (match(addressText,
1208 | allowRules[seAllowRules[i] + j])) {
1209 | good = 1;
1210 | break;
1211 | }
1212 | }
1213 | if (!good) {
1214 | refuse(index, logNotAllowed);
1215 | return;
1216 | }
1217 | }
1218 | /* 2. Check deny rules specific to this forwarding rule. If
1219 | it matches any of the deny rules, kick it out. */
1220 | if (seDenyRulesTotal[i]) {
1221 | for (j = 0; (j < seDenyRulesTotal[i]); j++) {
1222 | if (match(addressText,
1223 | denyRules[seDenyRules[i] + j])) {
1224 | refuse(index, logDenied);
1225 | }
1226 | }
1227 | }
1228 | /* Now open a connection to the local server.
1229 | This, too, is nonblocking. Why wait
1230 | for anything when you don't have to? */
1231 | openLocalFd(i, index);
1232 | return;
1233 | shortage:
1234 | fprintf(stderr, "rinetd: not enough memory to "
1235 | "add slots. Currently %d slots.\n", o);
1236 | /* Go back to the previous total number of slots */
1237 | coTotal = o;
1238 | }
1239 |
1240 | void openLocalFd(int se, int i)
1241 | {
1242 | int j;
1243 | struct sockaddr_in saddr;
1244 | loFds[i] = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
1245 | if (loFds[i] == INVALID_SOCKET) {
1246 | closesocket(reFds[i]);
1247 | reClosed[i] = 1;
1248 | loClosed[i] = 1;
1249 | coClosed[i] = 1;
1250 | log(i, coSe[i], logLocalSocketFailed);
1251 | return;
1252 | }
1253 | #ifndef WIN32
1254 | if (loFds[i] > maxfd) {
1255 | maxfd = loFds[i];
1256 | }
1257 | #endif /* WIN32 */
1258 | /* Bind the local socket */
1259 | saddr.sin_family = AF_INET;
1260 | saddr.sin_port = INADDR_ANY;
1261 | saddr.sin_addr.s_addr = 0;
1262 | if (bind(loFds[i], (struct sockaddr *) &saddr, sizeof(saddr)) == SOCKET_ERROR) {
1263 | closesocket(loFds[i]);
1264 | closesocket(reFds[i]);
1265 | reClosed[i] = 1;
1266 | loClosed[i] = 1;
1267 | coClosed[i] = 1;
1268 | log(i, coSe[i], logLocalBindFailed);
1269 | return;
1270 | }
1271 | memset(&saddr, 0, sizeof(struct sockaddr_in));
1272 | saddr.sin_family = AF_INET;
1273 | memcpy(&saddr.sin_addr, &seLocalAddrs[se], sizeof(struct in_addr));
1274 | saddr.sin_port = seLocalPorts[se];
1275 | #ifndef WIN32
1276 | #ifdef LINUX
1277 | j = 0;
1278 | setsockopt(loFds[i], SOL_SOCKET, SO_LINGER, &j, sizeof(j));
1279 | #else
1280 | j = 1024;
1281 | setsockopt(loFds[i], SOL_SOCKET, SO_SNDBUF, &j, sizeof(j));
1282 | #endif /* LINUX */
1283 | #endif /* WIN32 */
1284 | j = 1;
1285 | ioctlsocket(loFds[i], FIONBIO, &j);
1286 | if (connect(loFds[i], (struct sockaddr *)&saddr,
1287 | sizeof(struct sockaddr_in)) == INVALID_SOCKET)
1288 | {
1289 | if ((GetLastError() != WSAEINPROGRESS) &&
1290 | (GetLastError() != WSAEWOULDBLOCK))
1291 | {
1292 | PERROR("rinetd: connect");
1293 | closesocket(loFds[i]);
1294 | closesocket(reFds[i]);
1295 | reClosed[i] = 1;
1296 | loClosed[i] = 1;
1297 | coClosed[i] = 1;
1298 | log(i, coSe[i], logLocalConnectFailed);
1299 | return;
1300 | }
1301 | }
1302 | }
1303 |
1304 | int getAddress(char *host, struct in_addr *iaddr)
1305 | {
1306 | char *p = host;
1307 | int ishost = 0;
1308 | while (*p) {
1309 | if (!(isdigit(*p) || ((*p) == '.'))) {
1310 | ishost = 1;
1311 | break;
1312 | }
1313 | p++;
1314 | }
1315 | if (ishost) {
1316 | struct hostent *h;
1317 | h = gethostbyname(host);
1318 | if (!h) {
1319 | return 0;
1320 | }
1321 | memcpy(
1322 | (void *) &iaddr->s_addr,
1323 | (void *) h->h_addr,
1324 | 4);
1325 | return 1;
1326 | } else {
1327 | iaddr->s_addr = inet_addr(host);
1328 | return 1;
1329 | }
1330 | }
1331 |
1332 | #ifndef WIN32
1333 | void plumber(int s)
1334 | {
1335 | /* Just reinstall */
1336 | signal(SIGPIPE, plumber);
1337 | }
1338 |
1339 | void hup(int s)
1340 | {
1341 | /* Learn the new rules */
1342 | readConfiguration();
1343 | /* And reinstall the signal handler */
1344 | signal(SIGHUP, hup);
1345 | }
1346 | #endif /* WIN32 */
1347 |
1348 | int safeRealloc(void **data, int oldsize, int newsize)
1349 | {
1350 | void *newData = malloc(newsize + 1);
1351 | if (!newData) {
1352 | return 0;
1353 | }
1354 | if (newsize < oldsize) {
1355 | memcpy(newData, *data, newsize);
1356 | } else {
1357 | memcpy(newData, *data, oldsize);
1358 | }
1359 | *data = newData;
1360 | return 1;
1361 | }
1362 |
1363 | void RegisterPID(void)
1364 | {
1365 | FILE *pid_file;
1366 | char *pid_file_name = "/var/run/rinetd.pid";
1367 | if (pidLogFileName) {
1368 | pid_file_name = pidLogFileName;
1369 | }
1370 | /* add other systems with wherever they register processes */
1371 | #if defined(LINUX)
1372 | pid_file = fopen(pid_file_name, "w");
1373 | if (pid_file == NULL) {
1374 | /* non-fatal, non-Linux may lack /var/run... */
1375 | fprintf(stderr, "rinetd: Couldn't write to "
1376 | "%s. PID was not logged.\n", pid_file_name);
1377 | } else {
1378 | /* error checking deliberately omitted */
1379 | fprintf(pid_file, "%d\n", getpid());
1380 | fclose(pid_file);
1381 | }
1382 | #endif /* LINUX */
1383 | }
1384 |
1385 | unsigned char nullAddress[4] = { 0, 0, 0, 0 };
1386 |
1387 | struct tm *get_gmtoff(int *tz);
1388 |
1389 | void log(int i, int coSe, int result)
1390 | {
1391 | unsigned char *reAddress;
1392 | int bytesOutput;
1393 | int bytesInput;
1394 | /* Bit of borrowing from Apache logging module here,
1395 | thanks folks */
1396 | int timz;
1397 | struct tm *t;
1398 | char tstr[1024];
1399 | char sign;
1400 | if (!log) {
1401 | return;
1402 | }
1403 | t = get_gmtoff(&timz);
1404 | sign = (timz < 0 ? '-' : '+');
1405 | if (timz < 0) {
1406 | timz = -timz;
1407 | }
1408 | strftime(tstr, sizeof(tstr), "%d/%b/%Y:%H:%M:%S ", t);
1409 |
1410 | if (i != -1) {
1411 | reAddress = reAddresses + i * 4;
1412 | bytesOutput = coBytesOutput[i];
1413 | bytesInput = coBytesInput[i];
1414 | } else {
1415 | reAddress = nullAddress;
1416 | bytesOutput = 0;
1417 | bytesInput = 0;
1418 | }
1419 | if (logFile) {
1420 | if (logFormatCommon) {
1421 | /* Fake a common log format log file in a way that
1422 | most web analyzers can do something interesting with.
1423 | We lie and say the protocol is HTTP because we don't
1424 | want the web analyzer to reject the line. We also
1425 | lie and claim success (code 200) because we don't
1426 | want the web analyzer to ignore the line as an
1427 | error and not analyze the "URL." We put a result
1428 | message into our "URL" instead. The last field
1429 | is an extra, giving the number of input bytes,
1430 | after several placeholders meant to fill the
1431 | positions frequently occupied by user agent,
1432 | referrer, and server name information. */
1433 | fprintf(logFile, "%d.%d.%d.%d - - "
1434 | "[%s %c%.2d%.2d] "
1435 | "\"GET /rinetd-services/%s/%d/%s/%d/%s HTTP/1.0\" "
1436 | "200 %d - - - %d\n",
1437 | reAddress[0],
1438 | reAddress[1],
1439 | reAddress[2],
1440 | reAddress[3],
1441 | tstr,
1442 | sign,
1443 | timz / 60,
1444 | timz % 60,
1445 | seFromHosts[coSe], seFromPorts[coSe],
1446 | seToHosts[coSe], seToPorts[coSe],
1447 | logMessages[result],
1448 | bytesOutput,
1449 | bytesInput);
1450 | } else {
1451 | /* Write an rinetd-specific log entry with a
1452 | less goofy format. */
1453 | fprintf(logFile, "%s\t%d.%d.%d.%d\t%s\t%d\t%s\t%d\t%d"
1454 | "\t%d\t%s\n",
1455 | tstr,
1456 | reAddress[0],
1457 | reAddress[1],
1458 | reAddress[2],
1459 | reAddress[3],
1460 | seFromHosts[coSe], seFromPorts[coSe],
1461 | seToHosts[coSe], seToPorts[coSe],
1462 | bytesInput,
1463 | bytesOutput,
1464 | logMessages[result]);
1465 | }
1466 | }
1467 | }
1468 |
1469 | int readArgs (int argc,
1470 | char **argv,
1471 | RinetdOptions *options)
1472 | {
1473 | int c;
1474 |
1475 | while (1) {
1476 | int option_index = 0;
1477 | static struct option long_options[] = {
1478 | {"conf-file", 1, 0, 'c'},
1479 | {"help", 0, 0, 'h'},
1480 | {"version", 0, 0, 'v'},
1481 | {0, 0, 0, 0}
1482 | };
1483 | c = getopt_long (argc, argv, "c:shv",
1484 | long_options, &option_index);
1485 | if (c == -1) {
1486 | break;
1487 | }
1488 | switch (c) {
1489 | case 'c':
1490 | options->conf_file = malloc(strlen(optarg) + 1);
1491 | if (!options->conf_file) {
1492 | fprintf(stderr, "Not enough memory to "
1493 | "launch rinetd.\n");
1494 | exit(1);
1495 | }
1496 | strcpy(options->conf_file, optarg);
1497 | break;
1498 | case 'h':
1499 | printf("Usage: rinetd [OPTION]\n"
1500 | " -c, --conf-file FILE read configuration "
1501 | "from FILE\n"
1502 | " -h, --help display this help\n"
1503 | " -v, --version display version "
1504 | "number\n\n");
1505 | printf("Most options are controlled through the\n"
1506 | "configuration file. See the rinetd(8)\n"
1507 | "manpage for more information.\n");
1508 | exit (0);
1509 | case 'v':
1510 | printf ("rinetd %s\n", VERSION);
1511 | exit (0);
1512 | case '?':
1513 | default:
1514 | exit (1);
1515 | }
1516 | }
1517 | return 0;
1518 | }
1519 |
1520 | /* get_gmtoff was borrowed from Apache. Thanks folks. */
1521 |
1522 | struct tm *get_gmtoff(int *tz) {
1523 | time_t tt = time(NULL);
1524 | struct tm gmt;
1525 | struct tm *t;
1526 | int days, hours, minutes;
1527 |
1528 | /* Assume we are never more than 24 hours away. */
1529 | gmt = *gmtime(&tt); /* remember gmtime/localtime return ptr to static */
1530 | t = localtime(&tt); /* buffer... so be careful */
1531 | days = t->tm_yday - gmt.tm_yday;
1532 | hours = ((days < -1 ? 24 : 1 < days ? -24 : days * 24)
1533 | + t->tm_hour - gmt.tm_hour);
1534 | minutes = hours * 60 + t->tm_min - gmt.tm_min;
1535 | *tz = minutes;
1536 | return t;
1537 | }
1538 |
1539 | int patternBad(char *pattern)
1540 | {
1541 | char *p = pattern;
1542 | while (*p) {
1543 | if (isdigit(*p) || ((*p) == '?') || ((*p) == '*') ||
1544 | ((*p) == '.'))
1545 | {
1546 | p++;
1547 | }
1548 | return 0;
1549 | }
1550 | return 1;
1551 | }
1552 |
1553 | void refuse(int index, int logCode)
1554 | {
1555 | closesocket(reFds[index]);
1556 | reClosed[index] = 1;
1557 | loClosed[index] = 1;
1558 | coClosed[index] = 1;
1559 | log(index, coSe[index], logCode);
1560 | }
1561 |
1562 | void term(int s)
1563 | {
1564 | /* Obey the request, but first flush the log */
1565 | if (logFile) {
1566 | fclose(logFile);
1567 | }
1568 | exit(0);
1569 | }
1570 |
1571 |
--------------------------------------------------------------------------------
/rinetd.dsp:
--------------------------------------------------------------------------------
1 | # Microsoft Developer Studio Project File - Name="rinetd" - Package Owner=<4>
2 | # Microsoft Developer Studio Generated Build File, Format Version 5.00
3 | # ** DO NOT EDIT **
4 |
5 | # TARGTYPE "Win32 (x86) Console Application" 0x0103
6 |
7 | CFG=rinetd - Win32 Debug
8 | !MESSAGE This is not a valid makefile. To build this project using NMAKE,
9 | !MESSAGE use the Export Makefile command and run
10 | !MESSAGE
11 | !MESSAGE NMAKE /f "rinetd.mak".
12 | !MESSAGE
13 | !MESSAGE You can specify a configuration when running NMAKE
14 | !MESSAGE by defining the macro CFG on the command line. For example:
15 | !MESSAGE
16 | !MESSAGE NMAKE /f "rinetd.mak" CFG="rinetd - Win32 Debug"
17 | !MESSAGE
18 | !MESSAGE Possible choices for configuration are:
19 | !MESSAGE
20 | !MESSAGE "rinetd - Win32 Release" (based on "Win32 (x86) Console Application")
21 | !MESSAGE "rinetd - Win32 Debug" (based on "Win32 (x86) Console Application")
22 | !MESSAGE
23 |
24 | # Begin Project
25 | # PROP Scc_ProjName ""
26 | # PROP Scc_LocalPath ""
27 | CPP=cl.exe
28 | RSC=rc.exe
29 |
30 | !IF "$(CFG)" == "rinetd - Win32 Release"
31 |
32 | # PROP BASE Use_MFC 0
33 | # PROP BASE Use_Debug_Libraries 0
34 | # PROP BASE Output_Dir "Release"
35 | # PROP BASE Intermediate_Dir "Release"
36 | # PROP BASE Target_Dir ""
37 | # PROP Use_MFC 0
38 | # PROP Use_Debug_Libraries 0
39 | # PROP Output_Dir "Release"
40 | # PROP Intermediate_Dir "Release"
41 | # PROP Ignore_Export_Lib 0
42 | # PROP Target_Dir ""
43 | # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
44 | # ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
45 | # ADD BASE RSC /l 0x409 /d "NDEBUG"
46 | # ADD RSC /l 0x409 /d "NDEBUG"
47 | BSC32=bscmake.exe
48 | # ADD BASE BSC32 /nologo
49 | # ADD BSC32 /nologo
50 | LINK32=link.exe
51 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
52 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /subsystem:console /machine:I386
53 |
54 | !ELSEIF "$(CFG)" == "rinetd - Win32 Debug"
55 |
56 | # PROP BASE Use_MFC 0
57 | # PROP BASE Use_Debug_Libraries 1
58 | # PROP BASE Output_Dir "Debug"
59 | # PROP BASE Intermediate_Dir "Debug"
60 | # PROP BASE Target_Dir ""
61 | # PROP Use_MFC 0
62 | # PROP Use_Debug_Libraries 1
63 | # PROP Output_Dir "Debug"
64 | # PROP Intermediate_Dir "Debug"
65 | # PROP Ignore_Export_Lib 0
66 | # PROP Target_Dir ""
67 | # ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
68 | # ADD CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
69 | # ADD BASE RSC /l 0x409 /d "_DEBUG"
70 | # ADD RSC /l 0x409 /d "_DEBUG"
71 | BSC32=bscmake.exe
72 | # ADD BASE BSC32 /nologo
73 | # ADD BSC32 /nologo
74 | LINK32=link.exe
75 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
76 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
77 |
78 | !ENDIF
79 |
80 | # Begin Target
81 |
82 | # Name "rinetd - Win32 Release"
83 | # Name "rinetd - Win32 Debug"
84 | # Begin Source File
85 |
86 | SOURCE=.\getopt.c
87 | # End Source File
88 | # Begin Source File
89 |
90 | SOURCE=.\match.c
91 | # End Source File
92 | # Begin Source File
93 |
94 | SOURCE=.\rinetd.c
95 | # End Source File
96 | # End Target
97 | # End Project
98 |
--------------------------------------------------------------------------------
/rinetd.dsw:
--------------------------------------------------------------------------------
1 | Microsoft Developer Studio Workspace File, Format Version 5.00
2 | # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
3 |
4 | ###############################################################################
5 |
6 | Project: "rinetd"=.\rinetd.dsp - Package Owner=<4>
7 |
8 | Package=<5>
9 | {{{
10 | }}}
11 |
12 | Package=<4>
13 | {{{
14 | }}}
15 |
16 | ###############################################################################
17 |
18 | Global:
19 |
20 | Package=<5>
21 | {{{
22 | }}}
23 |
24 | Package=<3>
25 | {{{
26 | }}}
27 |
28 | ###############################################################################
29 |
30 |
--------------------------------------------------------------------------------
/rinetd.html:
--------------------------------------------------------------------------------
1 | rinetd: a user-mode port redirect utility
2 | Description
3 |
4 | Redirects TCP connections from one IP address and port to another. rinetd
5 | is a single-process server which handles any number of connections to
6 | the address/port pairs specified in the file /etc/rinetd.conf
.
7 | Since rinetd runs as a single process using nonblocking I/O, it is
8 | able to redirect a large number of connections without a severe
9 | impact on the machine. This makes it practical to run TCP services
10 | on machines inside an IP masquerading firewall. rinetd does not
11 | redirect FTP, because FTP requires more than one socket.
12 |
13 |
14 | rinetd is typically launched at boot time, using the following syntax:
15 |
16 |
17 | /usr/sbin/rinetd
18 |
19 |
20 | The configuration file is found in the file
21 | /etc/rinetd.conf
, unless
22 | another file is specified using the -c
command line option.
23 |
24 | Forwarding Rules
25 |
26 | Most entries in the configuration file are forwarding rules. The
27 | format of a forwarding rule is as follows:
28 |
29 |
30 | bindaddress bindport connectaddress connectport
31 |
32 | For example:
33 |
34 | 206.125.69.81 80 10.1.1.2 80
35 |
36 |
37 | Would redirect all connections to port 80 of the "real" IP address
38 | 206.125.69.81, which could be a virtual interface, through
39 | rinetd to port 80 of the address 10.1.1.2, which would typically
40 | be a machine on the inside of a firewall which has no
41 | direct routing to the outside world.
42 |
43 |
44 | Although responding on individual interfaces rather than on all
45 | interfaces is one of rinetd's primary features, sometimes it is
46 | preferable to respond on all IP addresses that belong to the server.
47 | In this situation, the special IP address 0.0.0.0
48 | can be used. For example:
49 |
50 |
51 | 0.0.0.0 23 10.1.1.2 23
52 |
53 |
54 | Would redirect all connections to port 23, for all IP addresses
55 | assigned to the server. This is the default behavior for most
56 | other programs.
57 |
58 |
59 | Service names can be specified instead of port numbers. On most systems,
60 | service names are defined in the file /etc/services.
61 |
62 |
63 | Both IP addresses and hostnames are accepted for
64 | bindaddress and connectaddress.
65 |
66 | Allow and Deny Rules
67 |
68 | Configuration files can also contain allow and deny rules.
69 |
70 |
71 | Allow rules which appear before the first forwarding rule are
72 | applied globally: if at least one global allow rule exists,
73 | and the address of a new connection does not
74 | satisfy at least one of the global allow rules, that connection
75 | is immediately rejected, regardless of any other rules.
76 |
77 |
78 | Allow rules which appear after a specific forwarding rule apply
79 | to that forwarding rule only. If at least one allow rule
80 | exists for a particular forwarding rule, and the address of a new
81 | connection does not satisfy at least one of the allow rules
82 | for that forwarding rule, that connection is immediately
83 | rejected, regardless of any other rules.
84 |
85 |
86 | Deny rules which appear before the first forwarding rule are
87 | applied globally: if the address of a new connection satisfies
88 | any of the global allow rules, that connection
89 | is immediately rejected, regardless of any other rules.
90 |
91 |
92 | Deny rules which appear after a specific forwarding rule apply
93 | to that forwarding rule only. If the address of a new
94 | connection satisfies any of the deny rules for that forwarding rule,
95 | that connection is immediately rejected, regardless of any other rules.
96 |
97 |
98 | The format of an allow rule is as follows:
99 |
100 |
101 | allow pattern
102 |
103 |
104 | Patterns can contain the following characters: 0, 1, 2, 3, 4, 5,
105 | 6, 7, 8, 9, . (period), ?, and *. The ? wildcard matches any one
106 | character. The * wildcard matches any number of characters, including
107 | zero.
108 |
109 |
110 | For example:
111 |
112 |
113 | allow 206.125.69.*
114 |
115 |
116 | This allow rule matches all IP addresses in the 206.125.69 class C domain.
117 |
118 |
119 | Host names are NOT permitted in allow and deny rules. The performance
120 | cost of looking up IP addresses to find their corresponding names
121 | is prohibitive. Since rinetd is a single process server, all other
122 | connections would be forced to pause during the address lookup.
123 |
124 | Logging
125 |
126 | rinetd is able to produce a log file in either of two formats:
127 | tab-delimited and web server-style "common log format."
128 |
129 |
130 | By default, rinetd does not produce a log file. To activate logging, add
131 | the following line to the configuration file:
132 |
133 |
134 | logfile log-file-location
135 |
136 |
137 | Example:
138 |
139 |
140 | logfile /var/log/rinetd.log
141 |
142 |
143 | By default, rinetd logs in a simple tab-delimited format containing
144 | the following information:
145 |
146 |
147 | Date and time
148 | Client address
149 |
150 | Listening host
151 |
152 | Listening port
153 |
154 | Forwarded-to host
155 |
156 | Forwarded-to port
157 |
158 | Bytes received from client
159 |
160 | Bytes sent to client
161 |
162 | Result message
163 |
164 |
165 | To activate web server-style "common log format" logging,
166 | add the following line to the configuration file:
167 |
168 |
169 | logcommon
170 |
171 | Command line options
172 |
173 | The -c command line option is used to specify an alternate
174 | configuration file.
175 |
176 |
177 | The -h command line option produces a short help message.
178 |
179 |
180 | The -v command line option displays the version number.
181 |
182 | Reinitializing rinetd
183 |
184 | The kill -1 signal (SIGHUP) can be used to cause rinetd
185 | to reload its configuration file without interrupting existing
186 | connections. Under Linux(tm) the process id
187 | is saved in the file /var/run/rinetd.pid
188 | to facilitate the kill -HUP. An alternate
189 | file name can be provided by using the pidlogfile
190 | configuration file option.
191 |
192 | Bugs
193 |
194 | The server redirected to is not able to identify the host the
195 | client really came from. This cannot be corrected; however,
196 | the log produced by rinetd provides a way to obtain this
197 | information. Under Unix, sockets would theoretically lose data when closed
198 | with SO_LINGER
turned off, but in Linux this is not the case
199 | (kernel source comments support this belief on my part). On non-Linux Unix
200 | platforms, alternate code which uses a different trick to work around
201 | blocking close()
is provided, but this code is untested.
202 |
203 |
204 | The logging is inadequate. The duration of the connection should be logged.
205 |
206 | License
207 |
208 | Copyright (c) 1997-2019, Thomas Boutell.
209 | This software is released for free use under the terms of
210 | the GNU General Public License, version 2 or higher.
211 |
212 | Thanks
213 |
214 | Thanks are due to Bill Davidsen, Libor Pechachek, Sascha Ziemann,
215 | Joel S. Noble, the Apache Group, and many others who have contributed
216 | advice, encouragement and/or source code to this and other open
217 | software projects.
218 |
219 |
--------------------------------------------------------------------------------
/rinetd.ncb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boutell/rinetd/e2fbc1559be2931a218e1dec51dcae75a30a7bce/rinetd.ncb
--------------------------------------------------------------------------------
/rinetd.opt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boutell/rinetd/e2fbc1559be2931a218e1dec51dcae75a30a7bce/rinetd.opt
--------------------------------------------------------------------------------
/rinetd.plg:
--------------------------------------------------------------------------------
1 | --------------------Configuration: rinetd - Win32 Debug--------------------
2 | Begining build with project "g:\rinetd\rinetd.dsp", at root.
3 | Active configuration is Win32 (x86) Console Application (based on Win32 (x86) Console Application)
4 |
5 | Project's tools are:
6 | "32-bit C/C++ Compiler for 80x86" with flags "/nologo /MLd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Fp"Debug/rinetd.pch" /YX /Fo"Debug/" /Fd"Debug/" /FD /c "
7 | "Win32 Resource Compiler" with flags "/l 0x409 /d "_DEBUG" "
8 | "Browser Database Maker" with flags "/nologo /o"Debug/rinetd.bsc" "
9 | "COFF Linker for 80x86" with flags "kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /subsystem:console /incremental:yes /pdb:"Debug/rinetd.pdb" /debug /machine:I386 /out:"Debug/rinetd.exe" /pdbtype:sept "
10 | "Custom Build" with flags ""
11 | "" with flags ""
12 |
13 | Creating temp file "c:\windows\TEMP\RSP10D4.TMP" with contents
16 | Creating command line "cl.exe @c:\windows\TEMP\RSP10D4.TMP"
17 | Creating temp file "c:\windows\TEMP\RSP10D5.TMP" with contents
21 | Creating command line "link.exe @c:\windows\TEMP\RSP10D5.TMP"
22 | Compiling...
23 | rinetd.c
24 | G:\rinetd\rinetd.c(965) : warning C4101: 'arg' : unreferenced local variable
25 | G:\rinetd\rinetd.c(992) : warning C4101: 'arg' : unreferenced local variable
26 | G:\rinetd\rinetd.c(1367) : warning C4101: 'pid_file' : unreferenced local variable
27 | Linking...
28 | LINK : LNK6004: Debug/rinetd.exe not found or not built by the last incremental link; performing full link
29 |
30 |
31 |
32 | rinetd.exe - 0 error(s), 3 warning(s)
33 |
--------------------------------------------------------------------------------