git ssb

0+

cel / sslh



Commit 2781c75ff99cd5da7b25f6b883d78ff3de987308

Added tranparent proyxing

Yves Rutschle committed on 7/21/2013, 11:46:45 AM
Parent: d02ffcd15482a7feaed11d9109ae578eda3734dd

Files changed

ChangeLogchanged
READMEchanged
common.cchanged
common.hchanged
sslh-fork.cchanged
sslh-main.cchanged
sslh-select.cchanged
ChangeLogView
@@ -1,5 +1,9 @@
11 vNEXT:
2+ Added --transparent option for transparent proxying.
3+ See README for iptables magic and capability
4+ management.
5+
26 Fixed bug in sslh-select: if socket dropped while
37 defered_data was present, sslh-select would crash.
48
59 v1.14: 21DEC2012
READMEView
@@ -156,34 +156,68 @@
156156
157157 sslh options: -i for inetd mode, --http to forward http
158158 connexions to port 80, and SSH connexions to port 22.
159159
160-==== IP_TPROXY support ====
160+==== capapbilities support ====
161161
162-There is a netfilter patch that adds an option to the Linux
163-TCP/IP stack to allow a program to set the source address
164-of an IP packet that it sends. This could let sslh set the
165-address of packets to that of the actual client, so that
166-sshd would see and log the IP address of the client, making
167-sslh transparent.
162+On Linux (only?), you can use POSIX capabilities to reduce a
163+server's capabilities to the minimum it needs (see
164+capabilities(8). For sslh, this is CAP_NET_ADMIN (to
165+perform transparent proxy-ing) and CAP_NET_BIND_SERVICE (to
166+bind to port 443 without being root).
168167
169-This is not, and won't be, implemented in sslh for the
170-following reasons (in increasing order of importance):
168+The simplest way to use capabilities is to give them to the
169+executable as root:
171170
172- * It's not vital: the real connecting IP address can be
173- found in logs. Little gain.
174- * It's Linux only: it means increased complexity for no
175- gain to some users.
176- * It's a patch: it means it'd only be useful to Linux
177- users who compile their own kernel.
178- * Only root can use the feature: that's a definite no-no.
179- Sslh should not, must not, will never run as root.
171+# setcap cap_net_bind_service,cap_net_admin+pe sslh-select
180172
181-This isn't to mean that it won't eventually get implemented,
182-when/if the feature finds its way into the main kernel and
183-it becomes usuable by non-root processes.
173+Then you can run sslh-select as an unpriviledged user, e.g.:
184174
175+$ sslh-select -p myname:443 --ssh localhost:22 --ssl localhost:443
185176
177+This has 2 advantages over starting as root with -u:
178+- You no longer start as root (duh)
179+- This enables transparent proxying.
180+
181+Caveat: CAP_NET_ADMIN does give sslh too many rights, e.g.
182+configuring the interface. If you're not going to use
183+transparent proxying, just don't use it.
184+
185+==== Transparent proxy support ====
186+
187+On Linux (only?) you can use the --transparent option to
188+request transparent proying. This means services behind sslh
189+(Apache, sshd and so on) will see the external IP and ports
190+as if the external world connected directly to them. This
191+simplifies IP-based access control (or makes it possible at
192+all).
193+
194+sslh needs extended rights to perform this: you'll need to
195+give it cap_net_admin capabilities (see appropriate chapter)
196+or run it as root (but don't do that).
197+
198+The firewalling tables also need to be adjusted as follow
199+(example to connect to https on 4443 -- adapt to your needs
200+(I don't think it is possible to have httpd listen to 443 in
201+this scheme -- let me know if you manage that))):
202+
203+# iptables -t mangle -N SSLH
204+# iptables -t mangle -A OUTPUT --protocol tcp --out-interface eth0 --sport 22 --jump SSLH
205+# iptables -t mangle -A OUTPUT --protocol tcp --out-interface eth0 --sport 4443 --jump SSLH
206+# iptables -t mangle -A SSLH --jump MARK --set-mark 0x1
207+# iptables -t mangle -A SSLH --jump ACCEPT
208+# ip rule add fwmark 0x1 lookup 100
209+# ip route add local 0.0.0.0/0 dev lo table 100
210+
211+This will only work if sslh does not use any loopback
212+addresses (no 127.0.0.1 or localhost), you'll need to use
213+explicit IP addresses (or names):
214+
215+sslh --listen 192.168.0.1:443 --ssh 192.168.0.1:22 --ssl 192.168.0.1:4443
216+
217+This will not work:
218+sslh --listen 192.168.0.1:443 --ssh 127.0.0.1:22 --ssl 127.0.0.1:4443
219+
186220 ==== Comments? Questions? ====
187221
188222 You can subscribe to the sslh mailing list here:
189223 http://rutschle.net/cgi-bin/mailman/listinfo/sslh
common.cView
@@ -24,8 +24,9 @@
2424 int probing_timeout = 2;
2525 int inetd = 0;
2626 int foreground = 0;
2727 int background = 0;
28+int transparent = 0;
2829 int numeric = 0;
2930 const char *user_name, *pid_file;
3031
3132 struct addrinfo *addr_listen = NULL; /* what addresses do we listen to? */
@@ -95,11 +96,37 @@
9596
9697 return num_addr;
9798 }
9899
100+/* Transparent proxying: bind the peer address of fd to the peer address of
101+ * fd_from */
102+#define IP_TRANSPARENT 19
103+int bind_peer(int fd, int fd_from)
104+{
105+ struct addrinfo from;
106+ struct sockaddr_storage ss;
107+ int res, trans = 1;
108+
109+ memset(&from, 0, sizeof(from));
110+ from.ai_addr = (struct sockaddr*)&ss;
111+ from.ai_addrlen = sizeof(ss);
112+
113+ res = getpeername(fd_from, from.ai_addr, &from.ai_addrlen);
114+ CHECK_RES_DIE(res, "getpeername");
115+ res = setsockopt(fd, SOL_IP, IP_TRANSPARENT, &trans, sizeof(trans));
116+ CHECK_RES_DIE(res, "setsockopt");
117+ res = bind(fd, from.ai_addr, from.ai_addrlen);
118+ CHECK_RES_RETURN(res, "bind");
119+
120+ return 0;
121+}
122+
99123 /* Connect to first address that works and returns a file descriptor, or -1 if
100- * none work. cnx_name points to the name of the service (for logging) */
101-int connect_addr(struct addrinfo *addr, const char* cnx_name)
124+ * none work.
125+ * If transparent proxying is on, use fd_from peer address on external address
126+ * of new file descriptor.
127+ * cnx_name points to the name of the service (for logging) */
128+int connect_addr(struct addrinfo *addr, int fd_from, const char* cnx_name)
102129 {
103130 struct addrinfo *a;
104131 char buf[NI_MAXHOST];
105132 int fd, res;
@@ -112,8 +139,10 @@
112139 fd = socket(a->ai_family, SOCK_STREAM, 0);
113140 if (fd == -1) {
114141 log_message(LOG_ERR, "forward to %s failed:socket: %s\n", cnx_name, strerror(errno));
115142 } else {
143+ if (transparent)
144+ bind_peer(fd, fd_from);
116145 res = connect(fd, a->ai_addr, a->ai_addrlen);
117146 if (res == -1) {
118147 log_message(LOG_ERR, "forward to %s failed:connect: %s\n",
119148 cnx_name, strerror(errno));
common.hView
@@ -33,9 +33,9 @@
3333 }
3434
3535 #define CHECK_RES_RETURN(res, str) \
3636 if (res == -1) { \
37- log_message(LOG_CRIT, "%s: %d\n", str, errno); \
37+ log_message(LOG_CRIT, "%s:%d:%s\n", str, errno, strerror(errno)); \
3838 return res; \
3939 }
4040
4141 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
@@ -79,9 +79,9 @@
7979
8080
8181 /* common.c */
8282 void init_cnx(struct connection *cnx);
83-int connect_addr(struct addrinfo *addr, const char* cnx_name);
83+int connect_addr(struct addrinfo *addr, int fd_from, const char* cnx_name);
8484 int fd2fd(struct queue *target, struct queue *from);
8585 char* sprintaddr(char* buf, size_t size, struct addrinfo *a);
8686 void resolve_name(struct addrinfo **out, char* fullname);
8787 struct proto* probe_client_protocol(struct connection *cnx);
@@ -99,9 +99,10 @@
9999
100100 int defer_write(struct queue *q, void* data, int data_size);
101101 int flush_defered(struct queue *q);
102102
103-extern int probing_timeout, verbose, inetd, foreground, background, numeric;
103+extern int probing_timeout, verbose, inetd, foreground,
104+ background, transparent, numeric;
104105 extern struct sockaddr_storage addr_ssl, addr_ssh, addr_openvpn;
105106 extern struct addrinfo *addr_listen;
106107 extern const char* USAGE_STRING;
107108 extern const char* user_name, *pid_file;
sslh-fork.cView
@@ -101,9 +101,9 @@
101101 exit(0);
102102 }
103103
104104 /* Connect the target socket */
105- out_socket = connect_addr(saddr, prot->description);
105+ out_socket = connect_addr(saddr, in_socket, prot->description);
106106 CHECK_RES_DIE(out_socket, "connect");
107107
108108 cnx.q[1].fd = out_socket;
109109
sslh-main.cView
@@ -57,8 +57,9 @@
5757 static struct option const_options[] = {
5858 { "inetd", no_argument, &inetd, 1 },
5959 { "foreground", no_argument, &foreground, 1 },
6060 { "background", no_argument, &background, 1 },
61+ { "transparent", no_argument, &transparent, 1 },
6162 { "numeric", no_argument, &numeric, 1 },
6263 { "verbose", no_argument, &verbose, 1 },
6364 { "user", required_argument, 0, 'u' },
6465 { "config", required_argument, 0, 'F' },
sslh-select.cView
@@ -121,9 +121,9 @@
121121 fd_set *fds_r, fd_set *fds_w)
122122 {
123123 struct queue *q = &cnx->q[1];
124124
125- q->fd = connect_addr(addr, cnx_name);
125+ q->fd = connect_addr(addr, cnx->q[0].fd, cnx_name);
126126 if (q->fd != -1) {
127127 log_connection(cnx);
128128 set_nonblock(q->fd);
129129 flush_defered(q);

Built with git-ssb-web