/** Convert IRC socket address to native format. * @param[out] v6 Native socket address. * @param[in] irc IRC socket address. * @param[in] compat_fd If non-negative, an FD specifying address family. * @return Length of address written to \a v6. */ int sockaddr_from_irc(struct sockaddr_in6 *v6, const struct irc_sockaddr *irc, int compat_fd, int family) { struct sockaddr_in6 sin6; socklen_t slen; assert(irc != 0); slen = sizeof(sin6); if (family) { /* accept whatever user specified */ } else if ((0 <= compat_fd) && (0 == getsockname(compat_fd, (struct sockaddr*)&sin6, &slen))) family = sin6.sin6_family; else if ((irc == &VirtualHost_v4) || irc_in_addr_is_ipv4(&irc->addr)) family = AF_INET; else family = AF_INET6; memset(v6, 0, sizeof(*v6)); if (family == AF_INET) { struct sockaddr_in *v4 = (struct sockaddr_in*)v6; v4->sin_family = AF_INET; memcpy(&v4->sin_addr, &irc->addr.in6_16[6], sizeof(v4->sin_addr)); v4->sin_port = htons(irc->port); return sizeof(*v4); } else { v6->sin6_family = AF_INET6; memcpy(&v6->sin6_addr, &irc->addr.in6_16[0], sizeof(v6->sin6_addr)); v6->sin6_port = htons(irc->port); return sizeof(*v6); } }
/** Start sending upings to a server. * @param[in] sptr Client requesting the upings. * @param[in] aconf ConfItem containing the address to ping. * @param[in] port Port number to ping. * @param[in] count Number of times to ping (should be at least 20). * @return Zero. */ int uping_server(struct Client* sptr, struct ConfItem* aconf, int port, int count) { int fd; int family = 0; struct UPing* pptr; struct irc_sockaddr *local; assert(0 != sptr); assert(0 != aconf); if (!irc_in_addr_valid(&aconf->address.addr)) { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :UPING: Host lookup failed for " "%s", sptr, aconf->name); return 0; } if (IsUPing(sptr)) uping_cancel(sptr, sptr); /* Cancel previous ping request */ if (irc_in_addr_is_ipv4(&aconf->address.addr)) { local = &VirtualHost_v4; family = AF_INET; } else { local = &VirtualHost_v6; } fd = os_socket(local, SOCK_DGRAM, "Outbound uping socket", family); if (fd < 0) return 0; pptr = (struct UPing*) MyMalloc(sizeof(struct UPing)); assert(0 != pptr); memset(pptr, 0, sizeof(struct UPing)); if (!socket_add(&pptr->socket, uping_read_callback, (void*) pptr, SS_DATAGRAM, SOCK_EVENT_READABLE, fd)) { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :UPING: Can't queue fd for " "reading", sptr); close(fd); MyFree(pptr); return 0; } pptr->fd = fd; memcpy(&pptr->addr.addr, &aconf->address.addr, sizeof(pptr->addr.addr)); pptr->addr.port = port; pptr->count = IRCD_MIN(20, count); pptr->client = sptr; pptr->freeable = UPING_PENDING_SOCKET; strcpy(pptr->name, aconf->name); pptr->next = pingList; pingList = pptr; SetUPing(sptr); uping_start(pptr); return 0; }
/** Send a query to look up the name for an address. * @param[in] query Callback information. * @param[in] addr Address to look up. * @param[in] request DNS lookup structure (may be NULL). */ static void do_query_number(dns_callback_f callback, void *ctx, const struct irc_in_addr *addr, struct reslist *request) { char ipbuf[128]; const unsigned char *cp; if (irc_in_addr_is_ipv4(addr)) { cp = (const unsigned char*)&addr->in6_16[6]; ircd_snprintf(NULL, ipbuf, sizeof(ipbuf), "%u.%u.%u.%u.in-addr.arpa.", (unsigned int)(cp[3]), (unsigned int)(cp[2]), (unsigned int)(cp[1]), (unsigned int)(cp[0])); } else { const char *intarpa; if (request != NULL && request->state == REQ_INT) intarpa = "int"; else intarpa = "arpa"; cp = (const unsigned char *)&addr->in6_16[0]; ircd_snprintf(NULL, ipbuf, sizeof(ipbuf), "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x." "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.%s.", (unsigned int)(cp[15]&0xf), (unsigned int)(cp[15]>>4), (unsigned int)(cp[14]&0xf), (unsigned int)(cp[14]>>4), (unsigned int)(cp[13]&0xf), (unsigned int)(cp[13]>>4), (unsigned int)(cp[12]&0xf), (unsigned int)(cp[12]>>4), (unsigned int)(cp[11]&0xf), (unsigned int)(cp[11]>>4), (unsigned int)(cp[10]&0xf), (unsigned int)(cp[10]>>4), (unsigned int)(cp[9]&0xf), (unsigned int)(cp[9]>>4), (unsigned int)(cp[8]&0xf), (unsigned int)(cp[8]>>4), (unsigned int)(cp[7]&0xf), (unsigned int)(cp[7]>>4), (unsigned int)(cp[6]&0xf), (unsigned int)(cp[6]>>4), (unsigned int)(cp[5]&0xf), (unsigned int)(cp[5]>>4), (unsigned int)(cp[4]&0xf), (unsigned int)(cp[4]>>4), (unsigned int)(cp[3]&0xf), (unsigned int)(cp[3]>>4), (unsigned int)(cp[2]&0xf), (unsigned int)(cp[2]>>4), (unsigned int)(cp[1]&0xf), (unsigned int)(cp[1]>>4), (unsigned int)(cp[0]&0xf), (unsigned int)(cp[0]>>4), intarpa); } if (request == NULL) { request = make_request(callback, ctx); request->state= REQ_PTR; request->type = T_PTR; memcpy(&request->addr, addr, sizeof(request->addr)); request->name = (char *)MyMalloc(HOSTLEN + 1); } Debug((DEBUG_DNS, "Requesting DNS PTR %s as %p", ipbuf, request)); query_name(ipbuf, C_IN, T_PTR, request); }
/** Convert IP addresses to canonical form for comparison. IPv4 * addresses are translated into 6to4 form; IPv6 addresses are left * alone. * @param[out] out Receives canonical format for address. * @param[in] in IP address to canonicalize. */ static void ip_registry_canonicalize(struct irc_in_addr *out, const struct irc_in_addr *in) { if (irc_in_addr_is_ipv4(in)) { out->in6_16[0] = htons(0x2002); out->in6_16[1] = in->in6_16[6]; out->in6_16[2] = in->in6_16[7]; out->in6_16[3] = out->in6_16[4] = out->in6_16[5] = 0; out->in6_16[6] = out->in6_16[7] = 0; } else memcpy(out, in, sizeof(*out)); }
/** Apply GeoIP country data to a client. * @param[in] cptr Client to apply GeoIP country data to. */ void geoip_apply(struct Client* cptr) { #ifdef USE_GEOIP int gcid = 0; #endif /* USE_GEOIP */ #ifdef USE_GEOIP_GL GeoIPLookup gl; #endif /* USE_GEOIP_GL */ if (!feature_bool(FEAT_GEOIP_ENABLE)) return; if (!(cptr)) return; #ifdef USE_GEOIP if (irc_in_addr_is_ipv4(&cli_ip(cptr))) { /* User is IPv4 so use gi4. */ if (gi4 != NULL) #ifdef USE_GEOIP_GL gcid = GeoIP_id_by_addr_gl(gi4, cli_sock_ip(cptr), &gl); #else gcid = GeoIP_id_by_addr(gi4, cli_sock_ip(cptr)); #endif /* USE_GEOIP_GL */ } else { /* User is IPv6 so use gi6. */ if (gi6 != NULL) #ifdef USE_GEOIP_GL gcid = GeoIP_id_by_addr_v6_gl(gi6, cli_sock_ip(cptr), &gl); #else gcid = GeoIP_id_by_addr_v6(gi6, cli_sock_ip(cptr)); #endif /* USE_GEOIP_GL */ } #endif /* USE_GEOIP */ #ifdef USE_GEOIP if (gcid == 0) { #endif /* USE_GEOIP */ ircd_strncpy((char *)&cli_countrycode(cptr), "--", 3); ircd_strncpy((char *)&cli_countryname(cptr), "Unknown", 8); ircd_strncpy((char *)&cli_continentcode(cptr), "--", 3); ircd_strncpy((char *)&cli_continentname(cptr), "Unknown", 8); #ifdef USE_GEOIP } else { ircd_strncpy((char *)&cli_countrycode(cptr), GeoIP_code_by_id(gcid), 3); ircd_strncpy((char *)&cli_countryname(cptr), GeoIP_name_by_id(gcid), 256); ircd_strncpy((char *)&cli_continentcode(cptr), GeoIP_continent_by_id(gcid), 3); ircd_strncpy((char *)&cli_continentname(cptr), geoip_continent_name_by_code(GeoIP_continent_by_id(gcid)), 256); } #endif /* USE_GEOIP */ SetGeoIP(cptr); }
/** Encode an IP address in the base64 used by numnicks. * For IPv4 addresses (including IPv4-mapped and IPv4-compatible IPv6 * addresses), the 32-bit host address is encoded directly as six * characters. * * For IPv6 addresses, each 16-bit address segment is encoded as three * characters, but the longest run of zero segments is encoded using an * underscore. * @param[out] buf Output buffer to write to. * @param[in] addr IP address to encode. * @param[in] count Number of bytes writable to \a buf. * @param[in] v6_ok If non-zero, peer understands base-64 encoded IPv6 addresses. */ const char* iptobase64(char* buf, const struct irc_in_addr* addr, unsigned int count, int v6_ok) { if (irc_in_addr_is_ipv4(addr)) { assert(count >= 6); inttobase64(buf, (ntohs(addr->in6_16[6]) << 16) | ntohs(addr->in6_16[7]), 6); } else if (!v6_ok) { assert(count >= 6); if (addr->in6_16[0] == htons(0x2002)) inttobase64(buf, (ntohs(addr->in6_16[1]) << 16) | ntohs(addr->in6_16[2]), 6); else if ((addr->in6_16[0] == htons(0x2001)) && (addr->in6_16[1] == 0)) inttobase64(buf, (ntohs(addr->in6_16[6] ^ 0xFFFF) << 16) | ntohs(addr->in6_16[7] ^ 0xFFFF), 6); else strcpy(buf, "AAAAAA"); } else { unsigned int max_start, max_zeros, curr_zeros, zero, ii; char *output = buf; assert(count >= 25); /* Can start by printing out the leading non-zero parts. */ for (ii = 0; (addr->in6_16[ii]) && (ii < 8); ++ii) { inttobase64(output, ntohs(addr->in6_16[ii]), 3); output += 3; } /* Find the longest run of zeros. */ for (max_start = zero = ii, max_zeros = curr_zeros = 0; ii < 8; ++ii) { if (!addr->in6_16[ii]) curr_zeros++; else if (curr_zeros > max_zeros) { max_start = ii - curr_zeros; max_zeros = curr_zeros; curr_zeros = 0; } } if (curr_zeros > max_zeros) { max_start = ii - curr_zeros; max_zeros = curr_zeros; curr_zeros = 0; } /* Print the rest of the address */ for (ii = zero; ii < 8; ) { if ((ii == max_start) && max_zeros) { *output++ = '_'; ii += max_zeros; } else { inttobase64(output, ntohs(addr->in6_16[ii]), 3); output += 3; ii++; } } *output = '\0'; } return buf; }
unsigned char getnodebits(struct irc_in_addr *ip) { trusthost *th; th = th_getbyhost(ip); if(th) return th->nodebits; if(irc_in_addr_is_ipv4(ip)) return 128; else return 64; }
/** Attempt to apply a SILENCE update to a user. * * Silences are propagated lazily between servers to save on bandwidth * and remote memory. Any removal and any silence exception must be * propagated until a server has not seen the mask being removed or * has no positive silences for the user. * * @param[in] sptr Client to update. * @param[in] mask Single silence mask to apply, optionally preceded by '+' or '-' and maybe '~'. * @return The new ban entry on success, NULL on failure. */ static struct Ban * apply_silence(struct Client *sptr, char *mask) { struct Ban *sile; int flags; int res; char orig_mask[NICKLEN+USERLEN+HOSTLEN+3]; assert(mask && mask[0]); /* Check for add or remove. */ if (mask[0] == '-') { flags = BAN_DEL; mask++; } else if (mask[0] == '+') { flags = BAN_ADD; mask++; } else flags = BAN_ADD; /* Check for being an exception. */ if (mask[0] == '~') { flags |= BAN_EXCEPTION; mask++; } /* Make the silence and set additional flags. */ ircd_strncpy(orig_mask, mask, sizeof(orig_mask) - 1); sile = make_ban(pretty_mask(mask)); sile->flags |= flags; /* If they're a local user trying to ban too broad a mask, forbid it. */ if (MyUser(sptr) && (sile->flags & BAN_IPMASK) && sile->addrbits > 0 && sile->addrbits < (irc_in_addr_is_ipv4(&sile->address) ? 112 : 32)) { send_reply(sptr, ERR_MASKTOOWIDE, orig_mask); free_ban(sile); return NULL; } /* Apply it to the silence list. */ res = apply_ban(&cli_user(sptr)->silence, sile, 1); return res ? NULL : sile; }
/** Start (or re-start) resolver. * This means read resolv.conf, initialize the list of pending * requests, open the resolver socket and initialize its timeout. */ void restart_resolver(void) { int need_v4; int need_v6; int ns; irc_res_init(); if (!request_list.next) request_list.next = request_list.prev = &request_list; /* Check which address family (or families) our nameservers use. */ for (need_v4 = need_v6 = ns = 0; ns < irc_nscount; ns++) { if (irc_in_addr_is_ipv4(&irc_nsaddr_list[ns].addr)) need_v4 = 1; else need_v6 = 1; } /* If we need an IPv4 socket, and don't have one, open it. */ if (need_v4 && !s_active(&res_socket_v4)) { int fd = os_socket(&VirtualHost_dns_v4, SOCK_DGRAM, "Resolver UDPv4 socket", AF_INET); if (fd >= 0) socket_add(&res_socket_v4, res_readreply, NULL, SS_DATAGRAM, SOCK_EVENT_READABLE, fd); } #ifdef AF_INET6 /* If we need an IPv6 socket, and don't have one, open it. */ if (need_v6 && !s_active(&res_socket_v6)) { int fd = os_socket(&VirtualHost_dns_v6, SOCK_DGRAM, "Resolver UDPv6 socket", AF_INET6); if (fd >= 0) socket_add(&res_socket_v6, res_readreply, NULL, SS_DATAGRAM, SOCK_EVENT_READABLE, fd); } #endif if (s_active(&res_socket_v4) || s_active(&res_socket_v6)) timer_init(&res_timeout); }
/** Attempt to write on a non-blocking UDP socket. * @param[in] fd File descriptor to write to. * @param[in] buf Output buffer to send from. * @param[in] length Number of bytes to write. * @param[out] count_out Receives number of bytes actually written. * @param[in] flags Flags for call to sendto(). * @param[in] peer Destination address of the message. * @return An IOResult value indicating status. */ IOResult os_sendto_nonb(int fd, const char* buf, unsigned int length, unsigned int* count_out, unsigned int flags, const struct irc_sockaddr* peer) { struct sockaddr_native addr; int res, size; assert(0 != buf); size = sockaddr_from_irc(&addr, peer, fd, 0); assert((addr.sn_family == AF_INET) == irc_in_addr_is_ipv4(&peer->addr)); if (-1 < (res = sendto(fd, buf, length, flags, (struct sockaddr*)&addr, size))) { if (count_out) *count_out = (unsigned) res; return IO_SUCCESS; } else { if (count_out) *count_out = 0; return is_blocked(errno) ? IO_BLOCKED : IO_FAILURE; } }
/** Send a message to all of our nameservers. * @param[in] msg Message to send. * @param[in] len Length of message. * @param[in] rcount Maximum number of servers to ask. * @return Number of servers that were successfully asked. */ static int send_res_msg(const char *msg, int len, int rcount) { int i; int sent = 0; int max_queries = IRCD_MIN(irc_nscount, rcount); /* RES_PRIMARY option is not implemented * if (res.options & RES_PRIMARY || 0 == max_queries) */ if (max_queries == 0) max_queries = 1; for (i = 0; i < max_queries; i++) { int fd = irc_in_addr_is_ipv4(&irc_nsaddr_list[i].addr) ? s_fd(&res_socket_v4) : s_fd(&res_socket_v6); if (os_sendto_nonb(fd, msg, len, NULL, 0, &irc_nsaddr_list[i]) == IO_SUCCESS) ++sent; } return(sent); }
static void outputtree(nick *np, unsigned int marker, trustgroup *originalgroup, trusthost *th, int depth, int showchildren) { const char *cidrstr; char *prespacebuf, *postspacebuf, parentbuf[512]; if(th->marker != marker) return; cidrstr = CIDRtostr(th->ip, th->bits); calculatespaces(depth + 2, 30 + 1, cidrstr, &prespacebuf, &postspacebuf); if(th->group == originalgroup) { if(!showchildren && th->group == originalgroup && th->children) prespacebuf[0] = '*'; else prespacebuf[0] = ' '; prespacebuf[1] = '>'; parentbuf[0] = '\0'; } else { /* show the ids of other groups */ snprintf(parentbuf, sizeof(parentbuf), "%-10d %s", th->group->id, th->group->name->content); } controlreply(np, "%s%s%s %-10d %-10d %-21s %-15d /%-14d%s", prespacebuf, cidrstr, postspacebuf, th->count, th->maxusage, (th->count>0)?"(now)":((th->lastseen>0)?trusts_timetostr(th->lastseen):"(never)"), th->maxpernode, (irc_in_addr_is_ipv4(&th->ip))?(th->nodebits - 96):th->nodebits, parentbuf); /* Make sure we're not seeing this subtree again. */ th->marker = -1; for(th=th->children;th;th=th->nextbychild) outputtree(np, marker, originalgroup, th, depth + 1, showchildren); }
/** Read a DNS reply from the nameserver and process it. * @param[in] ev I/O activity event for resolver socket. */ static void res_readreply(struct Event *ev) { struct irc_sockaddr lsin; struct Socket *sock; char buf[sizeof(HEADER) + MAXPACKET]; HEADER *header; struct reslist *request = NULL; unsigned int rc; int answer_count; assert((ev_socket(ev) == &res_socket_v4) || (ev_socket(ev) == &res_socket_v6)); sock = ev_socket(ev); if (IO_SUCCESS != os_recvfrom_nonb(s_fd(sock), buf, sizeof(buf), &rc, &lsin) || (rc <= sizeof(HEADER))) return; /* * check against possibly fake replies */ if (!res_ourserver(&lsin)) return; /* * convert DNS reply reader from Network byte order to CPU byte order. */ header = (HEADER *)buf; header->ancount = ntohs(header->ancount); header->qdcount = ntohs(header->qdcount); header->nscount = ntohs(header->nscount); header->arcount = ntohs(header->arcount); /* * response for an id which we have already received an answer for * just ignore this response. */ if (0 == (request = find_id(header->id))) return; if ((header->rcode != NO_ERRORS) || (header->ancount == 0)) { if (SERVFAIL == header->rcode || NXDOMAIN == header->rcode) { /* * If a bad error was returned, we stop here and don't send * send any more (no retries granted). */ Debug((DEBUG_DNS, "Request %p has bad response (state %d type %d rcode %d)", request, request->state, request->type, header->rcode)); (*request->callback)(request->callback_ctx, NULL, NULL); rem_request(request); } else { /* * If we haven't already tried this, and we're looking up AAAA, try A * now */ if (request->state == REQ_AAAA && request->type == T_AAAA) { request->timeout += feature_int(FEAT_IRCD_RES_TIMEOUT); resend_query(request); } else if (request->type == T_PTR && request->state != REQ_INT && !irc_in_addr_is_ipv4(&request->addr)) { request->state = REQ_INT; request->timeout += feature_int(FEAT_IRCD_RES_TIMEOUT); resend_query(request); } } return; } /* * If this fails there was an error decoding the received packet, * try it again and hope it works the next time. */ answer_count = proc_answer(request, header, buf, buf + rc); if (answer_count) { if (request->type == T_PTR) { if (request->name == NULL) { /* * got a PTR response with no name, something bogus is happening * don't bother trying again, the client address doesn't resolve */ Debug((DEBUG_DNS, "Request %p PTR had empty name", request)); (*request->callback)(request->callback_ctx, NULL, NULL); rem_request(request); return; } /* * Lookup the 'authoritative' name that we were given for the * ip#. */ #ifdef IPV6 if (!irc_in_addr_is_ipv4(&request->addr)) do_query_name(request->callback, request->callback_ctx, request->name, NULL, T_AAAA); else #endif do_query_name(request->callback, request->callback_ctx, request->name, NULL, T_A); Debug((DEBUG_DNS, "Request %p switching to forward resolution", request)); rem_request(request); } else { /* * got a name and address response, client resolved */ (*request->callback)(request->callback_ctx, &request->addr, request->name); Debug((DEBUG_DNS, "Request %p got forward resolution", request)); rem_request(request); } } else if (!request->sent) { /* XXX - we got a response for a query we didn't send with a valid id? * this should never happen, bail here and leave the client unresolved */ assert(0); /* XXX don't leak it */ Debug((DEBUG_DNS, "Request %p was unexpected(!)", request)); rem_request(request); } }
char * generate_hostmask(struct userNode *user, int options) { irc_in_addr_t ip; char *nickname, *ident, *hostname, *mask; int len, ii; /* figure out string parts */ if (options & GENMASK_OMITNICK) nickname = NULL; else if (options & GENMASK_USENICK) nickname = user->nick; else nickname = "*"; if (options & GENMASK_STRICT_IDENT) // sethost - reed/apples if (IsSetHost(user)) { ident = alloca(strcspn(user->sethost, "@")+2); safestrncpy(ident, user->sethost, strcspn(user->sethost, "@")+1); } else ident = user->ident; else if (options & GENMASK_ANY_IDENT) ident = "*"; else { // sethost - reed/apples if (IsSetHost(user)) { ident = alloca(strcspn(user->sethost, "@")+3); ident[0] = '*'; safestrncpy(ident+1, user->sethost, strcspn(user->sethost, "@")+1); } else { ident = alloca(strlen(user->ident)+2); ident[0] = '*'; strcpy(ident+1, user->ident + ((*user->ident == '~')?1:0)); } } hostname = user->hostname; if (IsFakeHost(user) && IsHiddenHost(user) && !(options & GENMASK_NO_HIDING)) { hostname = user->fakehost; } else if (IsHiddenHost(user)) { int style = 1; char *data; data = conf_get_data("server/hidden_host_type", RECDB_QSTRING); if (data) style = atoi(data); if (((style == 1) || (style == 3)) && user->handle_info && hidden_host_suffix && !(options & GENMASK_NO_HIDING)) { hostname = alloca(strlen(user->handle_info->handle) + strlen(hidden_host_suffix) + 2); sprintf(hostname, "%s.%s", user->handle_info->handle, hidden_host_suffix); } else if (((style == 2) || (style == 3)) && !(options & GENMASK_NO_HIDING)) { hostname = alloca(strlen(user->crypthost)); sprintf(hostname, "%s", user->crypthost); } } else if (options & GENMASK_STRICT_HOST) { if (options & GENMASK_BYIP) hostname = (char*)irc_ntoa(&user->ip); } else if ((options & GENMASK_BYIP) || irc_pton(&ip, NULL, hostname)) { /* Should generate an IP-based hostmask. */ hostname = alloca(IRC_NTOP_MAX_SIZE); hostname[IRC_NTOP_MAX_SIZE-1] = '\0'; if (irc_in_addr_is_ipv4(user->ip)) { /* By popular acclaim, a /16 hostmask is used. */ sprintf(hostname, "%d.%d.*", user->ip.in6_8[12], user->ip.in6_8[13]); } else if (irc_in_addr_is_ipv6(user->ip)) { /* Who knows what the default mask should be? Use a /48 to start with. */ sprintf(hostname, "%x:%x:%x:*", user->ip.in6[0], user->ip.in6[1], user->ip.in6[2]); } else { /* Unknown type; just copy IP directly. */ irc_ntop(hostname, IRC_NTOP_MAX_SIZE, &user->ip); } } else { int cnt; /* This heuristic could be made smarter. Is it worth the effort? */ for (ii=cnt=0; hostname[ii]; ii++) if (hostname[ii] == '.') cnt++; if (cnt == 0 || cnt == 1) { /* only a one- or two-level domain name; leave hostname */ } else if (cnt == 2) { for (ii=0; user->hostname[ii] != '.'; ii++) ; /* Add 3 to account for the *. and \0. */ hostname = alloca(strlen(user->hostname+ii)+3); sprintf(hostname, "*.%s", user->hostname+ii+1); } else { for (cnt=3, ii--; cnt; ii--) if (user->hostname[ii] == '.') cnt--; /* The loop above will overshoot the dot one character; we skip forward two (the one character and the dot) when printing, so we only add one for the \0. */ hostname = alloca(strlen(user->hostname+ii)+1); sprintf(hostname, "*.%s", user->hostname+ii+2); } } // sethost - reed/apples if (IsSetHost(user)) hostname = strchr(user->sethost, '@') + 1; /* Emit hostmask */ len = strlen(ident) + strlen(hostname) + 2; if (nickname) { len += strlen(nickname) + 1; mask = malloc(len); sprintf(mask, "%s!%s@%s", nickname, ident, hostname); } else { mask = malloc(len); sprintf(mask, "%s@%s", ident, hostname); } return mask; }
char *hidehost_ipv4(struct irc_in_addr *ip) { unsigned int a, b, c, d; static char buf[512], res[512], res2[512], result[128]; unsigned long n; unsigned int alpha, beta, gamma, delta; unsigned char *pch; /* * Output: ALPHA.BETA.GAMMA.DELTA.IP * ALPHA is unique for a.b.c.d * BETA is unique for a.b.c.* * GAMMA is unique for a.b.* * We cloak like this: * ALPHA = downsample24(md5(md5("KEY2:A.B.C.D:KEY3")+"KEY1")); * BETA = downsample24(md5(md5("KEY3:A.B.C:KEY1")+"KEY2")); * GAMMA = downsample24(md5(md5("KEY1:A.B:KEY2")+"KEY3")); * DELTA = downsample24(md5(md5("KEY2:A:KEY1:KEY3")+"KEY1")); */ if (!irc_in_addr_is_ipv4(ip)) return hidehost_ipv6(ip); pch = (unsigned char*)&ip->in6_16[6]; a = *pch++; b = *pch; pch = (unsigned char*)&ip->in6_16[7]; c = *pch++; d = *pch; /* ALPHA... */ ircd_snprintf(0, buf, 512, "%s:%d.%d.%d.%d:%s", KEY2, a, b, c, d, KEY3); DoMD5((unsigned char *)&res, (unsigned char *)&buf, strlen(buf)); strcpy(res+16, KEY1); /* first 16 bytes are filled, append our key.. */ n = strlen(res+16) + 16; DoMD5((unsigned char *)&res2, (unsigned char *)&res, n); alpha = downsample24((unsigned char *)&res2); /* BETA... */ ircd_snprintf(0, buf, 512, "%s:%d.%d.%d:%s", KEY3, a, b, c, KEY1); DoMD5((unsigned char *)&res, (unsigned char *)&buf, strlen(buf)); strcpy(res+16, KEY2); /* first 16 bytes are filled, append our key.. */ n = strlen(res+16) + 16; DoMD5((unsigned char *)&res2, (unsigned char *)&res, n); beta = downsample24((unsigned char *)&res2); /* GAMMA... */ ircd_snprintf(0, buf, 512, "%s:%d.%d:%s", KEY1, a, b, KEY2); DoMD5((unsigned char *)&res, (unsigned char *)&buf, strlen(buf)); strcpy(res+16, KEY3); /* first 16 bytes are filled, append our key.. */ n = strlen(res+16) + 16; DoMD5((unsigned char *)&res2, (unsigned char *)&res, n); gamma = downsample24((unsigned char *)&res2); /* DELTA... */ ircd_snprintf(0, buf, 512, "%s:%d:%s:%s", KEY2, a, KEY1, KEY3); DoMD5((unsigned char *)&res, (unsigned char *)&buf, strlen(buf)); strcpy(res+16, KEY1); /* first 16 bytes are filled, append our key.. */ n = strlen(res+16) + 16; DoMD5((unsigned char *)&res2, (unsigned char *)&res, n); delta = downsample24((unsigned char *)&res2); ircd_snprintf(0, result, HOSTLEN, "%X.%X.%X.%X.IP", alpha, beta, gamma, delta); return result; }
char *hidehost_ipv6(struct irc_in_addr *ip) { unsigned int a, b, c, d, e, f, g, h; static char buf[512], res[512], res2[512], result[128]; unsigned long n; unsigned int alpha, beta, gamma, delta; /* * Output: ALPHA:BETA:GAMMA:IP * ALPHA is unique for a:b:c:d:e:f:g:h * BETA is unique for a:b:c:d:e:f:g * GAMMA is unique for a:b:c:d * We cloak like this: * ALPHA = downsample24(md5(md5("KEY2:a:b:c:d:e:f:g:h:KEY3")+"KEY1")); * BETA = downsample24(md5(md5("KEY3:a:b:c:d:e:f:g:KEY1")+"KEY2")); * GAMMA = downsample24(md5(md5("KEY1:a:b:c:d:KEY2")+"KEY3")); * DELTA = downsample24(md5(md5("KEY2:a:b:KEY1:KEY3")+"KEY1")); */ if (irc_in_addr_is_ipv4(ip)) return hidehost_ipv4(ip); a = ntohs(ip->in6_16[0]); b = ntohs(ip->in6_16[1]); c = ntohs(ip->in6_16[2]); d = ntohs(ip->in6_16[3]); e = ntohs(ip->in6_16[4]); f = ntohs(ip->in6_16[5]); g = ntohs(ip->in6_16[6]); h = ntohs(ip->in6_16[7]); /* ALPHA... */ ircd_snprintf(0, buf, 512, "%s:%x:%x:%x:%x:%x:%x:%x:%x:%s", KEY2, a, b, c, d, e, f, g, h, KEY3); DoMD5((unsigned char *)&res, (unsigned char *)&buf, strlen(buf)); strcpy(res+16, KEY1); /* first 16 bytes are filled, append our key.. */ n = strlen(res+16) + 16; DoMD5((unsigned char *)&res2, (unsigned char *)&res, n); alpha = downsample24((unsigned char *)&res2); /* BETA... */ ircd_snprintf(0, buf, 512, "%s:%x:%x:%x:%x:%x:%x:%x:%s", KEY3, a, b, c, d, e, f, g, KEY1); DoMD5((unsigned char *)&res, (unsigned char *)&buf, strlen(buf)); strcpy(res+16, KEY2); /* first 16 bytes are filled, append our key.. */ n = strlen(res+16) + 16; DoMD5((unsigned char *)&res2, (unsigned char *)&res, n); beta = downsample24((unsigned char *)&res2); /* GAMMA... */ ircd_snprintf(0, buf, 512, "%s:%x:%x:%x:%x:%s", KEY1, a, b, c, d, KEY2); DoMD5((unsigned char *)&res, (unsigned char *)&buf, strlen(buf)); strcpy(res+16, KEY3); /* first 16 bytes are filled, append our key.. */ n = strlen(res+16) + 16; DoMD5((unsigned char *)&res2, (unsigned char *)&res, n); gamma = downsample24((unsigned char *)&res2); /* DELTA... */ ircd_snprintf(0, buf, 512, "%s:%x:%x:%s:%s", KEY2, a, b, KEY1, KEY3); DoMD5((unsigned char *)&res, (unsigned char *)&buf, strlen(buf)); strcpy(res+16, KEY1); /* first 16 bytes are filled, append our key.. */ n = strlen(res+16) + 16; DoMD5((unsigned char *)&res2, (unsigned char *)&res, n); delta = downsample24((unsigned char *)&res2); ircd_snprintf(0, result, HOSTLEN, "%X:%X:%X:%X:IP", alpha, beta, gamma, delta); return result; }
/** Set up address and port and make a connection. * @param aconf Provides the connection information. * @param cptr Client structure for the peer. * @return Non-zero on success; zero on failure. */ static int connect_inet(struct ConfItem* aconf, struct Client* cptr) { const struct irc_sockaddr *local; IOResult result; int family = 0; assert(0 != aconf); assert(0 != cptr); /* * Might as well get sockhost from here, the connection is attempted * with it so if it fails its useless. */ if (irc_in_addr_valid(&aconf->origin.addr)) local = &aconf->origin; else if (irc_in_addr_is_ipv4(&aconf->address.addr)) { local = &VirtualHost_v4; family = AF_INET; } else local = &VirtualHost_v6; cli_fd(cptr) = os_socket(local, SOCK_STREAM, cli_name(cptr), family); if (cli_fd(cptr) < 0) return 0; /* * save connection info in client */ memcpy(&cli_ip(cptr), &aconf->address.addr, sizeof(cli_ip(cptr))); ircd_ntoa_r(cli_sock_ip(cptr), &cli_ip(cptr)); /* * we want a big buffer for server connections */ if (!os_set_sockbufs(cli_fd(cptr), feature_int(FEAT_SOCKSENDBUF), feature_int(FEAT_SOCKRECVBUF))) { cli_error(cptr) = errno; report_error(SETBUFS_ERROR_MSG, cli_name(cptr), errno); close(cli_fd(cptr)); cli_fd(cptr) = -1; return 0; } /* * Set the TOS bits - this is nonfatal if it doesn't stick. */ if (!os_set_tos(cli_fd(cptr), feature_int(FEAT_TOS_SERVER))) { report_error(TOS_ERROR_MSG, cli_name(cptr), errno); } if ((result = os_connect_nonb(cli_fd(cptr), &aconf->address)) == IO_FAILURE) { cli_error(cptr) = errno; report_error(CONNECT_ERROR_MSG, cli_name(cptr), errno); close(cli_fd(cptr)); cli_fd(cptr) = -1; return 0; } if (!socket_add(&(cli_socket(cptr)), client_sock_callback, (void*) cli_connect(cptr), (result == IO_SUCCESS) ? SS_CONNECTED : SS_CONNECTING, SOCK_EVENT_READABLE, cli_fd(cptr))) { cli_error(cptr) = ENFILE; report_error(REGISTER_ERROR_MSG, cli_name(cptr), ENFILE); close(cli_fd(cptr)); cli_fd(cptr) = -1; return 0; } cli_freeflag(cptr) |= FREEFLAG_SOCKET; return 1; }