[ previous ] [ next ] [ threads ]
 
 From:  Dirk-Willem van Gulik <dirkx at webweaving dot org>
 To:  Brandon Holland <brandon at cookssaw dot com>
 Cc:  "'Falcor'" <falcor at netassassin dot com>, m0n0wall at lists dot m0n0 dot ch
 Subject:  RE: [m0n0wall] windows built in "ident"...
 Date:  Tue, 30 Dec 2003 14:29:48 -0800 (PST)
> If I had something that actually needed a "correct" ident response
> (maybe there are still some IRC servers out there that must "qualify"
> you?) maybe then, if those IRC servers were important, I'd do it. BUT: I
> still wouldn't want a port forward straight into my LAN.

Yes there are; I use something called oidentd which I hacked to always
give the same reply:

default {
        default {
                force reply "chuck at webweaving dot org"
        }
}

before that I used the code below. Feel free to hack it - it needs some
cleanup, modernizing, error trapping, checks for buffer overruns and to be
nice; we should actually pick up the comma separated ports and echo them
in the reply. (And do this in such a way that it does not easily lead to
dos-es, etc, etc).

Dw

/* (c) 2001 Dirk-Willem van Gulik, All Rights Reserved.
 *     See http://www.webweaving.org/LICENSE for the license
 */

#define USAGE "identd [-d] [ip:port]\n"

#include <ctype.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/socket.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <signal.h>
#include <term.h>
#include <sys/select.h>
#include <sys/time.h>
#include <syslog.h>
#include <stdarg.h>

int verbose = 0;

#define pdie(x) { perror(x); exit(4); }

#ifndef max
#define   max(a,b)        (a > b ? a : b)
#endif

#define BLOG (25)       /* Listen queue */
#define TIMEOUT (10)    /* 10 second timeout */
#define REPLY           "1 , 1 : USERID : OTHER :
chuck at webweaving dot org\r\n"
                        /* http://www.webweaving.org/chuck */

void usage() {
        fprintf(stderr,USAGE);
        exit(1);
}

void sigpipe( int in ) {
        return;
}

int string2sockaddr(
        struct sockaddr * out, char * in,
        unsigned long ip,
        unsigned short port
        )
{
        char * c = strchr(in,':');
        if (c) {
                *c = '\0'; c++;
                port = atoi(c);
                if (port == 0 && c[0] != '0') {
                        struct servent * e = getservbyname( c, "tcp" );
                        if (!e) {
                                fprintf(stderr,"No port number for
Protocol '%s'",c);
                                return -2;
                        };
                        port = e->s_port;
                };
        };
#ifndef INADDR_NONE
#define INADDR_NONE     (-1)    /* 255.255.255.255 bkptr */
#endif
        if ((in[0] != '\0') && ((ip = inet_addr(in)) == INADDR_NONE)) {
                struct hostent * e = gethostbyname(in);
                if (e == NULL) {
                        fprintf(stderr,"No IP address for  host
'%s'\n",in);
                        return -3;
                };
                if (e->h_addrtype != AF_INET) {
                        fprintf(stderr,"No IPv4 address for  host
'%s'\n",in);
                        return -3;
                };
                ip = ((unsigned long *)(e->h_addr_list[0]))[0];
                if ((e->h_addr_list[5] != 0))
                        fprintf(stderr,"Warning - "
                          "more than one IP address for '%s' - taking
first\n",in);
        };
#if BSD
        ((struct sockaddr_in *)out)->sin_len = sizeof(struct sockaddr_in);
#endif
        ((struct sockaddr_in *)out)->sin_family = AF_INET;
        ((struct sockaddr_in *)out)->sin_port = htons( port );
        ((struct sockaddr_in *)out)->sin_addr.s_addr = htonl( ip );
        if (verbose)
                printf("Interface and port: %s:%d\n",
                        inet_ntoa((((struct sockaddr_in
*)out)->sin_addr)),
                        ntohs(((struct sockaddr_in *)out)->sin_port));
        return 0;
}

int main ( int argc, char ** argv )
{
     extern char *optarg;
     extern int optind;
     struct sockaddr in;
     char ch;
     const int yes = 1;
     int blog = BLOG;
     int s;
     char * myname = argv[0];

     while ((ch = getopt(argc, argv, "qmivo:")) != -1)
             switch(ch) {
             case 'v':  verbose = 1;
                        break;
             case 'h':  /* no break */
             case '?':  /* no break */
             default:   usage();
                        break;
        }

     argc -= optind;
     argv += optind;

     if (argc > 1)
                usage();

     if (verbose)
        printf("Inbound (i.e. listening to)\n\t");
     else
        openlog(myname,LOG_CONS|LOG_NDELAY,LOG_DAEMON); /* no error
returned */

     if (argc == 0)
        argv[0] = strdup(":113");

     if (string2sockaddr( &in,argv[0],INADDR_ANY,0))
                exit(2);

     if ((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
                pdie("Failed to open socket");

     if (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes)) < 0)
                pdie("Set socket reuse");

     if(bind(s, &in,sizeof(in)))
                pdie("Failed to bind in-port");

     if (listen(s,blog) <0)
                pdie("Listen");

     if (verbose)
                printf("Ident waiting for requests\n");
     else
        daemon(0,0);

     signal(SIGPIPE,&sigpipe);

     while(1) {
        struct sockaddr con;
        int len = sizeof(con);
        int cons = accept(s,&con,&len);
        struct timeval to;
        int noreply = 1;
        int written = 0;

        if (cons == -1) {
                perror("Error on accept");
                continue;
        };

        if (verbose)
                printf("Incoming: %s:%d\n",
                        inet_ntoa((((struct sockaddr_in
*)&con)->sin_addr)),
                        ntohs(((struct sockaddr_in *)&con)->sin_port));

        to.tv_sec = TIMEOUT;
        to.tv_usec = 0;
        do {
                unsigned char buff[ 4 * 1024 +1 ];
                fd_set  * lst = malloc(cons+1),
                        * xst = malloc(cons+1),
                        * wst = malloc(cons+1);
                int n;

                FD_ZERO(lst); FD_ZERO(xst); FD_ZERO(wst);

                if (noreply)
                        FD_SET(cons,lst);
                else
                        FD_SET(cons,wst);

                n = select(cons+1,lst,wst,xst,&to);

                if (n == 0) {
                        if (verbose)
                                printf("Timeout waiting\n");
                        break;
                }
                else
                if ((n == -1) && (errno == EAGAIN))
                        continue;
                else
                if (n == -1) {
                        if (verbose)
                                fprintf(stderr,"Select error:%s\n",
                                        strerror(errno));
                        else
                                syslog(LOG_ERR,"identd select error:%s\n",
                                        strerror(errno));
                        break;
                }

                if (FD_ISSET(cons,xst))
                        break;

                if (noreply) {
                        memset(buff,sizeof(buff),0);
                        n = read(cons,buff,sizeof(buff));
                } else {
                        n =
write(cons,REPLY+written,sizeof(REPLY)-written);
                        printf("Written reply\n");
                };

                if (n == 0)
                        break; /* normal close */
                else
                if ((n == -1) && (errno == EAGAIN))
                        continue; /* normal interrupt. */
                else
                if (n == -1) {
                        if (verbose)
                                fprintf(stderr,"I/O error:%s\n",
                                        strerror(errno));
                        else
                                syslog(LOG_ERR,"identd i/o error:%s\n",
                                        strerror(errno));
                        break;
                }

                if (noreply) {
                        while(n>0) {
                                n--;
                                if ((buff[n] == '\r') || (buff[n] ==
'\n')) {
                                        noreply = 0;
                                        n = 0;
                                        // shutdown(cons,SHUT_RD);
                                }
                        }
                        if (noreply)
                                noreply ++;
                } else {
                        written += n;
                        if (written >= sizeof(REPLY))
                                break;
                }
        } while (noreply < 3);
        if (verbose)
                printf("And closing\n");
        shutdown(cons,SHUT_WR);
        close(cons);

     } while(1);
     /* NOT REACHED */
}