s4 dns: Better error handling when parsing invalid or unknown records
authorKai Blin <kai@samba.org>
Fri, 1 Oct 2010 03:35:00 +0000 (20:35 -0700)
committerKai Blin <kai@samba.org>
Sat, 23 Oct 2010 10:17:06 +0000 (10:17 +0000)
librpc/idl/dns.idl
librpc/idl/dnsp.idl
librpc/ndr/ndr_dns.c
source4/dns_server/dns_server.c

index b4075365ab0f6046d46dc7c185b2d11a58155f78..486b16e50b382c275c6ae48bddffaccb2a0f0d21 100644 (file)
@@ -60,7 +60,9 @@ interface dns
        } dns_rcode;
 
        typedef [public,enum16bit] enum {
-               DNS_QCLASS_IP = 0x01
+               DNS_QCLASS_IP   = 0x0001,
+               DNS_QCLASS_NONE = 0x00FE,
+               DNS_QCLASS_ANY  = 0x00FF
        } dns_qclass;
 
        /* These vese values could have been merged with NBT_QTYPE values, but
index 3a8e384dbe6ec4b171b3e10243480be77b872189..905e42048223e1bbe71d8492bd9028f8588fef8d 100644 (file)
@@ -113,8 +113,8 @@ interface dnsp
                dns_record_type wType;
                uint32          dwFlags;
                uint32          dwSerial;
-               uint32          dwTtlSeconds;
-               uint32          dwTimeStamp;
+               [flag(NDR_BIG_ENDIAN)] uint32   dwTtlSeconds;
+               uint32          dwTimeStamp;
                uint32          dwReserved;
                [switch_is(wType)] dnsRecordData data;
        } dnsp_DnssrvRpcRecord;
index 4f39eb4e67ed7eae9fedac4f8de8bdef43a8a69b..ee2f1ce5cf46e1c4231aa8ba26a1d872e1cc98eb 100644 (file)
@@ -220,9 +220,14 @@ _PUBLIC_ enum ndr_err_code ndr_push_dns_res_rec(struct ndr_push *ndr, int ndr_fl
                        NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->ttl));
                        _saved_offset1 = ndr->offset;
                        NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0));
-                       NDR_CHECK(ndr_push_set_switch_value(ndr, &r->rdata, r->rr_type));
-                       NDR_CHECK(ndr_push_dns_rdata(ndr, NDR_SCALARS, &r->rdata));
-
+                       if (r->length > 0) {
+                               NDR_CHECK(ndr_push_set_switch_value(ndr, &r->rdata, r->rr_type));
+                               NDR_CHECK(ndr_push_dns_rdata(ndr, NDR_SCALARS, &r->rdata));
+                               if (r->unexpected.length > 0) {
+                                       return ndr_push_error(ndr, NDR_ERR_LENGTH,
+                                                             "Invalid...Unexpected blob lenght is too large");
+                               }
+                       }
                        if (r->unexpected.length > UINT16_MAX) {
                                return ndr_push_error(ndr, NDR_ERR_LENGTH,
                                                      "Unexpected blob lenght is too large");
@@ -260,8 +265,12 @@ _PUBLIC_ enum ndr_err_code ndr_pull_dns_res_rec(struct ndr_pull *ndr, int ndr_fl
                        NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->ttl));
                        NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->length));
                        _saved_offset1 = ndr->offset;
-                       NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->rdata, r->rr_type));
-                       NDR_CHECK(ndr_pull_dns_rdata(ndr, NDR_SCALARS, &r->rdata));
+                       if (r->length > 0) {
+                               NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->rdata, r->rr_type));
+                               NDR_CHECK(ndr_pull_dns_rdata(ndr, NDR_SCALARS, &r->rdata));
+                       } else {
+                               ZERO_STRUCT(r->rdata);
+                       }
                        length = ndr->offset - _saved_offset1;
                        if (length > r->length) {
                                return ndr_pull_error(ndr, NDR_ERR_LENGTH,
index ac1431cf48b841beb3331efe9a543d4c59edbb42..08d6c5dfc203777ec39a81071fb5cb51157be914 100644 (file)
@@ -241,6 +241,7 @@ static NTSTATUS handle_question(struct dns_server *dns,
                        ans[ai].rr_type = DNS_QTYPE_CNAME;
                        ans[ai].rr_class = DNS_QCLASS_IP;
                        ans[ai].ttl = recs[ri].dwTtlSeconds;
+                       ans[ai].length = UINT16_MAX;
                        ans[ai].rdata.cname_record = talloc_strdup(ans, recs[ri].data.cname);
                        ai++;
                }
@@ -256,6 +257,7 @@ static NTSTATUS handle_question(struct dns_server *dns,
                        ans[ai].rr_type = DNS_QTYPE_A;
                        ans[ai].rr_class = DNS_QCLASS_IP;
                        ans[ai].ttl = recs[ri].dwTtlSeconds;
+                       ans[ai].length = UINT16_MAX;
                        ans[ai].rdata.ipv4_record = talloc_strdup(ans, recs[ri].data.ipv4);
                        ai++;
                }
@@ -271,6 +273,7 @@ static NTSTATUS handle_question(struct dns_server *dns,
                        ans[ai].rr_type = DNS_QTYPE_AAAA;
                        ans[ai].rr_class = DNS_QCLASS_IP;
                        ans[ai].ttl = recs[ri].dwTtlSeconds;
+                       ans[ai].length = UINT16_MAX;
                        ans[ai].rdata.ipv6_record = recs[ri].data.ipv6;
                        ai++;
                }
@@ -286,6 +289,7 @@ static NTSTATUS handle_question(struct dns_server *dns,
                        ans[ai].rr_type = DNS_QTYPE_NS;
                        ans[ai].rr_class = DNS_QCLASS_IP;
                        ans[ai].ttl = recs[ri].dwTtlSeconds;
+                       ans[ai].length = UINT16_MAX;
                        ans[ai].rdata.ns_record = recs[ri].data.ns;
                        ai++;
                }
@@ -301,6 +305,7 @@ static NTSTATUS handle_question(struct dns_server *dns,
                        ans[ai].rr_type = DNS_QTYPE_SRV;
                        ans[ai].rr_class = DNS_QCLASS_IP;
                        ans[ai].ttl = recs[ri].dwTtlSeconds;
+                       ans[ai].length = UINT16_MAX;
                        ans[ai].rdata.srv_record.priority = recs[ri].data.srv.wPriority;
                        ans[ai].rdata.srv_record.weight = recs[ri].data.srv.wWeight;
                        ans[ai].rdata.srv_record.port = recs[ri].data.srv.wPort;
@@ -319,6 +324,7 @@ static NTSTATUS handle_question(struct dns_server *dns,
                        ans[ai].rr_type = DNS_QTYPE_SOA;
                        ans[ai].rr_class = DNS_QCLASS_IP;
                        ans[ai].ttl = recs[ri].dwTtlSeconds;
+                       ans[ai].length = UINT16_MAX;
                        ans[ai].rdata.soa_record.mname  = recs[ri].data.soa.mname;
                        ans[ai].rdata.soa_record.rname  = recs[ri].data.soa.rname;
                        ans[ai].rdata.soa_record.serial = recs[ri].data.soa.serial;
@@ -333,6 +339,10 @@ static NTSTATUS handle_question(struct dns_server *dns,
                return NT_STATUS_NOT_IMPLEMENTED;
        }
 
+       if (*ancount == ai) {
+               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+       }
+
        *ancount = ai;
        *answers = ans;
 
@@ -401,14 +411,22 @@ static NTSTATUS dns_process(struct dns_server *dns,
 {
        enum ndr_err_code ndr_err;
        NTSTATUS ret;
-       struct dns_name_packet *in_packet = talloc_zero(mem_ctx, struct dns_name_packet);
-       /* TODO: We don't really need an out_packet. */
-       struct dns_name_packet *out_packet = talloc_zero(mem_ctx, struct dns_name_packet);
+       struct dns_name_packet *in_packet;
+       struct dns_name_packet *out_packet;
        struct dns_res_rec *answers = NULL, *nsrecs = NULL, *additional = NULL;
        uint16_t num_answers = 0 , num_nsrecs = 0, num_additional = 0;
        uint16_t reply_code;
 
-       if (in_packet == NULL) return NT_STATUS_INVALID_PARAMETER;
+       if (in->length < 12) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       in_packet = talloc_zero(mem_ctx, struct dns_name_packet);
+       /* TODO: We don't really need an out_packet. */
+       out_packet = talloc_zero(mem_ctx, struct dns_name_packet);
+
+       if (in_packet == NULL) return NT_STATUS_NO_MEMORY;
+       if (out_packet == NULL) return NT_STATUS_NO_MEMORY;
 
        dump_data(2, in->data, in->length);
 
@@ -417,7 +435,12 @@ static NTSTATUS dns_process(struct dns_server *dns,
        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
                TALLOC_FREE(in_packet);
                DEBUG(0, ("Failed to parse packet %d!\n", ndr_err));
-               return NT_STATUS_COULD_NOT_INTERPRET;
+               *out = *in;
+
+               out->data[2] |= 0x80; /* Toggle DNS_FLAG_REPLY */
+               out->data[3] |= DNS_RCODE_FORMERR;
+
+               return NT_STATUS_OK;
        }
 
        NDR_PRINT_DEBUG(dns_name_packet, in_packet);
@@ -439,7 +462,7 @@ static NTSTATUS dns_process(struct dns_server *dns,
                                                &answers, &num_answers,
                                                &nsrecs,  &num_nsrecs,
                                                &additional, &num_additional);
-               reply_code = DNS_RCODE_REFUSED;
+               reply_code = DNS_RCODE_NOTIMP;
                break;
        default:
                ret = NT_STATUS_NOT_IMPLEMENTED;
@@ -467,7 +490,12 @@ static NTSTATUS dns_process(struct dns_server *dns,
                TALLOC_FREE(in_packet);
                TALLOC_FREE(out_packet);
                DEBUG(0, ("Failed to push packet %d!\n", ndr_err));
-               return NT_STATUS_INTERNAL_ERROR;
+               *out = *in;
+
+               out->data[2] |= 0x80; /* Toggle DNS_FLAG_REPLY */
+               out->data[3] |= DNS_RCODE_SERVFAIL;
+
+               return NT_STATUS_OK;
        }
 
        dump_data(2, out->data, out->length);