Permalink
Browse files

Initial git release (rel-0-26)

  • Loading branch information...
stealth committed Dec 9, 2011
0 parents commit 95252acdd1352c6d7d8b7b335bd88e24b89e2b11
Showing with 1,237 additions and 0 deletions.
  1. +15 −0 Changelog
  2. +27 −0 Makefile
  3. +49 −0 README
  4. +14 −0 config.h
  5. +208 −0 main.cc
  6. +126 −0 multicore.cc
  7. +13 −0 multicore.h
  8. +29 −0 nf-setup
  9. +234 −0 socket.cc
  10. +62 −0 socket.h
  11. +361 −0 sshttp.cc
  12. +99 −0 sshttp.h
  13. BIN sshttp.jpg
@@ -0,0 +1,15 @@
0.26
----
+ Fri Aug 19 2011
+ Fixed logging inside chroot by adding LOG_NDELAY
+ Fixed potential connection slowdown by special usage patterns where a lot of clients
could slow down other users connections
0.25
---
+ Added multicore and HTTPS support
@@ -0,0 +1,27 @@
# sshttp Makefile
CXX=c++
CFLAGS=-c -O2 -Wall
CFLAGS+=-DUSE_CAPS
LD=ld
LIBS=-lcap
all: socket.o main.o sshttp.o multicore.o
$(CXX) *.o $(LIBS) -o sshttpd
clean:
rm -rf *.o sshttpd
multicore.o: multicore.cc multicore.h
$(CXX) $(CFLAGS) multicore.cc
sshttp.o: sshttp.cc sshttp.h
$(CXX) $(CFLAGS) -ansi -pedantic sshttp.cc
main.o: main.cc
$(CXX) $(CFLAGS) -ansi -pedantic main.cc
socket.o: socket.cc socket.h
$(CXX) -DLINUX26 $(CFLAGS) -ansi -pedantic socket.cc
49 README
@@ -0,0 +1,49 @@
sshttp - hiding a SSH server behind a HTTP server
=================================================
In case your FW policy forbids SSH access to the DMZ or internal
network from outside, but you still want to use SSH on machines
which only have one open port, e.g. HTTP, you can use "sshttpd".
sshttpd is an easy to use OSI-Layer5 switching daemon. It runs
transparently on HTTP port (-L switch, default 80) and decides
on incoming connections whether this is SSH or HTTP traffic.
If its HTTP traffic it switches the traffic to the HTTP_PORT
(-H, default 8080) and if its SSH traffic to SSH_PORT (-S, default
22) respectively.
You might need to edit "nf-setup" script to match your ports (22, 80 and 8080
are just fine) and run it to install the proxy rules.
Your sshd has to run on $SSH_PORT and your webserver on $HTTP_PORT.
Thats basically it. Go ahead and run sshttpd (as root) and it will layer5-switch
your traffic destinated to TCP port 80.
You dont need to patch any of your ssh/web client or server software. It
works as is. sshttpd runs only on Linux and needs IP_TRANSPARENT support.
It would work without, but by using IP_TRANSPARENT it is possible to even
have unmodified syslogs, e.g. the original source IP/port of incoming connections
is passed as-is to the SSH/HTTP servers.
sshttpd is also a tricky anti-SSH0day (if ever:) and anti SSH-scanning/bruteforcing
measurement.
sshttpd has small footprint and was optimized for speed so it also runs
on heavily loaded web servers.
Since version 0.24, sshttpd also supports multiple CPU cores. Unless
"-n 1" is used as switch, sshttpd binds one thread per CPU core,
to better exploit the hardware if running on heavily used web servers.
It still runs this fixed number of threads no matter how many 1000s connection
it handles at the same time.
sshttpd also runs as user nobody in a chroot now (configurable via -U and -R switch)
if compiled with USE_CAPS. It can now also distinguish between SSH and SSL
sessions, you just have to use an LOCAL_PORT of 443 or 4433 and change
the HTTP_PORT in the nf-setup script to match your webservers HTTPS port.
You cannot mix HTTP/SSH and HTTPS/SSH in one sshttpd instance but you can
run two sshttpd's to reach that goal: one on LOCAL_PORT 80 and one on
LOCAL_PORT 443.
If you want to use the least-privilege feature you need to
install libcap and libcap-devel packages.
Hints/bug reports beyond RTFM to sebastian.krahmer [at] gmail com.
@@ -0,0 +1,14 @@
#ifndef __config_h__
#define __config_h__
#include <stdint.h>
namespace Config
{
extern uint16_t ssh_port, http_port, local_port;
extern std::string root, user;
extern int cores, master;
}
#endif
208 main.cc
@@ -0,0 +1,208 @@
/*
* Copyright (C) 2010 Sebastian Krahmer.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Sebastian Krahmer.
* 4. The name Sebastian Krahmer may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <syslog.h>
#include <unistd.h>
#include <stdint.h>
#include <cstdlib>
#include <cstdio>
#include <cerrno>
#include <cstring>
#include <signal.h>
#include <fcntl.h>
#include <string>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <sys/time.h>
#include <sys/resource.h>
#ifdef USE_CAPS
#include <sys/prctl.h>
#include <sys/capability.h>
#endif
#include "sshttp.h"
#include "multicore.h"
using namespace std;
namespace Config
{
uint16_t ssh_port = 22, http_port = 8080, local_port = 80;
string root = "/var/lib/empty", user = "nobody";
int cores = -1, master = 1;
}
void die(const char *s)
{
perror(s);
exit(errno);
}
void close_fds()
{
struct rlimit rl;
if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
die("getrlimit");
for (unsigned int i = 3; i <= rl.rlim_max; ++i)
close(i);
close(0);
open("/dev/null", O_RDWR);
dup2(0, 1);
}
int main(int argc, char **argv)
{
int c;
while ((c = getopt(argc, argv, "S:H:L:R:U:n:")) != -1) {
switch (c) {
case 'S':
Config::ssh_port = atoi(optarg);
break;
case 'H':
Config::http_port = atoi(optarg);
break;
case 'L':
Config::local_port = atoi(optarg);
break;
case 'R':
Config::root = optarg;
break;
case 'U':
Config::user = optarg;
break;
case 'n':
Config::cores = atoi(optarg);
break;
default:
printf("sshttpd [-n CPU cores] [-S ssh port] [-H http port] [-L local port] ");
#ifdef USE_CAPS
printf("[-U user] [-R chroot]");
#endif
printf("\n");
exit(1);
}
}
printf("sshttpd: Using HTTP_PORT=%d SSH_PORT=%d and local port=%d. Going background.",
Config::http_port, Config::ssh_port, Config::local_port);
#ifdef USE_CAPS
printf(" Using caps/chroot.");
#endif
printf("\n");
close_fds();
openlog("sshttpd", LOG_NOWAIT|LOG_PID|LOG_NDELAY, LOG_DAEMON);
sshttp sh;
if (sh.init(Config::local_port) < 0) {
fprintf(stderr, "%s", sh.why());
exit(errno);
}
NS_Misc::init_multicore();
NS_Misc::setup_multicore(Config::cores);
#ifdef USE_CAPS
struct passwd *pw = getpwnam(Config::user.c_str());
if (!pw)
die("unknown user:getpwnam");
if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0)
die("prctl");
if (chroot(Config::root.c_str()) < 0)
die("chroot");
if (setgid(pw->pw_gid) < 0)
die("setgid");
if (initgroups(Config::user.c_str(), pw->pw_gid) < 0)
die("initgroups");
if (setuid(pw->pw_uid) < 0)
die("setuid");
// CAP_NET_BIND_SERVICE because we bind to original
// source/port which might be privileged
cap_t my_caps;
cap_value_t cv[2] = {CAP_NET_ADMIN, CAP_NET_BIND_SERVICE};
if ((my_caps = cap_init()) == NULL)
die("cap_init");
if (cap_set_flag(my_caps, CAP_EFFECTIVE, 2, cv, CAP_SET) < 0)
die("cap_set_flag");
if (cap_set_flag(my_caps, CAP_PERMITTED, 2, cv, CAP_SET) < 0)
die("cap_set_flag");
if (cap_set_proc(my_caps) < 0)
die("cap_set_proc");
cap_free(my_caps);
#endif
if (chdir("/") < 0)
die("chdir");
if (Config::master) {
if (fork() > 0)
exit(0);
setsid();
}
dup2(0, 2);
sh.ssh_port(Config::ssh_port);
sh.http_port(Config::http_port);
syslog(LOG_ERR, "sshttpd started, ready to rock");
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = SIG_IGN;
if (sigaction(SIGINT, &sa, NULL) < 0 ||
sigaction(SIGPIPE, &sa, NULL) < 0 ||
sigaction(SIGURG, &sa, NULL) < 0 ||
sigaction(SIGHUP, &sa, NULL) < 0)
syslog(LOG_ERR, "Nuts?! Failed to set signal handlers.");
for (;;) {
if (sh.loop() < 0)
syslog(LOG_ERR, "%s", sh.why());
}
return 0;
}
Oops, something went wrong.

0 comments on commit 95252ac

Please sign in to comment.