int match_cidr(const char *s1, const char *s2) { struct irc_inaddr ipaddr, maskaddr; char mask[BUFSIZE]; char address[NICKLEN + USERLEN + HOSTLEN + 6]; char *ipmask; char *ip; char *len; int cidrlen, aftype; strcpy(mask, s1); strcpy(address, s2); ipmask = strrchr(mask, '@'); if(ipmask == NULL) return 0; *ipmask++ = '\0'; ip = strrchr(address, '@'); if(ip == NULL) return 0; *ip++ = '\0'; len = strrchr(ipmask, '/'); if(len == NULL) return 0; *len++ = '\0'; cidrlen = atoi(len); if(cidrlen == 0) return 0; #ifdef IPV6 if(strchr(ip, ':') && strchr(ipmask, ':')) aftype = AF_INET6; else #endif if(!strchr(ip, ':') && !strchr(ipmask, ':')) aftype = AF_INET; else return 0; inetpton(aftype, ip, &ipaddr); inetpton(aftype, ipmask, &maskaddr); if(comp_with_mask(&IN_ADDR(ipaddr), &IN_ADDR(maskaddr), cidrlen) && match(mask, address)) return 1; else return 0; }
static void ccf_nameserver(adns_state ads, const char *fn, int lno, const char *buf) { struct in_addr ia; if (inetpton(AF_INET, buf,&ia) <=0) { configparseerr(ads,fn,lno,"invalid nameserver address `%s'",buf); return; } adns__debug(ads,-1,0,"using nameserver %s",inetntoa((char *)&ia)); addserver(ads,ia); }
static void connect_dns_callback(void* vptr, adns_answer* reply) #endif { struct ConfItem* aconf = (struct ConfItem*) vptr; aconf->dns_pending = 0; #ifndef USE_ADNS if (reply) { #ifdef IPV6 char name[HOSTLEN]; inet_ntop(AF_INET, reply->hp->h_addr, name, HOSTLEN); inetpton(AFINET, name, &aconf->ipnum); #else memcpy(&aconf->ipnum, reply->hp->h_addr, sizeof(struct in_addr)); #endif connect_server(aconf, 0, reply); #else if (reply && reply->status == adns_s_ok) { #ifdef IPV6 /* IPV6 connect lookup not working with ADNS -FIX- */ #else aconf->ipnum.s_addr = reply->rrs.addr->addr.inet.sin_addr.s_addr; #endif MyFree(reply); connect_server(aconf, 0, NULL); #endif } else sendto_realops("Connect to %s failed: host lookup", aconf->host); } /* * set_sock_buffers - set send and receive buffers for socket * returns true (1) if successful, false (0) otherwise */ int set_sock_buffers(int fd, int size) { if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char*) &size, sizeof(size)) || setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char*) &size, sizeof(size))) return 0; return 1; } /* * disable_sock_options - if remote has any socket options set, disable them * returns true (1) if successful, false (0) otherwise */ static int disable_sock_options(int fd) { #if defined(IP_OPTIONS) && defined(IPPROTO_IP) /* Broken on ipv6 - stu */ #ifndef IPV6 if (setsockopt(fd, IPPROTO_IP, IP_OPTIONS, NULL, 0)) return 0; #endif /* IPv6 */ #endif return 1; } /* * set_non_blocking - Set the client connection into non-blocking mode. * If your system doesn't support this, you're screwed, ircd will run like * crap. * returns true (1) if successful, false (0) otherwise */ int set_non_blocking(int fd) { /* * NOTE: consult ALL your relevant manual pages *BEFORE* changing * these ioctl's. There are quite a few variations on them, * as can be seen by the PCS one. They are *NOT* all the same. * Heed this well. - Avalon. */ /* This portion of code might also apply to NeXT. -LynX */ #ifdef NBLOCK_SYSV int res = 1; if (ioctl(fd, FIONBIO, &res) == -1) return 0; #else /* !NBLOCK_SYSV */ int nonb = 0; int res; #ifdef NBLOCK_POSIX nonb |= O_NONBLOCK; #endif #ifdef NBLOCK_BSD nonb |= O_NDELAY; #endif res = fcntl(fd, F_GETFL, 0); if (-1 == res || fcntl(fd, F_SETFL, res | nonb) == -1) return 0; #endif /* !NBLOCK_SYSV */ return 1; }
/* * add_listener- create a new listener * port - the port number to listen on * vhost_ip - if non-null must contain a valid IP address string in * the format "255.255.255.255" */ void add_listener(int port, const char *vhost_ip, int family) { struct Listener *listener; struct irc_sockaddr_storage vaddr; /* * if no port in conf line, don't bother */ if(port == 0) return; memset(&vaddr, 0, sizeof(vaddr)); vaddr.ss_family = family; if(vhost_ip != NULL) { if(family == AF_INET) { if(inetpton(family, vhost_ip, &((struct sockaddr_in *) &vaddr)->sin_addr) <= 0) return; } #ifdef IPV6 else { if(inetpton(family, vhost_ip, &((struct sockaddr_in6 *) &vaddr)->sin6_addr) <= 0) return; } #endif } else { switch (family) { case AF_INET: ((struct sockaddr_in *) &vaddr)->sin_addr.s_addr = INADDR_ANY; break; #ifdef IPV6 case AF_INET6: memcpy(&((struct sockaddr_in6 *) &vaddr)->sin6_addr, &in6addr_any, sizeof(struct in6_addr)); break; default: return; #endif } } switch (family) { case AF_INET: SET_SS_LEN(vaddr, sizeof(struct sockaddr_in)); ((struct sockaddr_in *) &vaddr)->sin_port = htons(port); break; #ifdef IPV6 case AF_INET6: SET_SS_LEN(vaddr, sizeof(struct sockaddr_in6)); ((struct sockaddr_in6 *) &vaddr)->sin6_port = htons(port); break; #endif default: break; } if((listener = find_listener(&vaddr))) { if(listener->fd > -1) return; } else { listener = make_listener(&vaddr); listener->next = ListenerPollList; ListenerPollList = listener; } listener->fd = -1; if(inetport(listener)) listener->active = 1; else close_listener(listener); }
/* * void comm_connect_tcp(int fd, const char *host, u_short port, * struct sockaddr *clocal, int socklen, * CNCB *callback, void *data, int aftype, int timeout) * Input: An fd to connect with, a host and port to connect to, * a local sockaddr to connect from + length(or NULL to use the * default), a callback, the data to pass into the callback, the * address family. * Output: None. * Side-effects: A non-blocking connection to the host is started, and * if necessary, set up for selection. The callback given * may be called now, or it may be called later. */ void comm_connect_tcp(int fd, const char *host, u_short port, struct sockaddr *clocal, int socklen, CNCB * callback, void *data, int aftype, int timeout) { void *ipptr = NULL; fde_t *F; s_assert(fd >= 0); F = &fd_table[fd]; F->flags.called_connect = 1; s_assert(callback); F->connect.callback = callback; F->connect.data = data; memset(&F->connect.hostaddr, 0, sizeof(F->connect.hostaddr)); #ifdef IPV6 if(aftype == AF_INET6) { struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&F->connect.hostaddr; SET_SS_LEN(F->connect.hostaddr, sizeof(struct sockaddr_in6)); in6->sin6_port = htons(port); in6->sin6_family = AF_INET6; ipptr = &in6->sin6_addr; } else #endif { struct sockaddr_in *in = (struct sockaddr_in *)&F->connect.hostaddr; SET_SS_LEN(F->connect.hostaddr, sizeof(struct sockaddr_in)); in->sin_port = htons(port); in->sin_family = AF_INET; ipptr = &in->sin_addr; } /* Note that we're using a passed sockaddr here. This is because * generally you'll be bind()ing to a sockaddr grabbed from * getsockname(), so this makes things easier. * XXX If NULL is passed as local, we should later on bind() to the * virtual host IP, for completeness. * -- adrian */ if((clocal != NULL) && (bind(F->fd, clocal, socklen) < 0)) { /* Failure, call the callback with COMM_ERR_BIND */ comm_connect_callback(F->fd, COMM_ERR_BIND); /* ... and quit */ return; } /* Next, if we have been given an IP, get the addr and skip the * DNS check (and head direct to comm_connect_tryconnect(). */ if(inetpton(aftype, host, ipptr) <= 0) { /* Send the DNS request, for the next level */ F->dns_query = MyMalloc(sizeof(struct DNSQuery)); F->dns_query->ptr = F; F->dns_query->callback = comm_connect_dns_callback; adns_gethost(host, aftype, F->dns_query); } else { /* We have a valid IP, so we just call tryconnect */ /* Make sure we actually set the timeout here .. */ comm_settimeout(F->fd, timeout * 1000, comm_connect_timeout, NULL); comm_connect_tryconnect(F->fd, NULL); } }
static int inetport(struct Listener* listener) { struct irc_sockaddr lsin; int fd; int opt = 1; /* * At first, open a new socket */ fd = comm_open(DEF_FAM, SOCK_STREAM, 0, "Listener socket"); #ifdef IPV6 if (!IN6_ARE_ADDR_EQUAL((struct in6_addr *)&listener->addr, &in6addr_any)) { #else if (INADDR_ANY != listener->addr.sins.sin.s_addr) { #endif inetntop(DEF_FAM, &IN_ADDR(listener->addr), listener->vhost, HOSTLEN); listener->name = listener->vhost; } if (fd == -1) { report_error(L_ALL, "opening listener socket %s:%s", get_listener_name(listener), errno); return 0; } else if ((HARD_FDLIMIT - 10) < fd) { report_error(L_ALL, "no more connections left for listener %s:%s", get_listener_name(listener), errno); fd_close(fd); return 0; } /* * XXX - we don't want to do all this crap for a listener * set_sock_opts(listener); */ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*) &opt, sizeof(opt))) { report_error(L_ALL, "setting SO_REUSEADDR for listener %s:%s", get_listener_name(listener), errno); fd_close(fd); return 0; } /* * Bind a port to listen for new connections if port is non-null, * else assume it is already open and try get something from it. */ memset(&lsin, 0, sizeof(struct irc_sockaddr)); S_FAM(lsin) = DEF_FAM; copy_s_addr(S_ADDR(lsin), IN_ADDR(listener->addr)); S_PORT(lsin) = htons(listener->port); if (bind(fd, (struct sockaddr*) &SOCKADDR(lsin), sizeof(struct irc_sockaddr))) { report_error(L_ALL, "binding listener socket %s:%s", get_listener_name(listener), errno); fd_close(fd); return 0; } if (listen(fd, HYBRID_SOMAXCONN)) { report_error(L_ALL, "listen failed for %s:%s", get_listener_name(listener), errno); fd_close(fd); return 0; } /* * XXX - this should always work, performance will suck if it doesn't */ if (!set_non_blocking(fd)) report_error(L_ALL, NONB_ERROR_MSG, get_listener_name(listener), errno); listener->fd = fd; /* Listen completion events are READ events .. */ accept_connection(fd, listener); return 1; } static struct Listener* find_listener(int port, struct irc_inaddr *addr) { struct Listener* listener = NULL; struct Listener* last_closed = NULL; for (listener = ListenerPollList; listener; listener = listener->next) { if ( (port == listener->port) && (!memcmp(&PIN_ADDR(addr), &IN_ADDR(listener->addr), sizeof(struct irc_inaddr)))) { /* Try to return an open listener, otherwise reuse a closed one */ if (listener->fd == -1) last_closed = listener; else return listener; } } return last_closed; } /* * add_listener- create a new listener * port - the port number to listen on * vhost_ip - if non-null must contain a valid IP address string in * the format "255.255.255.255" */ void add_listener(int port, const char* vhost_ip) { struct Listener* listener; struct irc_inaddr vaddr; /* * if no port in conf line, don't bother */ if (port == 0) return; #ifdef IPV6 copy_s_addr(IN_ADDR(vaddr), &in6addr_any); #else copy_s_addr(IN_ADDR(vaddr), INADDR_ANY); #endif if (vhost_ip) { if(inetpton(DEF_FAM, vhost_ip, &IN_ADDR(vaddr)) <= 0) return; } if ((listener = find_listener(port, &vaddr))) { if (listener->fd > -1) return; } else { listener = make_listener(port, &vaddr); listener->next = ListenerPollList; ListenerPollList = listener; } listener->fd = -1; if (inetport(listener)) listener->active = 1; else close_listener(listener); } /* * close_listener - close a single listener */ void close_listener(struct Listener* listener) { assert(listener != NULL); if(listener == NULL) return; if (listener->fd >= 0) { fd_close(listener->fd); listener->fd = -1; } listener->active = 0; if (listener->ref_count) return; free_listener(listener); }
int init_resolver(int op) { int ret = 0; #ifdef LRAND48 srand48(time(NULL)); #endif if (op & RES_INITLIST) { bzero((char *)&reinfo, sizeof(reinfo)); first = last = NULL; } if (op & RES_CALLINIT) { ret = ircd_res_init(); if (!ircd_res.nscount) { ircd_res.nscount = 1; #ifdef INET6 if (!inetpton(AF_INET6, "::1", &ircd_res.nsaddr_list[0].sin6_addr.s6_addr)) { bcopy(minus_one, ircd_res.nsaddr_list[0].sin6_addr.s6_addr, IN6ADDRSZ); } #else ircd_res.nsaddr_list[0].sin_addr.s_addr = inetaddr("127.0.0.1"); #endif } } if (op & RES_INITSOCK) { int on = 0; ret = resfd = socket(AFINET, SOCK_DGRAM, 0); (void) SETSOCKOPT(ret, SOL_SOCKET, SO_BROADCAST, &on, on); /* The following frame is a hack to allow resolving * in FreeBSD jail(). As it is harmless elsewhere, it is * not #ifdef-ed. * Note that currently IPv6 within jail() is not * supported by the FreeBSD. */ { struct SOCKADDR_IN res_addr; memset(&res_addr, 0, sizeof(res_addr)); res_addr.SIN_FAMILY = AFINET; #ifdef INET6 res_addr.sin6_addr = in6addr_any; #else res_addr.sin_addr.s_addr = htonl(INADDR_ANY); #endif bind(resfd, (SAP) &res_addr, sizeof(res_addr)); } } #ifdef DEBUG if (op & RES_INITDEBG); ircd_res.options |= RES_DEBUG; #endif if (op & RES_INITCACH) { bzero((char *)&cainfo, sizeof(cainfo)); bzero((char *)hashtable, sizeof(hashtable)); } if (op == 0) ret = resfd; return ret; }
static void ccf_sortlist(adns_state ads, const char *fn, int lno, const char *buf) { const char *word; char tbuf[200], *slash, *ep; struct in_addr base, mask; int l; unsigned long initial, baselocal; if (!buf) return; ads->nsortlist= 0; while (nextword(&buf,&word,&l)) { if (ads->nsortlist >= MAXSORTLIST) { adns__diag(ads,-1,0,"too many sortlist entries, ignoring %.*s onwards",l,word); return; } if (l >= sizeof(tbuf)) { configparseerr(ads,fn,lno,"sortlist entry `%.*s' too long",l,word); continue; } memcpy(tbuf,word,l); tbuf[l]= 0; slash= strchr(tbuf,'/'); if (slash) *slash++= 0; if (inetpton(AF_INET, tbuf,&base) <= 0) { configparseerr(ads,fn,lno,"invalid address `%s' in sortlist",tbuf); continue; } if (slash) { if (strchr(slash,'.')) { if (inetpton(AF_INET, slash,&mask) <= 0) { configparseerr(ads,fn,lno,"invalid mask `%s' in sortlist",slash); continue; } if (base.s_addr & ~mask.s_addr) { configparseerr(ads,fn,lno, "mask `%s' in sortlist overlaps address `%s'",slash,tbuf); continue; } } else { initial= strtoul(slash,&ep,10); if (*ep || initial>32) { configparseerr(ads,fn,lno,"mask length `%s' invalid",slash); continue; } mask.s_addr= htonl((0x0ffffffffUL) << (32-initial)); } } else { baselocal= ntohl(base.s_addr); if (!baselocal & 0x080000000UL) /* class A */ mask.s_addr= htonl(0x0ff000000UL); else if ((baselocal & 0x0c0000000UL) == 0x080000000UL) mask.s_addr= htonl(0x0ffff0000UL); /* class B */ else if ((baselocal & 0x0f0000000UL) == 0x0e0000000UL) mask.s_addr= htonl(0x0ff000000UL); /* class C */ else { configparseerr(ads,fn,lno, "network address `%s' in sortlist is not in classed ranges," " must specify mask explicitly", tbuf); continue; } } ads->sortlist[ads->nsortlist].base= base; ads->sortlist[ads->nsortlist].mask= mask; ads->nsortlist++; } }
/* * add_listener- create a new listener * port - the port number to listen on * vhost_ip - if non-null must contain a valid IP address string in the format "255.255.255.255" * options - listener options * cp - listener default code page */ void add_listener(int port, const char* vhost_ip, char* options, char* cp) { struct Listener* listener; struct IN_ADDR vaddr; /* * if no port in conf line, don't bother */ if (0 == port) return; #ifdef IPV6 vaddr = INADDRANY; #else vaddr.s_addr = INADDRANY; #endif if (vhost_ip) { #ifdef IPV6 if(inetpton(AFINET, vhost_ip, &vaddr) == 0) return; #else vaddr.s_addr = inet_addr(vhost_ip); if (INADDR_NONE == vaddr.s_addr) return; #endif } if ((listener = find_listener(port, vaddr))) { listener->active = 1; return; } if(options && *options) irclog(L_NOTICE,"Adding listener for %s, port %d Options:%s", vhost_ip ? vhost_ip : "ANY", port, options ); else irclog(L_NOTICE,"Adding listener for %s, port %d", vhost_ip ? vhost_ip : "ANY", port); listener = make_listener(port, vaddr); if(options) { while(*options) { switch(*options) { case 's' : #ifdef HAVE_SSL if(no_ssl) irclog(L_WARN,"ignoring port with 's' option!"); else listener->options |= LST_SSL; #else irclog(L_WARN,"ircd compiled without SSL support, ignoring port with 's' option!"); #endif break; case 'S' : listener->options |= LST_SERVER; break; case 'W' : listener->options |= LST_WEBCHAT; break; case 'J' : listener->options |= LST_JAVACR; break; case 'n' : listener->options |= LST_NOSPOOF; break; } ++options; } } if(cp && cp[0]) { listener->codepage = codepage_find(cp); if(listener->codepage==-1) irclog(L_WARN,"Codepage %s defined on P:line was not loaded!", cp); } else listener->codepage=-1; if (inetport(listener)) { listener->active = 1; listener->next = ListenerPollList; ListenerPollList = listener; } else free_listener(listener); }