Nmap Development mailing list archives

[nmap] set source port in unprivileged mode


From: Simone Chiarelli <simchi88 () gmail com>
Date: Sat, 3 Jan 2015 03:47:56 +0100

It’s possible to set source port in tcp/connect scan mode even while unprivileged (for ports higher than 1023).
Would it be feasible to add such feature to nmap?
Following code is PoC:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>

typedef unsigned short port;
typedef char * host;
typedef int sock;

int timeval_subtract(struct timeval *x, struct timeval *y, struct timeval *result);
int socket_wait(int sock, long sec, int usec, int r, int w);

int main(int argc, char *argv[]){
        int errn = EXIT_SUCCESS;
        if(argc-1 < 4){
                fprintf(stderr, "%s <srcport> <target> <port> <timeout ms>\n", argv[0]);
                exit(EXIT_FAILURE);
        }
        port srcPort = atoi(argv[1]);
        host targetHost = argv[2];
        port dstPort = atoi(argv[3]);
        int usecTimeOut = atoi(argv[4])*1000;

        //Resolve host
        struct hostent *endPointEntry = gethostbyname(targetHost);
        if(endPointEntry == NULL){
                herror(targetHost);
                exit(EXIT_FAILURE);
        }

        struct in_addr *targetAddr = (struct in_addr *)*endPointEntry->h_addr_list;
        // printf("Resolved Address: %s\n", inet_ntoa(*targetAddr));

        //Create socket
        sock endPointSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if(endPointSocket == -1){
                perror("Could not create socket");
                exit(EXIT_FAILURE);
        }

        //Set socket options
        int on = 1;

        if(setsockopt(endPointSocket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1){
                perror("setsockopt");
                errn = EXIT_FAILURE;
                goto cleanAndExit;
        }

        if(setsockopt(endPointSocket, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)) == -1){
                perror("setsockopt");
                errn = EXIT_FAILURE;
                goto cleanAndExit;
        }

        //Set lingering in order to send rst after successfull connection
        struct linger lingerOpt = {0};
        lingerOpt.l_onoff = 1;
        lingerOpt.l_linger = 0;

        if (setsockopt(endPointSocket, SOL_SOCKET, SO_LINGER, (const char *) &lingerOpt, sizeof(lingerOpt)) != 0){
                perror("setsockopt");
                errn = EXIT_FAILURE;
                goto cleanAndExit;
        }

        //Set non-blocking
        if(fcntl(endPointSocket, F_SETFL, O_NONBLOCK) == -1){
                perror("fcntl");
                errn = EXIT_FAILURE;
                goto cleanAndExit;
        }

        struct sockaddr_in bindAddr = {0};
        bindAddr.sin_family = AF_INET;
        bindAddr.sin_addr.s_addr = htonl(INADDR_ANY);
        bindAddr.sin_port = htons(srcPort);

        if(bind(endPointSocket, (struct sockaddr *) &bindAddr, sizeof(bindAddr)) == -1){
                fprintf(stderr, "Could not bind to INADDR_ANY:%hu (err: %s)\n", srcPort, strerror(errno));
                errn = EXIT_FAILURE;
                goto cleanAndExit;
        }

        // printf("Bound to INADDR_ANY:%hu\n", srcPort);

        struct sockaddr_in endPointAddr = {0};
        endPointAddr.sin_family = AF_INET;
        endPointAddr.sin_addr = *targetAddr;
        endPointAddr.sin_port = htons(dstPort);

        // struct timeval start = {0};
        // if(gettimeofday(&start, NULL) != 0){
        //      perror("gettimeofday");
        //      errn = EXIT_FAILURE;
        //      goto cleanAndExit;
        // }

        connect(endPointSocket, (struct sockaddr *) &endPointAddr, sizeof(endPointAddr));

        int werr = socket_wait(endPointSocket, 0, usecTimeOut, 1, 1);
        errn = errno;

        // struct timeval end = {0};
        // gettimeofday(&end, NULL);

        // struct timeval lapse = {0};
        // timeval_subtract(&end, &start, &lapse);

        // printf("Elapsed: %ld.%06d sec(s)\n", lapse.tv_sec, lapse.tv_usec);

        if(werr < 0){
                fprintf(stderr, "Could not connect to %s:%hu (err: %s)\n", targetHost, dstPort, strerror(errn));
                errn = EXIT_FAILURE;
                goto cleanAndExit;
        }

        printf("Connected to %s:%hu\n", targetHost, dstPort);

cleanAndExit:
        close(endPointSocket);
        return errn;
}

int socket_wait(int sock, long sec, int usec, int r, int w)
{
    struct timeval tv = {0,0};
    fd_set fdset;
    fd_set *rfds, *wfds;
    int n, so_error;
    unsigned so_len;

    FD_ZERO (&fdset);
    FD_SET  (sock, &fdset);
    tv.tv_sec = sec;
    tv.tv_usec = usec;

    if (r) rfds = &fdset; else rfds = NULL;
    if (w) wfds = &fdset; else wfds = NULL;

    while ((n = select (sock+1, rfds, wfds, NULL, &tv)) == -1 && errno == EINTR);
    switch (n) {
    case 0:
        //perror ("wait timed out");
        return -errno;
    case -1:
        perror ("error during wait");
        return -errno;
    default:
        so_len = sizeof(so_error);
        so_error = 0;
        getsockopt (sock, SOL_SOCKET, SO_ERROR, &so_error, &so_len);
        if (so_error == 0)
            return 0;
        errno = so_error;
        return -errno;
    }
}

int timeval_subtract(struct timeval *x, struct timeval *y, struct timeval *result)
{
        if (x->tv_usec < y->tv_usec) {
                int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
                y->tv_usec -= 1000000 * nsec;
                y->tv_sec += nsec;
        }
        if (x->tv_usec - y->tv_usec > 1000000) {
                int nsec = (x->tv_usec - y->tv_usec) / 1000000;
                y->tv_usec += 1000000 * nsec;
                y->tv_sec -= nsec;
        }

        result->tv_sec = x->tv_sec - y->tv_sec;
        result->tv_usec = x->tv_usec - y->tv_usec;

        return x->tv_sec < y->tv_sec;
}
_______________________________________________
Sent through the dev mailing list
http://nmap.org/mailman/listinfo/dev
Archived at http://seclists.org/nmap-dev/

Current thread: