const char * val_get_ns_string(struct sockaddr *serv, char *dst, size_t size) { struct sockaddr_in *sin; #ifdef VAL_IPV6 struct sockaddr_in6 *sin6; #endif struct sockaddr_storage *server; const char *addr = NULL; if ((serv == NULL) || (dst == NULL)) return NULL; server = (struct sockaddr_storage *) serv; switch (server->ss_family) { case AF_INET: sin = (struct sockaddr_in *) server; INET_NTOP(AF_INET, ((struct sockaddr *)sin), sizeof(struct sockaddr_in), dst, size, addr); return addr; #ifdef VAL_IPV6 case AF_INET6: sin6 = (struct sockaddr_in6 *) server; INET_NTOP(AF_INET6, ((struct sockaddr *)sin6), sizeof(struct sockaddr_in), dst, size, addr); return addr; #endif } return NULL; }
static int SPF_i_match_ip6(SPF_server_t *spf_server, SPF_request_t *spf_request, SPF_mech_t *mech, struct in6_addr ipv6 ) { char src_ip6_buf[ INET6_ADDRSTRLEN ]; char dst_ip6_buf[ INET6_ADDRSTRLEN ]; struct in6_addr src_ipv6; int cidr, cidr_save, mask; int i; int match; if ( spf_request->client_ver != AF_INET6 ) return FALSE; src_ipv6 = spf_request->ipv6; cidr = SPF_i_mech_cidr(spf_request, mech); if ( cidr == 0 ) cidr = 128; cidr_save = cidr; match = TRUE; for( i = 0; i < array_elem( ipv6.s6_addr ) && match; i++ ) { if ( cidr > 8 ) mask = 0xff; else if ( cidr > 0 ) mask = (0xff << (8 - cidr)) & 0xff; else break; cidr -= 8; match = (src_ipv6.s6_addr[i] & mask) == (ipv6.s6_addr[i] & mask); } if (spf_server->debug) { INET_NTOP(AF_INET6, &src_ipv6.s6_addr, src_ip6_buf, sizeof(src_ip6_buf)); INET_NTOP(AF_INET6, &ipv6.s6_addr, dst_ip6_buf, sizeof(dst_ip6_buf)); SPF_debugf( "ip_match: %s == %s (/%d): %d", src_ip6_buf, dst_ip6_buf, cidr_save, match ); } return match; }
// #define addrfmt(x, s) x.fmt(s, sizeof(s)) cstr PackedSockAddr::fmt(str s, size_t len) const { memset(s, 0, len); const byte family = get_family(); str i; if (family == AF_INET) { INET_NTOP(family, (uint32*)&_sin4, s, len); i = s; while (*++i) {} } else { i = s; *i++ = '['; INET_NTOP(family, (in6_addr*)&_in._in6addr, i, len-1); while (*++i) {} *i++ = ']'; } snprintf(i, len - (i-s), ":%u", _port); return s; }
static int SPF_i_match_ip4(SPF_server_t *spf_server, SPF_request_t *spf_request, SPF_mech_t *mech, struct in_addr ipv4 ) { char src_ip4_buf[ INET_ADDRSTRLEN ]; char dst_ip4_buf[ INET_ADDRSTRLEN ]; char mask_ip4_buf[ INET_ADDRSTRLEN ]; struct in_addr src_ipv4; int cidr, mask; if ( spf_request->client_ver != AF_INET ) return FALSE; src_ipv4 = spf_request->ipv4; cidr = SPF_i_mech_cidr( spf_request, mech ); if ( cidr == 0 ) cidr = 32; mask = 0xffffffff << (32 - cidr); mask = htonl(mask); if (spf_server->debug) { INET_NTOP(AF_INET, &src_ipv4.s_addr, src_ip4_buf, sizeof(src_ip4_buf)); INET_NTOP(AF_INET, &ipv4.s_addr, dst_ip4_buf, sizeof(dst_ip4_buf)); INET_NTOP(AF_INET, &mask, mask_ip4_buf, sizeof(mask_ip4_buf)); SPF_debugf( "ip_match: %s == %s (/%d %s): %d", src_ip4_buf, dst_ip4_buf, cidr, mask_ip4_buf, (src_ipv4.s_addr & mask) == (ipv4.s_addr & mask)); } return (src_ipv4.s_addr & mask) == (ipv4.s_addr & mask); }
static int add_multicast_group(SOCKET sock, const struct sockaddr *psa) { #if defined(WIN32) LOG(X_ERROR("Multicast not implemented on this system type")); return -1; #else if(psa->sa_family == AF_INET6) { LOG(X_ERROR("IPv6 multicast group addition not implemented")); return -1; } struct ip_mreq mcip; char tmp[128]; memset(&mcip, 0, sizeof(mcip)); mcip.imr_multiaddr.s_addr = ((const struct sockaddr_in *) psa)->sin_addr.s_addr; mcip.imr_interface.s_addr = INADDR_ANY; if(setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mcip, sizeof(mcip)) < 0) { LOG(X_ERROR("Unable to add multicast membership for %s"), INET_NTOP(*psa, tmp, sizeof(tmp))); return -1; } LOG(X_DEBUG("Subscribed to multicast membership for %s"), INET_NTOP(*psa, tmp, sizeof(tmp))); return 0; #endif // WIN32 }
int sdputil_init(SDP_DESCR_T *pSdp, uint8_t payloadType, unsigned int clockRateHz, XC_CODEC_TYPE_T codecType, const char *pDstHost, uint16_t dstPort, uint16_t dstPortRtcp, const SRTP_CTXT_T *pSrtp, const DTLS_CFG_T *pDtlsCfg, const STUN_REQUESTOR_CFG_T *pStunCfg, const SDP_CODEC_PARAM_T *pCodecSpecific, const FRAME_RATE_T *pFps, const VID_ENCODER_FBREQUEST_T *pFbReq) { int rc = 0; char tmp[128]; struct sockaddr_storage connectip; if(!pSdp || payloadType > 0x7f || !pDstHost) { return -1; } memset(&connectip, 0, sizeof(connectip)); if(!net_isipv4(pDstHost) && !net_isipv6(pDstHost)) { // // INADDR_NONE // pDstHost = "0.0.0.0"; } net_getaddress(pDstHost, &connectip); if(INET_ADDR_VALID(connectip) && INET_IS_MULTICAST(connectip)) { pSdp->c.ttl = 64; } else if(INET_ADDR_VALID(connectip) && INET_ADDR_LOCALHOST(connectip)) { pSdp->c.ttl = 0; } else { //connectip.s_addr = net_getlocalip(); // // For remote unicast destinations, leave the remote ip into the 'c=' field // which may be contrary to RFC4566 // //connectip.s_addr = INADDR_ANY; pSdp->c.ttl = 0; } pSdp->c.ip_family = connectip.ss_family; strncpy(pSdp->c.iphost, INET_NTOP(connectip, tmp, sizeof(tmp)), sizeof(pSdp->c.iphost)); // // Only write the RTCP port attribute in the SDP if using a non-default port // if(dstPortRtcp == RTCP_PORT_FROM_RTP(dstPort)) { dstPortRtcp = 0; } if(pFps && pFps->clockHz > 0 && pFps->frameDeltaHz > 0) { memcpy(&pSdp->vid.fps, pFps, sizeof(pSdp->vid.fps)); } switch(codecType) { case XC_CODEC_TYPE_H264: case XC_CODEC_TYPE_MPEG4V: case XC_CODEC_TYPE_H263: case XC_CODEC_TYPE_H263_PLUS: case XC_CODEC_TYPE_VP8: pSdp->vid.common.available = 1; pSdp->vid.common.codecType = codecType; pSdp->vid.common.payloadType = payloadType; pSdp->vid.common.port = dstPort; pSdp->vid.common.portRtcp = dstPortRtcp; pSdp->vid.common.clockHz = clockRateHz; pSdp->vid.common.transType = SDP_TRANS_TYPE_RTP_UDP; if(pDtlsCfg) { if(pDtlsCfg->dtls_srtp) { pSdp->vid.common.transType = SDP_TRANS_TYPE_SRTP_DTLS_UDP; } else { pSdp->vid.common.transType = SDP_TRANS_TYPE_DTLS_UDP; } memcpy(&pSdp->vid.common.fingerprint, &pDtlsCfg->fingerprint, sizeof(pSdp->vid.common.fingerprint)); } if(pSrtp) { pSdp->vid.common.transType = SDP_TRANS_TYPE_SRTP_SDES_UDP; if((rc = sdputil_initsrtp(&pSdp->vid.common.srtp, pSrtp)) < 0) { return rc; } } if(pStunCfg && pStunCfg->bindingRequest) { if(pStunCfg->reqUsername) { strncpy(pSdp->vid.common.ice.ufrag, pStunCfg->reqUsername, STUN_STRING_MAX - 1); } if(pStunCfg->reqPass) { strncpy(pSdp->vid.common.ice.pwd, pStunCfg->reqPass, STUN_STRING_MAX - 1); } } if(codecType == XC_CODEC_TYPE_H264) { strncpy(pSdp->vid.common.encodingName, SDP_RTPMAP_ENCODINGNAME_H264, sizeof(pSdp->vid.common.encodingName)); } else if(codecType == XC_CODEC_TYPE_MPEG4V) { strncpy(pSdp->vid.common.encodingName, SDP_RTPMAP_ENCODINGNAME_MPEG4V, sizeof(pSdp->vid.common.encodingName)); } else if(codecType == XC_CODEC_TYPE_H263) { strncpy(pSdp->vid.common.encodingName, SDP_RTPMAP_ENCODINGNAME_H263, sizeof(pSdp->vid.common.encodingName)); } else if(codecType == XC_CODEC_TYPE_H263_PLUS) { strncpy(pSdp->vid.common.encodingName, SDP_RTPMAP_ENCODINGNAME_H263_PLUS, sizeof(pSdp->vid.common.encodingName)); } else if(codecType == XC_CODEC_TYPE_VP8) { strncpy(pSdp->vid.common.encodingName, SDP_RTPMAP_ENCODINGNAME_VP8, sizeof(pSdp->vid.common.encodingName)); } break; case XC_CODEC_TYPE_AAC: case XC_CODEC_TYPE_AMRNB: case XC_CODEC_TYPE_SILK: case XC_CODEC_TYPE_OPUS: case XC_CODEC_TYPE_G711_MULAW: case XC_CODEC_TYPE_G711_ALAW: pSdp->aud.common.available = 1; pSdp->aud.common.codecType = codecType; pSdp->aud.common.payloadType = payloadType; pSdp->aud.common.port = dstPort; pSdp->aud.common.portRtcp = dstPortRtcp; pSdp->aud.common.clockHz = clockRateHz; pSdp->aud.common.transType = SDP_TRANS_TYPE_RTP_UDP; if(pDtlsCfg) { if(pDtlsCfg->dtls_srtp) { pSdp->aud.common.transType = SDP_TRANS_TYPE_SRTP_DTLS_UDP; } else { pSdp->aud.common.transType = SDP_TRANS_TYPE_DTLS_UDP; } memcpy(&pSdp->aud.common.fingerprint, &pDtlsCfg->fingerprint, sizeof(pSdp->aud.common.fingerprint)); } if(pSrtp) { pSdp->aud.common.transType = SDP_TRANS_TYPE_SRTP_SDES_UDP; if((rc = sdputil_initsrtp(&pSdp->aud.common.srtp, pSrtp)) < 0) { return rc; } } if(pStunCfg && pStunCfg->bindingRequest) { if(pStunCfg->reqUsername) { strncpy(pSdp->aud.common.ice.ufrag, pStunCfg->reqUsername, STUN_STRING_MAX - 1); } if(pStunCfg->reqPass) { strncpy(pSdp->aud.common.ice.pwd, pStunCfg->reqPass, STUN_STRING_MAX - 1); } } if(codecType == XC_CODEC_TYPE_AAC) { strncpy(pSdp->aud.common.encodingName, SDP_RTPMAP_ENCODINGNAME_AAC, sizeof(pSdp->aud.common.encodingName)); } else if(codecType == XC_CODEC_TYPE_AMRNB) { strncpy(pSdp->aud.common.encodingName, SDP_RTPMAP_ENCODINGNAME_AMR, sizeof(pSdp->aud.common.encodingName)); } else if(codecType == XC_CODEC_TYPE_SILK) { strncpy(pSdp->aud.common.encodingName, SDP_RTPMAP_ENCODINGNAME_SILK, sizeof(pSdp->aud.common.encodingName)); } else if(codecType == XC_CODEC_TYPE_OPUS) { strncpy(pSdp->aud.common.encodingName, SDP_RTPMAP_ENCODINGNAME_OPUS, sizeof(pSdp->aud.common.encodingName)); } else if(codecType == XC_CODEC_TYPE_G711_MULAW) { strncpy(pSdp->aud.common.encodingName, SDP_RTPMAP_ENCODINGNAME_PCMU, sizeof(pSdp->aud.common.encodingName)); } else if(codecType == XC_CODEC_TYPE_G711_ALAW) { strncpy(pSdp->aud.common.encodingName, SDP_RTPMAP_ENCODINGNAME_PCMA, sizeof(pSdp->aud.common.encodingName)); } break; case MEDIA_FILE_TYPE_MP2TS: pSdp->vid.common.available = 1; pSdp->vid.common.codecType = MEDIA_FILE_TYPE_MP2TS; pSdp->vid.common.payloadType = payloadType; pSdp->vid.common.port = dstPort; pSdp->vid.common.portRtcp = dstPortRtcp; pSdp->vid.common.clockHz = 90000; if(pSrtp) { pSdp->vid.common.transType = SDP_TRANS_TYPE_SRTP_SDES_UDP; if((rc = sdputil_initsrtp(&pSdp->vid.common.srtp, pSrtp)) < 0) { return rc; } } strncpy(pSdp->vid.common.encodingName, SDP_RTPMAP_ENCODINGNAME_MP2TS, sizeof(pSdp->vid.common.encodingName)); break; default: return -1; } // // Advertise any a=rtcp-fb: SDP flags // if(pSdp->vid.common.available) { if(pFbReq && (pFbReq->firCfg.fir_send_from_decoder || pFbReq->firCfg.fir_send_from_local || pFbReq->firCfg.fir_send_from_remote || pFbReq->firCfg.fir_send_from_capture)) { pSdp->vid.common.rtcpfb.fmtidmin1 = pSdp->vid.common.payloadType + 1; pSdp->vid.common.rtcpfb.flags |= SDP_RTCPFB_TYPE_CCM | SDP_RTCPFB_TYPE_CCM_FIR; } if(pFbReq && pFbReq->nackRtpRetransmit) { pSdp->vid.common.rtcpfb.flags |= SDP_RTCPFB_TYPE_NACK | SDP_RTCPFB_TYPE_NACK_GENERIC; } //pSdp->vid.common.rtcpfb.flags |= SDP_RTCPFB_TYPE_TRRINT; //pSdp->vid.common.rtcpfb.trrIntervalMs |= 30; } // // Codec specific default settings // switch(codecType) { case XC_CODEC_TYPE_H264: if(pCodecSpecific && (pCodecSpecific->flags & SDP_CODEC_PARAM_FLAGS_PKTZMODE)) { switch(pCodecSpecific->u.pktzMode) { case PKTZ_H264_MODE_0: pSdp->vid.u.h264.packetization_mode = 0; break; case PKTZ_H264_MODE_2: LOG(X_WARNING("H.264 NAL Packetization mode 2 not supported. Using mode 1")); case PKTZ_H264_MODE_1: case PKTZ_H264_MODE_NOTSET: default: pSdp->vid.u.h264.packetization_mode = 1; break; } } break; case XC_CODEC_TYPE_MPEG4V: pSdp->vid.u.mpg4v.profile_level_id = 1; break; case XC_CODEC_TYPE_VP8: break; case XC_CODEC_TYPE_AAC: strncpy(pSdp->aud.u.aac.mode, "AAC-hbr", sizeof(pSdp->aud.u.aac.mode)); pSdp->aud.u.aac.sizelength = 13; pSdp->aud.u.aac.indexlength = 3; pSdp->aud.u.aac.indexdeltalength = 3; break; case XC_CODEC_TYPE_AMRNB: pSdp->aud.channels = 1; pSdp->aud.u.amr.octet_align = 1; break; case XC_CODEC_TYPE_SILK: if(pCodecSpecific && (pCodecSpecific->flags & SDP_CODEC_PARAM_FLAGS_CHANNELS)) { pSdp->aud.channels = pCodecSpecific->u.channels; } else { pSdp->aud.channels = 1; } //pSdp->aud.u.silk.dummy = 0; break; case XC_CODEC_TYPE_OPUS: if(pCodecSpecific && (pCodecSpecific->flags & SDP_CODEC_PARAM_FLAGS_CHANNELS)) { pSdp->aud.channels = pCodecSpecific->u.channels;; } else { pSdp->aud.channels = 1; } break; case XC_CODEC_TYPE_G711_MULAW: case XC_CODEC_TYPE_G711_ALAW: pSdp->aud.channels = 1; break; default: break; } return rc; }
SPF_errcode_t SPF_record_interpret(SPF_record_t *spf_record, SPF_request_t *spf_request, SPF_response_t *spf_response, int depth) { SPF_server_t *spf_server; /* Temporaries */ int i, j; int m; /* Mechanism iterator */ SPF_mech_t *mech; SPF_data_t *data; SPF_data_t *data_end; /* XXX Replace with size_t data_len */ /* Where to insert the local policy (whitelist) */ SPF_mech_t *local_policy; /* Not the local policy */ int found_all; /* A crappy temporary. */ char *buf = NULL; size_t buf_len = 0; ns_type fetch_ns_type; const char *lookup; SPF_dns_rr_t *rr_a; SPF_dns_rr_t *rr_aaaa; SPF_dns_rr_t *rr_ptr; SPF_dns_rr_t *rr_mx; SPF_errcode_t err; SPF_dns_server_t*resolver; /* An SPF record for subrequests - replaces c_results */ SPF_record_t *spf_record_subr; SPF_response_t *save_spf_response; SPF_response_t *spf_response_subr; const char *save_cur_dom; struct in_addr addr4; struct in6_addr addr6; int max_ptr; int max_mx; int max_exceeded; char ip4_buf[ INET_ADDRSTRLEN ]; char ip6_buf[ INET6_ADDRSTRLEN ]; /* * make sure we were passed valid data to work with */ SPF_ASSERT_NOTNULL(spf_record); SPF_ASSERT_NOTNULL(spf_request); SPF_ASSERT_NOTNULL(spf_response); spf_server = spf_record->spf_server; SPF_ASSERT_NOTNULL(spf_server); SPF_ASSERT_NOTNULL(spf_response->spf_record_exp); if (depth > 20) return DONE_PERMERR(SPF_E_RECURSIVE); if ( spf_request->client_ver != AF_INET && spf_request->client_ver != AF_INET6 ) return DONE_PERMERR(SPF_E_NOT_CONFIG); if (spf_request->cur_dom == NULL) return DONE_PERMERR(SPF_E_NOT_CONFIG); /* * localhost always gets a free ride */ #if 0 /* This should have been done already before we got here. */ if ( SPF_request_is_loopback( spf_request ) ) return DONE(SPF_RESULT_PASS,SPF_REASON_LOCALHOST,SPF_E_SUCCESS); #endif /* * Do some start up stuff if we haven't recursed yet */ local_policy = NULL; if ( spf_request->use_local_policy ) { /* * find the location for the whitelist execution * * Philip Gladstone says: * * I think that the localpolicy should only be inserted if the * final mechanism is '-all', and it should be inserted after * the last mechanism which is not '-'. * * Thus for the case of 'v=spf1 +a +mx -all', this would be * interpreted as 'v=spf1 +a +mx +localpolicy -all'. Whereas * 'v=spf1 -all' would remain the same (no non-'-' * mechanism). 'v=spf1 +a +mx -exists:%stuff -all' would * become 'v=spf1 +a +mx +localpolicy -exists:%stuff -all'. */ if ( spf_server->local_policy ) { mech = spf_record->mech_first; found_all = FALSE; for(m = 0; m < spf_record->num_mech; m++) { if ( mech->mech_type == MECH_ALL && (mech->prefix_type == PREFIX_FAIL || mech->prefix_type == PREFIX_UNKNOWN || mech->prefix_type == PREFIX_SOFTFAIL ) ) found_all = TRUE; if ( mech->prefix_type != PREFIX_FAIL && mech->prefix_type != PREFIX_SOFTFAIL ) local_policy = mech; mech = SPF_mech_next( mech ); } if ( !found_all ) local_policy = NULL; } } /* * evaluate the mechanisms */ #define SPF_ADD_DNS_MECH() do { spf_response->num_dns_mech++; } while(0) #define SPF_MAYBE_SKIP_CIDR() \ do { \ if ( data < data_end && data->dc.parm_type == PARM_CIDR ) \ data = SPF_data_next( data ); \ } while(0) #define SPF_GET_LOOKUP_DATA() \ do { \ if ( data == data_end ) \ lookup = spf_request->cur_dom; \ else { \ err = SPF_record_expand_data( spf_server, \ spf_request, spf_response, \ data, ((char *)data_end - (char *)data), \ &buf, &buf_len ); \ if (err == SPF_E_NO_MEMORY) { \ SPF_FREE_LOOKUP_DATA(); \ return DONE_TEMPERR(err); \ } \ if (err) { \ SPF_FREE_LOOKUP_DATA(); \ return DONE_PERMERR(err); \ } \ lookup = buf; \ } \ } while(0) #define SPF_FREE_LOOKUP_DATA() \ do { if (buf != NULL) { free(buf); buf = NULL; } } while(0) resolver = spf_server->resolver; mech = spf_record->mech_first; for (m = 0; m < spf_record->num_mech; m++) { /* This is as good a place as any. */ /* XXX Rip this out and put it into a macro which can go into inner loops. */ if (spf_response->num_dns_mech > spf_server->max_dns_mech) { SPF_FREE_LOOKUP_DATA(); return DONE(SPF_RESULT_PERMERROR, SPF_REASON_NONE, SPF_E_BIG_DNS); } data = SPF_mech_data(mech); data_end = SPF_mech_end_data(mech); switch (mech->mech_type) { case MECH_A: SPF_ADD_DNS_MECH(); SPF_MAYBE_SKIP_CIDR(); SPF_GET_LOOKUP_DATA(); if (spf_request->client_ver == AF_INET) fetch_ns_type = ns_t_a; else fetch_ns_type = ns_t_aaaa; rr_a = SPF_dns_lookup(resolver, lookup, fetch_ns_type, TRUE); if (spf_server->debug) SPF_debugf("found %d A records for %s (herrno: %d)", rr_a->num_rr, lookup, rr_a->herrno); if (rr_a->herrno == TRY_AGAIN) { SPF_dns_rr_free(rr_a); SPF_FREE_LOOKUP_DATA(); return DONE_TEMPERR(SPF_E_DNS_ERROR); /* REASON_MECH */ } for (i = 0; i < rr_a->num_rr; i++) { /* XXX Should this be hoisted? */ if (rr_a->rr_type != fetch_ns_type) continue; if (spf_request->client_ver == AF_INET) { if (SPF_i_match_ip4(spf_server, spf_request, mech, rr_a->rr[i]->a)) { SPF_dns_rr_free(rr_a); SPF_FREE_LOOKUP_DATA(); return DONE_MECH(mech->prefix_type); } } else { if (SPF_i_match_ip6(spf_server, spf_request, mech, rr_a->rr[i]->aaaa)) { SPF_dns_rr_free(rr_a); SPF_FREE_LOOKUP_DATA(); return DONE_MECH(mech->prefix_type); } } } SPF_dns_rr_free(rr_a); break; case MECH_MX: SPF_ADD_DNS_MECH(); SPF_MAYBE_SKIP_CIDR(); SPF_GET_LOOKUP_DATA(); rr_mx = SPF_dns_lookup(resolver, lookup, ns_t_mx, TRUE); if (spf_server->debug) SPF_debugf("found %d MX records for %s (herrno: %d)", rr_mx->num_rr, lookup, rr_mx->herrno); if (rr_mx->herrno == TRY_AGAIN) { SPF_dns_rr_free(rr_mx); SPF_FREE_LOOKUP_DATA(); return DONE_TEMPERR(SPF_E_DNS_ERROR); } /* The maximum number of MX records we will inspect. */ max_mx = rr_mx->num_rr; max_exceeded = 0; if (max_mx > spf_server->max_dns_mx) { max_exceeded = 1; max_mx = SPF_server_get_max_dns_mx(spf_server); } for (j = 0; j < max_mx; j++) { /* XXX Should this be hoisted? */ if (rr_mx->rr_type != ns_t_mx) continue; if (spf_request->client_ver == AF_INET) fetch_ns_type = ns_t_a; else fetch_ns_type = ns_t_aaaa; rr_a = SPF_dns_lookup(resolver, rr_mx->rr[j]->mx, fetch_ns_type, TRUE ); if (spf_server->debug) SPF_debugf("%d: found %d A records for %s (herrno: %d)", j, rr_a->num_rr, rr_mx->rr[j]->mx, rr_a->herrno); if (rr_a->herrno == TRY_AGAIN) { SPF_dns_rr_free(rr_mx); SPF_dns_rr_free(rr_a); SPF_FREE_LOOKUP_DATA(); return DONE_TEMPERR(SPF_E_DNS_ERROR); } for (i = 0; i < rr_a->num_rr; i++) { /* XXX Should this be hoisted? */ if (rr_a->rr_type != fetch_ns_type) continue; if (spf_request->client_ver == AF_INET) { if (SPF_i_match_ip4(spf_server, spf_request, mech, rr_a->rr[i]->a)) { SPF_dns_rr_free(rr_mx); SPF_dns_rr_free(rr_a); SPF_FREE_LOOKUP_DATA(); return DONE(mech->prefix_type, SPF_REASON_MECH, SPF_E_SUCCESS); } } else { if (SPF_i_match_ip6(spf_server, spf_request, mech, rr_a->rr[i]->aaaa)) { SPF_dns_rr_free(rr_mx); SPF_dns_rr_free(rr_a); SPF_FREE_LOOKUP_DATA(); return DONE(mech->prefix_type, SPF_REASON_MECH, SPF_E_SUCCESS); } } } SPF_dns_rr_free(rr_a); } SPF_dns_rr_free( rr_mx ); if (max_exceeded) { SPF_FREE_LOOKUP_DATA(); return DONE(SPF_RESULT_PERMERROR, SPF_REASON_NONE, SPF_E_BIG_DNS); } break; case MECH_PTR: SPF_ADD_DNS_MECH(); SPF_GET_LOOKUP_DATA(); if (spf_request->client_ver == AF_INET) { rr_ptr = SPF_dns_rlookup(resolver, spf_request->ipv4, ns_t_ptr, TRUE); if (spf_server->debug) { INET_NTOP(AF_INET, &spf_request->ipv4.s_addr, ip4_buf, sizeof(ip4_buf)); SPF_debugf("got %d PTR records for %s (herrno: %d)", rr_ptr->num_rr, ip4_buf, rr_ptr->herrno); } if (rr_ptr->herrno == TRY_AGAIN) { SPF_dns_rr_free(rr_ptr); SPF_FREE_LOOKUP_DATA(); return DONE_TEMPERR(SPF_E_DNS_ERROR); } /* The maximum number of PTR records we will inspect. */ max_ptr = rr_ptr->num_rr; max_exceeded = 0; if (max_ptr > spf_server->max_dns_ptr) { max_exceeded = 1; max_ptr = SPF_server_get_max_dns_ptr(spf_server); } for (i = 0; i < max_ptr; i++) { /* XXX MX has a 'continue' case here which should be hoisted. */ rr_a = SPF_dns_lookup(resolver, rr_ptr->rr[i]->ptr, ns_t_a, TRUE); if (spf_server->debug) SPF_debugf( "%d: found %d A records for %s (herrno: %d)", i, rr_a->num_rr, rr_ptr->rr[i]->ptr, rr_a->herrno ); if (rr_a->herrno == TRY_AGAIN) { SPF_dns_rr_free(rr_ptr); SPF_dns_rr_free(rr_a); SPF_FREE_LOOKUP_DATA(); return DONE_TEMPERR( SPF_E_DNS_ERROR ); } for (j = 0; j < rr_a->num_rr; j++) { /* XXX MX has a 'continue' case here which should be hoisted. */ if (spf_server->debug) { INET_NTOP(AF_INET, &rr_a->rr[j]->a.s_addr, ip4_buf, sizeof(ip4_buf)); SPF_debugf("%d: %d: found %s", i, j, ip4_buf); } if (rr_a->rr[j]->a.s_addr == spf_request->ipv4.s_addr) { if (SPF_i_match_domain(spf_server, rr_ptr->rr[i]->ptr, lookup)) { SPF_dns_rr_free(rr_ptr); SPF_dns_rr_free(rr_a); SPF_FREE_LOOKUP_DATA(); return DONE_MECH(mech->prefix_type); } } } SPF_dns_rr_free(rr_a); } SPF_dns_rr_free(rr_ptr); if (max_exceeded) { SPF_FREE_LOOKUP_DATA(); return DONE(SPF_RESULT_PERMERROR, SPF_REASON_NONE, SPF_E_BIG_DNS); } } else if ( spf_request->client_ver == AF_INET6 ) { rr_ptr = SPF_dns_rlookup6(resolver, spf_request->ipv6, ns_t_ptr, TRUE); if ( spf_server->debug ) { INET_NTOP( AF_INET6, &spf_request->ipv6.s6_addr, ip6_buf, sizeof( ip6_buf ) ); SPF_debugf( "found %d PTR records for %s (herrno: %d)", rr_ptr->num_rr, ip6_buf, rr_ptr->herrno ); } if( rr_ptr->herrno == TRY_AGAIN ) { SPF_dns_rr_free(rr_ptr); SPF_FREE_LOOKUP_DATA(); return DONE_TEMPERR( SPF_E_DNS_ERROR ); } max_ptr = rr_ptr->num_rr; max_exceeded = 0; if (max_ptr > spf_server->max_dns_ptr) { max_ptr = SPF_server_get_max_dns_ptr(spf_server); max_exceeded = 1; } for (i = 0; i < max_ptr; i++) { /* XXX MX has a 'continue' case here which should be hoisted. */ rr_aaaa = SPF_dns_lookup(resolver, rr_ptr->rr[i]->ptr, ns_t_aaaa, TRUE); if ( spf_server->debug ) SPF_debugf("%d: found %d AAAA records for %s (herrno: %d)", i, rr_aaaa->num_rr, rr_ptr->rr[i]->ptr, rr_aaaa->herrno); if( rr_aaaa->herrno == TRY_AGAIN ) { SPF_dns_rr_free(rr_ptr); SPF_dns_rr_free(rr_aaaa); SPF_FREE_LOOKUP_DATA(); return DONE_TEMPERR( SPF_E_DNS_ERROR ); } for( j = 0; j < rr_aaaa->num_rr; j++ ) { /* XXX MX has a 'continue' case here which should be hoisted. */ if ( spf_server->debug ) { INET_NTOP(AF_INET6, &rr_aaaa->rr[j]->aaaa.s6_addr, ip6_buf, sizeof(ip6_buf)); SPF_debugf( "%d: %d: found %s", i, j, ip6_buf ); } if (memcmp(&rr_aaaa->rr[j]->aaaa, &spf_request->ipv6, sizeof(spf_request->ipv6)) == 0) { if (SPF_i_match_domain(spf_server, rr_ptr->rr[i]->ptr, lookup)) { SPF_dns_rr_free( rr_ptr ); SPF_dns_rr_free(rr_aaaa); SPF_FREE_LOOKUP_DATA(); return DONE_MECH( mech->prefix_type ); } } } SPF_dns_rr_free(rr_aaaa); } SPF_dns_rr_free(rr_ptr); if (max_exceeded) { SPF_FREE_LOOKUP_DATA(); return DONE(SPF_RESULT_PERMERROR, SPF_REASON_NONE, SPF_E_BIG_DNS); } } break; case MECH_INCLUDE: case MECH_REDIRECT: SPF_ADD_DNS_MECH(); err = SPF_record_expand_data(spf_server, spf_request, spf_response, SPF_mech_data(mech), SPF_mech_data_len(mech), &buf, &buf_len ); if ( err == SPF_E_NO_MEMORY ) { SPF_FREE_LOOKUP_DATA(); return DONE_TEMPERR( err ); } if ( err ) { SPF_FREE_LOOKUP_DATA(); return DONE_PERMERR( err ); } lookup = buf; /* XXX Maintain a stack depth here. Limit at 10. */ if (strcmp(lookup, spf_request->cur_dom) == 0) { SPF_FREE_LOOKUP_DATA(); return DONE_PERMERR( SPF_E_RECURSIVE ); } /* * get the (compiled) SPF record */ spf_record_subr = NULL; /* Remember to reset this. */ save_cur_dom = spf_request->cur_dom; spf_request->cur_dom = lookup; err = SPF_server_get_record(spf_server, spf_request, spf_response, &spf_record_subr); if ( spf_server->debug > 0 ) SPF_debugf( "include/redirect: got SPF record: %s", SPF_strerror( err ) ); if (err != SPF_E_SUCCESS) { spf_request->cur_dom = save_cur_dom; if (spf_record_subr) SPF_record_free(spf_record_subr); SPF_FREE_LOOKUP_DATA(); if (err == SPF_E_DNS_ERROR) return DONE_TEMPERR( err ); else return DONE_PERMERR( err ); } SPF_ASSERT_NOTNULL(spf_record_subr); /* * If we are a redirect which is not within the scope * of any include. */ if (mech->mech_type == MECH_REDIRECT) { save_spf_response = NULL; if (spf_response->spf_record_exp == spf_record) spf_response->spf_record_exp = spf_record_subr; SPF_ASSERT_NOTNULL(spf_response->spf_record_exp); } else { save_spf_response = spf_response; spf_response = SPF_response_new(spf_request); if (! spf_response) { if (spf_record_subr) SPF_record_free(spf_record_subr); SPF_FREE_LOOKUP_DATA(); return DONE_TEMPERR(SPF_E_NO_MEMORY); } spf_response->spf_record_exp = spf_record; SPF_ASSERT_NOTNULL(spf_response->spf_record_exp); } /* * find out whether this configuration passes */ err = SPF_record_interpret(spf_record_subr, spf_request, spf_response, depth + 1); spf_request->cur_dom = save_cur_dom; /* Now, if we were a redirect, the child called done() * and used spf_record_exp. In that case, we need not * worry that spf_record_subr is invalid after the free. * If we were not a redirect, then spf_record_subr * is still the record it was in the first place. * Thus we do not need to reset it now. */ SPF_record_free(spf_record_subr); spf_record_subr = NULL; if ( spf_server->debug > 0 ) SPF_debugf( "include/redirect: executed SPF record: %s result: %s reason: %s", SPF_strerror( err ), SPF_strresult( spf_response->result ), SPF_strreason( spf_response->reason ) ); if (mech->mech_type == MECH_REDIRECT) { SPF_FREE_LOOKUP_DATA(); return err; /* One way or the other */ } else { // if (spf_response->result != SPF_RESULT_INVALID) { /* Set everything up properly again. */ spf_response_subr = spf_response; spf_response = save_spf_response; save_spf_response = NULL; /* Rewrite according to prefix of include */ switch (SPF_response_result(spf_response_subr)) { case SPF_RESULT_PASS: /* Pass */ SPF_FREE_LOOKUP_DATA(); SPF_response_free(spf_response_subr); return DONE_MECH( mech->prefix_type ); case SPF_RESULT_FAIL: case SPF_RESULT_SOFTFAIL: case SPF_RESULT_NEUTRAL: /* No match */ SPF_response_free(spf_response_subr); break; case SPF_RESULT_TEMPERROR: /* Generate TempError */ err = SPF_response_errcode(spf_response_subr); SPF_FREE_LOOKUP_DATA(); SPF_response_free(spf_response_subr); return DONE_TEMPERR( err ); case SPF_RESULT_NONE: /* Generate PermError */ SPF_FREE_LOOKUP_DATA(); SPF_response_free(spf_response_subr); return DONE_PERMERR(SPF_E_INCLUDE_RETURNED_NONE); case SPF_RESULT_PERMERROR: case SPF_RESULT_INVALID: /* Generate PermError */ err = SPF_response_errcode(spf_response_subr); SPF_FREE_LOOKUP_DATA(); SPF_response_free(spf_response_subr); return DONE_PERMERR( err ); } #if 0 SPF_FREE_LOOKUP_DATA(); return err; /* The sub-interpret called done() */ #endif } break; case MECH_IP4: memcpy(&addr4, SPF_mech_ip4_data(mech), sizeof(addr4)); if ( SPF_i_match_ip4( spf_server, spf_request, mech, addr4 ) ) { SPF_FREE_LOOKUP_DATA(); return DONE_MECH( mech->prefix_type ); } break; case MECH_IP6: memcpy(&addr6, SPF_mech_ip6_data(mech), sizeof(addr6)); if ( SPF_i_match_ip6( spf_server, spf_request, mech, addr6 ) ) { SPF_FREE_LOOKUP_DATA(); return DONE_MECH( mech->prefix_type ); } break; case MECH_EXISTS: SPF_ADD_DNS_MECH(); err = SPF_record_expand_data(spf_server, spf_request, spf_response, SPF_mech_data(mech),SPF_mech_data_len(mech), &buf, &buf_len); if (err != SPF_E_SUCCESS) { SPF_FREE_LOOKUP_DATA(); return DONE_TEMPERR( err ); } lookup = buf; rr_a = SPF_dns_lookup(resolver, lookup, ns_t_a, FALSE ); if ( spf_server->debug ) SPF_debugf( "found %d A records for %s (herrno: %d)", rr_a->num_rr, lookup, rr_a->herrno ); if( rr_a->herrno == TRY_AGAIN ) { SPF_dns_rr_free(rr_a); SPF_FREE_LOOKUP_DATA(); return DONE_TEMPERR(SPF_E_DNS_ERROR); } if ( rr_a->num_rr > 0 ) { SPF_dns_rr_free(rr_a); SPF_FREE_LOOKUP_DATA(); return DONE_MECH(mech->prefix_type); } SPF_dns_rr_free(rr_a); break; case MECH_ALL: SPF_FREE_LOOKUP_DATA(); if (mech->prefix_type == PREFIX_UNKNOWN) return DONE_PERMERR(SPF_E_UNKNOWN_MECH); return DONE_MECH(mech->prefix_type); break; default: SPF_FREE_LOOKUP_DATA(); return DONE_PERMERR(SPF_E_UNKNOWN_MECH); break; } /* * execute the local policy */ if ( mech == local_policy ) { err = SPF_record_interpret(spf_server->local_policy, spf_request, spf_response, depth + 1); if ( spf_server->debug > 0 ) SPF_debugf( "local_policy: executed SPF record: %s result: %s reason: %s", SPF_strerror( err ), SPF_strresult( spf_response->result ), SPF_strreason( spf_response->reason ) ); if (spf_response->result != SPF_RESULT_INVALID) { SPF_FREE_LOOKUP_DATA(); return err; } } mech = SPF_mech_next( mech ); } SPF_FREE_LOOKUP_DATA(); /* falling off the end is the same as ?all */ return DONE( SPF_RESULT_NEUTRAL, SPF_REASON_DEFAULT, SPF_E_SUCCESS ); }
static void print_addrinfo(int type, void *ainfo) { struct sockaddr_in *s_inaddr = NULL; struct sockaddr_in6 *s_in6addr = NULL; struct addrinfo *a = (struct addrinfo *) ainfo; char buf[INET6_ADDRSTRLEN]; size_t buflen = INET6_ADDRSTRLEN; while (a != NULL) { printf("{\n"); printf("\tFlags: %d [", a->ai_flags); if (a->ai_flags & AI_PASSIVE) printf("AI_PASSIVE "); if (a->ai_flags & AI_CANONNAME) printf("AI_CANONNAME "); if (a->ai_flags & AI_NUMERICHOST) printf("AI_NUMERICHOST "); #ifdef AI_V4MAPPED if (a->ai_flags & AI_V4MAPPED) printf("AI_V4MAPPED "); #endif #ifdef AI_ALL if (a->ai_flags & AI_ALL) printf("AI_ALL "); #endif #ifdef AI_ADDRCONFIG if (a->ai_flags & AI_ADDRCONFIG) printf("AI_ADDRCONFIG "); #endif // if (a->ai_flags & AI_NUMERICSERV) printf("AI_NUMERICSERV "); printf("]\n"); printf("\tFamily: %d [%s]\n", a->ai_family, (a->ai_family == AF_UNSPEC) ? "AF_UNSPEC" : (a->ai_family == AF_INET) ? "AF_INET" : (a->ai_family == AF_INET6) ? "AF_INET6" : "Unknown"); printf("\tSockType: %d [%s]\n", a->ai_socktype, (a->ai_socktype == SOCK_STREAM) ? "SOCK_STREAM" : (a->ai_socktype == SOCK_DGRAM) ? "SOCK_DGRAM" : (a->ai_socktype == SOCK_RAW) ? "SOCK_RAW" : "Unknown"); printf("\tProtocol: %d [%s]\n", a->ai_protocol, (a->ai_protocol == IPPROTO_IP) ? "IPPROTO_IP" : (a->ai_protocol == IPPROTO_TCP) ? "IPPROTO_TCP" : (a->ai_protocol == IPPROTO_UDP) ? "IPPROTO_UDP" : "Unknown"); printf("\tAddrLen: %d\n", a->ai_addrlen); if (a->ai_addr != NULL) { const char *addr = NULL; printf("\tAddrPtr: %p\n", a->ai_addr); if (a->ai_family == AF_INET) { s_inaddr = (struct sockaddr_in *) (a->ai_addr); INET_NTOP(AF_INET, ((struct sockaddr *)s_inaddr), sizeof(s_inaddr), buf, buflen, addr); printf("\tAddr: %s\n", addr); } else if (a->ai_family == AF_INET6) { s_in6addr = (struct sockaddr_in6 *) (a->ai_addr); INET_NTOP(AF_INET6, ((struct sockaddr *)s_in6addr), sizeof(s_in6addr), buf, buflen, addr); printf("\tAddr: %s\n", addr); } else printf ("\tAddr: Cannot parse address. Unknown protocol family\n"); } else printf("\tAddr: (null)\n"); if (a->ai_canonname) printf("\tCanonName: %s\n", a->ai_canonname); else printf("\tCanonName: (null)\n"); printf("}\n"); a = (struct addrinfo *) (a->ai_next); } }
/* * Function: get_hostent_from_etc_hosts * * Purpose: Read the ETC_HOSTS file and check if it contains the given name. * Return the result in a hostent structure. * * Parameters: * ctx -- The validation context. * name -- The domain name or IP address in string form. * af -- The address family: AF_INET or AF_INET6. * ret -- Pointer to a hostent structure to return the result. * This parameter must not be NULL. * buf -- A buffer to store auxiliary data. This parameter must not be NULL. * buflen -- Length of the buffer 'buf'. * offset -- Pointer to an integer variable that contains the offset in the buffer * 'buf', where data can be written. When this function writes any data * in the auxiliary data, the offset is incremented accordingly. This * parameter must not be NULL. * * Return value: Returns NULL on failure and 'ret' on success. * * See also: get_hostent_from_response() */ static struct hostent * get_hostent_from_etc_hosts(val_context_t * ctx, const char *name, int af, struct hostent *ret, char *buf, int buflen, int *offset) { int orig_offset = 0; struct hosts *hs = NULL; struct hosts *h_prev = NULL; if ((ret == NULL) || (buf == NULL) || (offset == NULL) || (*offset < 0)) { return NULL; } /* * Parse the /etc/hosts file */ hs = parse_etc_hosts(name); orig_offset = *offset; memset(ret, 0, sizeof(struct hostent)); /* * XXX: todo -- can hs have more than one element ? */ while (hs) { struct sockaddr_in sa; #if defined( WIN32 ) size_t addrlen4 = sizeof(struct sockaddr_in); #endif #ifdef VAL_IPV6 struct sockaddr_in6 sa6; #if defined( WIN32 ) size_t addrlen6 = sizeof(struct sockaddr_in6); #endif #endif char addr_buf[INET6_ADDRSTRLEN]; int i, alias_count; int len = 0; const char *addr = NULL; size_t buflen = INET6_ADDRSTRLEN; if ((af == AF_INET) && (INET_PTON(AF_INET, hs->address, ((struct sockaddr *)&sa), &addrlen4) > 0)) { INET_NTOP(AF_INET, (&sa), sizeof(sa), addr_buf, buflen, addr); val_log(ctx, LOG_DEBUG, "get_hostent_from_etc_hosts(): type of address is IPv4"); val_log(ctx, LOG_DEBUG, "get_hostent_from_etc_hosts(): Address is: %s", addr ); } #ifdef VAL_IPV6 else if ((af == AF_INET6) && (INET_PTON(AF_INET6, hs->address, ((struct sockaddr *)&sa6), &addrlen6) > 0)) { INET_NTOP(AF_INET6, (&sa6), sizeof(sa6), addr_buf, buflen, addr); val_log(ctx, LOG_DEBUG, "get_hostent_from_etc_hosts(): type of address is IPv6"); val_log(ctx, LOG_DEBUG, "get_hostent_from_etc_hosts(): Address is: %s", addr ); } #endif else { /* * not a valid address ... skip this line */ val_log(ctx, LOG_WARNING, "get_hostent_from_etc_hosts(): error in address format: %s", hs->address); h_prev = hs; hs = hs->next; FREE_HOSTS(h_prev); continue; } // Name len = (hs->canonical_hostname == NULL) ? 0 : strlen(hs->canonical_hostname); if (hs->canonical_hostname) { ret->h_name = (char *) bufalloc(buf, buflen, offset, len + 1); if (ret->h_name == NULL) { goto err; } memcpy(ret->h_name, hs->canonical_hostname, len + 1); } else { ret->h_name = NULL; } // Aliases alias_count = 0; while (hs->aliases[alias_count]) { alias_count++; } alias_count++; ret->h_aliases = (char **) bufalloc(buf, buflen, offset, alias_count * sizeof(char *)); if (ret->h_aliases == NULL) { goto err; } for (i = 0; i < alias_count; i++) { len = (hs->aliases[i] == NULL) ? 0 : strlen(hs->aliases[i]); if (hs->aliases[i]) { ret->h_aliases[i] = (char *) bufalloc(buf, buflen, offset, len + 1); if (ret->h_aliases[i] == NULL) { goto err; } memcpy(ret->h_aliases[i], hs->aliases[i], len + 1); } else { ret->h_aliases[i] = NULL; } } // Addresses ret->h_addr_list = (char **) bufalloc(buf, buflen, offset, 2 * sizeof(char *)); if ((ret->h_addr_list == NULL) || ((af != AF_INET) && (af != AF_INET6))) { goto err; } if (af == AF_INET) { ret->h_addrtype = AF_INET; ret->h_length = sizeof(struct in_addr); ret->h_addr_list[0] = (char *) bufalloc(buf, buflen, offset, sizeof(struct in_addr)); if (ret->h_addr_list[0] == NULL) { goto err; } memcpy(ret->h_addr_list[0], &sa.sin_addr, sizeof(struct in_addr)); ret->h_addr_list[1] = 0; } #ifdef VAL_IPV6 else if (af == AF_INET6) { ret->h_addrtype = AF_INET6; ret->h_length = sizeof(struct in6_addr); ret->h_addr_list[0] = (char *) bufalloc(buf, buflen, offset, sizeof(struct in6_addr)); if (ret->h_addr_list[0] == NULL) { goto err; } memcpy(ret->h_addr_list[0], &sa6.sin6_addr, sizeof(struct in6_addr)); ret->h_addr_list[1] = 0; } #endif /* * clean up host list */ while (hs) { h_prev = hs; hs = hs->next; FREE_HOSTS(h_prev); } return ret; } return NULL; err: /* * clean up host list */ while (hs) { h_prev = hs; hs = hs->next; FREE_HOSTS(h_prev); } *offset = orig_offset; return NULL; } /* get_hostent_from_etc_hosts() */
int main(int argc, char *argv[]) { const char *allowed_args = "hl:x:p:o:sv:i:r:V"; char *node = NULL; int retval; int async = 1; val_log_t *logp; char *label_str = NULL; struct val_daneparams daneparams; struct val_danestatus *danestatus = NULL; struct val_ssl_data *ssl_dane_data = NULL; int port = 443; int proto = DANE_PARAM_PROTO_TCP; val_context_t *context = NULL; val_status_t val_status; struct addrinfo *val_ainfo = NULL; struct addrinfo hints; int ret = 0; int dane_retval = VAL_DANE_INTERNAL_ERROR; int ai_retval = 0; int err; /* Parse the command line */ while (1) { int c; #ifdef HAVE_GETOPT_LONG int opt_index = 0; #ifdef HAVE_GETOPT_LONG_ONLY c = getopt_long_only(argc, argv, allowed_args, prog_options, &opt_index); #else c = getopt_long(argc, argv, allowed_args, prog_options, &opt_index); #endif #else /* only have getopt */ c = getopt(argc, argv, allowed_args); #endif if (c == -1) { break; } switch (c) { case 'h': usage(argv[0]); return -1; case 'l': label_str = optarg; break; case 'o': logp = val_log_add_optarg(optarg, 1); if (NULL == logp) { /* err msg already logged */ usage(argv[0]); return -1; } break; case 's': async = 0; break; case 'p': port = atoi(optarg); break; case 'x': if(strncmp(optarg, DANE_PARAM_PROTO_STR_TCP, strlen(DANE_PARAM_PROTO_STR_TCP))) proto = DANE_PARAM_PROTO_TCP; else if (strncmp(optarg, DANE_PARAM_PROTO_STR_UDP, strlen(DANE_PARAM_PROTO_STR_UDP))) proto = DANE_PARAM_PROTO_UDP; else if (strncmp(optarg, DANE_PARAM_PROTO_STR_SCTP, strlen(DANE_PARAM_PROTO_STR_SCTP))) proto = DANE_PARAM_PROTO_SCTP; else { usage(argv[0]); return -1; } break; case 'v': dnsval_conf_set(optarg); break; case 'i': root_hints_set(optarg); break; case 'r': resolv_conf_set(optarg); break; case 'V': version(); return 0; default: fprintf(stderr, "Invalid option %s\n", argv[optind - 1]); usage(argv[0]); return -1; } } if (optind < argc) { node = argv[optind++]; } else { fprintf(stderr, "Error: node name not specified\n"); usage(argv[0]); return -1; } if (VAL_NO_ERROR != (retval = val_create_context(label_str, &context))) { fprintf(stderr, "Cannot create context %s(%d)\n", p_val_error(retval), retval); return -1; } daneparams.port = port; daneparams.proto = proto; memset(&hints, 0, sizeof(struct addrinfo)); #ifdef AI_ADDRCONFIG hints.ai_flags = AI_ADDRCONFIG; #endif if (!async) { /* synchronous lookup and validation */ ai_retval = val_getaddrinfo(context, node, NULL, &hints, &val_ainfo, &val_status); dane_retval = val_getdaneinfo(context, node, &daneparams, &danestatus); } else { #ifdef VAL_NO_ASYNC fprintf(stderr, "async support not available\n"); #else struct dane_cb cb_data_dane = { &dane_retval, &danestatus, 0 }; val_dane_callback my_dane_cb = &_danecallback; struct timeval tv; val_async_status *das = NULL; /* helps us cancel the lookup if we need to */ struct getaddr_s cb_data_ai = { &ai_retval, &val_ainfo, &val_status, 0 }; val_gai_callback my_ai_cb = &_aicallback; val_gai_status *status = NULL; /* * submit requests */ if (VAL_NO_ERROR != val_dane_submit(context, node, &daneparams, my_dane_cb, &cb_data_dane, &das) || VAL_NO_ERROR != val_getaddrinfo_submit(context, node, NULL, &hints, my_ai_cb, &cb_data_ai, 0, &status)) { dane_retval = VAL_DANE_INTERNAL_ERROR; goto done; } /* * wait for it to complete */ #if 0 while(0 == cb_data_dane.done || 0 == cb_data_ai.done) { tv.tv_sec = 10; tv.tv_usec = 0; val_async_check_wait(context, NULL, NULL, &tv, 0); } #endif #if 1 while(0 == cb_data_dane.done || 0 == cb_data_ai.done) { fd_set activefds; int nfds = 0; int ready; FD_ZERO(&activefds); tv.tv_sec = 10; /* 10 sec */ tv.tv_usec = 0; val_async_select_info(context, &activefds, &nfds, &tv); ready = select(nfds+1, &activefds, NULL, NULL, &tv); if (ready < 0) { continue; } val_async_check(context, &activefds, &nfds, 0); } #endif #endif } done: if (ai_retval != 0) { fprintf(stderr, "Error in val_getaddrinfo(): %d\n", ai_retval); return -1; } if (!val_istrusted(val_status)) { fprintf(stderr, "Address lookup information could not be validated: %s\n", p_val_status(val_status)); } else if(dane_retval == VAL_DANE_NOERROR && proto == DANE_PARAM_PROTO_TCP) { /* Set up the SSL connection */ SSL_library_init(); SSL_load_error_strings(); const SSL_METHOD *meth = SSLv23_client_method(); SSL_CTX *sslctx = SSL_CTX_new(meth); struct addrinfo *ai = NULL; int presetup_okay; /* * OpenSSL only does protocol negotiation on SSLv23_client_method; * we need to set SNI to get the correct certificate from many * modern browsers, so we disable both SSLv2 and SSLv3 if we can. * That leaves (currently) TLSv1.0 TLSv1.1 TLSv1.2 */ long ssl_options = 0 #ifdef SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv2 #endif #ifdef SSL_OP_NO_SSLv3 | SSL_OP_NO_SSLv3 #endif ; if (!SSL_CTX_set_options(sslctx, ssl_options)) { fprintf(stderr, "Failed to set SSL context options (%ld): %s\n", ssl_options, ssl_error()); presetup_okay = 0; } else { presetup_okay = 1; } if (VAL_NO_ERROR != (err = val_enable_dane_ssl(context, sslctx, node, danestatus, &ssl_dane_data))) { fprintf(stderr, "Could not set danestatus for SSL connection %s\n", p_val_error(err)); } ai = val_ainfo; while(presetup_okay && ai && (ai->ai_protocol == IPPROTO_TCP) && (ai->ai_family == AF_INET || ai->ai_family == AF_INET6)) { int sock; char buf[INET6_ADDRSTRLEN]; size_t buflen = sizeof(buf); const char *addr = NULL; if (ai->ai_family == AF_INET) { sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); ((struct sockaddr_in *)(ai)->ai_addr)->sin_port = htons(port); } else { sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); ((struct sockaddr_in6 *)(ai)->ai_addr)->sin6_port = htons(port); } INET_NTOP(ai->ai_family, ai->ai_addr, sizeof(ai->ai_addr), buf, buflen, addr); fprintf(stderr, "Connecting to %s\n", addr); if (0 == connect(sock, ai->ai_addr, ai->ai_addrlen)) { SSL *ssl = SSL_new(sslctx); BIO * sbio = BIO_new_socket(sock,BIO_NOCLOSE); #if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT) SSL_set_tlsext_host_name(ssl, node); #endif SSL_set_bio(ssl,sbio,sbio); if ((err = SSL_connect(ssl)) != 1) { fprintf(stderr, "SSL Connect to %s failed: %d\n", node, err); } SSL_shutdown(ssl); SSL_free(ssl); } else { fprintf(stderr, "TCP Connect to %s failed\n", node); } ai = (struct addrinfo *) (ai->ai_next); } } else if (dane_retval == VAL_DANE_IGNORE_TLSA) { fprintf(stderr, "TLSA is either provably non-existant or provably insecure. It will be ignored.\n"); } else { fprintf(stderr, "TLSA record could not be validated.\n"); ret = 1; } if (danestatus != NULL) val_free_dane(danestatus); if (val_ainfo != NULL) val_freeaddrinfo(val_ainfo); val_free_dane_ssl(ssl_dane_data);/* MUST happen before we free the context*/ val_free_context(context); val_free_validator_state(); return ret; }