From: Kai Blin Date: Fri, 22 Oct 2010 07:37:38 +0000 (+0200) Subject: ndr dns: Add simple parser X-Git-Url: http://git.samba.org/?a=commitdiff_plain;h=719a6bbfede5b124c96f7c84d27e68ac285b073a;p=mat%2Fsamba.git ndr dns: Add simple parser --- diff --git a/librpc/idl/dns.idl b/librpc/idl/dns.idl index 1ccf822336..16dcf52929 100644 --- a/librpc/idl/dns.idl +++ b/librpc/idl/dns.idl @@ -10,7 +10,7 @@ import "misc.idl"; [ - helper("librpc/ndr/ndr_dnsp.h"), + helper("librpc/ndr/ndr_dns.h"), helpstring("DNS records"), version(0.0), uuid("a047c001-5f22-40b0-9d52-7042c43f711a") @@ -109,7 +109,7 @@ interface dns } dns_qtype; typedef [public] struct { - dnsp_name name; + dns_string name; dns_qtype question_type; dns_qclass question_class; } dns_name_question; @@ -120,12 +120,13 @@ interface dns } dns_rdata_data; typedef [nodiscriminant,public] union { - [case(DNS_QTYPE_A)] ipv4address ipv4_address; + [case(DNS_QTYPE_A),subcontext(2)] ipv4address ipv4_address; + [case(DNS_QTYPE_AAAA),subcontext(2)] ipv6address ipv6_address; [default] dns_rdata_data data; } dns_rdata; typedef [flag(LIBNDR_PRINT_ARRAY_HEX),public] struct { - dnsp_name name; + dns_string name; dns_qtype rr_type; dns_qclass rr_class; uint32 ttl; diff --git a/librpc/ndr/libndr.h b/librpc/ndr/libndr.h index c110b76ae5..6bc96cada6 100644 --- a/librpc/ndr/libndr.h +++ b/librpc/ndr/libndr.h @@ -92,6 +92,7 @@ struct ndr_push { struct ndr_token_list *relative_list; struct ndr_token_list *relative_begin_list; struct ndr_token_list *nbt_string_list; + struct ndr_token_list *dns_string_list; struct ndr_token_list *full_ptr_list; /* this is used to ensure we generate unique reference IDs */ diff --git a/librpc/ndr/ndr_dns.c b/librpc/ndr/ndr_dns.c new file mode 100644 index 0000000000..18dde2bd1a --- /dev/null +++ b/librpc/ndr/ndr_dns.c @@ -0,0 +1,210 @@ +/* + Unix SMB/CIFS implementation. + + manipulate dns name structures + + Copyright (C) 2010 Kai Blin + + Heavily based on nbtname.c which is: + + Copyright (C) Andrew Tridgell 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/* + see rfc1002 for the detailed format of compressed names +*/ + +#include "includes.h" +#include "librpc/gen_ndr/ndr_dns.h" +#include "librpc/gen_ndr/ndr_misc.h" +#include "system/locale.h" +#include "lib/util/util_net.h" + +/* don't allow an unlimited number of name components */ +#define MAX_COMPONENTS 10 + +/** + print a dns string +*/ +_PUBLIC_ void ndr_print_dns_string(struct ndr_print *ndr, const char *name, const char *s) +{ + ndr_print_string(ndr, name, s); +} + +/* + pull one component of a dns_string +*/ +static enum ndr_err_code ndr_pull_component(struct ndr_pull *ndr, + uint8_t **component, + uint32_t *offset, + uint32_t *max_offset) +{ + uint8_t len; + unsigned int loops = 0; + while (loops < 5) { + if (*offset >= ndr->data_size) { + return ndr_pull_error(ndr, NDR_ERR_STRING, + "BAD DNS NAME component"); + } + len = ndr->data[*offset]; + if (len == 0) { + *offset += 1; + *max_offset = MAX(*max_offset, *offset); + *component = NULL; + return NDR_ERR_SUCCESS; + } + if ((len & 0xC0) == 0xC0) { + /* its a label pointer */ + if (1 + *offset >= ndr->data_size) { + return ndr_pull_error(ndr, NDR_ERR_STRING, + "BAD DNS NAME component"); + } + *max_offset = MAX(*max_offset, *offset + 2); + *offset = ((len&0x3F)<<8) | ndr->data[1 + *offset]; + *max_offset = MAX(*max_offset, *offset); + loops++; + continue; + } + if ((len & 0xC0) != 0) { + /* its a reserved length field */ + return ndr_pull_error(ndr, NDR_ERR_STRING, + "BAD DNS NAME component"); + } + if (*offset + len + 2 > ndr->data_size) { + return ndr_pull_error(ndr, NDR_ERR_STRING, + "BAD DNS NAME component"); + } + *component = (uint8_t*)talloc_strndup(ndr, (const char *)&ndr->data[1 + *offset], len); + NDR_ERR_HAVE_NO_MEMORY(*component); + *offset += len + 1; + *max_offset = MAX(*max_offset, *offset); + return NDR_ERR_SUCCESS; + } + + /* too many pointers */ + return ndr_pull_error(ndr, NDR_ERR_STRING, "BAD DNS NAME component"); +} + +/** + pull a dns_string from the wire +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_dns_string(struct ndr_pull *ndr, int ndr_flags, const char **s) +{ + uint32_t offset = ndr->offset; + uint32_t max_offset = offset; + unsigned num_components; + char *name; + + if (!(ndr_flags & NDR_SCALARS)) { + return NDR_ERR_SUCCESS; + } + + name = NULL; + + /* break up name into a list of components */ + for (num_components=0;num_componentsoffset = max_offset; + + return NDR_ERR_SUCCESS; +} + +/** + push a dns string to the wire +*/ +_PUBLIC_ enum ndr_err_code ndr_push_dns_string(struct ndr_push *ndr, int ndr_flags, const char *s) +{ + if (!(ndr_flags & NDR_SCALARS)) { + return NDR_ERR_SUCCESS; + } + + while (s && *s) { + enum ndr_err_code ndr_err; + char *compname; + size_t complen; + uint32_t offset; + + /* see if we have pushed the remaing string allready, + * if so we use a label pointer to this string + */ + ndr_err = ndr_token_retrieve_cmp_fn(&ndr->dns_string_list, s, &offset, (comparison_fn_t)strcmp, false); + if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + uint8_t b[2]; + + if (offset > 0x3FFF) { + return ndr_push_error(ndr, NDR_ERR_STRING, + "offset for dns string label pointer %u[%08X] > 0x00003FFF", + offset, offset); + } + + b[0] = 0xC0 | (offset>>8); + b[1] = (offset & 0xFF); + + return ndr_push_bytes(ndr, b, 2); + } + + complen = strcspn(s, "."); + + /* we need to make sure the length fits into 6 bytes */ + if (complen > 0x3F) { + return ndr_push_error(ndr, NDR_ERR_STRING, + "component length %u[%08X] > 0x0000003F", + (unsigned)complen, (unsigned)complen); + } + + compname = talloc_asprintf(ndr, "%c%*.*s", + (unsigned char)complen, + (unsigned char)complen, + (unsigned char)complen, s); + NDR_ERR_HAVE_NO_MEMORY(compname); + + /* remember the current componemt + the rest of the string + * so it can be reused later + */ + NDR_CHECK(ndr_token_store(ndr, &ndr->dns_string_list, s, ndr->offset)); + + /* push just this component into the blob */ + NDR_CHECK(ndr_push_bytes(ndr, (const uint8_t *)compname, complen+1)); + talloc_free(compname); + + s += complen; + if (*s == '.') s++; + } + + /* if we reach the end of the string and have pushed the last component + * without using a label pointer, we need to terminate the string + */ + return ndr_push_bytes(ndr, (const uint8_t *)"", 1); +} diff --git a/librpc/ndr/ndr_dns.h b/librpc/ndr/ndr_dns.h new file mode 100644 index 0000000000..d0b6ab36f3 --- /dev/null +++ b/librpc/ndr/ndr_dns.h @@ -0,0 +1,3 @@ +_PUBLIC_ void ndr_print_dns_string(struct ndr_print *ndr, const char *name, const char *s); +_PUBLIC_ enum ndr_err_code ndr_pull_dns_string(struct ndr_pull *ndr, int ndr_flags, const char **s); +_PUBLIC_ enum ndr_err_code ndr_push_dns_string(struct ndr_push *ndr, int ndr_flags, const char *s); diff --git a/librpc/wscript_build b/librpc/wscript_build index 2d053e49a5..995382db14 100644 --- a/librpc/wscript_build +++ b/librpc/wscript_build @@ -18,8 +18,8 @@ bld.SAMBA_SUBSYSTEM('NDR_DNSSERVER', ) bld.SAMBA_SUBSYSTEM('NDR_DNS', - source='../librpc/gen_ndr/ndr_dns.c', - public_deps='LIBNDR NDR_DNSP' + source='../librpc/gen_ndr/ndr_dns.c ../librpc/ndr/ndr_dns.c', + public_deps='LIBNDR' ) bld.SAMBA_SUBSYSTEM('NDR_DSBACKUP', diff --git a/pidl/lib/Parse/Pidl/NDR.pm b/pidl/lib/Parse/Pidl/NDR.pm index b5dd2aaf9c..21b75687a7 100644 --- a/pidl/lib/Parse/Pidl/NDR.pm +++ b/pidl/lib/Parse/Pidl/NDR.pm @@ -72,6 +72,7 @@ my $scalar_alignment = { 'WERROR' => 4, 'NTSTATUS' => 4, 'COMRESULT' => 4, + 'dns_string' => 4, 'nbt_string' => 4, 'wrepl_nbt_name' => 4, 'ipv4address' => 4, diff --git a/pidl/lib/Parse/Pidl/Samba4/Python.pm b/pidl/lib/Parse/Pidl/Samba4/Python.pm index cf554f5c0c..f79981e317 100644 --- a/pidl/lib/Parse/Pidl/Samba4/Python.pm +++ b/pidl/lib/Parse/Pidl/Samba4/Python.pm @@ -916,6 +916,11 @@ sub ConvertObjectFromPythonData($$$$$$;$) return; } + if ($actual_ctype->{TYPE} eq "SCALAR" and ($actual_ctype->{NAME} eq "dns_string" or $actual_ctype->{NAME} eq "dns_name")) { + $self->pidl("$target = talloc_strdup($mem_ctx, PyString_AS_STRING($cvar));"); + return; + } + if ($actual_ctype->{TYPE} eq "SCALAR" and $actual_ctype->{NAME} eq "ipv4address") { $self->pidl("$target = PyString_AS_STRING($cvar);"); return; @@ -1094,6 +1099,10 @@ sub ConvertScalarToPython($$$) return "PyString_FromString_check_null($cvar)"; } + if (($ctypename eq "dns_string" or $ctypename eq "dns_name")) { + return "PyString_FromString_check_null($cvar)"; + } + # Not yet supported if ($ctypename eq "string_array") { return "PyCObject_FromTallocPtr($cvar)"; } if ($ctypename eq "ipv4address") { return "PyString_FromString_check_null($cvar)"; } diff --git a/pidl/lib/Parse/Pidl/Typelist.pm b/pidl/lib/Parse/Pidl/Typelist.pm index 00204a3cfc..4733f91565 100644 --- a/pidl/lib/Parse/Pidl/Typelist.pm +++ b/pidl/lib/Parse/Pidl/Typelist.pm @@ -20,7 +20,7 @@ use strict; my %types = (); my @reference_scalars = ( - "string", "string_array", "nbt_string", + "string", "string_array", "nbt_string", "dns_string", "wrepl_nbt_name", "ipv4address", "ipv6address" ); @@ -54,6 +54,7 @@ my %scalars = ( "WERROR" => "WERROR", "NTSTATUS" => "NTSTATUS", "COMRESULT" => "COMRESULT", + "dns_string" => "const char *", "nbt_string" => "const char *", "wrepl_nbt_name"=> "struct nbt_name *", "ipv4address" => "const char *", diff --git a/source4/dns_server/dns_server.c b/source4/dns_server/dns_server.c index de9ad5336f..5d9a5086ba 100644 --- a/source4/dns_server/dns_server.c +++ b/source4/dns_server/dns_server.c @@ -33,6 +33,8 @@ #include "lib/socket/netif.h" #include "dns_server/dns_server.h" #include "param/param.h" +#include "librpc/ndr/libndr.h" +#include "librpc/gen_ndr/ndr_dns.h" /* hold information about one dns socket */ struct dns_socket { @@ -87,7 +89,21 @@ bool dns_process(struct dns_server *dns, DATA_BLOB *in, DATA_BLOB *out) { - DEBUG(0, ("FIXME: actually process DNS packet here\n")); + enum ndr_err_code ndr_err; + struct dns_name_packet *packet = talloc(mem_ctx, struct dns_name_packet); + if (packet == NULL) return false; + + dump_data(0, in->data, in->length); + + ndr_err = ndr_pull_struct_blob(in, packet, packet, + (ndr_pull_flags_fn_t)ndr_pull_dns_name_packet); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + TALLOC_FREE(packet); + DEBUG(0, ("Failed to parse packet %d!\n", ndr_err)); + return false; + } + + NDR_PRINT_DEBUG(dns_name_packet, packet); return true; } diff --git a/source4/librpc/wscript_build b/source4/librpc/wscript_build index 734274379a..a7d10e5ddd 100755 --- a/source4/librpc/wscript_build +++ b/source4/librpc/wscript_build @@ -96,7 +96,9 @@ bld.SAMBA_LIBRARY('NDR_STANDARD', source='../../librpc/gen_ndr/ndr_atsvc.c ../../librpc/gen_ndr/ndr_eventlog6.c', vnum='0.0.1', pc_files='../../librpc/ndr_standard.pc', - deps='NDR_SECURITY NDR_LSA NDR_SAMR NDR_NETLOGON NDR_EVENTLOG NDR_DFS NDR_NTSVCS NDR_SVCCTL NDR_INITSHUTDOWN NDR_WKSSVC NDR_SRVSVC NDR_WINREG NDR_ECHO LIBSECURITY', + deps='''NDR_SECURITY NDR_LSA NDR_SAMR NDR_NETLOGON NDR_EVENTLOG NDR_DFS + NDR_NTSVCS NDR_SVCCTL NDR_INITSHUTDOWN NDR_WKSSVC NDR_SRVSVC NDR_WINREG + NDR_ECHO LIBSECURITY NDR_DNS''', public_deps='LIBNDR', public_headers='../../librpc/gen_ndr/samr.h ../../librpc/gen_ndr/ndr_samr.h ../../librpc/gen_ndr/lsa.h ../../librpc/gen_ndr/netlogon.h ../../librpc/gen_ndr/atsvc.h ../../librpc/gen_ndr/ndr_atsvc.h ../../librpc/gen_ndr/ndr_svcctl.h ../../librpc/gen_ndr/svcctl.h', header_path='gen_ndr'