// file: tcprobe.cpp, Marcus Fritzsch , 20050328 // // $Id: tcprobe.cpp,v 1.6 2005/04/08 15:08:32 m Exp $ // // vim: set ts=2 // // The backtrace and SignalTranslator code is derived/adopted from // 'C++ exception-handling tricks for Linux' by sachin_agrawal // - try googling for it! // // some words about the following code: // I wrote these classes to get the c-sockets interface (currently // only inet) to c++. All errno codes are translated to the OSError // exception (which has a backtrace and a message telling you about // what failed) - in addition, I added code to translate SIGX to // Exceptions - this comes in really handy when debugging ;) // // compile: g++ -rdynamic tcprobe.cpp -O0 -o tcprobe // note: -rdynamic is needed to get backtrace symbol names! #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // SYSWRAP: // __Ret__ variable to store syscall ret-val // __What__ complete system call. e.g. write (1,"Hi", 2) // __ErrMsg__ message for OSError exception // // example: // SYSWRAP(numBytes, write (2, "error\n", 6), "write failed"); // --> this one will throw an OSError exception with respective // errno and the message given (also, a backtrace will be // stored in the exception #define SYSWRAP(__Ret__,__What__,__ErrMsg__) \ { \ int __R__ = -1; \ while ((__R__ = __What__) < 0 && errno == EINTR) \ ; \ if (__R__ < 0) \ throw OSError (__ErrMsg__); \ __Ret__ = __R__; \ } // just in case I don't need the return of the call #define SYSWRAP2(__What__,__ErrMsg__) \ { \ int __R__ = -1; \ while ((__R__ = __What__) < 0 && errno == EINTR) \ ; \ if (__R__ < 0) \ throw OSError (__ErrMsg__); \ } // enable backtrace on exception //#define BACK_TRACE typedef sockaddr_in SAI; typedef sockaddr SA; typedef timeval TV; typedef in_addr IA; typedef hostent HE; using namespace std; //////////////////////////////////////////////////////////////////////////// // class ExceptionTracer class ExceptionTracer : public exception { protected: #ifdef BACK_TRACE char * array [30]; char ** m_tbsyms; int m_size; #endif public: ExceptionTracer () throw () { #ifdef BACK_TRACE void * array[30]; m_size = ::backtrace (array, 30); // OK... how the f... I free m_tbsyms when I donÄt need it anymore?!? m_tbsyms = backtrace_symbols (array, m_size); #endif } void backtrace (ostream & os = cout) throw () { #ifdef BACK_TRACE os << "++++ backtrace:" << endl; for (int i = 1; i < m_size; i++) // skip first, ie ExceptionTracer () os << '\t' << setw (2) << i-1 << ": " << m_tbsyms [i] << endl; m_size = 0; m_tbsyms = 0; os << endl; #endif } virtual ~ExceptionTracer () throw () { #ifdef BACK_TRACE free (m_tbsyms); #endif } }; // class ExceptionTracer //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// // class Exception class Exception : public ExceptionTracer { protected: const char * m_msg; public: Exception () throw () : ExceptionTracer () { m_msg = ""; } Exception (const char * m) throw () : ExceptionTracer () { m_msg = m; } virtual const char * what () throw () { ostringstream os; os << "Exception: " << m_msg << endl; #ifdef BACK_TRACE backtrace (os); #endif return os.str ().c_str (); } virtual ~Exception () throw () { } }; // class Exception //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// // class OSError class OSError : public Exception { int m_errno; public: OSError () throw () : Exception () { m_errno = errno; } OSError (const char * m) throw () : Exception (m) { m_errno = errno; } virtual const char * what () throw () { ostringstream os; os << "OSError: " << m_msg << ": " << strerror (m_errno) << " (" << m_errno << ")" << endl; backtrace (os); return os.str ().c_str (); } int Errno () const throw () { return m_errno; } virtual ~OSError () throw () { } }; // class OSError //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// // class SignalTranslator template class SignalTranslator { private: class SingleTonTranslator { public: SingleTonTranslator () { signal(SignalExceptionClass::GetSignalNumber (), SignalHandler); } static void SignalHandler (int) { throw SignalExceptionClass (); } }; public: SignalTranslator () { static SingleTonTranslator translator; } }; class SegmentationFault : public Exception { public: static int GetSignalNumber () { return SIGSEGV; } }; SignalTranslator SegmentationFaultTranslator; class InterruptException : public Exception { public: static int GetSignalNumber () { return SIGINT; } }; SignalTranslator InterruptExceptionTranslator; // class SignalTranslator //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// // class Address class Address { IA m_addr; public: Address (); Address (string h); string host (); void host (string h); // static for on-the-fly use :o) static IA addr (string h); IA addr () const; // static, to be used from static addr static IA fromString (string s); friend ostream & operator << (ostream & os, Address a) { os << a.host (); return os; } }; Address::Address () { m_addr = fromString ("0.0.0.0"); } Address::Address (string h) { m_addr = fromString (h); } IA Address::fromString (string s) { HE * he; IA a; if (!(he = gethostbyname (s.c_str ()))) throw Exception ("Address::fromString gethostbyname failed"); // need to (deep)copy what I need! memcpy (&a, he->h_addr, sizeof (he->h_addr)); return a; } string Address::host () { char * buf; if (! (buf = inet_ntoa (m_addr))) throw Exception ("Address::host inet_ntoa failed!"); return buf; } void Address::host (string h) { m_addr = fromString (h); } IA Address::addr (string h) { return fromString (h); } IA Address::addr () const { return m_addr; } // class Address //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// // class SocketAddress class SocketAddress { SAI m_sockaddr; SAI get_sockaddr_in (string h, unsigned short p); public: SocketAddress () {} SocketAddress (SAI sai); SocketAddress (string h, unsigned short p); SocketAddress (Address a, unsigned short p); SocketAddress (unsigned short p); // shorthand for binds to 0.0.0.0:p unsigned short port () const; void port (unsigned short p); string host (); void host (string h); SAI addr () const; friend ostream & operator << (ostream & os, SocketAddress sa) { os << sa.host () << ':' << sa.port (); return os; } }; SAI SocketAddress::get_sockaddr_in (string h, unsigned short p) { SAI sai; sai.sin_addr = Address::fromString (h); sai.sin_port = htons (p); sai.sin_family = AF_INET; return sai; } SocketAddress::SocketAddress (SAI sai) { m_sockaddr = sai; } SocketAddress::SocketAddress (string h, unsigned short p) { m_sockaddr = get_sockaddr_in (h, p); } SocketAddress::SocketAddress (Address a, unsigned short p) { m_sockaddr.sin_port = htons (p); m_sockaddr.sin_family = AF_INET; m_sockaddr.sin_addr = a.addr (); } SocketAddress::SocketAddress (unsigned short p) { m_sockaddr = get_sockaddr_in ("0.0.0.0", p); } unsigned short SocketAddress::port () const { return ntohs (m_sockaddr.sin_port); } void SocketAddress::port (unsigned short p) { m_sockaddr.sin_port = htons (p); } string SocketAddress::host () { char * b; if (! (b = inet_ntoa (m_sockaddr.sin_addr))) throw Exception ("SocketAddress::host inet_ntoa failed!"); return b; } void SocketAddress::host (string h) { m_sockaddr = get_sockaddr_in (h, ntohs (m_sockaddr.sin_port)); } SAI SocketAddress::addr () const { return m_sockaddr; } // class SocketAddress //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// // class Socket class Socket { int m_fd; SocketAddress m_addr; int m_backlog; int m_type; int m_proto; int do_socket_call (); public: Socket (int fd); Socket (int fd, SAI sai); Socket (SocketAddress sa, int type, int proto); Socket (string h, unsigned short p, int type, int proto); Socket (Address h, unsigned short p, int type, int proto); Socket (unsigned short p, int type, int proto); ~Socket () { close (); } void connect (); // for these two, buf has to be a valid buffer to buflen bytes int recv (char * buf, int buflen, int flags = 0); int recvfrom (char * buf, int buflen, int flags = 0); // the next two take a pointer to a buffer, which then is // allocated through new buflen bytes // NOTE: yes, these are to be delete[]d ;) int recv (char ** bufp, int buflen, int flags = 0); int recvfrom (char ** bufp, int buflen, SocketAddress from, int flags = 0); int send (char * buf, int buflen, int flags = 0); int sendto (char * buf, int buflen, int flags = 0); int sendto (char * buf, int buflen, SocketAddress to, int flags = 0); void bind (); void listen (int backlog); Socket accept (); void shutdown (int how); void close (); int addflags (int flags); int subflags (int flags); // some accessors... SocketAddress sockaddr () const { return m_addr; } int fd () const { return m_fd; } int backlog () const { return m_backlog; } int type () const { return m_type; } int proto () const { return m_proto; } void sockaddr (SocketAddress sa) { m_addr = sa; } void fd (int f) { m_fd = f; } void backlog (int bl) { m_backlog = bl; } void type (int t) { m_type = t; } void proto (int p) { m_proto = p; } }; int Socket::do_socket_call () { int s = -1; SYSWRAP(s, socket (PF_INET, m_type, m_proto), "socket"); int v = 1; SYSWRAP2(setsockopt (s, SOL_SOCKET, SO_REUSEADDR, &v, sizeof v), "setsockopt"); return s; } Socket::Socket (int fd) { SAI sai; int l; m_fd = fd; SYSWRAP2(getsockname (m_fd, (SA *) &sai, (socklen_t *) &l), "getsockname"); m_addr = SocketAddress (sai); l = sizeof m_type; SYSWRAP2(getsockopt (m_fd, SOL_SOCKET, SO_TYPE, &m_type, (socklen_t *) &l), "getsockopt"); m_backlog = 1; m_proto = m_type == SOCK_STREAM ? IPPROTO_TCP : IPPROTO_UDP; } Socket::Socket (int fd, SAI sai) { int l; m_fd = fd; m_addr = SocketAddress (sai); l = sizeof m_type; SYSWRAP2(getsockopt (m_fd, SOL_SOCKET, SO_TYPE, &m_type, (socklen_t *) &l), "getsockopt"); m_backlog = 1; m_proto = m_type == SOCK_STREAM ? IPPROTO_TCP : IPPROTO_UDP; } Socket::Socket (SocketAddress sa, int type, int proto) { m_addr = sa; m_type = type; m_proto = proto; m_backlog = 1; m_fd = do_socket_call (); } Socket::Socket (string h, unsigned short p, int type, int proto) { m_addr = SocketAddress (h, p); m_type = type; m_proto = proto; m_backlog = 1; m_fd = do_socket_call (); } Socket::Socket (Address h, unsigned short p, int type, int proto) { m_addr = SocketAddress (h, p); m_type = type; m_proto = proto; m_backlog = 1; m_fd = do_socket_call (); } Socket::Socket (unsigned short p, int type, int proto) { m_addr = SocketAddress (p); m_type = type; m_proto = proto; m_backlog = 1; m_fd = do_socket_call (); } void Socket::connect () { int r; SYSWRAP(r, ::connect (m_fd, (SA *) &m_addr.addr (), sizeof (SA)), "connect"); } int Socket::recv (char * buf, int buflen, int flags) { int n = 0; SYSWRAP(n, ::recv (m_fd, buf, buflen, flags), "recv"); return n; } int Socket::recvfrom (char * buf, int buflen, int flags) { int n = 0; int l; SYSWRAP(n, ::recvfrom (m_fd, buf, buflen, flags, (SA *) &m_addr.addr (), (socklen_t *) &l), "recvfrom"); return n; } int Socket::recv (char ** bufp, int buflen, int flags) { int n = 0; *bufp = new char [buflen]; SYSWRAP(n, ::recv (m_fd, *bufp, buflen, flags), "recv"); return n; } int Socket::recvfrom (char ** bufp, int buflen, SocketAddress from, int flags) { int n = 0, l = sizeof from; *bufp = new char [buflen]; SYSWRAP(n, ::recvfrom (m_fd, *bufp, buflen, flags, (SA *) &from.addr (), (socklen_t *) &l), "recvfrom"); return n; } int Socket::send (char * buf, int buflen, int flags) { int n = 0; SYSWRAP(n, ::send (m_fd, buf, buflen, flags), "send"); return n; } int Socket::sendto (char * buf, int buflen, int flags) { int n = 0; SYSWRAP(n, ::sendto (m_fd, buf, buflen, flags, (SA *) &m_addr.addr (), sizeof (SA)), "sendto"); return n; } int Socket::sendto (char * buf, int buflen, SocketAddress to, int flags) { int n = 0; SYSWRAP(n, ::sendto (m_fd, buf, buflen, flags, (SA *) &to.addr (), sizeof (to)), "sendto"); return n; } void Socket::bind () { SYSWRAP2(::bind (m_fd, (SA *) &m_addr.addr (), sizeof (SA)), "bind"); } void Socket::listen (int backlog) { m_backlog = backlog; SYSWRAP2(::listen (m_fd, backlog), "listen"); } Socket Socket::accept () { SAI sai; int l = sizeof (SAI), r = -1; bzero (&sai, sizeof (SAI)); SYSWRAP(r, ::accept (m_fd, (SA *) &sai, (socklen_t *) &l), "accept"); return Socket (r, sai); } void Socket::shutdown (int how) { try { SYSWRAP2(::shutdown (m_fd, how), "shutdown/SHUT_RDWR"); } catch (OSError & e) { if (e.Errno () != ENOTCONN) // this one is not critical... throw; } } void Socket::close () { shutdown (SHUT_RDWR); try { SYSWRAP2(::close (m_fd), "close"); } catch (OSError & e) { if (e.Errno () != EBADF) throw; } } int Socket::addflags (int flags) { int fl; SYSWRAP(fl, fcntl (m_fd, F_GETFL), "fcntl/F_GETFL"); fl |= flags; SYSWRAP2(fcntl (m_fd, F_SETFL, fl), "fcntl/F_SETFL"); return fl; } int Socket::subflags (int flags) { int fl; SYSWRAP(fl, fcntl (m_fd, F_GETFL), "fcntl/F_GETFL"); fl &= ~flags; SYSWRAP2(fcntl (m_fd, F_SETFL, fl), "fcntl/F_SETFL"); return fl; } // class Socket //////////////////////////////////////////////////////////////////////////// unsigned short ports [] = { 1, 7, 9, 11, 13, 15, 17, 18, 19, 20, 21, 22, 23, 25, 37, 42, 43, 49, 50, 53, 57, 65, 67, 68, 70, 77, 79, 80, 87, 88, 95, 98, 101, 102, 104, 105, 106, 107, 109, 110, 111, 113, 115, 117, 119, 123, 129, 135, 137, 138, 139, 143, 161, 162, 163, 164, 174, 177, 178, 179, 191, 194, 199, 201, 202, 204, 206, 209, 210, 213, 220, 345, 346, 347, 369, 370, 371, 372, 389, 406, 443, 444, 445, 465, 487, 500, 512, 513, 514, 515, 526, 530, 531, 532, 538, 540, 543, 544, 548, 554, 556, 563, 587, 607, 610, 611, 612, 631, 636, 655, 706, 749, 750, 751, 754, 760, 761, 765, 775, 777, 783, 808, 871, 873, 901, 989, 990, 992, 993, 994, 995, 1001, 1080, 1099, 1109, 1127, 1178, 1214, 1236, 1241, 1300, 1313, 1314, 1352, 1433, 1434, 1524, 1525, 1529, 1645, 1646, 1649, 1701, 1812, 1813, 1957, 1958, 1959, 2000, 2003, 2010, 2053, 2101, 2105, 2111, 2121, 2150, 2401, 2430, 2431, 2432, 2433, 2583, 2600, 2601, 2602, 2603, 2604, 2605, 2606, 2607, 2608, 2628, 2947, 2988, 2989, 3050, 3130, 3306, 3493, 3632, 3690, 4224, 4557, 4559, 4600, 4899, 4949, 5002, 5051, 5052, 5151, 5222, 5269, 5308, 5354, 5355, 5432, 5555, 5556, 5667, 5674, 5675, 5680, 6000, 6001, 6002, 6003, 6004, 6005, 6006, 6007, 6346, 6347, 6566, 6667, 7000, 7001, 7002, 7003, 7004, 7005, 7006, 7007, 7008, 7009, 7100, 8021, 8080, 8081, 8088, 9098, 9101, 9102, 9103, 9673, 10081, 10082, 10083, 11201, 11371, 15345, 17004, 20011, 20012, 22273, 24554, 27374, 57000, 60177, 60179, 0 }; //////////////////////////////////////////// // example on tcp-connect scanning a host // //////////////////////////////////////////// int main (int argc, char ** argv) { int i = 1; if (! argv [1]) { cerr << "usage: " << *argv << " host-to-scan" << endl; return !0; } Address theHost; try { theHost = Address (argv [1]); } catch (Exception & e) { cerr << e.what () << endl; return !0; } while (ports [i]) { try { Socket s (theHost, ports [i], SOCK_STREAM, IPPROTO_TCP); s.addflags (O_NONBLOCK); int count = 100; while (count) { try { s.connect (); cout << s.sockaddr (); char buf [100]; usleep (200000); // to get some data to recv... try { buf [s.recv (buf, 100)-1] = 0; cout << "\t" << buf; } catch (OSError & e) { if (e.Errno () != EAGAIN) throw; } cout << endl; break; } catch (OSError & err) { if (err.Errno () == ECONNREFUSED) break; if (err.Errno () != EINPROGRESS && err.Errno () != EALREADY) throw; usleep (5000); } --count; } } catch (Exception & exc) { cerr << exc.what () << endl; return !0; } ++i; } return 0; }