void iwn_wapi_sm_rx_wai(struct wapi_asue_st *wpa_s, const unsigned char *src_addr, const unsigned char *buf, size_t len) { size_t plen; struct wai_hdr *hdr; u8 *wai_payload ; int res = 0; int frmlen = 0; src_addr = src_addr;/*disable warnning*/ if(wpa_s->wapi_state <WAPISM_AL_ASSOC) { iwn_wpa_printf(MSG_DEBUG, "wpa_s->wapi_state <WAPISM_AL_ASSOC"); return ; } else if((wpa_s->ap_type == AUTH_TYPE_WAPI) && (iwn_eloop.has_cert == 0)) { iwn_wpa_printf(MSG_DEBUG, "No cert"); return ; } hdr = (struct wai_hdr *) buf; if(check_wai_frame(wpa_s, buf, len) != 0){ iwn_wpa_printf(MSG_DEBUG, "WPA: WAI frame is wrong"); return; } wai_payload = (u8 *) (hdr + 1); GETSHORT((buf+6), frmlen); //plen = iwn_ntohs(hdr->length) - sizeof(*hdr); plen = frmlen - sizeof(*hdr); iwn_wpa_printf(MSG_ERROR, "iwn_wapi_sm_rx_wai plen = '%d', hdr->length = '%d'. stype = %d\n", plen, frmlen, hdr->stype); switch (hdr->stype) { case WAI_AUTHACTIVE: res = waigroup_cert_1_3(wpa_s, wai_payload, plen); if(res == -1) wapi_supplicant_key_negotiation_state_report(WPA_ASSOCIATED); break; case WAI_ACCESS_AUTH_RESPONSE: res = waigroup_cert_3_3(wpa_s, wai_payload, plen); if (0 == res) { timer_reset(); } else if (-1 == res) { timer_resend(); } else if (-2 == res) { setPskIncorrect(); } break; case WAI_USK_NEGOTIATION_REQUEST: res = waigroup_unicast_1_3(wpa_s, wai_payload, plen); if(res == -1) wapi_supplicant_key_negotiation_state_report(WPA_ASSOCIATED); else if (-2 == res) { setPskIncorrect(); } break; case WAI_USK_NEGOTIATION_CONFIRMATION: res = waigroup_unicast_3_3(wpa_s, wai_payload, plen); if (0 == res) { timer_reset(); } else if (-1 == res) { timer_resend(); } break; case WAI_MSK_ANNOUNCEMENT: res = waigroup_multicast_1_2(wpa_s, wai_payload,plen); break; case WAI_STAKEY_REQUEST: iwn_wpa_printf(MSG_DEBUG, "WPA: receive ignore frame stype %u", hdr->stype); break; case WAI_PREAUTH_START: case WAI_ACCESS_AUTH_REQUEST: case WAI_CERT_AUTH_REQUEST: case WAI_CERT_AUTH_RESPONSE: case WAI_USK_NEGOTIATION_RESPONSE: case WAI_MSK_ANNOUNCEMENT_RESPONSE: iwn_wpa_printf(MSG_DEBUG, "WPA: receive error frame stype %u", hdr->stype); break; default: iwn_wpa_printf(MSG_DEBUG, "WPA: receive unknown frame stype %u", hdr->stype); return; } wpa_s->rxfrag = free_rxfrag(wpa_s->rxfrag); }
static int dnsdb_find(void *handle, uschar *filename, const uschar *keystring, int length, uschar **result, uschar **errmsg, uint *do_cache) { int rc; int size = 256; int ptr = 0; int sep = 0; int defer_mode = PASS; int dnssec_mode = OK; int save_retrans = dns_retrans; int save_retry = dns_retry; int type; int failrc = FAIL; const uschar *outsep = CUS"\n"; const uschar *outsep2 = NULL; uschar *equals, *domain, *found; /* Because we're the working in the search pool, we try to reclaim as much store as possible later, so we preallocate the result here */ uschar *yield = store_get(size); dns_record *rr; dns_answer dnsa; dns_scan dnss; handle = handle; /* Keep picky compilers happy */ filename = filename; length = length; do_cache = do_cache; /* If the string starts with '>' we change the output separator. If it's followed by ';' or ',' we set the TXT output separator. */ while (isspace(*keystring)) keystring++; if (*keystring == '>') { outsep = keystring + 1; keystring += 2; if (*keystring == ',') { outsep2 = keystring + 1; keystring += 2; } else if (*keystring == ';') { outsep2 = US""; keystring++; } while (isspace(*keystring)) keystring++; } /* Check for a modifier keyword. */ for (;;) { if (strncmpic(keystring, US"defer_", 6) == 0) { keystring += 6; if (strncmpic(keystring, US"strict", 6) == 0) { defer_mode = DEFER; keystring += 6; } else if (strncmpic(keystring, US"lax", 3) == 0) { defer_mode = PASS; keystring += 3; } else if (strncmpic(keystring, US"never", 5) == 0) { defer_mode = OK; keystring += 5; } else { *errmsg = US"unsupported dnsdb defer behaviour"; return DEFER; } } else if (strncmpic(keystring, US"dnssec_", 7) == 0) { keystring += 7; if (strncmpic(keystring, US"strict", 6) == 0) { dnssec_mode = DEFER; keystring += 6; } else if (strncmpic(keystring, US"lax", 3) == 0) { dnssec_mode = PASS; keystring += 3; } else if (strncmpic(keystring, US"never", 5) == 0) { dnssec_mode = OK; keystring += 5; } else { *errmsg = US"unsupported dnsdb dnssec behaviour"; return DEFER; } } else if (strncmpic(keystring, US"retrans_", 8) == 0) { int timeout_sec; if ((timeout_sec = readconf_readtime(keystring += 8, ',', FALSE)) <= 0) { *errmsg = US"unsupported dnsdb timeout value"; return DEFER; } dns_retrans = timeout_sec; while (*keystring != ',') keystring++; } else if (strncmpic(keystring, US"retry_", 6) == 0) { int retries; if ((retries = (int)strtol(CCS keystring + 6, CSS &keystring, 0)) < 0) { *errmsg = US"unsupported dnsdb retry count"; return DEFER; } dns_retry = retries; } else break; while (isspace(*keystring)) keystring++; if (*keystring++ != ',') { *errmsg = US"dnsdb modifier syntax error"; return DEFER; } while (isspace(*keystring)) keystring++; } /* Figure out the "type" value if it is not T_TXT. If the keystring contains an = this must be preceded by a valid type name. */ type = T_TXT; if ((equals = Ustrchr(keystring, '=')) != NULL) { int i, len; uschar *tend = equals; while (tend > keystring && isspace(tend[-1])) tend--; len = tend - keystring; for (i = 0; i < nelem(type_names); i++) if (len == Ustrlen(type_names[i]) && strncmpic(keystring, US type_names[i], len) == 0) { type = type_values[i]; break; } if (i >= nelem(type_names)) { *errmsg = US"unsupported DNS record type"; return DEFER; } keystring = equals + 1; while (isspace(*keystring)) keystring++; } /* Initialize the resolver in case this is the first time it has been used. */ dns_init(FALSE, FALSE, dnssec_mode != OK); /* The remainder of the string must be a list of domains. As long as the lookup for at least one of them succeeds, we return success. Failure means that none of them were found. The original implementation did not support a list of domains. Adding the list feature is compatible, except in one case: when PTR records are being looked up for a single IPv6 address. Fortunately, we can hack in a compatibility feature here: If the type is PTR and no list separator is specified, and the entire remaining string is valid as an IP address, set an impossible separator so that it is treated as one item. */ if (type == T_PTR && keystring[0] != '<' && string_is_ip_address(keystring, NULL) != 0) sep = -1; /* SPF strings should be concatenated without a separator, thus make it the default if not defined (see RFC 4408 section 3.1.3). Multiple SPF records are forbidden (section 3.1.2) but are currently not handled specially, thus they are concatenated with \n by default. MX priority and value are space-separated by default. SRV and TLSA record parts are space-separated by default. */ if (!outsep2) switch(type) { case T_SPF: outsep2 = US""; break; case T_SRV: case T_MX: case T_TLSA: outsep2 = US" "; break; } /* Now scan the list and do a lookup for each item */ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) { uschar rbuffer[256]; int searchtype = (type == T_CSA)? T_SRV : /* record type we want */ (type == T_MXH)? T_MX : (type == T_ZNS)? T_NS : type; /* If the type is PTR or CSA, we have to construct the relevant magic lookup key if the original is an IP address (some experimental protocols are using PTR records for different purposes where the key string is a host name, and Exim's extended CSA can be keyed by domains or IP addresses). This code for doing the reversal is now in a separate function. */ if ((type == T_PTR || type == T_CSA) && string_is_ip_address(domain, NULL) != 0) { dns_build_reverse(domain, rbuffer); domain = rbuffer; } do { DEBUG(D_lookup) debug_printf("dnsdb key: %s\n", domain); /* Do the lookup and sort out the result. There are four special types that are handled specially: T_CSA, T_ZNS, T_ADDRESSES and T_MXH. The first two are handled in a special lookup function so that the facility could be used from other parts of the Exim code. T_ADDRESSES is handled by looping over the types of A lookup. T_MXH affects only what happens later on in this function, but for tidiness it is handled by the "special". If the lookup fails, continue with the next domain. In the case of DEFER, adjust the final "nothing found" result, but carry on to the next domain. */ found = domain; #if HAVE_IPV6 if (type == T_ADDRESSES) /* NB cannot happen unless HAVE_IPV6 */ { if (searchtype == T_ADDRESSES) searchtype = T_AAAA; else if (searchtype == T_AAAA) searchtype = T_A; rc = dns_special_lookup(&dnsa, domain, searchtype, CUSS &found); } else #endif rc = dns_special_lookup(&dnsa, domain, type, CUSS &found); lookup_dnssec_authenticated = dnssec_mode==OK ? NULL : dns_is_secure(&dnsa) ? US"yes" : US"no"; if (rc == DNS_NOMATCH || rc == DNS_NODATA) continue; if ( rc != DNS_SUCCEED || (dnssec_mode == DEFER && !dns_is_secure(&dnsa)) ) { if (defer_mode == DEFER) { dns_retrans = save_retrans; dns_retry = save_retry; dns_init(FALSE, FALSE, FALSE); /* clr dnssec bit */ return DEFER; /* always defer */ } if (defer_mode == PASS) failrc = DEFER; /* defer only if all do */ continue; /* treat defer as fail */ } /* Search the returned records */ for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); rr != NULL; rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) { if (rr->type != searchtype) continue; if (*do_cache > rr->ttl) *do_cache = rr->ttl; if (type == T_A || type == T_AAAA || type == T_ADDRESSES) { dns_address *da; for (da = dns_address_from_rr(&dnsa, rr); da; da = da->next) { if (ptr != 0) yield = string_catn(yield, &size, &ptr, outsep, 1); yield = string_cat(yield, &size, &ptr, da->address); } continue; } /* Other kinds of record just have one piece of data each, but there may be several of them, of course. */ if (ptr != 0) yield = string_catn(yield, &size, &ptr, outsep, 1); if (type == T_TXT || type == T_SPF) { if (outsep2 == NULL) { /* output only the first item of data */ yield = string_catn(yield, &size, &ptr, (uschar *)(rr->data+1), (rr->data)[0]); } else { /* output all items */ int data_offset = 0; while (data_offset < rr->size) { uschar chunk_len = (rr->data)[data_offset++]; if (outsep2[0] != '\0' && data_offset != 1) yield = string_catn(yield, &size, &ptr, outsep2, 1); yield = string_catn(yield, &size, &ptr, US ((rr->data)+data_offset), chunk_len); data_offset += chunk_len; } } } else if (type == T_TLSA) { uint8_t usage, selector, matching_type; uint16_t i, payload_length; uschar s[MAX_TLSA_EXPANDED_SIZE]; uschar * sp = s; uschar * p = US rr->data; usage = *p++; selector = *p++; matching_type = *p++; /* What's left after removing the first 3 bytes above */ payload_length = rr->size - 3; sp += sprintf(CS s, "%d%c%d%c%d%c", usage, *outsep2, selector, *outsep2, matching_type, *outsep2); /* Now append the cert/identifier, one hex char at a time */ for (i=0; i < payload_length && sp-s < (MAX_TLSA_EXPANDED_SIZE - 4); i++) sp += sprintf(CS sp, "%02x", (unsigned char)p[i]); yield = string_cat(yield, &size, &ptr, s); } else /* T_CNAME, T_CSA, T_MX, T_MXH, T_NS, T_PTR, T_SOA, T_SRV */ { int priority, weight, port; uschar s[264]; uschar * p = US rr->data; switch (type) { case T_MXH: /* mxh ignores the priority number and includes only the hostnames */ GETSHORT(priority, p); break; case T_MX: GETSHORT(priority, p); sprintf(CS s, "%d%c", priority, *outsep2); yield = string_cat(yield, &size, &ptr, s); break; case T_SRV: GETSHORT(priority, p); GETSHORT(weight, p); GETSHORT(port, p); sprintf(CS s, "%d%c%d%c%d%c", priority, *outsep2, weight, *outsep2, port, *outsep2); yield = string_cat(yield, &size, &ptr, s); break; case T_CSA: /* See acl_verify_csa() for more comments about CSA. */ GETSHORT(priority, p); GETSHORT(weight, p); GETSHORT(port, p); if (priority != 1) continue; /* CSA version must be 1 */ /* If the CSA record we found is not the one we asked for, analyse the subdomain assertions in the port field, else analyse the direct authorization status in the weight field. */ if (Ustrcmp(found, domain) != 0) { if (port & 1) *s = 'X'; /* explicit authorization required */ else *s = '?'; /* no subdomain assertions here */ } else { if (weight < 2) *s = 'N'; /* not authorized */ else if (weight == 2) *s = 'Y'; /* authorized */ else if (weight == 3) *s = '?'; /* unauthorizable */ else continue; /* invalid */ } s[1] = ' '; yield = string_catn(yield, &size, &ptr, s, 2); break; default: break; } /* GETSHORT() has advanced the pointer to the target domain. */ rc = dn_expand(dnsa.answer, dnsa.answer + dnsa.answerlen, p, (DN_EXPAND_ARG4_TYPE)s, sizeof(s)); /* If an overlong response was received, the data will have been truncated and dn_expand may fail. */ if (rc < 0) { log_write(0, LOG_MAIN, "host name alias list truncated: type=%s " "domain=%s", dns_text_type(type), domain); break; } else yield = string_cat(yield, &size, &ptr, s); if (type == T_SOA && outsep2 != NULL) { unsigned long serial, refresh, retry, expire, minimum; p += rc; yield = string_catn(yield, &size, &ptr, outsep2, 1); rc = dn_expand(dnsa.answer, dnsa.answer + dnsa.answerlen, p, (DN_EXPAND_ARG4_TYPE)s, sizeof(s)); if (rc < 0) { log_write(0, LOG_MAIN, "responsible-mailbox truncated: type=%s " "domain=%s", dns_text_type(type), domain); break; } else yield = string_cat(yield, &size, &ptr, s); p += rc; GETLONG(serial, p); GETLONG(refresh, p); GETLONG(retry, p); GETLONG(expire, p); GETLONG(minimum, p); sprintf(CS s, "%c%lu%c%lu%c%lu%c%lu%c%lu", *outsep2, serial, *outsep2, refresh, *outsep2, retry, *outsep2, expire, *outsep2, minimum); yield = string_cat(yield, &size, &ptr, s); } } } /* Loop for list of returned records */ /* Loop for set of A-lookup types */ } while (type == T_ADDRESSES && searchtype != T_A); } /* Loop for list of domains */ /* Reclaim unused memory */ store_reset(yield + ptr + 1); /* If ptr == 0 we have not found anything. Otherwise, insert the terminating zero and return the result. */ dns_retrans = save_retrans; dns_retry = save_retry; dns_init(FALSE, FALSE, FALSE); /* clear the dnssec bit for getaddrbyname */ if (ptr == 0) return failrc; yield[ptr] = 0; *result = yield; return OK; }
int dns_special_lookup(dns_answer *dnsa, const uschar *name, int type, const uschar **fully_qualified_name) { switch (type) { /* The "mx hosts only" type doesn't require any special action here */ case T_MXH: return dns_lookup(dnsa, name, T_MX, fully_qualified_name); /* Find nameservers for the domain or the nearest enclosing zone, excluding the root servers. */ case T_ZNS: type = T_NS; /* FALLTHROUGH */ case T_SOA: { const uschar *d = name; while (d != 0) { int rc = dns_lookup(dnsa, d, type, fully_qualified_name); if (rc != DNS_NOMATCH && rc != DNS_NODATA) return rc; while (*d != 0 && *d != '.') d++; if (*d++ == 0) break; } return DNS_NOMATCH; } /* Try to look up the Client SMTP Authorization SRV record for the name. If there isn't one, search from the top downwards for a CSA record in a parent domain, which might be making assertions about subdomains. If we find a record we set fully_qualified_name to whichever lookup succeeded, so that the caller can tell whether to look at the explicit authorization field or the subdomain assertion field. */ case T_CSA: { uschar *srvname, *namesuff, *tld, *p; int priority, weight, port; int limit, rc, i; BOOL ipv6; dns_record *rr; dns_scan dnss; DEBUG(D_dns) debug_printf("CSA lookup of %s\n", name); srvname = string_sprintf("_client._smtp.%s", name); rc = dns_lookup(dnsa, srvname, T_SRV, NULL); if (rc == DNS_SUCCEED || rc == DNS_AGAIN) { if (rc == DNS_SUCCEED) *fully_qualified_name = string_copy(name); return rc; } /* Search for CSA subdomain assertion SRV records from the top downwards, starting with the 2nd level domain. This order maximizes cache-friendliness. We skip the top level domains to avoid loading their nameservers and because we know they'll never have CSA SRV records. */ namesuff = Ustrrchr(name, '.'); if (namesuff == NULL) return DNS_NOMATCH; tld = namesuff + 1; ipv6 = FALSE; limit = dns_csa_search_limit; /* Use more appropriate search parameters if we are in the reverse DNS. */ if (strcmpic(namesuff, US".arpa") == 0) if (namesuff - 8 > name && strcmpic(namesuff - 8, US".in-addr.arpa") == 0) { namesuff -= 8; tld = namesuff + 1; limit = 3; } else if (namesuff - 4 > name && strcmpic(namesuff - 4, US".ip6.arpa") == 0) { namesuff -= 4; tld = namesuff + 1; ipv6 = TRUE; limit = 3; } DEBUG(D_dns) debug_printf("CSA TLD %s\n", tld); /* Do not perform the search if the top level or 2nd level domains do not exist. This is quite common, and when it occurs all the search queries would go to the root or TLD name servers, which is not friendly. So we check the AUTHORITY section; if it contains the root's SOA record or the TLD's SOA then the TLD or the 2LD (respectively) doesn't exist and we can skip the search. If the TLD and the 2LD exist but the explicit CSA record lookup failed, then the AUTHORITY SOA will be the 2LD's or a subdomain thereof. */ if (rc == DNS_NOMATCH) { /* This is really gross. The successful return value from res_search() is the packet length, which is stored in dnsa->answerlen. If we get a negative DNS reply then res_search() returns -1, which causes the bounds checks for name decompression to fail when it is treated as a packet length, which in turn causes the authority search to fail. The correct packet length has been lost inside libresolv, so we have to guess a replacement value. (The only way to fix this properly would be to re-implement res_search() and res_query() so that they don't muddle their success and packet length return values.) For added safety we only reset the packet length if the packet header looks plausible. */ HEADER *h = (HEADER *)dnsa->answer; if (h->qr == 1 && h->opcode == QUERY && h->tc == 0 && (h->rcode == NOERROR || h->rcode == NXDOMAIN) && ntohs(h->qdcount) == 1 && ntohs(h->ancount) == 0 && ntohs(h->nscount) >= 1) dnsa->answerlen = MAXPACKET; for (rr = dns_next_rr(dnsa, &dnss, RESET_AUTHORITY); rr; rr = dns_next_rr(dnsa, &dnss, RESET_NEXT) ) if (rr->type != T_SOA) continue; else if (strcmpic(rr->name, US"") == 0 || strcmpic(rr->name, tld) == 0) return DNS_NOMATCH; else break; } for (i = 0; i < limit; i++) { if (ipv6) { /* Scan through the IPv6 reverse DNS in chunks of 16 bits worth of IP address, i.e. 4 hex chars and 4 dots, i.e. 8 chars. */ namesuff -= 8; if (namesuff <= name) return DNS_NOMATCH; } else /* Find the start of the preceding domain name label. */ do if (--namesuff <= name) return DNS_NOMATCH; while (*namesuff != '.'); DEBUG(D_dns) debug_printf("CSA parent search at %s\n", namesuff + 1); srvname = string_sprintf("_client._smtp.%s", namesuff + 1); rc = dns_lookup(dnsa, srvname, T_SRV, NULL); if (rc == DNS_AGAIN) return rc; if (rc != DNS_SUCCEED) continue; /* Check that the SRV record we have found is worth returning. We don't just return the first one we find, because some lower level SRV record might make stricter assertions than its parent domain. */ for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) { if (rr->type != T_SRV) continue; /* Extract the numerical SRV fields (p is incremented) */ p = rr->data; GETSHORT(priority, p); GETSHORT(weight, p); weight = weight; /* compiler quietening */ GETSHORT(port, p); /* Check the CSA version number */ if (priority != 1) continue; /* If it's making an interesting assertion, return this response. */ if (port & 1) { *fully_qualified_name = namesuff + 1; return DNS_SUCCEED; } } } return DNS_NOMATCH; } default: if (type >= 0) return dns_lookup(dnsa, name, type, fully_qualified_name); } /* Control should never reach here */ return DNS_FAIL; }
static unsigned char *php_parserr(unsigned char *cp, unsigned char* end, querybuf *answer, int type_to_fetch, bool store, Array &subarray) { unsigned short type, cls ATTRIBUTE_UNUSED, dlen; unsigned long ttl; int64_t n, i; unsigned short s; unsigned char *tp, *p; char name[255 + 2]; // IETF STD 13 section 3.1; 255 bytes int have_v6_break = 0, in_v6_break = 0; n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, sizeof(name) - 2); if (n < 0) { return NULL; } cp += n; CHECKCP(10); GETSHORT(type, cp); GETSHORT(cls, cp); GETLONG(ttl, cp); GETSHORT(dlen, cp); CHECKCP(dlen); if (type_to_fetch != T_ANY && type != type_to_fetch) { cp += dlen; return cp; } if (!store) { cp += dlen; return cp; } subarray.set(s_host, String(name, CopyString)); switch (type) { case DNS_T_A: CHECKCP(4); subarray.set(s_type, s_A); snprintf(name, sizeof(name), "%d.%d.%d.%d", cp[0], cp[1], cp[2], cp[3]); subarray.set(s_ip, String(name, CopyString)); cp += dlen; break; case DNS_T_MX: CHECKCP(2); subarray.set(s_type, s_MX); GETSHORT(n, cp); subarray.set(s_pri, n); /* no break; */ case DNS_T_CNAME: if (type == DNS_T_CNAME) { subarray.set(s_type, s_CNAME); } /* no break; */ case DNS_T_NS: if (type == DNS_T_NS) { subarray.set(s_type, s_NS); } /* no break; */ case DNS_T_PTR: if (type == DNS_T_PTR) { subarray.set(s_type, s_PTR); } n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) - 2); if (n < 0) { return NULL; } cp += n; subarray.set(s_target, String(name, CopyString)); break; case DNS_T_HINFO: /* See RFC 1010 for values */ subarray.set(s_type, s_HINFO); CHECKCP(1); n = *cp & 0xFF; cp++; CHECKCP(n); subarray.set(s_cpu, String((const char *)cp, n, CopyString)); cp += n; CHECKCP(1); n = *cp & 0xFF; cp++; CHECKCP(n); subarray.set(s_os, String((const char *)cp, n, CopyString)); cp += n; break; case DNS_T_TXT: { int l1 = 0, l2 = 0; String s = String(dlen, ReserveString); tp = (unsigned char *)s.mutableData(); while (l1 < dlen) { n = cp[l1]; if ((n + l1) > dlen) { // bad record, don't set anything break; } memcpy(tp + l1 , cp + l1 + 1, n); l1 = l1 + n + 1; l2 = l2 + n; } s.setSize(l2); cp += dlen; subarray.set(s_type, s_TXT); subarray.set(s_txt, s); break; } case DNS_T_SOA: subarray.set(s_type, s_SOA); n = dn_expand(answer->qb2, end, cp, name, (sizeof name) -2); if (n < 0) { return NULL; } cp += n; subarray.set(s_mname, String(name, CopyString)); n = dn_expand(answer->qb2, end, cp, name, (sizeof name) -2); if (n < 0) { return NULL; } cp += n; subarray.set(s_rname, String(name, CopyString)); CHECKCP(5*4); GETLONG(n, cp); subarray.set(s_serial, n); GETLONG(n, cp); subarray.set(s_refresh, n); GETLONG(n, cp); subarray.set(s_retry, n); GETLONG(n, cp); subarray.set(s_expire, n); GETLONG(n, cp); subarray.set(s_minimum_ttl, n); break; case DNS_T_AAAA: tp = (unsigned char *)name; CHECKCP(8*2); for (i = 0; i < 8; i++) { GETSHORT(s, cp); if (s != 0) { if (tp > (u_char *)name) { in_v6_break = 0; tp[0] = ':'; tp++; } tp += sprintf((char *)tp, "%x", s); } else { if (!have_v6_break) { have_v6_break = 1; in_v6_break = 1; tp[0] = ':'; tp++; } else if (!in_v6_break) { tp[0] = ':'; tp++; tp[0] = '0'; tp++; } } } if (have_v6_break && in_v6_break) { tp[0] = ':'; tp++; } tp[0] = '\0'; subarray.set(s_type, s_AAAA); subarray.set(s_ipv6, String(name, CopyString)); break; case DNS_T_A6: p = cp; subarray.set(s_type, s_A6); CHECKCP(1); n = ((int)cp[0]) & 0xFF; cp++; subarray.set(s_masklen, n); tp = (unsigned char *)name; if (n > 15) { have_v6_break = 1; in_v6_break = 1; tp[0] = ':'; tp++; } if (n % 16 > 8) { /* Partial short */ if (cp[0] != 0) { if (tp > (u_char *)name) { in_v6_break = 0; tp[0] = ':'; tp++; } sprintf((char *)tp, "%x", cp[0] & 0xFF); } else { if (!have_v6_break) { have_v6_break = 1; in_v6_break = 1; tp[0] = ':'; tp++; } else if (!in_v6_break) { tp[0] = ':'; tp++; tp[0] = '0'; tp++; } } cp++; } for (i = (n + 8)/16; i < 8; i++) { CHECKCP(2); GETSHORT(s, cp); if (s != 0) { if (tp > (u_char *)name) { in_v6_break = 0; tp[0] = ':'; tp++; } tp += sprintf((char*)tp,"%x",s); } else { if (!have_v6_break) { have_v6_break = 1; in_v6_break = 1; tp[0] = ':'; tp++; } else if (!in_v6_break) { tp[0] = ':'; tp++; tp[0] = '0'; tp++; } } } if (have_v6_break && in_v6_break) { tp[0] = ':'; tp++; } tp[0] = '\0'; subarray.set(s_ipv6, String(name, CopyString)); if (cp < p + dlen) { n = dn_expand(answer->qb2, end, cp, name, (sizeof name) - 2); if (n < 0) { return NULL; } cp += n; subarray.set(s_chain, String(name, CopyString)); } break; case DNS_T_SRV: CHECKCP(3*2); subarray.set(s_type, s_SRV); GETSHORT(n, cp); subarray.set(s_pri, n); GETSHORT(n, cp); subarray.set(s_weight, n); GETSHORT(n, cp); subarray.set(s_port, n); n = dn_expand(answer->qb2, end, cp, name, (sizeof name) - 2); if (n < 0) { return NULL; } cp += n; subarray.set(s_target, String(name, CopyString)); break; case DNS_T_NAPTR: CHECKCP(2*2); subarray.set(s_type, s_NAPTR); GETSHORT(n, cp); subarray.set(s_order, n); GETSHORT(n, cp); subarray.set(s_pref, n); CHECKCP(1); n = (cp[0] & 0xFF); ++cp; CHECKCP(n); subarray.set(s_flags, String((const char *)cp, n, CopyString)); cp += n; CHECKCP(1); n = (cp[0] & 0xFF); ++cp; CHECKCP(n); subarray.set(s_services, String((const char *)cp, n, CopyString)); cp += n; CHECKCP(1); n = (cp[0] & 0xFF); ++cp; CHECKCP(n); subarray.set(s_regex, String((const char *)cp, n, CopyString)); cp += n; n = dn_expand(answer->qb2, end, cp, name, (sizeof name) - 2); if (n < 0) { return NULL; } cp += n; subarray.set(s_replacement, String(name, CopyString)); break; default: cp += dlen; } subarray.set(s_class, s_IN); subarray.set(s_ttl, (int)ttl); return cp; }
static size_t process_reply(struct dns_header *header, time_t now, struct server *server, size_t n, int check_rebind, int checking_disabled) { unsigned char *pheader, *sizep; int munged = 0, is_sign; size_t plen; /* If upstream is advertising a larger UDP packet size than we allow, trim it so that we don't get overlarge requests for the client. We can't do this for signed packets. */ if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign)) && !is_sign) { unsigned short udpsz; unsigned char *psave = sizep; GETSHORT(udpsz, sizep); if (udpsz > daemon->edns_pktsz) PUTSHORT(daemon->edns_pktsz, psave); } /* RFC 4035 sect 4.6 para 3 */ if (!is_sign && !option_bool(OPT_DNSSEC)) header->hb4 &= ~HB4_AD; if (OPCODE(header) != QUERY || (RCODE(header) != NOERROR && RCODE(header) != NXDOMAIN)) return n; /* Complain loudly if the upstream server is non-recursive. */ if (!(header->hb4 & HB4_RA) && RCODE(header) == NOERROR && ntohs(header->ancount) == 0 && server && !(server->flags & SERV_WARNED_RECURSIVE)) { prettyprint_addr(&server->addr, daemon->namebuff); my_syslog(LOG_WARNING, _("nameserver %s refused to do a recursive query"), daemon->namebuff); if (!option_bool(OPT_LOG)) server->flags |= SERV_WARNED_RECURSIVE; } if (daemon->bogus_addr && RCODE(header) != NXDOMAIN && check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now)) { munged = 1; SET_RCODE(header, NXDOMAIN); header->hb3 &= ~HB3_AA; } else { if (RCODE(header) == NXDOMAIN && extract_request(header, n, daemon->namebuff, NULL) && check_for_local_domain(daemon->namebuff, now)) { /* if we forwarded a query for a locally known name (because it was for an unknown type) and the answer is NXDOMAIN, convert that to NODATA, since we know that the domain exists, even if upstream doesn't */ munged = 1; header->hb3 |= HB3_AA; SET_RCODE(header, NOERROR); } if (extract_addresses(header, n, daemon->namebuff, now, is_sign, check_rebind, checking_disabled)) { my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff); munged = 1; } } /* do this after extract_addresses. Ensure NODATA reply and remove nameserver info. */ if (munged) { header->ancount = htons(0); header->nscount = htons(0); header->arcount = htons(0); } /* the bogus-nxdomain stuff, doctor and NXDOMAIN->NODATA munging can all elide sections of the packet. Find the new length here and put back pseudoheader if it was removed. */ return resize_packet(header, n, pheader, plen); }
static bool ProcessDNSRecords( const unsigned char * reply, const unsigned char * replyEnd, unsigned char * cp, size_t anCount, size_t nsCount, size_t arCount, DNS_RECORD * results) { DNS_RECORD lastRecord = 0; size_t rrCount = anCount + nsCount + arCount; nsCount += anCount; arCount += nsCount; size_t i; for (i = 0; i < rrCount; i++) { int section; if (i < anCount) section = DnsSectionAnswer; else if (i < nsCount) section = DnsSectionAuthority; else // if (i < arCount) section = DnsSectionAddtional; // get the name char pName[MAXDNAME]; if (!GetDN(reply, replyEnd, cp, pName)) return false; // get other common parts of the record unsigned short type; unsigned short dnsClass; unsigned long ttl; unsigned short dlen; GETSHORT(type, cp); GETSHORT(dnsClass, cp); GETLONG (ttl, cp); GETSHORT(dlen, cp); // // Avoid unused compiler warning // (void)dnsClass; (void)ttl; unsigned char * data = cp; cp += dlen; DNS_RECORD newRecord = 0; switch (type) { default: newRecord = (DNS_RECORD)malloc(sizeof(DnsRecord) + sizeof(unsigned long) + dlen); newRecord->Data.Null.dwByteCount = dlen; memcpy(&newRecord->Data, data, dlen); break; case T_SRV: newRecord = (DNS_RECORD)malloc(sizeof(DnsRecord)); memset(newRecord, 0, sizeof(DnsRecord)); GETSHORT(newRecord->Data.SRV.wPriority, data); GETSHORT(newRecord->Data.SRV.wWeight, data); GETSHORT(newRecord->Data.SRV.wPort, data); if (!GetDN(reply, replyEnd, data, newRecord->Data.SRV.pNameTarget)) { free(newRecord); return false; } break; case T_MX: newRecord = (DNS_RECORD)malloc(sizeof(DnsRecord)); memset(newRecord, 0, sizeof(DnsRecord)); GETSHORT(newRecord->Data.MX.wPreference, data); if (!GetDN(reply, replyEnd, data, newRecord->Data.MX.pNameExchange)) { free(newRecord); return false; } break; case T_A: newRecord = (DNS_RECORD)malloc(sizeof(DnsRecord)); memset(newRecord, 0, sizeof(DnsRecord)); GETLONG(newRecord->Data.A.IpAddress, data); break; case T_NS: newRecord = (DNS_RECORD)malloc(sizeof(DnsRecord)); memset(newRecord, 0, sizeof(DnsRecord)); if (!GetDN(reply, replyEnd, data, newRecord->Data.NS.pNameHost)) { free (newRecord); return false; } break; } // initialise the new record if (newRecord != 0) { newRecord->wType = type; newRecord->Flags.S.Section = section; newRecord->pNext = 0; strcpy(newRecord->pName, pName); bool hasPlaceHolder = false; if (*results == 0) { *results = newRecord; hasPlaceHolder = true; } else if (lastRecord != 0) { lastRecord->pNext = newRecord; hasPlaceHolder = true; } if (hasPlaceHolder) { lastRecord = newRecord; newRecord = 0; } else { // // This can never happen but we need to satisfy coverity scan. // free(newRecord); newRecord = 0; } } } return true; }
/* * get_input - called when incoming data is available. */ static void get_input(void) { int len, i; u_char *p; u_short protocol; struct protent *protp; p = inpacket_buf; /* point to beginning of packet buffer */ len = read_packet(inpacket_buf); if (len < 0) return; if (len == 0) { etime = time(NULL); minutes = (etime-stime)/60; syslog(LOG_NOTICE, "Modem hangup, connected for %d minutes", (minutes >1) ? minutes : 1); hungup = 1; lcp_lowerdown(0); /* serial link is no longer available */ link_terminated(0); return; } if (debug /*&& (debugflags & DBG_INPACKET)*/) log_packet(p, len, "rcvd ", LOG_DEBUG); if (len < PPP_HDRLEN) { MAINDEBUG((LOG_INFO, "io(): Received short packet.")); return; } p += 2; /* Skip address and control */ GETSHORT(protocol, p); len -= PPP_HDRLEN; /* * Toss all non-LCP packets unless LCP is OPEN. */ if (protocol != PPP_LCP && lcp_fsm[0].state != OPENED) { MAINDEBUG((LOG_INFO, "get_input: Received non-LCP packet when LCP not open.")); return; } /* * Until we get past the authentication phase, toss all packets * except LCP, LQR and authentication packets. */ if (phase <= PHASE_AUTHENTICATE && !(protocol == PPP_LCP || protocol == PPP_LQR || protocol == PPP_PAP || protocol == PPP_CHAP)) { MAINDEBUG((LOG_INFO, "get_input: discarding proto 0x%x in phase %d", protocol, phase)); return; } /* * Upcall the proper protocol input routine. */ for (i = 0; (protp = protocols[i]) != NULL; ++i) { if (protp->protocol == protocol && protp->enabled_flag) { (*protp->input)(0, p, len); return; } if (protocol == (protp->protocol & ~0x8000) && protp->enabled_flag && protp->datainput != NULL) { (*protp->datainput)(0, p, len); return; } } if (debug) syslog(LOG_WARNING, "Unsupported protocol (0x%x) received", protocol); lcp_sprotrej(0, p - PPP_HDRLEN, len + PPP_HDRLEN); }
static int printZone(ns_type xfr, const char *zone, const struct sockaddr_in *sin, ns_tsig_key *key) { static u_char *answer = NULL; static int answerLen = 0; querybuf buf; int msglen, amtToRead, numRead, result, sockFD, len; int count, type, rlen, done, n; int numAnswers, numRecords, soacnt; u_char *cp, tmp[NS_INT16SZ]; char dname[2][NS_MAXDNAME]; enum { NO_ERRORS, ERR_READING_LEN, ERR_READING_MSG, ERR_PRINTING } error; pid_t zpid = -1; u_char *newmsg; int newmsglen; ns_tcp_tsig_state tsig_state; int tsig_ret, tsig_required, tsig_present; switch (xfr) { case ns_t_axfr: case ns_t_zxfr: break; default: fprintf(stderr, ";; %s - transfer type not supported\n", p_type(xfr)); return (ERROR); } /* * Create a query packet for the requested zone name. */ msglen = res_nmkquery(&res, ns_o_query, zone, queryClass, ns_t_axfr, NULL, 0, 0, buf.qb2, sizeof buf); if (msglen < 0) { if (res.options & RES_DEBUG) fprintf(stderr, ";; res_nmkquery failed\n"); return (ERROR); } /* * Sign the message if a key was sent */ if (key == NULL) { newmsg = (u_char *)&buf; newmsglen = msglen; } else { DST_KEY *dstkey; int bufsize, siglen; u_char sig[64]; int ret; /* ns_sign() also calls dst_init(), but there is no harm * doing it twice */ dst_init(); bufsize = msglen + 1024; newmsg = (u_char *) malloc(bufsize); if (newmsg == NULL) { errno = ENOMEM; return (-1); } memcpy(newmsg, (u_char *)&buf, msglen); newmsglen = msglen; if (strcmp(key->alg, NS_TSIG_ALG_HMAC_MD5) != 0) dstkey = NULL; else dstkey = dst_buffer_to_key(key->name, KEY_HMAC_MD5, NS_KEY_TYPE_AUTH_ONLY, NS_KEY_PROT_ANY, key->data, key->len); if (dstkey == NULL) { errno = EINVAL; if (key) free(newmsg); return (-1); } siglen = sizeof(sig); /* newmsglen++; */ ret = ns_sign(newmsg, &newmsglen, bufsize, NOERROR, dstkey, NULL, 0, sig, &siglen, 0); if (ret < 0) { if (key) free (newmsg); if (ret == NS_TSIG_ERROR_NO_SPACE) errno = EMSGSIZE; else if (ret == -1) errno = EINVAL; return (ret); } ns_verify_tcp_init(dstkey, sig, siglen, &tsig_state); } /* * Set up a virtual circuit to the server. */ if ((sockFD = socket(sin->sin_family, SOCK_STREAM, 0)) < 0) { int e = errno; perror(";; socket"); return (e); } switch (sin->sin_family) { case AF_INET: if (bind(sockFD, (struct sockaddr *)&myaddress, sizeof myaddress) < 0){ int e = errno; fprintf(stderr, ";; bind(%s port %u): %s\n", inet_ntoa(myaddress.sin_addr), ntohs(myaddress.sin_port), strerror(e)); (void) close(sockFD); sockFD = -1; return (e); } if (connect(sockFD, (const struct sockaddr *)sin, sizeof *sin) < 0) { int e = errno; perror(";; connect"); (void) close(sockFD); sockFD = -1; return (e); } break; case AF_INET6: if (bind(sockFD, (struct sockaddr *)&myaddress6, sizeof myaddress6) < 0){ int e = errno; char buf[80]; fprintf(stderr, ";; bind(%s port %u): %s\n", inet_ntop(AF_INET6, &myaddress6.sin6_addr, buf, sizeof(buf)), ntohs(myaddress6.sin6_port), strerror(e)); (void) close(sockFD); sockFD = -1; return (e); } if (connect(sockFD, (const struct sockaddr *)sin, sizeof(struct sockaddr_in6)) < 0) { int e = errno; perror(";; connect"); (void) close(sockFD); sockFD = -1; return (e); } break; } /* * Send length & message for zone transfer */ ns_put16(newmsglen, tmp); if (write(sockFD, (char *)tmp, NS_INT16SZ) != NS_INT16SZ || write(sockFD, (char *)newmsg, newmsglen) != newmsglen) { int e = errno; if (key) free (newmsg); perror(";; write"); (void) close(sockFD); sockFD = -1; return (e); } else if (key) free (newmsg); /* * If we're compressing, push a gzip into the pipeline. */ if (xfr == ns_t_zxfr) { enum { rd = 0, wr = 1 }; int z[2]; if (pipe(z) < 0) { int e = errno; perror(";; pipe"); (void) close(sockFD); sockFD = -1; return (e); } zpid = vfork(); if (zpid < 0) { int e = errno; perror(";; fork"); (void) close(sockFD); sockFD = -1; return (e); } else if (zpid == 0) { /* Child. */ (void) close(z[rd]); (void) dup2(sockFD, STDIN_FILENO); (void) close(sockFD); (void) dup2(z[wr], STDOUT_FILENO); (void) close(z[wr]); execlp("gzip", "gzip", "-d", "-v", NULL); perror(";; child: execlp(gunzip)"); _exit(1); } /* Parent. */ (void) close(z[wr]); (void) dup2(z[rd], sockFD); (void) close(z[rd]); } result = 0; numAnswers = 0; numRecords = 0; soacnt = 0; error = NO_ERRORS; numRead = 0; dname[0][0] = '\0'; for (done = 0; !done; (void)NULL) { /* * Read the length of the response. */ cp = tmp; amtToRead = INT16SZ; while (amtToRead > 0 && (numRead = read(sockFD, cp, amtToRead)) > 0) { cp += numRead; amtToRead -= numRead; } if (numRead <= 0) { error = ERR_READING_LEN; break; } len = ns_get16(tmp); if (len == 0) break; /* nothing left to read */ /* * The server sent too much data to fit the existing buffer -- * allocate a new one. */ if (len > answerLen) { if (answerLen != 0) free(answer); answerLen = len; answer = (u_char *)malloc(answerLen); } /* * Read the response. */ amtToRead = len; cp = answer; while (amtToRead > 0 && (numRead = read(sockFD, cp, amtToRead)) > 0) { cp += numRead; amtToRead -= numRead; } if (numRead <= 0) { error = ERR_READING_MSG; break; } result = print_axfr(stdout, answer, len); if (result != 0) { error = ERR_PRINTING; break; } numRecords += htons(((HEADER *)answer)->ancount); numAnswers++; /* Header. */ cp = answer + HFIXEDSZ; /* Question. */ for (count = ntohs(((HEADER *)answer)->qdcount); count > 0; count--) { n = dn_skipname(cp, answer + len); if (n < 0) { error = ERR_PRINTING; done++; break; } cp += n + QFIXEDSZ; if (cp > answer + len) { error = ERR_PRINTING; done++; break; } } /* Answer. */ for (count = ntohs(((HEADER *)answer)->ancount); count > 0 && !done; count--) { n = dn_expand(answer, answer + len, cp, dname[soacnt], sizeof dname[0]); if (n < 0) { error = ERR_PRINTING; done++; break; } cp += n; if (cp + 3 * INT16SZ + INT32SZ > answer + len) { error = ERR_PRINTING; done++; break; } GETSHORT(type, cp); cp += INT16SZ; cp += INT32SZ; /* ttl */ GETSHORT(rlen, cp); cp += rlen; if (cp > answer + len) { error = ERR_PRINTING; done++; break; } if (type == T_SOA && soacnt++ && ns_samename(dname[0], dname[1]) == 1) { done++; break; } } /* * Verify the TSIG */ if (key) { if (ns_find_tsig(answer, answer + len) != NULL) tsig_present = 1; else tsig_present = 0; if (numAnswers == 1 || soacnt > 1) tsig_required = 1; else tsig_required = 0; tsig_ret = ns_verify_tcp(answer, &len, &tsig_state, tsig_required); if (tsig_ret == 0) { if (tsig_present) printf("; TSIG ok\n"); } else printf("; TSIG invalid\n"); } } printf(";; Received %d answer%s (%d record%s).\n", numAnswers, (numAnswers != 1) ? "s" : "", numRecords, (numRecords != 1) ? "s" : ""); (void) close(sockFD); sockFD = -1; /* * If we were uncompressing, reap the uncompressor. */ if (xfr == ns_t_zxfr) { pid_t pid; int status = 0; pid = wait(&status); if (pid < 0) { int e = errno; perror(";; wait"); return (e); } if (pid != zpid) { fprintf(stderr, ";; wrong pid (%lu != %lu)\n", (u_long)pid, (u_long)zpid); return (ERROR); } printf(";; pid %lu: exit %d, signal %d, core %c\n", (u_long)pid, WEXITSTATUS(status), WIFSIGNALED(status) ? WTERMSIG(status) : 0, WCOREDUMP(status) ? 't' : 'f'); } switch (error) { case NO_ERRORS: return (0); case ERR_READING_LEN: return (EMSGSIZE); case ERR_PRINTING: return (result); case ERR_READING_MSG: return (EMSGSIZE); default: return (EFAULT); } }
main () { int i, j, hl, rc, qc, ac, p, a; int op, class, type, datalen, buflen, msgl; u_short qtype, qclass, rtype, rclass, l, l2; u_long rttl; u_char buf[100], *cp; char dn[100], *dname, *z, ping[50]; struct rrec newrr, *rec; union { char cdat[4]; unsigned long ldat; struct in_addr adat; } dat; union { u_char data[DATALEN]; HEADER head; } data; hl = sizeof (HEADER); signal (SIGALRM, tfunc); res_init(); printf ("Inhalt von resolv.conf\n"); printf ("domain: %s\n", _res.defdname); /* printf ("MAXDNSRCH = %d\n", MAXDNSRCH); for (i=0; i<MAXDNSRCH; i++) printf ("%s\n", _res.dnsrch[i]); */ printf ("%d Name-Server\n", MAXNS); for (i=0; i<MAXNS; i++) printf ("%s\n", inet_ntoa(_res.nsaddr_list[i].sin_addr)); /* printf ("number of addresses: %d \n", _res.ascount); printf ("number of name servers: %d \n", _res.nscount); */ /*printf ("%d %s\n", _res.ascount, inet_ntoa(_res.sort_list[0]));*/ /* strcpy (dn, "zeus.rz.htwk-leipzig.de"); */ /* strcpy (dn, "caramba.cs.tu-berlin.de"); */ /* strcpy (dn, "ftp.cs.tu-berlin.de"); */ /* strcpy (dn, "moses.imn.htwk-leipzig.de"); */ /* strcpy (dn, "moses"); */ do { printf ("\nSuche nach IP-Adresse von\n"); printf ("Hostname: "); z = gets (dn); printf ("\n"); if (z) { dname = dn; strcpy (data.data, dn); datalen = strlen(dn)+1; op = QUERY; buflen = sizeof(buf); /* _res.options |= RES_DEBUG; */ _res.retrans = 10; _res.retry = 2; class = C_IN; type = T_A; rc=res_mkquery (op, dname, class, type, data.data, datalen, &newrr, buf, buflen); buflen = rc; alarm (10); msgl=res_send (buf, buflen, data.data, DATALEN); if (msgl>0) { /* printf ("\nsend: %d\n", msgl); */ /* for (i=0; i< msgl; i++) { for (j=0; j<4; j++) dat.cdat[j] = data.data[i+j]; */ /* printf ("%x ", dat.ldat); if (dat.ldat==x) printf ("\n%d %x\n", i, dat.ldat); } printf ("\n"); */ /* for (i=0; i< msgl;i++) { j = data.data[i] & 0xff; printf ("%2x ", j); } printf ("\n"); for (i=0; i< msgl;i++) if (data.data[i]>31) printf ("%c ", data.data[i]); printf ("\n"); */ /* printf ("%x \n", x); */ ac = data.head.ancount; qc = data.head.qdcount; p = hl; printf ("Query\n"); while (qc) { l = data.data[p]; while (l > 0 && l < 64) { /* printf ("%d \n", p); */ for (i=1; i<=l; i++) putchar (data.data[p+i]); p = p + l + 1; l = data.data[p]; if (l) putchar ('.'); } putchar ('\n'); p++; cp = data.data+p; /* GETSHORT verlangt Pointervariable !! */ /* einfache Zuweisung (auch mit cast) ergibt falsche Werte evtl. Probleme mit integralen Grenzen ?? */ GETSHORT (qtype, cp); /* oder: qtype = _getshort(data.data+p);*/ p = p + sizeof(u_short); cp = data.data+p; GETSHORT (qclass, cp); p = p + sizeof(u_short); cp = data.data+p; printf ("QTYPE=%d, QCLASS=%d", qtype, qclass); qc--; putchar ('\n'); } printf ("\n%d Answers\n", ac); a=1; while (ac) { printf ("%d.\n", a); l = data.data[p]; while (l > 0 && l < 64) { /* printf ("%d \n", p); */ for (i=1; i<=l; i++) putchar (data.data[p+i]); p = p + l + 1; l = data.data[p]; if (l) putchar ('.'); else putchar ('\n'); } if (l>63) { rc=dn_expand (data.data, data.data+msgl, cp, buf, buflen); printf ("%s\n", buf); p += 2; } else p++; cp = data.data+p; GETSHORT (rtype, cp); p = p + sizeof(u_short); cp = data.data+p; GETSHORT (rclass, cp); p = p + sizeof(u_short); cp = data.data+p; GETLONG (rttl, cp); p = p + sizeof(u_long); printf ("RRTYPE=%d, RRCLASS=%d RRTTL=%d\n", rtype, rclass, rttl); cp = data.data+p; GETSHORT (l, cp); p = p + sizeof(u_short); if (rtype == 1) { for (j = 0; j< l; j++) dat.cdat[j] = data.data[p+j]; /* printf ("IP-Adresse: %x \n", dat.ldat); */ printf ("IP-Adresse: %s \n", inet_ntoa (dat.adat)); sprintf (buf, "%s", inet_ntoa (dat.adat)); strcpy (ping, "ping "); strcat (ping, buf); strcat (ping, " 10"); printf ("%s\n", ping); system (ping); p += l; } if (rtype == 5) { l2 = l; l = data.data[p]; while (l > 0 && l < 64) { /* printf ("%d \n", p); */ for (i=1; i<=l; i++) putchar (data.data[p+i]); p = p + l + 1; l = data.data[p]; if (l) putchar ('.'); else putchar('\n'); } if (l>63) { rc=dn_expand (data.data, data.data+msgl, cp, buf, buflen); printf ("%s\n", buf); p += 2; } else p++; l = l2; } putchar ('\n'); ac--; a++; } } else printf ("not found\n"); } } while (z); }
static int waigroup_cert_3_3(struct wapi_asue_st* wpa_s, u8* payload, int len) { u8 flag = 0 ; u8 *Nasue = NULL, *Nae = NULL, *acc_res = NULL; u8 *asue_key_data = NULL,*ae_key_data = NULL; u8 *ae_id = NULL, *asue_id = NULL, *cert_res = NULL; u8 *ae_sign = NULL; int request_len = 0; const struct cert_obj_st_t *cert_obj = NULL; iwn_wpa_printf(MSG_DEBUG, "WPA: in %s:%d", __func__, __LINE__); if (wpa_s->wapi_state != WAPISM_CNT_REQ) { return -1; } wapi_supplicant_key_negotiation_state_report(WPA_4WAY_HANDSHAKE); /*flag*/ flag = payload[0]; iwn_wpa_printf(MSG_DEBUG, "WPA: in %s:%d,flag=%d", __func__, __LINE__,flag); iwn_wpa_printf(MSG_DEBUG, "WPA: in %s:%d,wpa_s->flag=%d,(flag & BIT(0) )=%d", __func__, __LINE__,flag,(flag & BIT(0) )); iwn_wpa_printf(MSG_DEBUG, "WPA: in %s:%d,wpa_s->flag=%d,(flag & BIT(0) )=%d", __func__, __LINE__,flag,(wpa_s->flag& BIT(0) )); iwn_wpa_printf(MSG_DEBUG, "WPA: in %s:%d,wpa_s->flag=%d,(flag & BIT(1) )=%d", __func__, __LINE__,flag,(flag & BIT(1) )); iwn_wpa_printf(MSG_DEBUG, "WPA: in %s:%d,wpa_s->flag=%d,(flag & BIT(1) )=%d", __func__, __LINE__,flag,(wpa_s->flag & BIT(1) )); if((flag &0x03)!= (wpa_s->flag & 0x03)) { iwn_wpa_printf(MSG_ERROR, "WPA: not same flag bit 0,1!\n"); return -1; } request_len +=1; Nasue = payload+1; if(Nasue == NULL) return -1; if(memcmp(Nasue, wpa_s->Nasue , 32)!=0) { iwn_wpa_printf(MSG_ERROR, "WPA: not same Nasue!\n"); return -1; } request_len +=32; Nae = Nasue + 32; if(Nae== NULL) return -1; memcpy(wpa_s->Nae, Nae, 32); request_len +=32; acc_res = Nae + 32; if(acc_res == NULL) return -1; if(acc_res[0] != 0) return -2; request_len +=1; asue_key_data = acc_res + 1; if(asue_key_data == NULL) return -1; if((asue_key_data[0]!=wpa_s->asue_key_data.length) ||memcmp((char *)asue_key_data+1, &(wpa_s->asue_key_data.data), wpa_s->asue_key_data.length )!=0) { iwn_wpa_printf(MSG_ERROR, "WPA: not same asue key data!,asue_len =%d,wpa_s->asue_key_data.length=%d\n",asue_key_data[0],wpa_s->asue_key_data.length); return -1; } request_len +=wpa_s->asue_key_data.length + 1; ae_key_data = asue_key_data + wpa_s->asue_key_data.length + 1; if(ae_key_data == NULL) return -1; memcpy(wpa_s->ae_key_data.data, ae_key_data+1,ae_key_data[0]); wpa_s->ae_key_data.length = ae_key_data[0]; request_len +=ae_key_data[0] + 1; ae_id = ae_key_data + ae_key_data[0] + 1; if(ae_id == NULL) return -1; if (cmp_var_struct(ae_id, &(wpa_s->ae_id), wpa_s->ae_id.id_len)) { iwn_wpa_printf(MSG_ERROR, "WPA: not same ae id!\n"); iwn_wpa_hexdump(MSG_ERROR, "ae_id", ae_id,wpa_s->ae_id.id_len+ 4); iwn_wpa_hexdump(MSG_ERROR, "wpa_s->ae_id", (unsigned char *)&(wpa_s->ae_id),wpa_s->ae_id.id_len+ 4); return -1; } request_len +=wpa_s->ae_id.id_len+ 4; iwn_wpa_printf(MSG_DEBUG, "WPA: in %s:%d,request_len=%d,wpa_s->ae_id.id_len=%d", __func__, __LINE__,request_len,wpa_s->ae_id.id_len); asue_id = ae_id + wpa_s->ae_id.id_len+ 4; if(asue_id == NULL) return -1; if (cmp_var_struct(asue_id, &(iwn_eloop.asue_id), iwn_eloop.asue_id.id_len)) { iwn_wpa_printf(MSG_ERROR, "WPA: not same asue id!\n"); return -1; } request_len +=iwn_eloop.asue_id.id_len+ 4; iwn_wpa_printf(MSG_DEBUG, "WPA: in %s:%d,request_len=%d,wpa_s->asue_id.id_len=%d", __func__, __LINE__,request_len,iwn_eloop.asue_id.id_len); if(flag & BIT(3)) { u8 *cert_pos = NULL, *asu_sign = NULL; u16 fix_data_len=0, sign_len=0; tkey *pubkey = NULL; iwn_wpa_printf(MSG_DEBUG, "WPA: in %s:%d,iwn_eloop.asue_id.id_len=%d", __func__, __LINE__,iwn_eloop.asue_id.id_len); cert_res = asue_id +iwn_eloop.asue_id.id_len+ 4; if(cert_res[0] != 2) { iwn_wpa_printf(MSG_ERROR, "cert result flag is not 2!\n"); return -1; } cert_pos = cert_res + 1 +2 + 32 + 32 + 1 + 2 ; GETSHORT((cert_pos), fix_data_len); cert_pos = cert_pos + fix_data_len + 2; if(cert_pos[0] != 0) { iwn_wpa_printf(MSG_ERROR, "cert result is not ok!\n"); return -2; } GETSHORT((cert_pos + 1 + 2), fix_data_len); asu_sign = cert_pos + fix_data_len + 1 + 2 + 2; GETSHORT((asu_sign + 1), sign_len); iwn_wpa_printf(MSG_DEBUG, "WPA: in %s:%d", __func__, __LINE__); GETSHORT((cert_res + 1), fix_data_len); cert_obj = get_cert_obj(iwn_eloop.cert_info.config.used_cert); pubkey = cert_obj->asu_pubkey; if(!(*cert_obj->verify)(pubkey->data, pubkey->length, cert_res,fix_data_len + 3, asu_sign + 1 + 2 + sign_len - 48, 48)) { iwn_wpa_hexdump(MSG_ERROR, "pubkey->data", pubkey->data,pubkey->length); iwn_wpa_hexdump(MSG_ERROR, "cert_res", cert_res,fix_data_len + 3); iwn_wpa_hexdump(MSG_ERROR, "asu_sign", asu_sign + 1 + 2 + sign_len - 48,48); return -1; } request_len +=fix_data_len + 3+sign_len+3 ; iwn_wpa_printf(MSG_DEBUG, "WPA: in %s:%d,request_len=%d,len=%d", __func__, __LINE__,request_len,len); } { tkey *pubkey = NULL; u16 fix_data_len = 0; u16 cert_flag = wpa_s->ae_cert.cert_flag;//iwn_ntohs(wpa_s->ae_cert.cert_flag); ae_sign = payload + len - 48; cert_obj = get_cert_obj(cert_flag); iwn_wpa_printf(MSG_DEBUG, "WPA: in %s:%d,wpa_s->ae_cert.len=%d", __func__, __LINE__,wpa_s->ae_cert.length); pubkey = (*cert_obj->get_public_key)((void *)&wpa_s->ae_cert); if(!(*cert_obj->verify)(pubkey->data, pubkey->length, payload,request_len, ae_sign, 48)) { pubkey = iwn_free_buffer(pubkey, sizeof(tkey)); printf("AE sign error!!!\n"); return -1; } iwn_wpa_printf(MSG_DEBUG, "WPA: in %s:%d", __func__, __LINE__); pubkey = iwn_free_buffer(pubkey, sizeof(tkey)); iwn_wpa_printf(MSG_DEBUG, "WPA: in %s:%d", __func__, __LINE__); GETSHORT((payload+request_len+1), fix_data_len); request_len += fix_data_len + 3; } if(len != request_len) { iwn_wpa_printf(MSG_DEBUG, "WPA: in %s:%d,request_len=%d,len=%d", __func__, __LINE__,request_len,len); return -1; } iwn_wpa_printf(MSG_DEBUG, "WPA: in %s:%d", __func__, __LINE__); asue_certauthbk_derivation(wpa_s); wpa_s->wapi_state = WAPISM_CNT_RESP; return 0; }
//****************************************************************************** // Parse DNS address from ipconfig options //****************************************************************************** Boolean Capi2ReadDnsSrv( PCHProtConfig_t *ipcnfg, u_long* primaryDns1, u_long* secDns1, u_long* primaryDns2, u_long* secDns2) { u_char *input; u_char code, id, len_pid; u_short protocol; int len, t_len; int i=0; int type, templ; u_long DNSsrvr; u_long l; *primaryDns1 = 0; *secDns1 = 0; *primaryDns2 = 0; *secDns2 = 0; IPCPDEBUG(("ReadDnsSrv, read dns_servers")); /* if option length == 2, no option data */ if (ipcnfg->length == 0) { IPCPDEBUG(("Network ignored protocol options")); /* (Not an error, network does not want to bother) */ return TRUE; } len = 0; if (( ipcnfg->options[len++] & 0x83 ) == 0x81) { IPCPDEBUG(("Bad protocol config option")); return FALSE; } t_len = len; while ( t_len < (ipcnfg->length) ) { input = (u_char *) &ipcnfg->options[t_len]; GETSHORT(protocol, input); GETCHAR(len_pid, input); GETCHAR(code, input); GETCHAR(id, input); GETSHORT(len, input); switch (protocol) { /* Check LCP option from the Network */ case PPP_LCP: break; /* Check IPCP option from the Network */ case PPP_IPCP: if ( code == CONFREQ ) { IPCPDEBUG((" ReadOptions: CONFREQ")); i=0; while (i<(len-4)) { GETCHAR(type, input); //RFC 1661, this is option type GETCHAR(templ, input); //RFC 1661, next byte is length GETLONG(l, input); //read but don't use i += templ; } } else if ( code == CONFACK || code == CONFNAK ) { IPCPDEBUG((" ReadOptions: CONFACK or CONFNAK")); i=0; while (i<(len-4)) { GETCHAR(type, input); //RFC 1661, this is option type GETCHAR(templ, input); //RFC 1661, next byte is length switch (type) { case CI_ADDR: GETLONG(l, input); IPCPDEBUG(("CI_ADDR")); break; case CI_DNSADDR_PRI: GETLONG(l, input); DNSsrvr = htonl(l); *primaryDns1 = DNSsrvr; IPCPDEBUG(("CI_DNSADDR_PRI =%x", DNSsrvr)); break; case (CI_DNSADDR_PRI+1): GETLONG(l, input); DNSsrvr = htonl(l); *primaryDns2 = DNSsrvr; IPCPDEBUG(("CI_DNSADDR_PRI =%x", DNSsrvr)); break; case CI_DNSADDR_SEC: GETLONG(l, input); DNSsrvr = htonl(l); *secDns1 = DNSsrvr; IPCPDEBUG(("CI_DNSADDR_SEC")); break; case (CI_DNSADDR_SEC+1): GETLONG(l, input); DNSsrvr = htonl(l); *secDns2 = DNSsrvr; IPCPDEBUG(("CI_DNSADDR_SEC")); break; default: break; } i += templ; } } else /* Network had rejected */ { while(i<(len-4)) { GETCHAR(type, input); GETCHAR(templ, input); switch (type) { case CI_DNSADDR_PRI: IPCPDEBUG(("CI_DNSADDR_PRI rejected")); break; case (CI_DNSADDR_PRI+1): IPCPDEBUG(("CI_DNSADDR_PRI+1 rejected")); break; case CI_DNSADDR_SEC: IPCPDEBUG(("CI_DNSADDR_SEC rejected")); break; case (CI_DNSADDR_SEC+1): // Not supported IPCPDEBUG(("CI_DNSADDR_SEC+1 rejected")); break; default: break; } i += templ; } IPCPDEBUG((" ReadOptions: IPCP REJed")); } break; default: break; } t_len += (len + 3); } return TRUE; }
struct wapi_rxfrag *iwn_wpa_defrag(struct wapi_asue_st *wpa_s, struct wapi_rxfrag *rxbuf) { u8 *buf =(u8 *)rxbuf->data; int len = rxbuf->data_len; struct wai_hdr *hdr = (struct wai_hdr *)buf; u16 rxseq=0, last_rxseq=0; u8 fragno, last_fragno; u8 more_frag = hdr->more_frag; struct wapi_rxfrag *wai_frame = NULL; GETSHORT(hdr->rxseq, rxseq); fragno = hdr->frag_sc; /* Quick way out, if there's nothing to defragment */ if ((!more_frag) && (fragno == 0) && (wpa_s->rxfrag== NULL)) { iwn_wpa_printf(MSG_DEBUG, "WPA: in %s:%d", __func__, __LINE__); return rxbuf; } /* * Update the time stamp. As a side effect, it * also makes sure that the timer will not change * ni->ni_rxfrag[0] for at least 1 second, or in * other words, for the remaining of this function. */ /* * Validate that fragment is in order and * related to the previous ones. */ if (wpa_s->rxfrag) { struct wai_hdr *hdr1; iwn_wpa_printf(MSG_DEBUG, "WPA: in %s:%d", __func__, __LINE__); hdr1 = (struct wai_hdr *) wpa_s->rxfrag->data; GETSHORT(hdr1->rxseq, last_rxseq); last_fragno = hdr1->frag_sc; if (rxseq != last_rxseq || fragno != last_fragno + 1 ||(wpa_s->rxfrag->maxlen - wpa_s->rxfrag->data_len< len) /*||(time(NULL) - wpa_s->rxfragstamp >1)*/ ) { /* * Unrelated fragment or no space for it, * clear current fragments */ wpa_s->rxfrag = free_rxfrag(wpa_s->rxfrag); } iwn_wpa_printf(MSG_DEBUG, "WPA: in %s:%d", __func__, __LINE__); } /* If this is the first fragment */ if (wpa_s->rxfrag == NULL && fragno == 0) { /*ni->ni_rxfrag[0] = skb;*/ wpa_s->rxfrag = malloc_rxfrag(PAGE_LEN); /* If more frags are coming */ if (more_frag) { wpa_put_frag(wpa_s->rxfrag, buf, len); iwn_wpa_printf(MSG_DEBUG, "WPA: in %s:%d", __func__, __LINE__); } } else { if (wpa_s->rxfrag) { struct wai_hdr *lhdr = (struct wai_hdr *)wpa_s->rxfrag->data; /* * We know we have enough space to copy, * we've verified that before */ /* Copy current fragment at end of previous one */ /* Update tail and length */ wpa_put_frag(wpa_s->rxfrag , buf + WAI_HDR, len - WAI_HDR); /* Keep a copy of last sequence and fragno */ *(u16 *)lhdr->rxseq = *(u16*)hdr->rxseq; lhdr->frag_sc = hdr->frag_sc; } } if (more_frag) { /* More to come */ wai_frame = NULL; } else { /* Last fragment received, we're done! */ wai_frame = wpa_s->rxfrag; } /* wpa_s->rxfragstamp = time(0);*/ return wai_frame; }
static int waigroup_cert_1_3(struct wapi_asue_st* wpa_s, u8* payload, int len) { u8 flag = 0; u8 *ae_auth_flag = NULL; u8 *asu_id = NULL; u8 *ae_cer = NULL; u8 *ecdh = NULL; int ret = -1; u8 auth_act_len = WAI_FLAG_LEN +32 +2/*ASU ID Identifier*/ +2/*ASU ID Length*/ +2/*AE Cert type*/ +2/*AE Cert length*/ +1/*ECDH Parameter Identifier*/ +2/*ECDH Parameter Length */; iwn_wpa_printf(MSG_DEBUG, "WPA: in %s:%d", __func__, __LINE__); wapi_supplicant_key_negotiation_state_report(WPA_4WAY_HANDSHAKE); if(len < auth_act_len) { iwn_wpa_printf(MSG_ERROR, "WPA: WAI frame payload too short"); return -1; } flag = payload[0]; ae_auth_flag = payload+1; asu_id = payload+1 + 32; len -= auth_act_len; if (AUTH_TYPE_WAPI != wpa_s->ap_type) { return -1; } else { int bk_up = flag & BIT(0); wapi_states require = bk_up ? WAPISM_FINISH : WAPISM_AL_ASSOC; if (wpa_s->wapi_state != require) { /* skip the usk update check */ if (wpa_s->usk_updated && bk_up && wpa_s->wapi_state == WAPISM_UNI_ACK) ; else return -1; } } if(flag &BIT(0)){ if(memcmp(ae_auth_flag, wpa_s->ae_auth_flag, 32) !=0) { iwn_wpa_printf(MSG_ERROR, "WPA: ae_auth_flag not same!\n"); return -1; } }else{ memcpy(wpa_s->ae_auth_flag, ae_auth_flag, 32); } /*get ASU ID*/ GETSHORT(asu_id, wpa_s->ae_asu_id.id_flag); GETSHORT((asu_id+2), wpa_s->ae_asu_id.id_len); if(len <wpa_s->ae_asu_id.id_len){ iwn_wpa_printf(MSG_ERROR, "WPA: WAI frame payload too short"); return -1; } else{ memcpy(wpa_s->ae_asu_id.id_data, asu_id+4, wpa_s->ae_asu_id.id_len); } len -= wpa_s->ae_asu_id.id_len; /*get AE Certificate*/ ae_cer = asu_id + 2 + 2 + wpa_s->ae_asu_id.id_len; GETSHORT(ae_cer, wpa_s->ae_cert.cert_flag); GETSHORT((ae_cer+2), wpa_s->ae_cert.length); if(len <wpa_s->ae_cert.length){ iwn_wpa_printf(MSG_ERROR, "WPA: WAI frame payload too short"); return -1; } else{ memcpy(wpa_s->ae_cert.data, ae_cer+4, wpa_s->ae_cert.length); } len -= wpa_s->ae_cert.length; /*get AE ID*/ iwn_wai_fixdata_id_by_ident(&wpa_s->ae_cert, &(wpa_s->ae_id), wpa_s->ae_cert.cert_flag); iwn_wpa_hexdump(MSG_DEBUG, "AE ID: ", wpa_s->ae_id.id_data, wpa_s->ae_id.id_len); /*get ECDH Parameter*/ ecdh = ae_cer + 2 + 2 + wpa_s->ae_cert.length; wpa_s->ecdh.para_flag = ecdh[0]; GETSHORT((ecdh + 1), wpa_s->ecdh.para_len); if(len <wpa_s->ecdh.para_len){ iwn_wpa_printf(MSG_ERROR, "WPA: WAI frame payload too short"); return -1; } else{ memcpy(wpa_s->ecdh.para_data, ecdh+3, wpa_s->ecdh.para_len); } len -= wpa_s->ecdh.para_len; if(len != 0) { iwn_wpa_printf(MSG_DEBUG, "WPA: in %s:%d", __func__, __LINE__); return -1; } asue_initialize_alg(wpa_s); ret = asue_x_x_p_derivation(wpa_s); if(ret == -1) return -1; get_random(wpa_s->Nasue, 32); if (waigroup_cert_2_3_send(wpa_s, payload, len)) { iwn_wpa_printf(MSG_DEBUG, "WPA: in %s:%d", __func__, __LINE__); return -1; } return 0; }
static int waigroup_cert_1_3_old(struct wapi_asue_st* wpa_s, u8* payload, int len) { u8 flag = 0; u8 *ae_auth_flag = NULL; u8 *asu_id = NULL; u8 *ae_cer = NULL; u8 *ecdh = NULL; u16 fix_data_len = 0; int request_len = 0; int ret = -1; iwn_wpa_printf(MSG_DEBUG, "WPA: in %s:%d", __func__, __LINE__); /*flag*/ wpa_s->flag = 0; flag = payload[0]; wpa_s->flag = flag; request_len +=1; { if (AUTH_TYPE_WAPI != wpa_s->ap_type) { return -1; } else { int bk_up = flag & BIT(0); wapi_states require = bk_up ? WAPISM_FINISH : WAPISM_AL_ASSOC; if (wpa_s->wapi_state != require) { /* skip the usk update check */ if (wpa_s->usk_updated && bk_up && wpa_s->wapi_state == WAPISM_UNI_ACK) ; else return -1; } } } ae_auth_flag = payload+1; if(ae_auth_flag == NULL) { iwn_wpa_printf(MSG_DEBUG, "WPA: in %s:%d", __func__, __LINE__); return -1; } if(flag &BIT(0)){ if(memcmp(ae_auth_flag, wpa_s->ae_auth_flag, 32) !=0) { iwn_wpa_printf(MSG_ERROR, "WPA: ae_auth_flag not same!\n"); return -1; } }else memcpy(wpa_s->ae_auth_flag, ae_auth_flag, 32); request_len +=32; asu_id = ae_auth_flag + 32; if(asu_id == NULL) { iwn_wpa_printf(MSG_DEBUG, "WPA: in %s:%d", __func__, __LINE__); return -1; } GETSHORT((asu_id + 2), fix_data_len); /*iwn_wpa_hexdump(MSG_DEBUG, "asu_id ", asu_id, fix_data_len+4);*/ memcpy(&(wpa_s->ae_asu_id), asu_id ,fix_data_len + 4) ; request_len +=2 + 2 +fix_data_len; ae_cer = asu_id + 2 + 2 + fix_data_len; if(ae_cer == NULL) { iwn_wpa_printf(MSG_DEBUG, "WPA: in %s:%d", __func__, __LINE__); return -1; } GETSHORT(ae_cer, wpa_s->ae_cert.cert_flag); ae_cer +=2; GETSHORT(ae_cer, wpa_s->ae_cert.length); ae_cer +=2; memcpy(wpa_s->ae_cert.data, ae_cer, wpa_s->ae_cert.length); ae_cer -= 4; fix_data_len = wpa_s->ae_cert.length; /*iwn_wpa_hexdump(MSG_DEBUG, "ae_cer ", ae_cer+2+2, fix_data_len);*/ request_len +=2 + 2 +fix_data_len; { u16 cert_flag = 0; /* get ae cert type */ GETSHORT(ae_cer , cert_flag); ((cert_id *)ae_cer)->length = fix_data_len; iwn_wai_fixdata_id_by_ident(ae_cer, &(wpa_s->ae_id), cert_flag); iwn_wpa_hexdump(MSG_DEBUG, "AE ID: ", wpa_s->ae_id.id_data, wpa_s->ae_id.id_len); } ecdh = ae_cer + 2 + 2 + fix_data_len; if(ecdh == NULL) return -1; wpa_s->ecdh.para_flag = ecdh[0]; GETSHORT((ecdh + 1), fix_data_len); wpa_s->ecdh.para_len = fix_data_len; request_len +=1 + 2 +fix_data_len; memcpy(&(wpa_s->ecdh.para_data), ecdh+3, fix_data_len); if(len != request_len) { iwn_wpa_printf(MSG_DEBUG, "WPA: in %s:%d", __func__, __LINE__); return -1; } asue_initialize_alg(wpa_s); ret = asue_x_x_p_derivation(wpa_s); if(ret == -1) return -1; get_random(wpa_s->Nasue, 32); if (waigroup_cert_2_3_send(wpa_s, payload, len)) { iwn_wpa_printf(MSG_DEBUG, "WPA: in %s:%d", __func__, __LINE__); return -1; } return 0; }
static int dns_query(AGENT_REQUEST *request, AGENT_RESULT *result, int short_answer) { #if defined(HAVE_RES_QUERY) || defined(_WINDOWS) size_t offset = 0; int res, type, retrans, retry, use_tcp, i, ret = SYSINFO_RET_FAIL, ip_type = AF_INET; char *ip, zone[MAX_STRING_LEN], buffer[MAX_STRING_LEN], *zone_str, *param, tmp[MAX_STRING_LEN]; struct in_addr inaddr; struct in6_addr in6addr; #ifndef _WINDOWS #if defined(HAVE_RES_NINIT) && !defined(_AIX) /* It seems that on some AIX systems with no updates installed res_ninit() can */ /* corrupt stack (see ZBX-14559). Use res_init() on AIX. */ struct __res_state res_state_local; #else /* thread-unsafe resolver API */ int saved_retrans, saved_retry, saved_nscount = 0; unsigned long saved_options; struct sockaddr_in saved_ns; # if defined(HAVE_RES_U_EXT) /* thread-unsafe resolver API /Linux/ */ int save_nssocks, saved_nscount6; # endif #endif #if defined(HAVE_RES_EXT_EXT) /* AIX */ union res_sockaddr_union saved_ns6; #elif defined(HAVE_RES_U_EXT_EXT) /* BSD */ struct sockaddr_in6 saved_ns6; #else struct sockaddr_in6 *saved_ns6; #endif struct sockaddr_in6 sockaddrin6; struct addrinfo hint, *hres = NULL; #endif typedef struct { const char *name; int type; } resolv_querytype_t; static const resolv_querytype_t qt[] = { {"ANY", T_ANY}, {"A", T_A}, {"AAAA", T_AAAA}, {"NS", T_NS}, {"MD", T_MD}, {"MF", T_MF}, {"CNAME", T_CNAME}, {"SOA", T_SOA}, {"MB", T_MB}, {"MG", T_MG}, {"MR", T_MR}, {"NULL", T_NULL}, #ifndef _WINDOWS {"WKS", T_WKS}, #endif {"PTR", T_PTR}, {"HINFO", T_HINFO}, {"MINFO", T_MINFO}, {"MX", T_MX}, {"TXT", T_TXT}, {"SRV", T_SRV}, {NULL} }; #ifdef _WINDOWS PDNS_RECORD pQueryResults, pDnsRecord; wchar_t *wzone; char tmp2[MAX_STRING_LEN]; DWORD options; #else char *name; unsigned char *msg_end, *msg_ptr, *p; int num_answers, num_query, q_type, q_class, q_len, value, c, n; struct servent *s; HEADER *hp; struct protoent *pr; #if PACKETSZ > 1024 unsigned char buf[PACKETSZ]; #else unsigned char buf[1024]; #endif typedef union { HEADER h; #if defined(NS_PACKETSZ) unsigned char buffer[NS_PACKETSZ]; #elif defined(PACKETSZ) unsigned char buffer[PACKETSZ]; #else unsigned char buffer[512]; #endif } answer_t; answer_t answer; #endif /* _WINDOWS */ zbx_vector_str_t answers; *buffer = '\0'; if (6 < request->nparam) { SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters.")); return SYSINFO_RET_FAIL; } ip = get_rparam(request, 0); zone_str = get_rparam(request, 1); #ifndef _WINDOWS memset(&hint, '\0', sizeof(hint)); hint.ai_family = PF_UNSPEC; hint.ai_flags = AI_NUMERICHOST; if (NULL != ip && '\0' != *ip && 0 == getaddrinfo(ip, NULL, &hint, &hres) && AF_INET6 == hres->ai_family) ip_type = hres->ai_family; if (NULL != hres) freeaddrinfo(hres); #endif if (NULL == zone_str || '\0' == *zone_str) strscpy(zone, "zabbix.com"); else strscpy(zone, zone_str); param = get_rparam(request, 2); if (NULL == param || '\0' == *param) type = T_SOA; else { for (i = 0; NULL != qt[i].name; i++) { if (0 == strcasecmp(qt[i].name, param)) { type = qt[i].type; break; } } if (NULL == qt[i].name) { SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid third parameter.")); return SYSINFO_RET_FAIL; } } param = get_rparam(request, 3); if (NULL == param || '\0' == *param) retrans = 1; else if (SUCCEED != is_uint31(param, &retrans) || 0 == retrans) { SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid fourth parameter.")); return SYSINFO_RET_FAIL; } param = get_rparam(request, 4); if (NULL == param || '\0' == *param) retry = 2; else if (SUCCEED != is_uint31(param, &retry) || 0 == retry) { SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid fifth parameter.")); return SYSINFO_RET_FAIL; } param = get_rparam(request, 5); if (NULL == param || '\0' == *param || 0 == strcmp(param, "udp")) use_tcp = 0; else if (0 == strcmp(param, "tcp")) use_tcp = 1; else { SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid sixth parameter.")); return SYSINFO_RET_FAIL; } #ifdef _WINDOWS options = DNS_QUERY_STANDARD | DNS_QUERY_BYPASS_CACHE; if (0 != use_tcp) options |= DNS_QUERY_USE_TCP_ONLY; wzone = zbx_utf8_to_unicode(zone); res = DnsQuery(wzone, type, options, NULL, &pQueryResults, NULL); zbx_free(wzone); if (1 == short_answer) { SET_UI64_RESULT(result, DNS_RCODE_NOERROR != res ? 0 : 1); ret = SYSINFO_RET_OK; goto clean_dns; } if (DNS_RCODE_NOERROR != res) { SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot perform DNS query: [%d]", res)); return SYSINFO_RET_FAIL; } pDnsRecord = pQueryResults; zbx_vector_str_create(&answers); while (NULL != pDnsRecord) { if (DnsSectionAnswer != pDnsRecord->Flags.S.Section) { pDnsRecord = pDnsRecord->pNext; continue; } if (NULL == pDnsRecord->pName) goto clean; offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "%-20s", zbx_unicode_to_utf8_static(pDnsRecord->pName, tmp, sizeof(tmp))); offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %-8s", decode_type(pDnsRecord->wType)); switch (pDnsRecord->wType) { case T_A: inaddr.s_addr = pDnsRecord->Data.A.IpAddress; offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", inet_ntoa(inaddr)); break; case T_AAAA: memcpy(&in6addr.s6_addr, &(pDnsRecord->Data.AAAA.Ip6Address), sizeof(in6addr.s6_addr)); offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", zbx_inet_ntop(AF_INET6, &in6addr, tmp, sizeof(tmp))); break; case T_NS: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", zbx_unicode_to_utf8_static(pDnsRecord->Data.NS.pNameHost, tmp, sizeof(tmp))); break; case T_MD: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", zbx_unicode_to_utf8_static(pDnsRecord->Data.MD.pNameHost, tmp, sizeof(tmp))); break; case T_MF: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", zbx_unicode_to_utf8_static(pDnsRecord->Data.MF.pNameHost, tmp, sizeof(tmp))); break; case T_CNAME: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", zbx_unicode_to_utf8_static(pDnsRecord->Data.CNAME.pNameHost, tmp, sizeof(tmp))); break; case T_SOA: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s %s %lu %lu %lu %lu %lu", zbx_unicode_to_utf8_static(pDnsRecord->Data.SOA.pNamePrimaryServer, tmp, sizeof(tmp)), zbx_unicode_to_utf8_static(pDnsRecord->Data.SOA.pNameAdministrator, tmp2, sizeof(tmp2)), pDnsRecord->Data.SOA.dwSerialNo, pDnsRecord->Data.SOA.dwRefresh, pDnsRecord->Data.SOA.dwRetry, pDnsRecord->Data.SOA.dwExpire, pDnsRecord->Data.SOA.dwDefaultTtl); break; case T_MB: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", zbx_unicode_to_utf8_static(pDnsRecord->Data.MB.pNameHost, tmp, sizeof(tmp))); break; case T_MG: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", zbx_unicode_to_utf8_static(pDnsRecord->Data.MG.pNameHost, tmp, sizeof(tmp))); break; case T_MR: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", zbx_unicode_to_utf8_static(pDnsRecord->Data.MR.pNameHost, tmp, sizeof(tmp))); break; case T_NULL: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " len:%lu", pDnsRecord->Data.Null.dwByteCount); break; case T_PTR: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", zbx_unicode_to_utf8_static(pDnsRecord->Data.PTR.pNameHost, tmp, sizeof(tmp))); break; case T_HINFO: for (i = 0; i < (int)(pDnsRecord->Data.HINFO.dwStringCount); i++) offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " \"%s\"", zbx_unicode_to_utf8_static(pDnsRecord->Data.HINFO.pStringArray[i], tmp, sizeof(tmp))); break; case T_MINFO: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s %s", zbx_unicode_to_utf8_static(pDnsRecord->Data.MINFO.pNameMailbox, tmp, sizeof(tmp)), zbx_unicode_to_utf8_static(pDnsRecord->Data.MINFO.pNameErrorsMailbox, tmp2, sizeof(tmp2))); break; case T_MX: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %hu %s", pDnsRecord->Data.MX.wPreference, zbx_unicode_to_utf8_static(pDnsRecord->Data.MX.pNameExchange, tmp, sizeof(tmp))); break; case T_TXT: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " \""); for (i = 0; i < (int)(pDnsRecord->Data.TXT.dwStringCount); i++) offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "%s ", zbx_unicode_to_utf8_static(pDnsRecord->Data.TXT.pStringArray[i], tmp, sizeof(tmp))); if (0 < i) offset -= 1; /* remove the trailing space */ offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "\""); break; case T_SRV: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %hu %hu %hu %s", pDnsRecord->Data.SRV.wPriority, pDnsRecord->Data.SRV.wWeight, pDnsRecord->Data.SRV.wPort, zbx_unicode_to_utf8_static(pDnsRecord->Data.SRV.pNameTarget, tmp, sizeof(tmp))); break; default: break; } zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "\n"); pDnsRecord = pDnsRecord->pNext; zbx_vector_str_append(&answers, zbx_strdup(NULL, buffer)); offset = 0; *buffer = '\0'; } #else /* not _WINDOWS */ #if defined(HAVE_RES_NINIT) && !defined(_AIX) memset(&res_state_local, 0, sizeof(res_state_local)); if (-1 == res_ninit(&res_state_local)) /* initialize always, settings might have changed */ #else if (-1 == res_init()) /* initialize always, settings might have changed */ #endif { SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot initialize DNS subsystem: %s", zbx_strerror(errno))); return SYSINFO_RET_FAIL; } #if defined(HAVE_RES_NINIT) && !defined(_AIX) if (-1 == (res = res_nmkquery(&res_state_local, QUERY, zone, C_IN, type, NULL, 0, NULL, buf, sizeof(buf)))) #else if (-1 == (res = res_mkquery(QUERY, zone, C_IN, type, NULL, 0, NULL, buf, sizeof(buf)))) #endif { SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot create DNS query: %s", zbx_strerror(errno))); return SYSINFO_RET_FAIL; } if (NULL != ip && '\0' != *ip && AF_INET == ip_type) { if (0 == inet_aton(ip, &inaddr)) { SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid IP address.")); return SYSINFO_RET_FAIL; } #if defined(HAVE_RES_NINIT) && !defined(_AIX) res_state_local.nsaddr_list[0].sin_addr = inaddr; res_state_local.nsaddr_list[0].sin_family = AF_INET; res_state_local.nsaddr_list[0].sin_port = htons(ZBX_DEFAULT_DNS_PORT); res_state_local.nscount = 1; #else /* thread-unsafe resolver API */ memcpy(&saved_ns, &(_res.nsaddr_list[0]), sizeof(struct sockaddr_in)); saved_nscount = _res.nscount; _res.nsaddr_list[0].sin_addr = inaddr; _res.nsaddr_list[0].sin_family = AF_INET; _res.nsaddr_list[0].sin_port = htons(ZBX_DEFAULT_DNS_PORT); _res.nscount = 1; #endif } else if (NULL != ip && '\0' != *ip && AF_INET6 == ip_type) { if (0 == inet_pton(ip_type, ip, &in6addr)) { SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid IPv6 address.")); return SYSINFO_RET_FAIL; } memset(&sockaddrin6, '\0', sizeof(sockaddrin6)); #if defined(HAVE_RES_SIN6_LEN) sockaddrin6.sin6_len = sizeof(sockaddrin6); #endif sockaddrin6.sin6_family = AF_INET6; sockaddrin6.sin6_addr = in6addr; sockaddrin6.sin6_port = htons(ZBX_DEFAULT_DNS_PORT); #if defined(HAVE_RES_NINIT) && !defined(_AIX) && (defined(HAVE_RES_U_EXT) || defined(HAVE_RES_U_EXT_EXT)) memset(&res_state_local.nsaddr_list[0], '\0', sizeof(res_state_local.nsaddr_list[0])); # ifdef HAVE_RES_U_EXT /* Linux */ saved_ns6 = res_state_local._u._ext.nsaddrs[0]; res_state_local._u._ext.nsaddrs[0] = &sockaddrin6; res_state_local._u._ext.nssocks[0] = -1; res_state_local._u._ext.nscount6 = 1; /* CentOS */ # elif HAVE_RES_U_EXT_EXT /* BSD */ if (NULL != res_state_local._u._ext.ext) memcpy(res_state_local._u._ext.ext, &sockaddrin6, sizeof(sockaddrin6)); res_state_local.nsaddr_list[0].sin_port = htons(ZBX_DEFAULT_DNS_PORT); # endif res_state_local.nscount = 1; #else memcpy(&saved_ns, &(_res.nsaddr_list[0]), sizeof(struct sockaddr_in)); saved_nscount = _res.nscount; # if defined(HAVE_RES_U_EXT) || defined(HAVE_RES_U_EXT_EXT) || defined(HAVE_RES_EXT_EXT) memset(&_res.nsaddr_list[0], '\0', sizeof(_res.nsaddr_list[0])); _res.nscount = 1; # endif # if defined(HAVE_RES_U_EXT) /* thread-unsafe resolver API /Linux/ */ saved_nscount6 = _res._u._ext.nscount6; saved_ns6 = _res._u._ext.nsaddrs[0]; save_nssocks = _res._u._ext.nssocks[0]; _res._u._ext.nsaddrs[0] = &sockaddrin6; _res._u._ext.nssocks[0] = -1; _res._u._ext.nscount6 = 1; # elif defined(HAVE_RES_U_EXT_EXT) /* thread-unsafe resolver API /BSD/ */ memcpy(&saved_ns6, _res._u._ext.ext, sizeof(saved_ns6)); _res.nsaddr_list[0].sin_port = htons(ZBX_DEFAULT_DNS_PORT); if (NULL != _res._u._ext.ext) memcpy(_res._u._ext.ext, &sockaddrin6, sizeof(sockaddrin6)); # elif defined(HAVE_RES_EXT_EXT) /* thread-unsafe resolver API /AIX/ */ memcpy(&saved_ns6, &(_res._ext.ext.nsaddrs[0]), sizeof(saved_ns6)); memcpy(&_res._ext.ext.nsaddrs[0], &sockaddrin6, sizeof(sockaddrin6)); # endif /* #if defined(HAVE_RES_U_EXT) */ #endif /* #if defined(HAVE_RES_NINIT) && !defined(_AIX) && (defined(HAVE_RES_U_EXT) || defined(HAVE_RES_U_EXT_EXT)) */ } #if defined(HAVE_RES_NINIT) && !defined(_AIX) && (defined(HAVE_RES_U_EXT) || defined(HAVE_RES_U_EXT_EXT)) if (0 != use_tcp) res_state_local.options |= RES_USEVC; res_state_local.retrans = retrans; res_state_local.retry = retry; res = res_nsend(&res_state_local, buf, res, answer.buffer, sizeof(answer.buffer)); # ifdef HAVE_RES_U_EXT /* Linux */ if (NULL != ip && '\0' != *ip && AF_INET6 == ip_type) res_state_local._u._ext.nsaddrs[0] = saved_ns6; # endif # ifdef HAVE_RES_NDESTROY res_ndestroy(&res_state_local); # else res_nclose(&res_state_local); # endif #else /* thread-unsafe resolver API */ saved_options = _res.options; saved_retrans = _res.retrans; saved_retry = _res.retry; if (0 != use_tcp) _res.options |= RES_USEVC; _res.retrans = retrans; _res.retry = retry; res = res_send(buf, res, answer.buffer, sizeof(answer.buffer)); _res.options = saved_options; _res.retrans = saved_retrans; _res.retry = saved_retry; if (NULL != ip && '\0' != *ip) { if (AF_INET6 == ip_type) { # if defined(HAVE_RES_U_EXT) /* Linux */ _res._u._ext.nsaddrs[0] = saved_ns6; _res._u._ext.nssocks[0] = save_nssocks; _res._u._ext.nscount6 = saved_nscount6; # elif defined(HAVE_RES_U_EXT_EXT) /* BSD */ if (NULL != _res._u._ext.ext) memcpy(_res._u._ext.ext, &saved_ns6, sizeof(saved_ns6)); # elif defined(HAVE_RES_EXT_EXT) /* AIX */ memcpy(&_res._ext.ext.nsaddrs[0], &saved_ns6, sizeof(saved_ns6)); # endif } memcpy(&(_res.nsaddr_list[0]), &saved_ns, sizeof(struct sockaddr_in)); _res.nscount = saved_nscount; } #endif hp = (HEADER *)answer.buffer; if (1 == short_answer) { SET_UI64_RESULT(result, NOERROR != hp->rcode || 0 == ntohs(hp->ancount) || -1 == res ? 0 : 1); return SYSINFO_RET_OK; } if (NOERROR != hp->rcode || 0 == ntohs(hp->ancount) || -1 == res) { SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot perform DNS query.")); return SYSINFO_RET_FAIL; } msg_end = answer.buffer + res; num_answers = ntohs(answer.h.ancount); num_query = ntohs(answer.h.qdcount); msg_ptr = answer.buffer + HFIXEDSZ; zbx_vector_str_create(&answers); /* skipping query records */ for (; 0 < num_query && msg_ptr < msg_end; num_query--) msg_ptr += dn_skipname(msg_ptr, msg_end) + QFIXEDSZ; for (; 0 < num_answers && msg_ptr < msg_end; num_answers--) { if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr))) { SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot decode DNS response.")); ret = SYSINFO_RET_FAIL; goto clean; } offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "%-20s", name); GETSHORT(q_type, msg_ptr); GETSHORT(q_class, msg_ptr); msg_ptr += INT32SZ; /* skipping TTL */ GETSHORT(q_len, msg_ptr); offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %-8s", decode_type(q_type)); switch (q_type) { case T_A: switch (q_class) { case C_IN: case C_HS: memcpy(&inaddr, msg_ptr, INADDRSZ); offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", inet_ntoa(inaddr)); break; default: ; } msg_ptr += q_len; break; case T_AAAA: switch (q_class) { case C_IN: case C_HS: memcpy(&in6addr, msg_ptr, IN6ADDRSZ); offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", inet_ntop(AF_INET6, &in6addr, tmp, sizeof(tmp))); break; default: ; } msg_ptr += q_len; break; case T_NS: case T_CNAME: case T_MB: case T_MD: case T_MF: case T_MG: case T_MR: case T_PTR: if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr))) { SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot decode DNS response.")); return SYSINFO_RET_FAIL; } offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", name); break; case T_MX: GETSHORT(value, msg_ptr); /* preference */ offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value); if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr))) /* exchange */ { SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot decode DNS response.")); return SYSINFO_RET_FAIL; } offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", name); break; case T_SOA: if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr))) /* source host */ { SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot decode DNS response.")); return SYSINFO_RET_FAIL; } offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", name); if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr))) /* administrator */ { SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot decode DNS response.")); return SYSINFO_RET_FAIL; } offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", name); GETLONG(value, msg_ptr); /* serial number */ offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value); GETLONG(value, msg_ptr); /* refresh time */ offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value); GETLONG(value, msg_ptr); /* retry time */ offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value); GETLONG(value, msg_ptr); /* expire time */ offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value); GETLONG(value, msg_ptr); /* minimum TTL */ offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value); break; case T_NULL: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " len:%d", q_len); msg_ptr += q_len; break; case T_WKS: if (INT32SZ + 1 > q_len) { SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot decode DNS response.")); return SYSINFO_RET_FAIL; } p = msg_ptr + q_len; memcpy(&inaddr, msg_ptr, INADDRSZ); msg_ptr += INT32SZ; offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", inet_ntoa(inaddr)); if (NULL != (pr = getprotobynumber(*msg_ptr))) offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", pr->p_name); else offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", (int)*msg_ptr); msg_ptr++; n = 0; while (msg_ptr < p) { c = *msg_ptr++; do { if (0 != (c & 0200)) { s = getservbyport((int)htons(n), pr ? pr->p_name : NULL); if (NULL != s) offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", s->s_name); else offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " #%d", n); } c <<= 1; } while (0 != (++n & 07)); } break; case T_HINFO: p = msg_ptr + q_len; c = *msg_ptr++; if (0 != c) { offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " \"%.*s\"", c, msg_ptr); msg_ptr += c; } if (msg_ptr < p) { c = *msg_ptr++; if (0 != c) { offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " \"%.*s\"", c, msg_ptr); msg_ptr += c; } } break; case T_MINFO: if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr))) /* mailbox responsible for mailing lists */ { SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot decode DNS response.")); return SYSINFO_RET_FAIL; } offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", name); if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr))) /* mailbox for error messages */ { SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot decode DNS response.")); return SYSINFO_RET_FAIL; } offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", name); break; case T_TXT: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " \""); p = msg_ptr + q_len; while (msg_ptr < p) { for (c = *msg_ptr++; 0 < c && msg_ptr < p; c--) offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "%c", *msg_ptr++); } offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "\""); break; case T_SRV: GETSHORT(value, msg_ptr); /* priority */ offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value); GETSHORT(value, msg_ptr); /* weight */ offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value); GETSHORT(value, msg_ptr); /* port */ offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value); if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr))) /* target */ { SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot decode DNS response.")); return SYSINFO_RET_FAIL; } offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", name); break; default: msg_ptr += q_len; break; } zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "\n"); zbx_vector_str_append(&answers, zbx_strdup(NULL, buffer)); offset = 0; *buffer = '\0'; } #endif /* _WINDOWS */ zbx_vector_str_sort(&answers, ZBX_DEFAULT_STR_COMPARE_FUNC); for (i = 0; i < answers.values_num; i++) offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "%s", answers.values[i]); if (0 != offset) buffer[--offset] = '\0'; SET_TEXT_RESULT(result, zbx_strdup(NULL, buffer)); ret = SYSINFO_RET_OK; clean: zbx_vector_str_clear_ext(&answers, zbx_str_free); zbx_vector_str_destroy(&answers); #ifdef _WINDOWS clean_dns: if (DNS_RCODE_NOERROR == res) DnsRecordListFree(pQueryResults, DnsFreeRecordList); #endif return ret; #else /* both HAVE_RES_QUERY and _WINDOWS not defined */ return SYSINFO_RET_FAIL; #endif /* defined(HAVE_RES_QUERY) || defined(_WINDOWS) */ }
/* Modified version of req_action */ static enum req_action req_iquery(HEADER *hp, u_char **cpp, u_char *eom, int *buflenp, u_char *msg) { int dlen, alen, n, type, class, count; char anbuf[2], *data, *fname; /* * Skip domain name, get class, and type. */ if ((n = dn_skipname(*cpp, eom)) < 0) { printf("FORMERR IQuery packet name problem\n"); hp->rcode = FORMERR; return (Finish); } *cpp += n; GETSHORT(type, *cpp); GETSHORT(class, *cpp); *cpp += INT32SZ; /* ttl */ GETSHORT(dlen, *cpp); *cpp += dlen; if (*cpp != eom) { printf("FORMERR IQuery message length off\n"); hp->rcode = FORMERR; return (Finish); } /* * not all inverse queries are handled. * this is a meaningless switch statement to preserve original program's structure */ switch (type) { case T_A: if (something == 0) return (Refuse); break; default: return (Refuse); } printf("req: IQuery class %d type %d\n", class, type); fname = (char *)msg + HFIXEDSZ; alen = (char *)*cpp - fname; /* Check to see if anbuf is large enough to store alen bytes*/ if ((size_t)alen > sizeof anbuf){ printf("BUFFER OVERFLOW DETECTED!\n"); return (Refuse); } printf("Copying %d bytes from fname to anbuf which can store %d bytes\n", alen, sizeof(anbuf)); /*OK*/ memcpy(anbuf, fname, alen); data = anbuf + alen - dlen; *cpp = (u_char *)fname; *buflenp -= HFIXEDSZ; count = 0; /* ..... do some other stuff */ return (Finish); }
int main(int argc, char *argv[]) { asyncns_t* asyncns = NULL; asyncns_query_t *q1, *q2, *q3; int r = 1, ret; struct addrinfo *ai, hints; struct sockaddr_in sa; char host[NI_MAXHOST] = "", serv[NI_MAXSERV] = ""; unsigned char *srv; signal(SIGCHLD, SIG_IGN); if (!(asyncns = asyncns_new(2))) { fprintf(stderr, "asyncns_new() failed\n"); goto fail; } /* Make a name -> address query */ memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; q1 = asyncns_getaddrinfo(asyncns, argc >= 2 ? argv[1] : "www.heise.de", NULL, &hints); if (!q1) fprintf(stderr, "asyncns_getaddrinfo(): %s\n", strerror(errno)); /* Make an address -> name query */ memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_addr.s_addr = inet_addr(argc >= 3 ? argv[2] : "193.99.144.71"); sa.sin_port = htons(80); q2 = asyncns_getnameinfo(asyncns, (struct sockaddr*) &sa, sizeof(sa), 0, 1, 1); if (!q2) fprintf(stderr, "asyncns_getnameinfo(): %s\n", strerror(errno)); /* Make a res_query() call */ q3 = asyncns_res_query(asyncns, "_xmpp-client._tcp.gmail.com", C_IN, T_SRV); if (!q3) fprintf(stderr, "asyncns_res_query(): %s\n", strerror(errno)); /* Wait until the three queries are completed */ while (!asyncns_isdone(asyncns, q1) || !asyncns_isdone(asyncns, q2) || !asyncns_isdone(asyncns, q3)) { if (asyncns_wait(asyncns, 1) < 0) { fprintf(stderr, "asyncns_wait(): %s\n", strerror(errno)); goto fail; } } /* Interpret the result of the name -> addr query */ if ((ret = asyncns_getaddrinfo_done(asyncns, q1, &ai))) fprintf(stderr, "error: %s %i\n", gai_strerror(ret), ret); else { struct addrinfo *i; for (i = ai; i; i = i->ai_next) { char t[256]; const char *p = NULL; if (i->ai_family == PF_INET) p = inet_ntop(AF_INET, &((struct sockaddr_in*) i->ai_addr)->sin_addr, t, sizeof(t)); else if (i->ai_family == PF_INET6) p = inet_ntop(AF_INET6, &((struct sockaddr_in6*) i->ai_addr)->sin6_addr, t, sizeof(t)); printf("%s\n", p); } asyncns_freeaddrinfo(ai); } /* Interpret the result of the addr -> name query */ if ((ret = asyncns_getnameinfo_done(asyncns, q2, host, sizeof(host), serv, sizeof(serv)))) fprintf(stderr, "error: %s %i\n", gai_strerror(ret), ret); else printf("%s -- %s\n", host, serv); /* Interpret the result of the SRV lookup */ if ((ret = asyncns_res_done(asyncns, q3, &srv)) < 0) { fprintf(stderr, "error: %s %i\n", strerror(errno), ret); } else if (ret == 0) { fprintf(stderr, "No reply for SRV lookup\n"); } else { int qdcount; int ancount; int len; const unsigned char *pos = srv + sizeof(HEADER); unsigned char *end = srv + ret; HEADER *head = (HEADER *)srv; char name[256]; qdcount = ntohs(head->qdcount); ancount = ntohs(head->ancount); printf("%d answers for srv lookup:\n", ancount); /* Ignore the questions */ while (qdcount-- > 0 && (len = dn_expand(srv, end, pos, name, 255)) >= 0) { assert(len >= 0); pos += len + QFIXEDSZ; } /* Parse the answers */ while (ancount-- > 0 && (len = dn_expand(srv, end, pos, name, 255)) >= 0) { /* Ignore the initial string */ uint16_t pref, weight, port; assert(len >= 0); pos += len; /* Ignore type, ttl, class and dlen */ pos += 10; GETSHORT(pref, pos); GETSHORT(weight, pos); GETSHORT(port, pos); len = dn_expand(srv, end, pos, name, 255); printf("\tpreference: %2d weight: %2d port: %d host: %s\n", pref, weight, port, name); pos += len; } asyncns_freeanswer(srv); } r = 0; fail: if (asyncns) asyncns_free(asyncns); return r; }
char *ipinfo_lookup(const char *domain) { unsigned char answer[PACKETSZ], *pt; char host[128]; char *txt; int len, exp, size, txtlen, type; if(res_init() < 0) { fprintf(stderr,"@res_init failed\n"); return NULL; } memset(answer, 0, PACKETSZ); if((len = res_query(domain, C_IN, T_TXT, answer, PACKETSZ)) < 0) { #ifdef IIDEBUG if (iihash) syslog(LOG_INFO, "Malloc-txt: %s", UNKN); #endif return (iihash)?strdup(UNKN):UNKN; } pt = answer + sizeof(HEADER); if((exp = dn_expand(answer, answer + len, pt, host, sizeof(host))) < 0) { printf("@dn_expand failed\n"); return NULL; } pt += exp; GETSHORT(type, pt); if(type != T_TXT) { printf("@Broken DNS reply.\n"); return NULL; } pt += INT16SZ; /* class */ if((exp = dn_expand(answer, answer + len, pt, host, sizeof(host))) < 0) { printf("@second dn_expand failed\n"); return NULL; } pt += exp; GETSHORT(type, pt); if(type != T_TXT) { printf("@Not a TXT record\n"); return NULL; } pt += INT16SZ; /* class */ pt += INT32SZ; /* ttl */ GETSHORT(size, pt); txtlen = *pt; if(txtlen >= size || !txtlen) { printf("@Broken TXT record (txtlen = %d, size = %d)\n", txtlen, size); return NULL; } if (txtlen > NAMELEN) txtlen = NAMELEN; if (iihash) { if (!(txt = malloc(txtlen + 1))) return NULL; } else txt = (char*)txtrec; pt++; strncpy(txt, (char*) pt, txtlen); txt[txtlen] = 0; #ifdef IIDEBUG if (iihash) syslog(LOG_INFO, "Malloc-txt(%p): %s", txt, txt); #endif return txt; }
static void do_section(const res_state statp, ns_msg *handle, ns_sect section, int pflag, FILE *file) { int n, sflag, rrnum; static int buflen = 2048; char *buf; ns_opcode opcode; ns_rr rr; /* * Print answer records. */ sflag = (statp->pfcode & pflag); if (statp->pfcode && !sflag) return; buf = malloc(buflen); if (buf == NULL) { fprintf(file, ";; memory allocation failure\n"); return; } opcode = (ns_opcode) ns_msg_getflag(*handle, ns_f_opcode); rrnum = 0; for (;;) { if (ns_parserr(handle, section, rrnum, &rr)) { if (errno != ENODEV) fprintf(file, ";; ns_parserr: %s\n", strerror(errno)); else if (rrnum > 0 && sflag != 0 && (statp->pfcode & RES_PRF_HEAD1)) putc('\n', file); goto cleanup; } if (rrnum == 0 && sflag != 0 && (statp->pfcode & RES_PRF_HEAD1)) fprintf(file, ";; %s SECTION:\n", p_section(section, opcode)); if (section == ns_s_qd) fprintf(file, ";;\t%s, type = %s, class = %s\n", ns_rr_name(rr), p_type(ns_rr_type(rr)), p_class(ns_rr_class(rr))); else if (section == ns_s_ar && ns_rr_type(rr) == ns_t_opt) { u_int16_t optcode, optlen, rdatalen = ns_rr_rdlen(rr); u_int32_t ttl = ns_rr_ttl(rr); fprintf(file, "; EDNS: version: %u, udp=%u, flags=%04x\n", (ttl>>16)&0xff, ns_rr_class(rr), ttl&0xffff); while (rdatalen >= 4) { const u_char *cp = ns_rr_rdata(rr); int i; GETSHORT(optcode, cp); GETSHORT(optlen, cp); if (optcode == NS_OPT_NSID) { fputs("; NSID: ", file); if (optlen == 0) { fputs("; NSID\n", file); } else { fputs("; NSID: ", file); for (i = 0; i < optlen; i++) fprintf(file, "%02x ", cp[i]); fputs(" (",file); for (i = 0; i < optlen; i++) fprintf(file, "%c", isprint(cp[i])? cp[i] : '.'); fputs(")\n", file); } } else { if (optlen == 0) { fprintf(file, "; OPT=%u\n", optcode); } else { fprintf(file, "; OPT=%u: ", optcode); for (i = 0; i < optlen; i++) fprintf(file, "%02x ", cp[i]); fputs(" (",file); for (i = 0; i < optlen; i++) fprintf(file, "%c", isprint(cp[i]) ? cp[i] : '.'); fputs(")\n", file); } } rdatalen -= 4 + optlen; } } else {
static GList * g_resolver_records_from_res_query (const gchar *rrname, gint rrtype, guchar *answer, gint len, gint herr, GError **error) { gint count; gchar namebuf[1024]; guchar *end, *p; guint16 type, qclass, rdlength; guint32 ttl; HEADER *header; GList *records; GVariant *record; if (len <= 0) { if (len == 0 || herr == HOST_NOT_FOUND || herr == NO_DATA) { g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND, _("No DNS record of the requested type for “%s”"), rrname); } else if (herr == TRY_AGAIN) { g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_TEMPORARY_FAILURE, _("Temporarily unable to resolve “%s”"), rrname); } else { g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_INTERNAL, _("Error resolving “%s”"), rrname); } return NULL; } records = NULL; header = (HEADER *)answer; p = answer + sizeof (HEADER); end = answer + len; /* Skip query */ count = ntohs (header->qdcount); while (count-- && p < end) { p += dn_expand (answer, end, p, namebuf, sizeof (namebuf)); p += 4; /* To silence gcc warnings */ namebuf[0] = namebuf[1]; } /* Read answers */ count = ntohs (header->ancount); while (count-- && p < end) { p += dn_expand (answer, end, p, namebuf, sizeof (namebuf)); GETSHORT (type, p); GETSHORT (qclass, p); GETLONG (ttl, p); ttl = ttl; /* To avoid -Wunused-but-set-variable */ GETSHORT (rdlength, p); if (type != rrtype || qclass != C_IN) { p += rdlength; continue; } switch (rrtype) { case T_SRV: record = parse_res_srv (answer, end, &p); break; case T_MX: record = parse_res_mx (answer, end, &p); break; case T_SOA: record = parse_res_soa (answer, end, &p); break; case T_NS: record = parse_res_ns (answer, end, &p); break; case T_TXT: record = parse_res_txt (answer, p + rdlength, &p); break; default: g_warn_if_reached (); record = NULL; break; } if (record != NULL) records = g_list_prepend (records, record); } if (records == NULL) { g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND, _("No DNS record of the requested type for “%s”"), rrname); return NULL; } else return records; }
/* * fsm_input - Input packet. */ void fsm_input(fsm *f, u_char *inpacket, int l) { u_char *inp = inpacket; u_char code, id; int len; /* * Parse header (code, id and length). * If packet too short, drop it. */ if (l < HEADERLEN) { FSMDEBUG((LOG_WARNING, "fsm_input(%x): Rcvd short header.\n", f->protocol)); return; } GETCHAR(code, inp); GETCHAR(id, inp); GETSHORT(len, inp); if (len < HEADERLEN) { FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd illegal length.\n", f->protocol)); return; } if (len > l) { FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd short packet.\n", f->protocol)); return; } len -= HEADERLEN; /* subtract header length */ if( f->state == LS_INITIAL || f->state == LS_STARTING ) { FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd packet in state %d (%s).\n", f->protocol, f->state, ppperr_strerr[f->state])); return; } FSMDEBUG((LOG_INFO, "fsm_input(%s):%d,%d,%d\n", PROTO_NAME(f), code, id, l)); /* * Action depends on code. */ switch (code) { case CONFREQ: fsm_rconfreq(f, id, inp, len); break; case CONFACK: fsm_rconfack(f, id, inp, len); break; case CONFNAK: case CONFREJ: fsm_rconfnakrej(f, code, id, inp, len); break; case TERMREQ: fsm_rtermreq(f, id, inp, len); break; case TERMACK: fsm_rtermack(f); break; case CODEREJ: fsm_rcoderej(f, inp, len); break; default: if( !f->callbacks->extcode || !(*f->callbacks->extcode)(f, code, id, inp, len) ) { fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN); } break; } }
/* ns_verify * Parameters: * statp res stuff * msg received message * msglen length of message * key tsig key used for verifying. * querysig (response), the signature in the query * querysiglen (response), the length of the signature in the query * sig (query), a buffer to hold the signature * siglen (query), input - length of signature buffer * output - length of signature * * Errors: * - bad input (-1) * - invalid dns message (NS_TSIG_ERROR_FORMERR) * - TSIG is not present (NS_TSIG_ERROR_NO_TSIG) * - key doesn't match (-ns_r_badkey) * - TSIG verification fails with BADKEY (-ns_r_badkey) * - TSIG verification fails with BADSIG (-ns_r_badsig) * - TSIG verification fails with BADTIME (-ns_r_badtime) * - TSIG verification succeeds, error set to BAKEY (ns_r_badkey) * - TSIG verification succeeds, error set to BADSIG (ns_r_badsig) * - TSIG verification succeeds, error set to BADTIME (ns_r_badtime) */ isc_result_t ns_verify(u_char *msg, unsigned *msglen, void *k, const u_char *querysig, unsigned querysiglen, u_char *sig, unsigned *siglen, time_t *timesigned, int nostrip) { HEADER *hp = (HEADER *)msg; DST_KEY *key = (DST_KEY *)k; u_char *cp = msg, *eom; char name[MAXDNAME], alg[MAXDNAME]; u_char *recstart, *rdatastart; u_char *sigstart, *otherstart; unsigned n; int error; u_int16_t type, length; u_int16_t fudge, sigfieldlen, id, otherfieldlen; dst_init(); if (msg == NULL || msglen == NULL || *msglen < 0) return ISC_R_INVALIDARG; eom = msg + *msglen; recstart = ns_find_tsig(msg, eom); if (recstart == NULL) return ISC_R_NO_TSIG; cp = recstart; /* Read the key name. */ n = dn_expand(msg, eom, cp, name, MAXDNAME); if (n < 0) return ISC_R_FORMERR; cp += n; /* Read the type. */ BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ); GETSHORT(type, cp); if (type != ns_t_tsig) return ISC_R_NO_TSIG; /* Skip the class and TTL, save the length. */ cp += INT16SZ + INT32SZ; GETSHORT(length, cp); if (eom - cp != length) return ISC_R_FORMERR; /* Read the algorithm name. */ rdatastart = cp; n = dn_expand(msg, eom, cp, alg, MAXDNAME); if (n < 0) return ISC_R_FORMERR; if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1) return ISC_R_INVALIDKEY; cp += n; /* Read the time signed and fudge. */ BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ); cp += INT16SZ; GETLONG((*timesigned), cp); GETSHORT(fudge, cp); /* Read the signature. */ BOUNDS_CHECK(cp, INT16SZ); GETSHORT(sigfieldlen, cp); BOUNDS_CHECK(cp, sigfieldlen); sigstart = cp; cp += sigfieldlen; /* Read the original id and error. */ BOUNDS_CHECK(cp, 2*INT16SZ); GETSHORT(id, cp); GETSHORT(error, cp); /* Parse the other data. */ BOUNDS_CHECK(cp, INT16SZ); GETSHORT(otherfieldlen, cp); BOUNDS_CHECK(cp, otherfieldlen); otherstart = cp; cp += otherfieldlen; if (cp != eom) return ISC_R_FORMERR; /* Verify that the key used is OK. */ if (key != NULL) { if (key->dk_alg != KEY_HMAC_MD5) return ISC_R_INVALIDKEY; if (error != ns_r_badsig && error != ns_r_badkey) { if (ns_samename(key->dk_key_name, name) != 1) return ISC_R_INVALIDKEY; } } hp->arcount = htons(ntohs(hp->arcount) - 1); /* * Do the verification. */ if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) { void *ctx; u_char buf[MAXDNAME]; /* Digest the query signature, if this is a response. */ dst_verify_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0); if (querysiglen > 0 && querysig != NULL) { u_int16_t len_n = htons(querysiglen); dst_verify_data(SIG_MODE_UPDATE, key, &ctx, (u_char *)&len_n, INT16SZ, NULL, 0); dst_verify_data(SIG_MODE_UPDATE, key, &ctx, querysig, querysiglen, NULL, 0); } /* Digest the message. */ dst_verify_data(SIG_MODE_UPDATE, key, &ctx, msg, (unsigned)(recstart - msg), NULL, 0); /* Digest the key name. */ n = ns_name_ntol(recstart, buf, sizeof(buf)); dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); /* Digest the class and TTL. */ dst_verify_data(SIG_MODE_UPDATE, key, &ctx, recstart + dn_skipname(recstart, eom) + INT16SZ, INT16SZ + INT32SZ, NULL, 0); /* Digest the algorithm. */ n = ns_name_ntol(rdatastart, buf, sizeof(buf)); dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); /* Digest the time signed and fudge. */ dst_verify_data(SIG_MODE_UPDATE, key, &ctx, rdatastart + dn_skipname(rdatastart, eom), INT16SZ + INT32SZ + INT16SZ, NULL, 0); /* Digest the error and other data. */ dst_verify_data(SIG_MODE_UPDATE, key, &ctx, otherstart - INT16SZ - INT16SZ, (unsigned)otherfieldlen + INT16SZ + INT16SZ, NULL, 0); n = dst_verify_data(SIG_MODE_FINAL, key, &ctx, NULL, 0, sigstart, sigfieldlen); if (n < 0) return ISC_R_BADSIG; if (sig != NULL && siglen != NULL) { if (*siglen < sigfieldlen) return ISC_R_NOSPACE; memcpy(sig, sigstart, sigfieldlen); *siglen = sigfieldlen; } } else { if (sigfieldlen > 0) return ISC_R_FORMERR; if (sig != NULL && siglen != NULL) *siglen = 0; } /* Reset the counter, since we still need to check for badtime. */ hp->arcount = htons(ntohs(hp->arcount) + 1); /* Verify the time. */ if (abs((*timesigned) - time(NULL)) > fudge) return ISC_R_BADTIME; if (nostrip == 0) { *msglen = recstart - msg; hp->arcount = htons(ntohs(hp->arcount) - 1); } if (error != NOERROR) return ns_rcode_to_isc (error); return ISC_R_SUCCESS; }
bool HHVM_FUNCTION(getmxrr, const String& hostname, VRefParam mxhostsRef, VRefParam weightsRef /* = null */) { IOStatusHelper io("dns_get_mx", hostname.data()); int count, qdc; unsigned short type, weight; unsigned char ans[MAXPACKET]; char buf[255 + 1]; // IETF STD 13 section 3.1; 255 bytes unsigned char *cp, *end; Array mxhosts; Array weights; SCOPE_EXIT { mxhostsRef.assignIfRef(mxhosts); weightsRef.assignIfRef(weights); }; /* Go! */ struct __res_state *res; res = ResolverInit::s_res.get()->getResolver(); if (res == NULL) { return false; } int i = res_nsearch(res, hostname.data(), C_IN, DNS_T_MX, (unsigned char*)&ans, sizeof(ans)); if (i < 0) { res_nclose(res); php_dns_free_res(res); return false; } if (i > (int)sizeof(ans)) { i = sizeof(ans); } HEADER *hp = (HEADER *)&ans; cp = (unsigned char *)&ans + HFIXEDSZ; end = (unsigned char *)&ans +i; for (qdc = ntohs((unsigned short)hp->qdcount); qdc--; cp += i + QFIXEDSZ) { if ((i = dn_skipname(cp, end)) < 0 ) { res_nclose(res); php_dns_free_res(res); return false; } } count = ntohs((unsigned short)hp->ancount); while (--count >= 0 && cp < end) { if ((i = dn_skipname(cp, end)) < 0 ) { res_nclose(res); php_dns_free_res(res); return false; } cp += i; GETSHORT(type, cp); cp += INT16SZ + INT32SZ; GETSHORT(i, cp); if (type != DNS_T_MX) { cp += i; continue; } GETSHORT(weight, cp); if ((i = dn_expand(ans, end, cp, buf, sizeof(buf)-1)) < 0) { res_nclose(res); php_dns_free_res(res); return false; } cp += i; mxhosts.append(String(buf, CopyString)); weights.append(weight); } res_nclose(res); php_dns_free_res(res); return true; }
isc_result_t ns_verify_tcp(u_char *msg, unsigned *msglen, ns_tcp_tsig_state *state, int required) { HEADER *hp = (HEADER *)msg; u_char *recstart, *rdatastart, *sigstart; unsigned sigfieldlen, otherfieldlen; u_char *cp, *eom = msg + *msglen, *cp2; char name[MAXDNAME], alg[MAXDNAME]; u_char buf[MAXDNAME]; int n, type, length, fudge, id, error; time_t timesigned; if (msg == NULL || msglen == NULL || state == NULL) return ISC_R_INVALIDARG; state->counter++; if (state->counter == 0) return (ns_verify(msg, msglen, state->key, state->sig, state->siglen, state->sig, &state->siglen, ×igned, 0)); if (state->siglen > 0) { u_int16_t siglen_n = htons(state->siglen); dst_verify_data(SIG_MODE_INIT, state->key, &state->ctx, NULL, 0, NULL, 0); dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, (u_char *)&siglen_n, INT16SZ, NULL, 0); dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, state->sig, state->siglen, NULL, 0); state->siglen = 0; } cp = recstart = ns_find_tsig(msg, eom); if (recstart == NULL) { if (required) return ISC_R_NO_TSIG; dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, msg, *msglen, NULL, 0); return ISC_R_SUCCESS; } hp->arcount = htons(ntohs(hp->arcount) - 1); dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, msg, (unsigned)(recstart - msg), NULL, 0); /* Read the key name. */ n = dn_expand(msg, eom, cp, name, MAXDNAME); if (n < 0) return ISC_R_FORMERR; cp += n; /* Read the type. */ BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ); GETSHORT(type, cp); if (type != ns_t_tsig) return ISC_R_NO_TSIG; /* Skip the class and TTL, save the length. */ cp += INT16SZ + INT32SZ; GETSHORT(length, cp); if (eom - cp != length) return ISC_R_FORMERR; /* Read the algorithm name. */ rdatastart = cp; n = dn_expand(msg, eom, cp, alg, MAXDNAME); if (n < 0) return ISC_R_FORMERR; if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1) return ISC_R_BADKEY; cp += n; /* Verify that the key used is OK. */ if ((ns_samename(state->key->dk_key_name, name) != 1 || state->key->dk_alg != KEY_HMAC_MD5)) return ISC_R_BADKEY; /* Read the time signed and fudge. */ BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ); cp += INT16SZ; GETLONG(timesigned, cp); GETSHORT(fudge, cp); /* Read the signature. */ BOUNDS_CHECK(cp, INT16SZ); GETSHORT(sigfieldlen, cp); BOUNDS_CHECK(cp, sigfieldlen); sigstart = cp; cp += sigfieldlen; /* Read the original id and error. */ BOUNDS_CHECK(cp, 2*INT16SZ); GETSHORT(id, cp); GETSHORT(error, cp); /* Parse the other data. */ BOUNDS_CHECK(cp, INT16SZ); GETSHORT(otherfieldlen, cp); BOUNDS_CHECK(cp, otherfieldlen); cp += otherfieldlen; if (cp != eom) return ISC_R_FORMERR; /* * Do the verification. */ /* Digest the time signed and fudge. */ cp2 = buf; PUTSHORT(0, cp2); /* Top 16 bits of time. */ PUTLONG(timesigned, cp2); PUTSHORT(NS_TSIG_FUDGE, cp2); dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, buf, (unsigned)(cp2 - buf), NULL, 0); n = dst_verify_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0, sigstart, sigfieldlen); if (n < 0) return ISC_R_BADSIG; if (sigfieldlen > sizeof(state->sig)) return ISC_R_BADSIG; if (sigfieldlen > sizeof(state->sig)) return ISC_R_NOSPACE; memcpy(state->sig, sigstart, sigfieldlen); state->siglen = sigfieldlen; /* Verify the time. */ if (abs(timesigned - time(NULL)) > fudge) return ISC_R_BADTIME; *msglen = recstart - msg; if (error != NOERROR) return ns_rcode_to_isc (error); return ISC_R_SUCCESS; }
/* * fsm_input - Input packet. */ void fsm_input(fsm *f, u_char *inpacket, int l) { u_char *inp; u_char code, id; int len; /* * Parse header (code, id and length). * If packet too short, drop it. */ inp = inpacket; if (l < HEADERLEN) { FSMDEBUG(("fsm_input(%x): Rcvd short header.", f->protocol)); return; } GETCHAR(code, inp); GETCHAR(id, inp); GETSHORT(len, inp); if (len < HEADERLEN) { FSMDEBUG(("fsm_input(%x): Rcvd illegal length.", f->protocol)); return; } if (len > l) { FSMDEBUG(("fsm_input(%x): Rcvd short packet.", f->protocol)); return; } len -= HEADERLEN; /* subtract header length */ if( f->state == PPP_FSM_INITIAL || f->state == PPP_FSM_STARTING ){ FSMDEBUG(("fsm_input(%x): Rcvd packet in state %d.", f->protocol, f->state)); return; } /* * Action depends on code. */ switch (code) { case CONFREQ: fsm_rconfreq(f, id, inp, len); break; case CONFACK: fsm_rconfack(f, id, inp, len); break; case CONFNAK: case CONFREJ: fsm_rconfnakrej(f, code, id, inp, len); break; case TERMREQ: fsm_rtermreq(f, id, inp, len); break; case TERMACK: fsm_rtermack(f); break; case CODEREJ: fsm_rcoderej(f, inp, len); break; default: if( !f->callbacks->extcode || !(*f->callbacks->extcode)(f, code, id, inp, len) ) fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN); break; } }
WORD _getshort (const BYTE *x) /* in <arpa/nameserv.h> */ { WORD res; GETSHORT (res, x); return (res); }
dns_record * dns_next_rr(dns_answer *dnsa, dns_scan *dnss, int reset) { HEADER *h = (HEADER *)dnsa->answer; int namelen; /* Reset the saved data when requested to, and skip to the first required RR */ if (reset != RESET_NEXT) { dnss->rrcount = ntohs(h->qdcount); dnss->aptr = dnsa->answer + sizeof(HEADER); /* Skip over questions; failure to expand the name just gives up */ while (dnss->rrcount-- > 0) { namelen = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, dnss->aptr, (DN_EXPAND_ARG4_TYPE) &(dnss->srr.name), DNS_MAXNAME); if (namelen < 0) { dnss->rrcount = 0; return NULL; } dnss->aptr += namelen + 4; /* skip name & type & class */ } /* Get the number of answer records. */ dnss->rrcount = ntohs(h->ancount); /* Skip over answers if we want to look at the authority section. Also skip the NS records (i.e. authority section) if wanting to look at the additional records. */ if (reset == RESET_ADDITIONAL) dnss->rrcount += ntohs(h->nscount); if (reset == RESET_AUTHORITY || reset == RESET_ADDITIONAL) { while (dnss->rrcount-- > 0) { namelen = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, dnss->aptr, (DN_EXPAND_ARG4_TYPE) &(dnss->srr.name), DNS_MAXNAME); if (namelen < 0) { dnss->rrcount = 0; return NULL; } dnss->aptr += namelen + 8; /* skip name, type, class & TTL */ GETSHORT(dnss->srr.size, dnss->aptr); /* size of data portion */ dnss->aptr += dnss->srr.size; /* skip over it */ } dnss->rrcount = (reset == RESET_AUTHORITY) ? ntohs(h->nscount) : ntohs(h->arcount); } } /* The variable dnss->aptr is now pointing at the next RR, and dnss->rrcount contains the number of RR records left. */ if (dnss->rrcount-- <= 0) return NULL; /* If expanding the RR domain name fails, behave as if no more records (something safe). */ namelen = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, dnss->aptr, (DN_EXPAND_ARG4_TYPE) &(dnss->srr.name), DNS_MAXNAME); if (namelen < 0) { dnss->rrcount = 0; return NULL; } /* Move the pointer past the name and fill in the rest of the data structure from the following bytes. */ dnss->aptr += namelen; GETSHORT(dnss->srr.type, dnss->aptr); /* Record type */ dnss->aptr += 6; /* Don't want class or TTL */ GETSHORT(dnss->srr.size, dnss->aptr); /* Size of data portion */ dnss->srr.data = dnss->aptr; /* The record's data follows */ dnss->aptr += dnss->srr.size; /* Advance to next RR */ /* Return a pointer to the dns_record structure within the dns_answer. This is for convenience so that the scans can use nice-looking for loops. */ return &(dnss->srr); }
char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len, char *buf, int buf_len) { int o, i, j, nodecode = 0; const struct opttab_t *ot = opttab; #ifdef HAVE_DHCP6 if (prot == AF_INET6) ot = opttab6; #endif for (o = 0; ot[o].name; o++) if (ot[o].val == opt) { if (buf) { memset(buf, 0, buf_len); if (ot[o].size & OT_ADDR_LIST) { struct all_addr addr; int addr_len = INADDRSZ; #ifdef HAVE_DHCP6 if (prot == AF_INET6) addr_len = IN6ADDRSZ; #endif for (buf[0]= 0, i = 0; i <= opt_len - addr_len; i += addr_len) { if (i != 0) strncat(buf, ", ", buf_len - strlen(buf)); /* align */ memcpy(&addr, &val[i], addr_len); inet_ntop(prot, &val[i], daemon->addrbuff, ADDRSTRLEN); strncat(buf, daemon->addrbuff, buf_len - strlen(buf)); } } else if (ot[o].size & OT_NAME) for (i = 0, j = 0; i < opt_len && j < buf_len ; i++) { char c = val[i]; if (isprint((int)c)) buf[j++] = c; } #ifdef HAVE_DHCP6 /* We don't handle compressed rfc1035 names, so no good in IPv4 land */ else if ((ot[o].size & OT_RFC1035_NAME) && prot == AF_INET6) { i = 0, j = 0; while (i < opt_len && val[i] != 0) { int k, l = i + val[i] + 1; for (k = i + 1; k < opt_len && k < l && j < buf_len ; k++) { char c = val[k]; if (isprint((int)c)) buf[j++] = c; } i = l; if (val[i] != 0 && j < buf_len) buf[j++] = '.'; } } else if ((ot[o].size & OT_CSTRING)) { int k, len; unsigned char *p; i = 0, j = 0; while (1) { p = &val[i]; GETSHORT(len, p); for (k = 0; k < len && j < buf_len; k++) { char c = *p++; if (isprint((int)c)) buf[j++] = c; } i += len +2; if (i >= opt_len) break; if (j < buf_len) buf[j++] = ','; } } #endif else if ((ot[o].size & (OT_DEC | OT_TIME)) && opt_len != 0) { unsigned int dec = 0; for (i = 0; i < opt_len; i++) dec = (dec << 8) | val[i]; if (ot[o].size & OT_TIME) prettyprint_time(buf, dec); else sprintf(buf, "%u", dec); } else nodecode = 1; } break; } if (opt_len != 0 && buf && (!ot[o].name || nodecode)) { int trunc = 0; if (opt_len > 14) { trunc = 1; opt_len = 14; } print_mac(buf, val, opt_len); if (trunc) strncat(buf, "...", buf_len - strlen(buf)); } return ot[o].name ? ot[o].name : ""; }
static unsigned char *php_parserr(unsigned char *cp, querybuf *answer, int type_to_fetch, bool store, Array &subarray) { unsigned short type, cls ATTRIBUTE_UNUSED, dlen; unsigned long ttl; int64_t n, i; unsigned short s; unsigned char *tp, *p; char name[MAXHOSTNAMELEN]; int have_v6_break = 0, in_v6_break = 0; n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, sizeof(name) - 2); if (n < 0) { return NULL; } cp += n; GETSHORT(type, cp); GETSHORT(cls, cp); GETLONG(ttl, cp); GETSHORT(dlen, cp); if (type_to_fetch != T_ANY && type != type_to_fetch) { cp += dlen; return cp; } if (!store) { cp += dlen; return cp; } subarray.set(s_host, String(name, CopyString)); switch (type) { case DNS_T_A: subarray.set(s_type, s_A); snprintf(name, sizeof(name), "%d.%d.%d.%d", cp[0], cp[1], cp[2], cp[3]); subarray.set(s_ip, String(name, CopyString)); cp += dlen; break; case DNS_T_MX: subarray.set(s_type, s_MX); GETSHORT(n, cp); subarray.set(s_pri, n); /* no break; */ case DNS_T_CNAME: if (type == DNS_T_CNAME) { subarray.set(s_type, s_CNAME); } /* no break; */ case DNS_T_NS: if (type == DNS_T_NS) { subarray.set(s_type, s_NS); } /* no break; */ case DNS_T_PTR: if (type == DNS_T_PTR) { subarray.set(s_type, s_PTR); } n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) - 2); if (n < 0) { return NULL; } cp += n; subarray.set(s_target, String(name, CopyString)); break; case DNS_T_HINFO: /* See RFC 1010 for values */ subarray.set(s_type, s_HINFO); n = *cp & 0xFF; cp++; subarray.set(s_cpu, String((const char *)cp, n, CopyString)); cp += n; n = *cp & 0xFF; cp++; subarray.set(s_os, String((const char *)cp, n, CopyString)); cp += n; break; case DNS_T_TXT: { int ll = 0; subarray.set(s_type, s_TXT); String s = String(dlen, ReserveString); tp = (unsigned char *)s.bufferSlice().ptr; while (ll < dlen) { n = cp[ll]; memcpy(tp + ll , cp + ll + 1, n); ll = ll + n + 1; } s.setSize(dlen > 0 ? dlen - 1 : 0); cp += dlen; subarray.set(s_txt, s); break; } case DNS_T_SOA: subarray.set(s_type, s_SOA); n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) -2); if (n < 0) { return NULL; } cp += n; subarray.set(s_mname, String(name, CopyString)); n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) -2); if (n < 0) { return NULL; } cp += n; subarray.set(s_rname, String(name, CopyString)); GETLONG(n, cp); subarray.set(s_serial, n); GETLONG(n, cp); subarray.set(s_refresh, n); GETLONG(n, cp); subarray.set(s_retry, n); GETLONG(n, cp); subarray.set(s_expire, n); GETLONG(n, cp); subarray.set(s_minimum_ttl, n); break; case DNS_T_AAAA: tp = (unsigned char *)name; for (i = 0; i < 8; i++) { GETSHORT(s, cp); if (s != 0) { if (tp > (u_char *)name) { in_v6_break = 0; tp[0] = ':'; tp++; } tp += sprintf((char *)tp, "%x", s); } else { if (!have_v6_break) { have_v6_break = 1; in_v6_break = 1; tp[0] = ':'; tp++; } else if (!in_v6_break) { tp[0] = ':'; tp++; tp[0] = '0'; tp++; } } } if (have_v6_break && in_v6_break) { tp[0] = ':'; tp++; } tp[0] = '\0'; subarray.set(s_type, s_AAAA); subarray.set(s_ipv6, String(name, CopyString)); break; case DNS_T_A6: p = cp; subarray.set(s_type, s_A6); n = ((int)cp[0]) & 0xFF; cp++; subarray.set(s_masklen, n); tp = (unsigned char *)name; if (n > 15) { have_v6_break = 1; in_v6_break = 1; tp[0] = ':'; tp++; } if (n % 16 > 8) { /* Partial short */ if (cp[0] != 0) { if (tp > (u_char *)name) { in_v6_break = 0; tp[0] = ':'; tp++; } sprintf((char *)tp, "%x", cp[0] & 0xFF); } else { if (!have_v6_break) { have_v6_break = 1; in_v6_break = 1; tp[0] = ':'; tp++; } else if (!in_v6_break) { tp[0] = ':'; tp++; tp[0] = '0'; tp++; } } cp++; } for (i = (n + 8)/16; i < 8; i++) { GETSHORT(s, cp); if (s != 0) { if (tp > (u_char *)name) { in_v6_break = 0; tp[0] = ':'; tp++; } tp += sprintf((char*)tp,"%x",s); } else { if (!have_v6_break) { have_v6_break = 1; in_v6_break = 1; tp[0] = ':'; tp++; } else if (!in_v6_break) { tp[0] = ':'; tp++; tp[0] = '0'; tp++; } } } if (have_v6_break && in_v6_break) { tp[0] = ':'; tp++; } tp[0] = '\0'; subarray.set(s_ipv6, String(name, CopyString)); if (cp < p + dlen) { n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) - 2); if (n < 0) { return NULL; } cp += n; subarray.set(s_chain, String(name, CopyString)); } break; case DNS_T_SRV: subarray.set(s_type, s_SRV); GETSHORT(n, cp); subarray.set(s_pri, n); GETSHORT(n, cp); subarray.set(s_weight, n); GETSHORT(n, cp); subarray.set(s_port, n); n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) - 2); if (n < 0) { return NULL; } cp += n; subarray.set(s_target, String(name, CopyString)); break; case DNS_T_NAPTR: subarray.set(s_type, s_NAPTR); GETSHORT(n, cp); subarray.set(s_order, n); GETSHORT(n, cp); subarray.set(s_pref, n); n = (cp[0] & 0xFF); subarray.set(s_flags, String((const char *)(++cp), n, CopyString)); cp += n; n = (cp[0] & 0xFF); subarray.set(s_services, String((const char *)(++cp), n, CopyString)); cp += n; n = (cp[0] & 0xFF); subarray.set(s_regex, String((const char *)(++cp), n, CopyString)); cp += n; n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) - 2); if (n < 0) { return NULL; } cp += n; subarray.set(s_replacement, String(name, CopyString)); break; default: cp += dlen; } subarray.set(s_class, s_IN); subarray.set(s_ttl, (int)ttl); return cp; }
/* Receive packet */ void l2tp_ctrl_input(l2tpd *_this, int listener_index, struct sockaddr *peer, struct sockaddr *sock, void *nat_t_ctx, u_char *pkt, int pktlen) { int i, len, offsiz, reqlen, is_ctrl; uint16_t mestype; struct l2tp_avp *avp, *avp0; l2tp_ctrl *ctrl; l2tp_call *call; char buf[L2TP_AVP_MAXSIZ], errmsg[256]; time_t curr_time; u_char *pkt0; struct l2tp_header hdr; char hbuf[NI_MAXHOST + NI_MAXSERV + 16]; ctrl = NULL; curr_time = get_monosec(); pkt0 = pkt; L2TP_CTRL_ASSERT(peer->sa_family == sock->sa_family); L2TP_CTRL_ASSERT(peer->sa_family == AF_INET || peer->sa_family == AF_INET6) /* * Parse L2TP Header */ memset(&hdr, 0, sizeof(hdr)); if (pktlen < 2) { snprintf(errmsg, sizeof(errmsg), "a short packet. " "length=%d", pktlen); goto bad_packet; } memcpy(&hdr, pkt, 2); pkt += 2; if (hdr.ver != L2TP_HEADER_VERSION_RFC2661) { /* XXX: only RFC2661 is supported */ snprintf(errmsg, sizeof(errmsg), "Unsupported version at header = %d", hdr.ver); goto bad_packet; } is_ctrl = (hdr.t != 0)? 1 : 0; /* calc required length */ reqlen = 6; /* for Flags, Tunnel-Id, Session-Id field */ if (hdr.l) reqlen += 2; /* for Length field (opt) */ if (hdr.s) reqlen += 4; /* for Ns, Nr field (opt) */ if (hdr.o) reqlen += 2; /* for Offset Size field (opt) */ if (reqlen > pktlen) { snprintf(errmsg, sizeof(errmsg), "a short packet. length=%d", pktlen); goto bad_packet; } if (hdr.l != 0) { GETSHORT(hdr.length, pkt); if (hdr.length > pktlen) { snprintf(errmsg, sizeof(errmsg), "Actual packet size is smaller than the length " "field %d < %d", pktlen, hdr.length); goto bad_packet; } pktlen = hdr.length; /* remove trailing trash */ } GETSHORT(hdr.tunnel_id, pkt); GETSHORT(hdr.session_id, pkt); if (hdr.s != 0) { GETSHORT(hdr.ns, pkt); GETSHORT(hdr.nr, pkt); } if (hdr.o != 0) { GETSHORT(offsiz, pkt); if (pktlen < offsiz) { snprintf(errmsg, sizeof(errmsg), "offset field is bigger than remaining packet " "length %d > %d", offsiz, pktlen); goto bad_packet; } pkt += offsiz; } L2TP_CTRL_ASSERT(pkt - pkt0 == reqlen); pktlen -= (pkt - pkt0); /* cut down the length of header */ ctrl = NULL; memset(buf, 0, sizeof(buf)); mestype = 0; avp = NULL; if (is_ctrl) { avp0 = (struct l2tp_avp *)buf; avp = avp_find_message_type_avp(avp0, pkt, pktlen); if (avp != NULL) mestype = avp->attr_value[0] << 8 | avp->attr_value[1]; } ctrl = l2tpd_get_ctrl(_this, hdr.tunnel_id); if (ctrl == NULL) { /* new control */ if (!is_ctrl) { snprintf(errmsg, sizeof(errmsg), "bad data message: tunnelId=%d is not " "found.", hdr.tunnel_id); goto bad_packet; } if (mestype != L2TP_AVP_MESSAGE_TYPE_SCCRQ) { snprintf(errmsg, sizeof(errmsg), "bad control message: tunnelId=%d is not " "found. mestype=%s", hdr.tunnel_id, avp_mes_type_string(mestype)); goto bad_packet; } if ((ctrl = l2tp_ctrl_create()) == NULL) { l2tp_ctrl_log(ctrl, LOG_ERR, "l2tp_ctrl_create() failed: %m"); goto fail; } if (l2tp_ctrl_init(ctrl, _this, peer, sock, nat_t_ctx) != 0) { l2tp_ctrl_log(ctrl, LOG_ERR, "l2tp_ctrl_start() failed: %m"); goto fail; } ctrl->listener_index = listener_index; l2tp_ctrl_reload(ctrl); } else { /* * treat as an error if src address and port is not * match. (because it is potentially DoS attach) */ int notmatch = 0; if (ctrl->peer.ss_family != peer->sa_family) notmatch = 1; else if (peer->sa_family == AF_INET) { if (SIN(peer)->sin_addr.s_addr != SIN(&ctrl->peer)->sin_addr.s_addr || SIN(peer)->sin_port != SIN(&ctrl->peer)->sin_port) notmatch = 1; } else if (peer->sa_family == AF_INET6) { if (!IN6_ARE_ADDR_EQUAL(&(SIN6(peer)->sin6_addr), &(SIN6(&ctrl->peer)->sin6_addr)) || SIN6(peer)->sin6_port != SIN6(&ctrl->peer)->sin6_port) notmatch = 1; } if (notmatch) { snprintf(errmsg, sizeof(errmsg), "tunnelId=%u is already assigned for %s", hdr.tunnel_id, addrport_tostring( (struct sockaddr *)&ctrl->peer, ctrl->peer.ss_len, hbuf, sizeof(hbuf))); goto bad_packet; } } ctrl->last_rcv = curr_time; call = NULL; if (hdr.session_id != 0) { /* search l2tp_call by Session ID */ /* linear search is enough for this purpose */ len = slist_length(&ctrl->call_list); for (i = 0; i < len; i++) { call = slist_get(&ctrl->call_list, i); if (call->session_id == hdr.session_id) break; call = NULL; } } if (!is_ctrl) { int delayed = 0; /* L2TP data */ if (ctrl->state != L2TP_CTRL_STATE_ESTABLISHED) { l2tp_ctrl_log(ctrl, LOG_WARNING, "Received Data packet in '%s'", l2tp_ctrl_state_string(ctrl)); goto fail; } if (call == NULL) { l2tp_ctrl_log(ctrl, LOG_WARNING, "Received a data packet but it has no call. " "session_id=%u", hdr.session_id); goto fail; } L2TP_CTRL_DBG((ctrl, DEBUG_LEVEL_2, "call=%u RECV ns=%u nr=%u snd_nxt=%u rcv_nxt=%u len=%d", call->id, hdr.ns, hdr.nr, call->snd_nxt, call->rcv_nxt, pktlen)); if (call->state != L2TP_CALL_STATE_ESTABLISHED){ l2tp_ctrl_log(ctrl, LOG_WARNING, "Received a data packet but call is not " "established"); goto fail; } if (hdr.s != 0) { if (SEQ_LT(hdr.ns, call->rcv_nxt)) { if (SEQ_LT(hdr.ns, call->rcv_nxt - L2TP_CALL_DELAY_LIMIT)) { /* sequence number seems to be delayed */ /* XXX: need to log? */ L2TP_CTRL_DBG((ctrl, LOG_DEBUG, "receive a out of sequence " "data packet: %u < %u.", hdr.ns, call->rcv_nxt)); return; } delayed = 1; } else { call->rcv_nxt = hdr.ns + 1; } } l2tp_call_ppp_input(call, pkt, pktlen, delayed); return; } if (hdr.s != 0) { L2TP_CTRL_DBG((ctrl, DEBUG_LEVEL_2, "RECV %s ns=%u nr=%u snd_nxt=%u snd_una=%u rcv_nxt=%u " "len=%d", (is_ctrl)? "C" : "", hdr.ns, hdr.nr, ctrl->snd_nxt, ctrl->snd_una, ctrl->rcv_nxt, pktlen)); if (pktlen <= 0) l2tp_ctrl_log(ctrl, LOG_INFO, "RecvZLB"); if (SEQ_GT(hdr.nr, ctrl->snd_una)) { if (hdr.nr == ctrl->snd_nxt || SEQ_LT(hdr.nr, ctrl->snd_nxt)) ctrl->snd_una = hdr.nr; else { l2tp_ctrl_log(ctrl, LOG_INFO, "Received message has bad Nr field: " "%u < %u.", hdr.ns, ctrl->snd_nxt); /* XXX Drop with ZLB? */ goto fail; } } if (l2tp_ctrl_txwin_size(ctrl) <= 0) { /* no waiting ack */ if (ctrl->hello_wait_ack != 0) { /* * Reset Hello state, as an ack for the Hello * is recived. */ ctrl->hello_wait_ack = 0; ctrl->hello_io_time = curr_time; } switch (ctrl->state) { case L2TP_CTRL_STATE_CLEANUP_WAIT: l2tp_ctrl_stop(ctrl, 0); return; } } if (hdr.ns != ctrl->rcv_nxt) { /* there are remaining packet */ if (l2tp_ctrl_resend_una_packets(ctrl) <= 0) { /* resend or sent ZLB */ l2tp_ctrl_send_ZLB(ctrl); } #ifdef L2TP_CTRL_DEBUG if (pktlen != 0) { /* not ZLB */ L2TP_CTRL_DBG((ctrl, LOG_DEBUG, "receive out of sequence %u must be %u. " "mestype=%s", hdr.ns, ctrl->rcv_nxt, avp_mes_type_string(mestype))); } #endif return; } if (pktlen <= 0) return; /* ZLB */ if (l2tp_ctrl_txwin_is_full(ctrl)) { L2TP_CTRL_DBG((ctrl, LOG_DEBUG, "Received message cannot be handled. " "Transmission window is full.")); l2tp_ctrl_send_ZLB(ctrl); return; } ctrl->rcv_nxt++; if (avp == NULL) { l2tpd_log(_this, LOG_WARNING, "bad control message: no message-type AVP."); goto fail; } } /* * state machine (RFC2661 pp. 56-57) */ switch (ctrl->state) { case L2TP_CTRL_STATE_IDLE: switch (mestype) { case L2TP_AVP_MESSAGE_TYPE_SCCRQ: if (l2tp_ctrl_recv_SCCRQ(ctrl, pkt, pktlen, _this, peer) == 0) { /* acceptable */ l2tp_ctrl_send_SCCRP(ctrl); ctrl->state = L2TP_CTRL_STATE_WAIT_CTL_CONN; return; } /* * in case un-acceptable, it was already processed * at l2tcp_ctrl_recv_SCCRQ */ return; case L2TP_AVP_MESSAGE_TYPE_SCCRP: /* * RFC specifies that sent of StopCCN in the state, * However as this implementation only support Passive * open, this packet will not received. */ /* FALLTHROUGH */ case L2TP_AVP_MESSAGE_TYPE_SCCCN: default: break; } goto fsm_fail; case L2TP_CTRL_STATE_WAIT_CTL_CONN: /* Wait-Ctl-Conn */ switch (mestype) { case L2TP_AVP_MESSAGE_TYPE_SCCCN: l2tp_ctrl_log(ctrl, LOG_INFO, "RecvSCCN"); if (l2tp_ctrl_send_ZLB(ctrl) == 0) { ctrl->state = L2TP_CTRL_STATE_ESTABLISHED; } return; case L2TP_AVP_MESSAGE_TYPE_StopCCN: goto receive_stop_ccn; case L2TP_AVP_MESSAGE_TYPE_SCCRQ: case L2TP_AVP_MESSAGE_TYPE_SCCRP: default: break; } break; /* fsm_fail */ case L2TP_CTRL_STATE_ESTABLISHED: /* Established */ switch (mestype) { case L2TP_AVP_MESSAGE_TYPE_SCCCN: case L2TP_AVP_MESSAGE_TYPE_SCCRQ: case L2TP_AVP_MESSAGE_TYPE_SCCRP: break; receive_stop_ccn: case L2TP_AVP_MESSAGE_TYPE_StopCCN: if (l2tp_ctrl_recv_StopCCN(ctrl, pkt, pktlen) == 0) { if (l2tp_ctrl_resend_una_packets(ctrl) <= 0) l2tp_ctrl_send_ZLB(ctrl); l2tp_ctrl_stop(ctrl, 0); return; } l2tp_ctrl_log(ctrl, LOG_ERR, "Received bad StopCCN"); l2tp_ctrl_send_ZLB(ctrl); l2tp_ctrl_stop(ctrl, 0); return; case L2TP_AVP_MESSAGE_TYPE_HELLO: if (l2tp_ctrl_resend_una_packets(ctrl) <= 0) l2tp_ctrl_send_ZLB(ctrl); return; case L2TP_AVP_MESSAGE_TYPE_CDN: case L2TP_AVP_MESSAGE_TYPE_ICRP: case L2TP_AVP_MESSAGE_TYPE_ICCN: if (call == NULL) { l2tp_ctrl_log(ctrl, LOG_INFO, "Unknown call message: %s", avp_mes_type_string(mestype)); goto fail; } /* FALLTHROUGH */ case L2TP_AVP_MESSAGE_TYPE_ICRQ: l2tp_call_recv_packet(ctrl, call, mestype, pkt, pktlen); return; default: break; } break; /* fsm_fail */ case L2TP_CTRL_STATE_CLEANUP_WAIT: if (mestype == L2TP_AVP_MESSAGE_TYPE_StopCCN) { /* * We left ESTABLISHED state, but the peer sent StopCCN. */ goto receive_stop_ccn; } break; /* fsm_fail */ } fsm_fail: /* state machine error */ l2tp_ctrl_log(ctrl, LOG_WARNING, "Received %s in '%s' state", avp_mes_type_string(mestype), l2tp_ctrl_state_string(ctrl)); l2tp_ctrl_stop(ctrl, L2TP_STOP_CCN_RCODE_FSM_ERROR); return; fail: if (ctrl != NULL && mestype != 0) { l2tp_ctrl_log(ctrl, LOG_WARNING, "Received %s in '%s' state", avp_mes_type_string(mestype), l2tp_ctrl_state_string(ctrl)); l2tp_ctrl_stop(ctrl, L2TP_STOP_CCN_RCODE_GENERAL_ERROR); } return; bad_packet: l2tpd_log(_this, LOG_INFO, "Received from=%s: %s", addrport_tostring(peer, peer->sa_len, hbuf, sizeof(hbuf)), errmsg); return; }