|
||||||||||
> 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 */ } |