From: Jeremy Harris Date: Sun, 27 Oct 2019 20:44:20 +0000 (+0000) Subject: DNS: tag res_search() hack by lookup type in debug output; munge ipv6 lines in testsuite X-Git-Url: https://git.exim.org/users/heiko/exim.git/commitdiff_plain/a713f76692228165883d92875fbad3bfb89c001e DNS: tag res_search() hack by lookup type in debug output; munge ipv6 lines in testsuite --- diff --git a/src/src/dns.c b/src/src/dns.c index 28bc5958d..7736a2204 100644 --- a/src/src/dns.c +++ b/src/src/dns.c @@ -693,7 +693,7 @@ success and packet length return values.) For added safety we only reset the packet length if the packet header looks plausible. */ static void -fake_dnsa_len_for_fail(dns_answer * dnsa) +fake_dnsa_len_for_fail(dns_answer * dnsa, int type) { const HEADER * h = (const HEADER *)dnsa->answer; @@ -706,8 +706,8 @@ if ( h->qr == 1 /* a response */ && ntohs(h->ancount) == 0 /* no answer records */ && ntohs(h->nscount) >= 1) /* authority records */ { - DEBUG(D_dns) debug_printf("faking res_search() response length as %d\n", - (int)sizeof(dnsa->answer)); + DEBUG(D_dns) debug_printf("faking res_search(%s) response length as %d\n", + dns_text_type(type), (int)sizeof(dnsa->answer)); dnsa->answerlen = sizeof(dnsa->answer); } } @@ -719,11 +719,11 @@ bother doing a separate lookup; if not found return a forever TTL. */ time_t -dns_expire_from_soa(dns_answer * dnsa) +dns_expire_from_soa(dns_answer * dnsa, int type) { dns_scan dnss; -fake_dnsa_len_for_fail(dnsa); +fake_dnsa_len_for_fail(dnsa, type); for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_AUTHORITY); rr; rr = dns_next_rr(dnsa, &dnss, RESET_NEXT) @@ -893,7 +893,7 @@ if (dnsa->answerlen < 0) switch (h_errno) case HOST_NOT_FOUND: DEBUG(D_dns) debug_printf("DNS lookup of %s (%s) gave HOST_NOT_FOUND\n" "returning DNS_NOMATCH\n", name, dns_text_type(type)); - return dns_fail_return(name, type, dns_expire_from_soa(dnsa), DNS_NOMATCH); + return dns_fail_return(name, type, dns_expire_from_soa(dnsa, type), DNS_NOMATCH); case TRY_AGAIN: DEBUG(D_dns) debug_printf("DNS lookup of %s (%s) gave TRY_AGAIN\n", @@ -913,7 +913,7 @@ if (dnsa->answerlen < 0) switch (h_errno) } DEBUG(D_dns) debug_printf("%s is in dns_again_means_nonexist: returning " "DNS_NOMATCH\n", name); - return dns_fail_return(name, type, dns_expire_from_soa(dnsa), DNS_NOMATCH); + return dns_fail_return(name, type, dns_expire_from_soa(dnsa, type), DNS_NOMATCH); #else /* For stand-alone tests */ return dns_fail_return(name, type, 0, DNS_AGAIN); @@ -927,7 +927,7 @@ if (dnsa->answerlen < 0) switch (h_errno) case NO_DATA: DEBUG(D_dns) debug_printf("DNS lookup of %s (%s) gave NO_DATA\n" "returning DNS_NODATA\n", name, dns_text_type(type)); - return dns_fail_return(name, type, dns_expire_from_soa(dnsa), DNS_NODATA); + return dns_fail_return(name, type, dns_expire_from_soa(dnsa, type), DNS_NODATA); default: DEBUG(D_dns) debug_printf("DNS lookup of %s (%s) gave unknown DNS error %d\n" @@ -1200,7 +1200,7 @@ switch (type) if (rc == DNS_NOMATCH) { - fake_dnsa_len_for_fail(dnsa); + fake_dnsa_len_for_fail(dnsa, T_CSA); for (rr = dns_next_rr(dnsa, &dnss, RESET_AUTHORITY); rr; rr = dns_next_rr(dnsa, &dnss, RESET_NEXT) diff --git a/src/src/functions.h b/src/src/functions.h index 3b3a12b18..35f8b6c83 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -198,7 +198,7 @@ extern BOOL dkim_transport_write_message(transport_ctx *, extern dns_address *dns_address_from_rr(dns_answer *, dns_record *); extern int dns_basic_lookup(dns_answer *, const uschar *, int); extern void dns_build_reverse(const uschar *, uschar *); -extern time_t dns_expire_from_soa(dns_answer *); +extern time_t dns_expire_from_soa(dns_answer *, int); extern void dns_init(BOOL, BOOL, BOOL); extern BOOL dns_is_aa(const dns_answer *); extern BOOL dns_is_secure(const dns_answer *); diff --git a/src/src/verify.c b/src/src/verify.c index 384739b2b..fc8cd84ea 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -3478,7 +3478,7 @@ else dns_basic_lookup(), we have a dnslist cache entry allocated and tree-inserted. So we may as well use it. */ - time_t soa_negttl = dns_expire_from_soa(dnsa); + time_t soa_negttl = dns_expire_from_soa(dnsa, T_A); cb->expiry = soa_negttl ? soa_negttl : time(NULL) + ttl; break; } diff --git a/test/runtest b/test/runtest index db855baf9..13070647f 100755 --- a/test/runtest +++ b/test/runtest @@ -1099,6 +1099,7 @@ RESET_AFTER_EXTRA_LINE_READ: next if /DNS lookup of \S+ \(AAAA\) using fakens/; next if / in dns_ipv4_lookup?/; next if / writing neg-cache entry for .*AAAA/; + next if /^faking res_search\(AAAA\) response length as 65535/; if (/DNS lookup of \S+ \(AAAA\) gave NO_DATA/) { diff --git a/test/stderr/0002 b/test/stderr/0002 index 3fbb40d2b..8f85e7146 100644 --- a/test/stderr/0002 +++ b/test/stderr/0002 @@ -298,7 +298,6 @@ looking up host name for V4NET.0.0.1 DNS lookup of 1.0.0.V4NET.in-addr.arpa (PTR) using fakens DNS lookup of 1.0.0.V4NET.in-addr.arpa (PTR) succeeded IP address lookup yielded "ten-1.test.ex" -faking res_search() response length as 65535 DNS lookup of ten-1.test.ex (A) using fakens DNS lookup of ten-1.test.ex (A) succeeded ten-1.test.ex V4NET.0.0.1 mx=-1 sort=xx diff --git a/test/stderr/0044 b/test/stderr/0044 index 1dcde9f8e..0de971e4a 100644 --- a/test/stderr/0044 +++ b/test/stderr/0044 @@ -240,9 +240,9 @@ new DNS lookup for 99.99.99.V4NET.rbl.test.ex DNS lookup of 99.99.99.V4NET.rbl.test.ex (A) using fakens DNS lookup of 99.99.99.V4NET.rbl.test.ex (A) gave HOST_NOT_FOUND returning DNS_NOMATCH -faking res_search() response length as 65535 +faking res_search(A) response length as 65535 writing neg-cache entry for 99.99.99.V4NET.rbl.test.ex-A-xxxx, ttl 3000 -faking res_search() response length as 65535 +faking res_search(A) response length as 65535 dnslists: wrote cache entry, ttl=3000 DNS lookup for 99.99.99.V4NET.rbl.test.ex failed => that means V4NET.99.99.99 is not listed at rbl.test.ex diff --git a/test/stderr/0094 b/test/stderr/0094 index d464d0a50..26cf91605 100644 --- a/test/stderr/0094 +++ b/test/stderr/0094 @@ -83,14 +83,12 @@ DNS lookup of 90.99.99.V4NET.in-addr.arpa (PTR) using fakens DNS lookup of 90.99.99.V4NET.in-addr.arpa (PTR) succeeded IP address lookup yielded "oneback.test.ex" alias "host1.masq.test.ex" -faking res_search() response length as 65535 DNS lookup of oneback.test.ex (A) using fakens DNS lookup of oneback.test.ex (A) succeeded oneback.test.ex V4NET.99.99.90 mx=-1 sort=xx checking addresses for oneback.test.ex Forward DNS security status: unverified V4NET.99.99.90 OK -faking res_search() response length as 65535 DNS lookup of host1.masq.test.ex (A) using fakens DNS lookup of host1.masq.test.ex (A) succeeded host1.masq.test.ex V4NET.90.90.90 mx=-1 sort=xx diff --git a/test/stderr/0183 b/test/stderr/0183 index 46d536a11..98d82f8e8 100644 --- a/test/stderr/0183 +++ b/test/stderr/0183 @@ -92,7 +92,7 @@ ten-1.test.ex in "*"? yes (matched "*") DNS lookup of ten-1.test.ex (MX) using fakens DNS lookup of ten-1.test.ex (MX) gave NO_DATA returning DNS_NODATA -faking res_search() response length as 65535 +faking res_search(MX) response length as 65535 writing neg-cache entry for ten-1.test.ex-MX-xxxx, ttl 3000 ten-1.test.ex (MX resp) DNSSEC DNS lookup of ten-1.test.ex (A) using fakens @@ -301,7 +301,7 @@ ten-1.test.ex in "*"? yes (matched "*") DNS lookup of ten-1.test.ex (MX) using fakens DNS lookup of ten-1.test.ex (MX) gave NO_DATA returning DNS_NODATA -faking res_search() response length as 65535 +faking res_search(MX) response length as 65535 writing neg-cache entry for ten-1.test.ex-MX-xxxx, ttl 3000 ten-1.test.ex (MX resp) DNSSEC DNS lookup of ten-1.test.ex (A) using fakens @@ -452,7 +452,7 @@ nonexist.test.ex in "*"? yes (matched "*") DNS lookup of nonexist.test.ex (MX) using fakens DNS lookup of nonexist.test.ex (MX) gave HOST_NOT_FOUND returning DNS_NOMATCH -faking res_search() response length as 65535 +faking res_search(MX) response length as 65535 writing neg-cache entry for nonexist.test.ex-MX-xxxx, ttl 3000 lookuphost router declined for userx@nonexist.test.ex "more" is false: skipping remaining routers @@ -512,7 +512,7 @@ ten-1.test.ex in "*"? yes (matched "*") DNS lookup of ten-1.test.ex (MX) using fakens DNS lookup of ten-1.test.ex (MX) gave NO_DATA returning DNS_NODATA -faking res_search() response length as 65535 +faking res_search(MX) response length as 65535 writing neg-cache entry for ten-1.test.ex-MX-xxxx, ttl 3000 ten-1.test.ex (MX resp) DNSSEC DNS lookup of ten-1.test.ex (A) using fakens @@ -557,7 +557,7 @@ nonexist.test.ex in "*"? yes (matched "*") DNS lookup of nonexist.test.ex (A) using fakens DNS lookup of nonexist.test.ex (A) gave HOST_NOT_FOUND returning DNS_NOMATCH -faking res_search() response length as 65535 +faking res_search(A) response length as 65535 writing neg-cache entry for nonexist.test.ex-A-xxxx, ttl 3000 useryz router: defer for usery@nonexist.test.ex message: lookup of host "nonexist.test.ex" failed in useryz router @@ -729,7 +729,7 @@ nonexist.example.com in "*"? yes (matched "*") DNS lookup of nonexist.example.com (MX) using fakens DNS lookup of nonexist.example.com (MX) gave HOST_NOT_FOUND returning DNS_NOMATCH -faking res_search() response length as 65535 +faking res_search(MX) response length as 65535 writing neg-cache entry for nonexist.example.com-MX-xxxx, ttl 2 lookuphost router declined for userx@nonexist.example.com "more" is false: skipping remaining routers @@ -773,7 +773,7 @@ DNS lookup of nonexist.example.com-MX: cached value DNS_NOMATCH past valid time DNS lookup of nonexist.example.com (MX) using fakens DNS lookup of nonexist.example.com (MX) gave HOST_NOT_FOUND returning DNS_NOMATCH -faking res_search() response length as 65535 +faking res_search(MX) response length as 65535 update neg-cache entry for nonexist.example.com-MX-xxxx, ttl 2 delay router declined for userd@nonexist.example.com "more" is false: skipping remaining routers diff --git a/test/stderr/0278 b/test/stderr/0278 index 715ac14b8..834155bf9 100644 --- a/test/stderr/0278 +++ b/test/stderr/0278 @@ -292,14 +292,13 @@ test.ex in "*"? yes (matched "*") DNS lookup of test.ex (MX) using fakens DNS lookup of test.ex (MX) gave NO_DATA returning DNS_NODATA -faking res_search() response length as 65535 +faking res_search(MX) response length as 65535 writing neg-cache entry for test.ex-MX-xxxx, ttl 3000 test.ex (MX resp) DNSSEC -faking res_search() response length as 65535 DNS lookup of test.ex (A) using fakens DNS lookup of test.ex (A) gave NO_DATA returning DNS_NODATA -faking res_search() response length as 65535 +faking res_search(A) response length as 65535 writing neg-cache entry for test.ex-A-xxxx, ttl 3000 r2 router declined for unknown@test.ex --------> r3 router <-------- diff --git a/test/stderr/0361 b/test/stderr/0361 index a8634a3f4..cd96418fe 100644 --- a/test/stderr/0361 +++ b/test/stderr/0361 @@ -100,17 +100,16 @@ recurse.test.ex in "*"? yes (matched "*") DNS lookup of recurse.test.ex (MX) using fakens DNS lookup of recurse.test.ex (MX) gave HOST_NOT_FOUND returning DNS_NOMATCH -faking res_search() response length as 65535 +faking res_search(MX) response length as 65535 writing neg-cache entry for recurse.test.ex-MX-xxxx, ttl 3000 r1 router widened recurse.test.ex to recurse.test.ex.test.ex recurse.test.ex.test.ex in "*"? yes (matched "*") DNS lookup of recurse.test.ex.test.ex (MX) using fakens DNS lookup of recurse.test.ex.test.ex (MX) gave NO_DATA returning DNS_NODATA -faking res_search() response length as 65535 +faking res_search(MX) response length as 65535 writing neg-cache entry for recurse.test.ex.test.ex-MX-xxxx, ttl 3000 recurse.test.ex.test.ex (MX resp) DNSSEC -faking res_search() response length as 65535 DNS lookup of recurse.test.ex.test.ex (A) using fakens DNS lookup of recurse.test.ex.test.ex (A) succeeded fully qualified name = recurse.test.ex.test.ex diff --git a/test/stderr/0381 b/test/stderr/0381 index 9cab0970b..42b52d031 100644 --- a/test/stderr/0381 +++ b/test/stderr/0381 @@ -41,14 +41,12 @@ DNS lookup of 97.99.99.V4NET.in-addr.arpa (PTR) using fakens DNS lookup of 97.99.99.V4NET.in-addr.arpa (PTR) succeeded IP address lookup yielded "x.gov.uk.test.ex" alias "x.co.uk.test.ex" -faking res_search() response length as 65535 DNS lookup of x.gov.uk.test.ex (A) using fakens DNS lookup of x.gov.uk.test.ex (A) succeeded x.gov.uk.test.ex V4NET.99.99.97 mx=-1 sort=xx checking addresses for x.gov.uk.test.ex Forward DNS security status: unverified V4NET.99.99.97 OK -faking res_search() response length as 65535 DNS lookup of x.co.uk.test.ex (A) using fakens DNS lookup of x.co.uk.test.ex (A) succeeded x.co.uk.test.ex V4NET.99.99.97 mx=-1 sort=xx diff --git a/test/stderr/0419 b/test/stderr/0419 index 0671390b9..39c797009 100644 --- a/test/stderr/0419 +++ b/test/stderr/0419 @@ -25,10 +25,8 @@ dnslookup router called for k@mxt13.test.ex mxt13.test.ex in "*"? yes (matched "*") DNS lookup of mxt13.test.ex (MX) using fakens DNS lookup of mxt13.test.ex (MX) succeeded -faking res_search() response length as 65535 DNS lookup of other1.test.ex (A) using fakens DNS lookup of other1.test.ex (A) succeeded -faking res_search() response length as 65535 DNS lookup of other2.test.ex (A) using fakens DNS lookup of other2.test.ex (A) succeeded other1.test.ex in "!mxt13.test.ex : !other1.test.ex : *.test.ex"? no (matched "!other1.test.ex") diff --git a/test/stderr/0463 b/test/stderr/0463 index 5c40269a8..c74dc0349 100644 --- a/test/stderr/0463 +++ b/test/stderr/0463 @@ -19,7 +19,7 @@ checking domains DNS lookup of ten-1 (MX) using fakens DNS lookup of ten-1 (MX) gave NO_DATA returning DNS_NODATA -faking res_search() response length as 65535 +faking res_search(MX) response length as 65535 writing neg-cache entry for ten-1-MX-xxxx, ttl 3000 Address records are not being sought ten-1 in "!@mx_any"? yes (end of list) @@ -30,10 +30,9 @@ ten-1 in "*"? yes (matched "*") DNS lookup of ten-1 (MX) using fakens DNS lookup of ten-1 (MX) gave NO_DATA returning DNS_NODATA -faking res_search() response length as 65535 +faking res_search(MX) response length as 65535 writing neg-cache entry for ten-1-MX-xxxx, ttl 3000 ten-1 (MX resp) DNSSEC -faking res_search() response length as 65535 DNS lookup of ten-1 (A) using fakens DNS lookup of ten-1 (A) succeeded fully qualified name = ten-1.test.ex @@ -51,7 +50,7 @@ checking domains DNS lookup of ten-1.test.ex (MX) using fakens DNS lookup of ten-1.test.ex (MX) gave NO_DATA returning DNS_NODATA -faking res_search() response length as 65535 +faking res_search(MX) response length as 65535 writing neg-cache entry for ten-1.test.ex-MX-xxxx, ttl 3000 Address records are not being sought ten-1.test.ex in "!@mx_any"? yes (end of list) @@ -62,10 +61,9 @@ ten-1.test.ex in "*"? yes (matched "*") DNS lookup of ten-1.test.ex (MX) using fakens DNS lookup of ten-1.test.ex (MX) gave NO_DATA returning DNS_NODATA -faking res_search() response length as 65535 +faking res_search(MX) response length as 65535 writing neg-cache entry for ten-1.test.ex-MX-xxxx, ttl 3000 ten-1.test.ex (MX resp) DNSSEC -faking res_search() response length as 65535 DNS lookup of ten-1.test.ex (A) using fakens DNS lookup of ten-1.test.ex (A) succeeded fully qualified name = ten-1.test.ex diff --git a/test/stderr/0545 b/test/stderr/0545 index a17553ace..f2e5e37b1 100644 --- a/test/stderr/0545 +++ b/test/stderr/0545 @@ -25,7 +25,7 @@ CNAME found: change to eximtesthost.test.ex DNS lookup of eximtesthost.test.ex (MX) using fakens DNS lookup of eximtesthost.test.ex (MX) gave NO_DATA returning DNS_NODATA -faking res_search() response length as 65535 +faking res_search(MX) response length as 65535 writing neg-cache entry for eximtesthost.test.ex-MX-xxxx, ttl 3000 alias-eximtesthost (MX resp) DNSSEC DNS lookup of alias-eximtesthost (A) using fakens @@ -100,7 +100,7 @@ CNAME found: change to eximtesthost.test.ex DNS lookup of eximtesthost.test.ex (MX) using fakens DNS lookup of eximtesthost.test.ex (MX) gave NO_DATA returning DNS_NODATA -faking res_search() response length as 65535 +faking res_search(MX) response length as 65535 writing neg-cache entry for eximtesthost.test.ex-MX-xxxx, ttl 3000 alias-eximtesthost.test.ex (MX resp) DNSSEC DNS lookup of alias-eximtesthost.test.ex (A) using fakens diff --git a/test/stderr/1006 b/test/stderr/1006 index c5dec1804..4c88e098f 100644 --- a/test/stderr/1006 +++ b/test/stderr/1006 @@ -13,13 +13,13 @@ DNS lookup of 46.test.ex (A) succeeded DNS lookup of v6.test.ex (MX) using fakens DNS lookup of v6.test.ex (MX) gave NO_DATA returning DNS_NODATA -faking res_search() response length as 65535 +faking res_search(MX) response length as 65535 writing neg-cache entry for v6.test.ex-MX-xxxx, ttl 3000 DNS lookup of v6.test.ex (AAAA) succeeded DNS lookup of v6.test.ex (A) using fakens DNS lookup of v6.test.ex (A) gave NO_DATA returning DNS_NODATA -faking res_search() response length as 65535 +faking res_search(A) response length as 65535 writing neg-cache entry for v6.test.ex-A-xxxx, ttl 3000 >>>>>>>>>>>>>>>> Exim pid=pppp (main) terminating with rc=0 >>>>>>>>>>>>>>>> Exim version x.yz .... @@ -35,12 +35,12 @@ DNS lookup of 46.test.ex (A) succeeded DNS lookup of v6.test.ex (MX) using fakens DNS lookup of v6.test.ex (MX) gave NO_DATA returning DNS_NODATA -faking res_search() response length as 65535 +faking res_search(MX) response length as 65535 writing neg-cache entry for v6.test.ex-MX-xxxx, ttl 3000 DNS lookup of v6.test.ex (A) using fakens DNS lookup of v6.test.ex (A) gave NO_DATA returning DNS_NODATA -faking res_search() response length as 65535 +faking res_search(A) response length as 65535 writing neg-cache entry for v6.test.ex-A-xxxx, ttl 3000 >>>>>>>>>>>>>>>> Exim pid=pppp (main) terminating with rc=2 >>>>>>>>>>>>>>>> diff --git a/test/stderr/2201 b/test/stderr/2201 index 051836904..23d3d6a5f 100644 --- a/test/stderr/2201 +++ b/test/stderr/2201 @@ -99,7 +99,7 @@ dnsdb key: unknown DNS lookup of unknown (TXT) using fakens DNS lookup of unknown (TXT) gave HOST_NOT_FOUND returning DNS_NOMATCH -faking res_search() response length as 65535 +faking res_search(TXT) response length as 65535 writing neg-cache entry for unknown-TXT-xxxx, ttl 3000 lookup failed unknown in "dnsdb;unknown"? no (end of list) diff --git a/test/stderr/4802 b/test/stderr/4802 index a2510cc3a..9575f881f 100644 --- a/test/stderr/4802 +++ b/test/stderr/4802 @@ -4,7 +4,6 @@ admin user dropping to exim gid; retaining priv uid DNS lookup of mx-sec-a-aa.test.ex (MX) using fakens DNS lookup of mx-sec-a-aa.test.ex (MX) succeeded -faking res_search() response length as 65535 DNS lookup of a-aa.test.ex (A) using fakens DNS lookup of a-aa.test.ex (A) succeeded DNS lookup of a-aa.test.ex (A/AAAA) requested AD, but got AA @@ -16,7 +15,6 @@ dropping to exim gid; retaining priv uid DNS lookup of mx-aa-a-sec.test.ex (MX) using fakens DNS lookup of mx-aa-a-sec.test.ex (MX) succeeded DNS lookup of mx-aa-a-sec.test.ex (MX) requested AD, but got AA -faking res_search() response length as 65535 DNS lookup of a-sec.test.ex (A) using fakens DNS lookup of a-sec.test.ex (A) succeeded >>>>>>>>>>>>>>>> Exim pid=pppp (main) terminating with rc=0 >>>>>>>>>>>>>>>> diff --git a/test/stderr/4803 b/test/stderr/4803 index e86035acd..a7aa7bfa8 100644 --- a/test/stderr/4803 +++ b/test/stderr/4803 @@ -4,7 +4,6 @@ admin user dropping to exim gid; retaining priv uid DNS lookup of mx-sec-a-aa.test.ex (MX) using fakens DNS lookup of mx-sec-a-aa.test.ex (MX) succeeded -faking res_search() response length as 65535 DNS lookup of a-aa.test.ex (A) using fakens DNS lookup of a-aa.test.ex (A) succeeded DNS faked the AD bit (got AA and matched with dns_trust_aa (test.ex in *)) @@ -20,7 +19,6 @@ DNS lookup of mx-aa-a-sec.test.ex (MX) succeeded DNS faked the AD bit (got AA and matched with dns_trust_aa (test.ex in *)) DNS faked the AD bit (got AA and matched with dns_trust_aa (test.ex in *)) DNS faked the AD bit (got AA and matched with dns_trust_aa (test.ex in *)) -faking res_search() response length as 65535 DNS lookup of a-sec.test.ex (A) using fakens DNS lookup of a-sec.test.ex (A) succeeded >>>>>>>>>>>>>>>> Exim pid=pppp (main) terminating with rc=0 >>>>>>>>>>>>>>>>