📄 dns.c
字号:
/* * DHCP clients and servers should use the following forms of client * identification, starting with the most preferable, and finishing * with the least preferable. If the client does not send any of these * forms of identification, the DHCP/DDNS interaction is not defined by * this specification. The most preferable form of identification is * the Globally Unique Identifier Option [TBD]. Next is the DHCP * Client Identifier option. Last is the client's link-layer address, * as conveyed in its DHCPREQUEST message. Implementors should note * that the link-layer address cannot be used if there are no * significant bytes in the chaddr field of the DHCP client's request, * because this does not constitute a unique identifier. * -- "Interaction between DHCP and DNS" * <draft-ietf-dhc-dhcp-dns-12.txt> * M. Stapp, Y. Rekhter */ /* Put the type in the first two bytes. */ id -> buffer -> data [0] = "0123456789abcdef" [type >> 4]; id -> buffer -> data [1] = "0123456789abcdef" [type % 15]; /* Mash together an MD5 hash of the identifier. */ MD5_Init (&md5); MD5_Update (&md5, data, len); MD5_Final (buf, &md5); /* Convert into ASCII. */ for (i = 0; i < MD5_DIGEST_LENGTH; i++) { id -> buffer -> data [i * 2 + 2] = "0123456789abcdef" [(buf [i] >> 4) & 0xf]; id -> buffer -> data [i * 2 + 3] = "0123456789abcdef" [buf [i] & 0xf]; } id -> len = MD5_DIGEST_LENGTH * 2 + 2; id -> buffer -> data [id -> len] = 0; id -> terminated = 1; return 1;}/* Now for the DDNS update code that is shared between client and server... */isc_result_t ddns_update_a (struct data_string *ddns_fwd_name, struct iaddr ddns_addr, struct data_string *ddns_dhcid, unsigned long ttl, int rrsetp){ ns_updque updqueue; ns_updrec *updrec; isc_result_t result; char ddns_address [16]; if (ddns_addr.len != 4) return ISC_R_INVALIDARG; /* %Audit% Cannot exceed 16 bytes. %2004.06.17,Safe% */ sprintf (ddns_address, "%u.%u.%u.%u", ddns_addr.iabuf[0], ddns_addr.iabuf[1], ddns_addr.iabuf[2], ddns_addr.iabuf[3]); /* * When a DHCP client or server intends to update an A RR, it first * prepares a DNS UPDATE query which includes as a prerequisite the * assertion that the name does not exist. The update section of the * query attempts to add the new name and its IP address mapping (an A * RR), and the DHCID RR with its unique client-identity. * -- "Interaction between DHCP and DNS" */ ISC_LIST_INIT (updqueue); /* * A RR does not exist. */ updrec = minires_mkupdrec (S_PREREQ, (const char *)ddns_fwd_name -> data, C_IN, T_A, 0); if (!updrec) { result = ISC_R_NOMEMORY; goto error; } updrec -> r_data = (unsigned char *)0; updrec -> r_size = 0; updrec -> r_opcode = rrsetp ? NXRRSET : NXDOMAIN; ISC_LIST_APPEND (updqueue, updrec, r_link); /* * Add A RR. */ updrec = minires_mkupdrec (S_UPDATE, (const char *)ddns_fwd_name -> data, C_IN, T_A, ttl); if (!updrec) { result = ISC_R_NOMEMORY; goto error; } updrec -> r_data = (unsigned char *)ddns_address; updrec -> r_size = strlen (ddns_address); updrec -> r_opcode = ADD; ISC_LIST_APPEND (updqueue, updrec, r_link); /* * Add DHCID RR. */ updrec = minires_mkupdrec (S_UPDATE, (const char *)ddns_fwd_name -> data, C_IN, T_DHCID, ttl); if (!updrec) { result = ISC_R_NOMEMORY; goto error; } updrec -> r_data = ddns_dhcid -> data; updrec -> r_size = ddns_dhcid -> len; updrec -> r_opcode = ADD; ISC_LIST_APPEND (updqueue, updrec, r_link); /* * Attempt to perform the update. */ result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue));#ifdef DEBUG_DNS_UPDATES print_dns_status ((int)result, &updqueue);#endif /* * If this update operation succeeds, the updater can conclude that it * has added a new name whose only RRs are the A and DHCID RR records. * The A RR update is now complete (and a client updater is finished, * while a server might proceed to perform a PTR RR update). * -- "Interaction between DHCP and DNS" */ if (result == ISC_R_SUCCESS) { log_info ("Added new forward map from %.*s to %s", (int)ddns_fwd_name -> len, (const char *)ddns_fwd_name -> data, ddns_address); goto error; } /* * If the first update operation fails with YXDOMAIN, the updater can * conclude that the intended name is in use. The updater then * attempts to confirm that the DNS name is not being used by some * other host. The updater prepares a second UPDATE query in which the * prerequisite is that the desired name has attached to it a DHCID RR * whose contents match the client identity. The update section of * this query deletes the existing A records on the name, and adds the * A record that matches the DHCP binding and the DHCID RR with the * client identity. * -- "Interaction between DHCP and DNS" */ if (result != (rrsetp ? ISC_R_YXRRSET : ISC_R_YXDOMAIN)) { log_error ("Unable to add forward map from %.*s to %s: %s", (int)ddns_fwd_name -> len, (const char *)ddns_fwd_name -> data, ddns_address, isc_result_totext (result)); goto error; } while (!ISC_LIST_EMPTY (updqueue)) { updrec = ISC_LIST_HEAD (updqueue); ISC_LIST_UNLINK (updqueue, updrec, r_link); minires_freeupdrec (updrec); } /* * DHCID RR exists, and matches client identity. */ updrec = minires_mkupdrec (S_PREREQ, (const char *)ddns_fwd_name -> data, C_IN, T_DHCID, 0); if (!updrec) { result = ISC_R_NOMEMORY; goto error; } updrec -> r_data = ddns_dhcid -> data; updrec -> r_size = ddns_dhcid -> len; updrec -> r_opcode = YXRRSET; ISC_LIST_APPEND (updqueue, updrec, r_link); /* * Delete A RRset. */ updrec = minires_mkupdrec (S_UPDATE, (const char *)ddns_fwd_name -> data, C_IN, T_A, 0); if (!updrec) { result = ISC_R_NOMEMORY; goto error; } updrec -> r_data = (unsigned char *)0; updrec -> r_size = 0; updrec -> r_opcode = DELETE; ISC_LIST_APPEND (updqueue, updrec, r_link); /* * Add A RR. */ updrec = minires_mkupdrec (S_UPDATE, (const char *)ddns_fwd_name -> data, C_IN, T_A, ttl); if (!updrec) { result = ISC_R_NOMEMORY; goto error; } updrec -> r_data = (unsigned char *)ddns_address; updrec -> r_size = strlen (ddns_address); updrec -> r_opcode = ADD; ISC_LIST_APPEND (updqueue, updrec, r_link); /* * Attempt to perform the update. */ result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue)); if (result != ISC_R_SUCCESS) { if (result == YXRRSET || result == YXDOMAIN || result == NXRRSET || result == NXDOMAIN) log_error ("Forward map from %.*s to %s already in use", (int)ddns_fwd_name -> len, (const char *)ddns_fwd_name -> data, ddns_address); else log_error ("Can't update forward map %.*s to %s: %s", (int)ddns_fwd_name -> len, (const char *)ddns_fwd_name -> data, ddns_address, isc_result_totext (result)); } else { log_info ("Added new forward map from %.*s to %s", (int)ddns_fwd_name -> len, (const char *)ddns_fwd_name -> data, ddns_address); }#if defined (DEBUG_DNS_UPDATES) print_dns_status ((int)result, &updqueue);#endif /* * If this query succeeds, the updater can conclude that the current * client was the last client associated with the domain name, and that * the name now contains the updated A RR. The A RR update is now * complete (and a client updater is finished, while a server would * then proceed to perform a PTR RR update). * -- "Interaction between DHCP and DNS" */ /* * If the second query fails with NXRRSET, the updater must conclude * that the client's desired name is in use by another host. At this * juncture, the updater can decide (based on some administrative * configuration outside of the scope of this document) whether to let * the existing owner of the name keep that name, and to (possibly) * perform some name disambiguation operation on behalf of the current * client, or to replace the RRs on the name with RRs that represent * the current client. If the configured policy allows replacement of * existing records, the updater submits a query that deletes the * existing A RR and the existing DHCID RR, adding A and DHCID RRs that * represent the IP address and client-identity of the new client. * -- "Interaction between DHCP and DNS" */ error: while (!ISC_LIST_EMPTY (updqueue)) { updrec = ISC_LIST_HEAD (updqueue); ISC_LIST_UNLINK (updqueue, updrec, r_link); minires_freeupdrec (updrec); } return result;}isc_result_t ddns_remove_a (struct data_string *ddns_fwd_name, struct iaddr ddns_addr, struct data_string *ddns_dhcid){ ns_updque updqueue; ns_updrec *updrec; isc_result_t result = SERVFAIL; char ddns_address [16]; if (ddns_addr.len != 4) return ISC_R_INVALIDARG; /* %Audit% Cannot exceed 16 bytes. %2004.06.17,Safe% */ sprintf (ddns_address, "%u.%u.%u.%u", ddns_addr.iabuf[0], ddns_addr.iabuf[1], ddns_addr.iabuf[2], ddns_addr.iabuf[3]); /* * The entity chosen to handle the A record for this client (either the * client or the server) SHOULD delete the A record that was added when * the lease was made to the client. * * In order to perform this delete, the updater prepares an UPDATE * query which contains two prerequisites. The first prerequisite * asserts that the DHCID RR exists whose data is the client identity * described in Section 4.3. The second prerequisite asserts that the * data in the A RR contains the IP address of the lease that has * expired or been released. * -- "Interaction between DHCP and DNS" */ ISC_LIST_INIT (updqueue); /* * DHCID RR exists, and matches client identity. */ updrec = minires_mkupdrec (S_PREREQ, (const char *)ddns_fwd_name -> data, C_IN, T_DHCID,0); if (!updrec) { result = ISC_R_NOMEMORY; goto error; } updrec -> r_data = ddns_dhcid -> data; updrec -> r_size = ddns_dhcid -> len; updrec -> r_opcode = YXRRSET; ISC_LIST_APPEND (updqueue, updrec, r_link); /* * A RR matches the expiring lease. */ updrec = minires_mkupdrec (S_PREREQ, (const char *)ddns_fwd_name -> data, C_IN, T_A, 0); if (!updrec) { result = ISC_R_NOMEMORY; goto error; } updrec -> r_data = (unsigned char *)ddns_address; updrec -> r_size = strlen (ddns_address); updrec -> r_opcode = YXRRSET; ISC_LIST_APPEND (updqueue, updrec, r_link); /* * Delete appropriate A RR. */ updrec = minires_mkupdrec (S_UPDATE, (const char *)ddns_fwd_name -> data, C_IN, T_A, 0); if (!updrec) { result = ISC_R_NOMEMORY; goto error; } updrec -> r_data = (unsigned char *)ddns_address; updrec -> r_size = strlen (ddns_address); updrec -> r_opcode = DELETE; ISC_LIST_APPEND (updqueue, updrec, r_link); /* * Attempt to perform the update. */ result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue)); print_dns_status ((int)result, &updqueue); /* * If the query fails, the updater MUST NOT delete the DNS name. It * may be that the host whose lease on the server has expired has moved * to another network and obtained a lease from a different server, * which has caused the client's A RR to be replaced. It may also be * that some other client has been configured with a name that matches * the name of the DHCP client, and the policy was that the last client * to specify the name would get the name. In this case, the DHCID RR * will no longer match the updater's notion of the client-identity of * the host pointed to by the DNS name. * -- "Interaction between DHCP and DNS" */ if (result != ISC_R_SUCCESS) { /* If the rrset isn't there, we didn't need to do the delete, which is success. */ if (result == ISC_R_NXRRSET || result == ISC_R_NXDOMAIN) result = ISC_R_SUCCESS; goto error; } while (!ISC_LIST_EMPTY (updqueue)) { updrec = ISC_LIST_HEAD (updqueue); ISC_LIST_UNLINK (updqueue, updrec, r_link); minires_freeupdrec (updrec); } /* If the deletion of the A succeeded, and there are no A records left for this domain, then we can blow away the DHCID record as well. We can't blow away the DHCID record above because it's possible that more than one A has been added to this domain name. */ ISC_LIST_INIT (updqueue); /* * A RR does not exist. */ updrec = minires_mkupdrec (S_PREREQ, (const char *)ddns_fwd_name -> data, C_IN, T_A, 0); if (!updrec) { result = ISC_R_NOMEMORY; goto error; } updrec -> r_data = (unsigned char *)0; updrec -> r_size = 0; updrec -> r_opcode = NXRRSET; ISC_LIST_APPEND (updqueue, updrec, r_link); /* * Delete appropriate DHCID RR. */ updrec = minires_mkupdrec (S_UPDATE, (const char *)ddns_fwd_name -> data, C_IN, T_DHCID, 0); if (!updrec) { result = ISC_R_NOMEMORY; goto error; } updrec -> r_data = ddns_dhcid -> data; updrec -> r_size = ddns_dhcid -> len; updrec -> r_opcode = DELETE; ISC_LIST_APPEND (updqueue, updrec, r_link); /* * Attempt to perform the update. */ result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue)); print_dns_status ((int)result, &updqueue); /* Fall through. */ error: while (!ISC_LIST_EMPTY (updqueue)) { updrec = ISC_LIST_HEAD (updqueue); ISC_LIST_UNLINK (updqueue, updrec, r_link); minires_freeupdrec (updrec); } return result;}#endif /* NSUPDATE */HASH_FUNCTIONS (dns_zone, const char *, struct dns_zone, dns_zone_hash_t, dns_zone_reference, dns_zone_dereference)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -