1 /* $NetBSD: dlz_mysql_dynamic.c,v 1.1.1.3 2014/12/10 03:34:31 christos Exp $ */
4 * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the
8 * above copyright notice and this permission notice appear in all
11 * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
12 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
13 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
14 * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
15 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
16 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
17 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
18 * USE OR PERFORMANCE OF THIS SOFTWARE.
20 * The development of Dynamically Loadable Zones (DLZ) for BIND 9 was
21 * conceived and contributed by Rob Butler.
23 * Permission to use, copy, modify, and distribute this software for any
24 * purpose with or without fee is hereby granted, provided that the
25 * above copyright notice and this permission notice appear in all
28 * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER
29 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
31 * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
32 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
33 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
34 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
35 * USE OR PERFORMANCE OF THIS SOFTWARE.
39 * Copyright (C) 1999-2001 Internet Software Consortium.
40 * Copyright (C) 2013 Internet Systems Consortium.
42 * Permission to use, copy, modify, and distribute this software for any
43 * purpose with or without fee is hereby granted, provided that the above
44 * copyright notice and this permission notice appear in all copies.
46 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
47 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
49 * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
50 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
51 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
52 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
53 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
57 * This provides the externally loadable MySQL DLZ module, without
67 #include <dlz_minimal.h>
70 #include <dlz_pthread.h>
72 #include <mysql/mysql.h>
74 #define dbc_search_limit 30
82 #define safeGet(in) in == NULL ? "" : in
85 * Structure to hold everthing needed by this "instance" of the MySQL
86 * module remember, the module code is only loaded once, but may have
87 * many separate instances.
91 db_list_t
*db
; /*%< handle to a list of DB */
94 dbinstance_t
*db
; /*%< handle to DB */
105 /* Helper functions from the dlz_dlopen driver */
107 dns_sdlz_putrr_t
*putrr
;
108 dns_sdlz_putnamedrr_t
*putnamedrr
;
109 dns_dlz_writeablezone_t
*writeable_zone
;
112 /* forward references */
114 dlz_findzonedb(void *dbdata
, const char *name
,
115 dns_clientinfomethods_t
*methods
,
116 dns_clientinfo_t
*clientinfo
);
119 dlz_destroy(void *dbdata
);
122 b9_add_helper(mysql_instance_t
*db
, const char *helper_name
, void *ptr
);
129 mysql_destroy(dbinstance_t
*db
) {
130 /* release DB connection */
131 if (db
->dbconn
!= NULL
)
132 mysql_close((MYSQL
*) db
->dbconn
);
134 /* destroy DB instance */
135 destroy_dbinstance(db
);
140 * Properly cleans up a list of database instances.
141 * This function is only used when the module is compiled for
142 * multithreaded operation.
145 mysql_destroy_dblist(db_list_t
*dblist
) {
146 dbinstance_t
*ndbi
= NULL
;
147 dbinstance_t
*dbi
= NULL
;
149 ndbi
= DLZ_LIST_HEAD(*dblist
);
150 while (ndbi
!= NULL
) {
152 ndbi
= DLZ_LIST_NEXT(dbi
, link
);
157 /* release memory for the list structure */
162 * Loops through the list of DB instances, attempting to lock
163 * on the mutex. If successful, the DBI is reserved for use
164 * and the thread can perform queries against the database.
165 * If the lock fails, the next one in the list is tried.
166 * looping continues until a lock is obtained, or until
167 * the list has been searched dbc_search_limit times.
168 * This function is only used when the module is compiled for
169 * multithreaded operation.
171 static dbinstance_t
*
172 mysql_find_avail_conn(mysql_instance_t
*mysql
) {
173 dbinstance_t
*dbi
= NULL
, *head
;
176 /* get top of list */
177 head
= dbi
= DLZ_LIST_HEAD(*(mysql
->db
));
179 /* loop through list */
180 while (count
< dbc_search_limit
) {
181 /* try to lock on the mutex */
182 if (dlz_mutex_trylock(&dbi
->lock
) == 0)
183 return (dbi
); /* success, return the DBI for use. */
185 /* not successful, keep trying */
186 dbi
= DLZ_LIST_NEXT(dbi
, link
);
188 /* check to see if we have gone to the top of the list. */
195 mysql
->log(ISC_LOG_INFO
,
196 "MySQL module unable to find available connection "
197 "after searching %d times", count
);
200 #endif /* PTHREADS */
203 * Allocates memory for a new string, and then constructs the new
204 * string by "escaping" the input string. The new string is
205 * safe to be used in queries. This is necessary because we cannot
206 * be sure of what types of strings are passed to us, and we don't
207 * want special characters in the string causing problems.
210 mysqldrv_escape_string(MYSQL
*mysql
, const char *instr
) {
219 outstr
= malloc((2 * len
* sizeof(char)) + 1);
223 mysql_real_escape_string(mysql
, outstr
, instr
, len
);
229 * This function is the real core of the module. Zone, record
230 * and client strings are passed in (or NULL is passed if the
231 * string is not available). The type of query we want to run
232 * is indicated by the query flag, and the dbdata object is passed
233 * passed in to. dbdata really holds a single database instance.
234 * The function will construct and run the query, hopefully getting
238 mysql_get_resultset(const char *zone
, const char *record
,
239 const char *client
, unsigned int query
,
240 void *dbdata
, MYSQL_RES
**rs
)
243 dbinstance_t
*dbi
= NULL
;
244 mysql_instance_t
*db
= (mysql_instance_t
*)dbdata
;
245 char *querystring
= NULL
;
251 /* find an available DBI from the list */
252 dbi
= mysql_find_avail_conn(db
);
255 * only 1 DBI - no need to lock instance lock either
256 * only 1 thread in the whole process, no possible contention.
258 dbi
= (dbinstance_t
*)(db
->db
);
259 #endif /* PTHREADS */
262 result
= ISC_R_FAILURE
;
266 /* what type of query are we going to run? */
269 if (dbi
->allnodes_q
== NULL
) {
270 result
= ISC_R_NOTIMPLEMENTED
;
275 if (dbi
->allowxfr_q
== NULL
) {
276 result
= ISC_R_NOTIMPLEMENTED
;
281 if (dbi
->authority_q
== NULL
) {
282 result
= ISC_R_NOTIMPLEMENTED
;
287 if (dbi
->findzone_q
== NULL
) {
288 db
->log(ISC_LOG_DEBUG(2),
289 "No query specified for findzone. "
290 "Findzone requires a query");
291 result
= ISC_R_FAILURE
;
296 if (dbi
->countzone_q
== NULL
) {
297 result
= ISC_R_NOTIMPLEMENTED
;
302 if (dbi
->lookup_q
== NULL
) {
303 db
->log(ISC_LOG_DEBUG(2),
304 "No query specified for lookup. "
305 "Lookup requires a query");
306 result
= ISC_R_FAILURE
;
311 db
->log(ISC_LOG_ERROR
,
312 "Incorrect query flag passed to "
313 "mysql_get_resultset");
314 result
= ISC_R_UNEXPECTED
;
320 if (dbi
->zone
!= NULL
)
323 dbi
->zone
= mysqldrv_escape_string((MYSQL
*) dbi
->dbconn
,
325 if (dbi
->zone
== NULL
) {
326 result
= ISC_R_NOMEMORY
;
332 if (record
!= NULL
) {
333 if (dbi
->record
!= NULL
)
336 dbi
->record
= mysqldrv_escape_string((MYSQL
*) dbi
->dbconn
,
338 if (dbi
->record
== NULL
) {
339 result
= ISC_R_NOMEMORY
;
345 if (client
!= NULL
) {
346 if (dbi
->client
!= NULL
)
349 dbi
->client
= mysqldrv_escape_string((MYSQL
*) dbi
->dbconn
,
351 if (dbi
->client
== NULL
) {
352 result
= ISC_R_NOMEMORY
;
359 * what type of query are we going to run? this time we build
360 * the actual query to run.
364 querystring
= build_querystring(dbi
->allnodes_q
);
367 querystring
= build_querystring(dbi
->allowxfr_q
);
370 querystring
= build_querystring(dbi
->authority_q
);
373 querystring
= build_querystring(dbi
->findzone_q
);
376 querystring
= build_querystring(dbi
->countzone_q
);
379 querystring
= build_querystring(dbi
->lookup_q
);
382 db
->log(ISC_LOG_ERROR
,
383 "Incorrect query flag passed to "
384 "mysql_get_resultset");
385 result
= ISC_R_UNEXPECTED
; goto cleanup
;
388 if (querystring
== NULL
) {
389 result
= ISC_R_NOMEMORY
;
393 /* output the full query string when debugging */
394 db
->log(ISC_LOG_DEBUG(1), "\nQuery String: %s\n", querystring
);
396 /* attempt query up to 3 times. */
397 for (i
= 0; i
< 3; i
++) {
398 qres
= mysql_query((MYSQL
*) dbi
->dbconn
, querystring
);
401 for (j
= 0; j
< 4; j
++)
402 if (mysql_ping((MYSQL
*) dbi
->dbconn
) == 0)
407 result
= ISC_R_SUCCESS
;
408 if (query
!= COUNTZONE
) {
409 *rs
= mysql_store_result((MYSQL
*) dbi
->dbconn
);
411 result
= ISC_R_FAILURE
;
414 result
= ISC_R_FAILURE
;
418 return (ISC_R_FAILURE
);
420 if (dbi
->zone
!= NULL
) {
424 if (dbi
->record
!= NULL
) {
428 if (dbi
->client
!= NULL
) {
433 /* release the lock so another thread can use this dbi */
434 (void) dlz_mutex_unlock(&dbi
->lock
);
436 if (querystring
!= NULL
)
443 * The processing of result sets for lookup and authority are
444 * exactly the same. So that functionality has been moved
445 * into this function to minimize code.
448 mysql_process_rs(mysql_instance_t
*db
, dns_sdlzlookup_t
*lookup
,
451 isc_result_t result
= ISC_R_NOTFOUND
;
459 fields
= mysql_num_fields(rs
); /* how many columns in result set */
460 row
= mysql_fetch_row(rs
); /* get a row from the result set */
461 while (row
!= NULL
) {
462 unsigned int len
= 0;
467 * one column in rs, it's the data field. use
468 * default type of A record, and default TTL
471 result
= db
->putrr(lookup
, "a", 86400, safeGet(row
[0]));
475 * two columns, data field, and data type.
476 * use default TTL of 86400.
478 result
= db
->putrr(lookup
, safeGet(row
[0]), 86400,
483 * three columns, all data no defaults.
484 * convert text to int, make sure it worked
487 ttl
= strtol(safeGet(row
[0]), &endp
, 10);
488 if (*endp
!= '\0' || ttl
< 0) {
489 db
->log(ISC_LOG_ERROR
,
490 "MySQL module ttl must be "
492 return (ISC_R_FAILURE
);
495 result
= db
->putrr(lookup
, safeGet(row
[1]), ttl
,
500 * more than 3 fields, concatenate the last
501 * ones together. figure out how long to make
504 for (j
= 2; j
< fields
; j
++)
505 len
+= strlen(safeGet(row
[j
])) + 1;
508 * allocate string memory, allow for NULL to
511 tmpString
= malloc(len
+ 1);
512 if (tmpString
== NULL
) {
513 db
->log(ISC_LOG_ERROR
,
514 "MySQL module unable to allocate "
515 "memory for temporary string");
516 mysql_free_result(rs
);
517 return (ISC_R_FAILURE
);
520 strcpy(tmpString
, safeGet(row
[2]));
521 for (j
= 3; j
< fields
; j
++) {
522 strcat(tmpString
, " ");
523 strcat(tmpString
, safeGet(row
[j
]));
526 ttl
= strtol(safeGet(row
[0]), &endp
, 10);
527 if (*endp
!= '\0' || ttl
< 0) {
528 db
->log(ISC_LOG_ERROR
,
529 "MySQL module ttl must be "
531 return (ISC_R_FAILURE
);
534 result
= db
->putrr(lookup
, safeGet(row
[1]),
539 if (result
!= ISC_R_SUCCESS
) {
540 mysql_free_result(rs
);
541 db
->log(ISC_LOG_ERROR
,
542 "putrr returned error: %d", result
);
543 return (ISC_R_FAILURE
);
546 row
= mysql_fetch_row(rs
);
549 mysql_free_result(rs
);
557 /*% determine if the zone is supported by (in) the database */
559 dlz_findzonedb(void *dbdata
, const char *name
,
560 dns_clientinfomethods_t
*methods
,
561 dns_clientinfo_t
*clientinfo
)
564 MYSQL_RES
*rs
= NULL
;
566 mysql_instance_t
*db
= (mysql_instance_t
*)dbdata
;
571 result
= mysql_get_resultset(name
, NULL
, NULL
, FINDZONE
, dbdata
, &rs
);
572 if (result
!= ISC_R_SUCCESS
|| rs
== NULL
) {
574 mysql_free_result(rs
);
576 db
->log(ISC_LOG_ERROR
,
577 "MySQL module unable to return "
578 "result set for findzone query");
580 return (ISC_R_FAILURE
);
584 * if we returned any rows, the zone is supported.
586 rows
= mysql_num_rows(rs
);
587 mysql_free_result(rs
);
589 mysql_get_resultset(name
, NULL
, NULL
, COUNTZONE
, dbdata
, NULL
);
590 return (ISC_R_SUCCESS
);
593 return (ISC_R_NOTFOUND
);
596 /*% Determine if the client is allowed to perform a zone transfer */
598 dlz_allowzonexfr(void *dbdata
, const char *name
, const char *client
) {
600 mysql_instance_t
*db
= (mysql_instance_t
*)dbdata
;
601 MYSQL_RES
*rs
= NULL
;
604 /* first check if the zone is supported by the database. */
605 result
= dlz_findzonedb(dbdata
, name
, NULL
, NULL
);
606 if (result
!= ISC_R_SUCCESS
)
607 return (ISC_R_NOTFOUND
);
610 * if we get to this point we know the zone is supported by
611 * the database the only questions now are is the zone
612 * transfer is allowed for this client and did the config file
613 * have an allow zone xfr query.
615 result
= mysql_get_resultset(name
, NULL
, client
, ALLOWXFR
,
617 if (result
== ISC_R_NOTIMPLEMENTED
)
620 if (result
!= ISC_R_SUCCESS
|| rs
== NULL
) {
622 mysql_free_result(rs
);
623 db
->log(ISC_LOG_ERROR
,
624 "MySQL module unable to return "
625 "result set for allow xfr query");
626 return (ISC_R_FAILURE
);
630 * count how many rows in result set; if we returned any,
631 * zone xfr is allowed.
633 rows
= mysql_num_rows(rs
);
634 mysql_free_result(rs
);
636 return (ISC_R_SUCCESS
);
638 return (ISC_R_NOPERM
);
642 * If the client is allowed to perform a zone transfer, the next order of
643 * business is to get all the nodes in the zone, so bind can respond to the
647 dlz_allnodes(const char *zone
, void *dbdata
, dns_sdlzallnodes_t
*allnodes
) {
649 mysql_instance_t
*db
= (mysql_instance_t
*)dbdata
;
650 MYSQL_RES
*rs
= NULL
;
658 result
= mysql_get_resultset(zone
, NULL
, NULL
, ALLNODES
, dbdata
, &rs
);
659 if (result
== ISC_R_NOTIMPLEMENTED
)
662 /* if we didn't get a result set, log an err msg. */
663 if (result
!= ISC_R_SUCCESS
) {
664 db
->log(ISC_LOG_ERROR
,
665 "MySQL module unable to return "
666 "result set for all nodes query");
670 result
= ISC_R_NOTFOUND
;
672 fields
= mysql_num_fields(rs
); /* how many columns in result set */
673 row
= mysql_fetch_row(rs
); /* get a row from the result set */
674 while (row
!= NULL
) {
676 db
->log(ISC_LOG_ERROR
,
677 "MySQL module too few fields returned "
678 "by all nodes query");
679 result
= ISC_R_FAILURE
;
683 ttl
= strtol(safeGet(row
[0]), &endp
, 10);
684 if (*endp
!= '\0' || ttl
< 0) {
685 db
->log(ISC_LOG_ERROR
,
686 "MySQL module ttl must be "
688 result
= ISC_R_FAILURE
;
693 result
= db
->putnamedrr(allnodes
, safeGet(row
[2]),
694 safeGet(row
[1]), ttl
,
697 unsigned int len
= 0;
700 * more than 4 fields, concatenate the last
703 for (j
= 3; j
< fields
; j
++)
704 len
+= strlen(safeGet(row
[j
])) + 1;
706 tmpString
= malloc(len
+ 1);
707 if (tmpString
== NULL
) {
708 db
->log(ISC_LOG_ERROR
,
709 "MySQL module unable to allocate "
710 "memory for temporary string");
711 result
= ISC_R_FAILURE
;
715 strcpy(tmpString
, safeGet(row
[3]));
716 for (j
= 4; j
< fields
; j
++) {
717 strcat(tmpString
, " ");
718 strcat(tmpString
, safeGet(row
[j
]));
721 result
= db
->putnamedrr(allnodes
, safeGet(row
[2]),
727 if (result
!= ISC_R_SUCCESS
) {
728 db
->log(ISC_LOG_ERROR
,
729 "putnamedrr returned error: %s", result
);
730 result
= ISC_R_FAILURE
;
734 row
= mysql_fetch_row(rs
);
739 mysql_free_result(rs
);
745 * If the lookup function does not return SOA or NS records for the zone,
746 * use this function to get that information for named.
749 dlz_authority(const char *zone
, void *dbdata
, dns_sdlzlookup_t
*lookup
) {
751 MYSQL_RES
*rs
= NULL
;
752 mysql_instance_t
*db
= (mysql_instance_t
*)dbdata
;
754 result
= mysql_get_resultset(zone
, NULL
, NULL
, AUTHORITY
, dbdata
, &rs
);
755 if (result
== ISC_R_NOTIMPLEMENTED
)
758 if (result
!= ISC_R_SUCCESS
) {
760 mysql_free_result(rs
);
761 db
->log(ISC_LOG_ERROR
,
762 "MySQL module unable to return "
763 "result set for authority query");
764 return (ISC_R_FAILURE
);
768 * lookup and authority result sets are processed in the same
769 * manner: mysql_process_rs does the job for both functions.
771 return (mysql_process_rs(db
, lookup
, rs
));
774 /*% If zone is supported, lookup up a (or multiple) record(s) in it */
776 dlz_lookup(const char *zone
, const char *name
,
777 void *dbdata
, dns_sdlzlookup_t
*lookup
,
778 dns_clientinfomethods_t
*methods
,
779 dns_clientinfo_t
*clientinfo
)
782 MYSQL_RES
*rs
= NULL
;
783 mysql_instance_t
*db
= (mysql_instance_t
*)dbdata
;
788 result
= mysql_get_resultset(zone
, name
, NULL
, LOOKUP
, dbdata
, &rs
);
790 /* if we didn't get a result set, log an err msg. */
791 if (result
!= ISC_R_SUCCESS
) {
793 mysql_free_result(rs
);
794 db
->log(ISC_LOG_ERROR
,
795 "MySQL module unable to return "
796 "result set for lookup query");
797 return (ISC_R_FAILURE
);
801 * lookup and authority result sets are processed in the same
802 * manner: mysql_process_rs does the job for both functions.
804 return (mysql_process_rs(db
, lookup
, rs
));
808 * Create an instance of the module.
811 dlz_create(const char *dlzname
, unsigned int argc
, char *argv
[],
814 isc_result_t result
= ISC_R_FAILURE
;
815 mysql_instance_t
*mysql
= NULL
;
816 dbinstance_t
*dbi
= NULL
;
821 const char *helper_name
;
822 #if MYSQL_VERSION_ID >= 50000
823 my_bool auto_reconnect
= 1;
828 #endif /* PTHREADS */
833 /* allocate memory for MySQL instance */
834 mysql
= calloc(1, sizeof(mysql_instance_t
));
836 return (ISC_R_NOMEMORY
);
837 memset(mysql
, 0, sizeof(mysql_instance_t
));
839 /* Fill in the helper functions */
840 va_start(ap
, dbdata
);
841 while ((helper_name
= va_arg(ap
, const char*)) != NULL
)
842 b9_add_helper(mysql
, helper_name
, va_arg(ap
, void*));
846 /* if debugging, let user know we are multithreaded. */
847 mysql
->log(ISC_LOG_DEBUG(1), "MySQL module running multithreaded");
849 /* if debugging, let user know we are single threaded. */
850 mysql
->log(ISC_LOG_DEBUG(1), "MySQL module running single threaded");
851 #endif /* PTHREADS */
853 /* verify we have at least 4 arg's passed to the module */
855 mysql
->log(ISC_LOG_ERROR
,
856 "MySQL module requires "
857 "at least 4 command line args.");
858 return (ISC_R_FAILURE
);
861 /* no more than 8 arg's should be passed to the module */
863 mysql
->log(ISC_LOG_ERROR
,
864 "MySQL module cannot accept "
865 "more than 7 command line args.");
866 return (ISC_R_FAILURE
);
869 /* get db name - required */
870 mysql
->dbname
= get_parameter_value(argv
[1], "dbname=");
871 if (mysql
->dbname
== NULL
) {
872 mysql
->log(ISC_LOG_ERROR
,
873 "MySQL module requires a dbname parameter.");
874 result
= ISC_R_FAILURE
;
878 /* get db port. Not required, but must be > 0 if specified */
879 tmp
= get_parameter_value(argv
[1], "port=");
883 mysql
->port
= strtol(tmp
, &endp
, 10);
884 if (*endp
!= '\0' || mysql
->port
< 0) {
885 mysql
->log(ISC_LOG_ERROR
,
886 "Mysql module: port "
887 "must be a positive number.");
889 result
= ISC_R_FAILURE
;
895 mysql
->host
= get_parameter_value(argv
[1], "host=");
896 mysql
->user
= get_parameter_value(argv
[1], "user=");
897 mysql
->pass
= get_parameter_value(argv
[1], "pass=");
898 mysql
->socket
= get_parameter_value(argv
[1], "socket=");
900 mysql
->flags
= CLIENT_REMEMBER_OPTIONS
;
902 tmp
= get_parameter_value(argv
[1], "compress=");
904 if (strcasecmp(tmp
, "true") == 0)
905 mysql
->flags
|= CLIENT_COMPRESS
;
909 tmp
= get_parameter_value(argv
[1], "ssl=");
911 if (strcasecmp(tmp
, "true") == 0)
912 mysql
->flags
|= CLIENT_SSL
;
916 tmp
= get_parameter_value(argv
[1], "space=");
918 if (strcasecmp(tmp
, "ignore") == 0)
919 mysql
->flags
|= CLIENT_IGNORE_SPACE
;
924 /* multithreaded build can have multiple DB connections */
925 tmp
= get_parameter_value(argv
[1], "threads=");
929 dbcount
= strtol(tmp
, &endp
, 10);
930 if (*endp
!= '\0' || dbcount
< 1) {
931 mysql
->log(ISC_LOG_ERROR
,
932 "MySQL database connection count "
933 "must be positive.");
935 result
= ISC_R_FAILURE
;
941 /* allocate memory for database connection list */
942 mysql
->db
= calloc(1, sizeof(db_list_t
));
943 if (mysql
->db
== NULL
) {
944 result
= ISC_R_NOMEMORY
;
948 /* initialize DB connection list */
949 DLZ_LIST_INIT(*(mysql
->db
));
952 * create the appropriate number of database instances (DBI)
953 * append each new DBI to the end of the list
955 for (i
= 0; i
< dbcount
; i
++) {
956 #endif /* PTHREADS */
959 result
= build_dbinstance(NULL
, NULL
, NULL
,
960 argv
[2], argv
[3], NULL
,
964 result
= build_dbinstance(NULL
, NULL
, argv
[4],
965 argv
[2], argv
[3], NULL
,
969 result
= build_dbinstance(argv
[5], NULL
, argv
[4],
970 argv
[2], argv
[3], NULL
,
974 result
= build_dbinstance(argv
[5], argv
[6], argv
[4],
975 argv
[2], argv
[3], NULL
,
979 result
= build_dbinstance(argv
[5], argv
[6], argv
[4],
980 argv
[2], argv
[3], argv
[7],
984 result
= ISC_R_FAILURE
;
988 if (result
!= ISC_R_SUCCESS
) {
989 mysql
->log(ISC_LOG_ERROR
,
990 "MySQL module could not create "
991 "database instance object.");
992 result
= ISC_R_FAILURE
;
997 /* when multithreaded, build a list of DBI's */
998 DLZ_LINK_INIT(dbi
, link
);
999 DLZ_LIST_APPEND(*(mysql
->db
), dbi
, link
);
1002 * when single threaded, hold onto the one connection
1008 /* create and set db connection */
1009 dbi
->dbconn
= mysql_init(NULL
);
1010 if (dbi
->dbconn
== NULL
) {
1011 mysql
->log(ISC_LOG_ERROR
,
1012 "MySQL module could not allocate "
1013 "memory for database connection");
1014 result
= ISC_R_FAILURE
;
1020 #if MYSQL_VERSION_ID >= 50000
1021 /* enable automatic reconnection. */
1022 if (mysql_options((MYSQL
*) dbi
->dbconn
, MYSQL_OPT_RECONNECT
,
1023 &auto_reconnect
) != 0) {
1024 mysql
->log(ISC_LOG_WARNING
,
1025 "MySQL module failed to set "
1026 "MYSQL_OPT_RECONNECT option, continuing");
1030 for (j
= 0; dbc
== NULL
&& j
< 4; j
++) {
1031 dbc
= mysql_real_connect((MYSQL
*) dbi
->dbconn
,
1032 mysql
->host
, mysql
->user
,
1033 mysql
->pass
, mysql
->dbname
,
1034 mysql
->port
, mysql
->socket
,
1037 mysql
->log(ISC_LOG_ERROR
,
1038 "MySQL connection failed: %s",
1039 mysql_error((MYSQL
*) dbi
->dbconn
));
1043 mysql
->log(ISC_LOG_ERROR
,
1044 "MySQL module failed to create "
1045 "database connection after 4 attempts");
1046 result
= ISC_R_FAILURE
;
1051 /* set DBI = null for next loop through. */
1054 #endif /* PTHREADS */
1058 return (ISC_R_SUCCESS
);
1067 * Destroy the module.
1070 dlz_destroy(void *dbdata
) {
1071 mysql_instance_t
*db
= (mysql_instance_t
*)dbdata
;
1073 /* cleanup the list of DBI's */
1075 mysql_destroy_dblist((db_list_t
*)(db
->db
));
1076 #else /* PTHREADS */
1078 #endif /* PTHREADS */
1080 if (db
->dbname
!= NULL
)
1082 if (db
->host
!= NULL
)
1084 if (db
->user
!= NULL
)
1086 if (db
->pass
!= NULL
)
1088 if (db
->socket
!= NULL
)
1093 * Return the version of the API
1096 dlz_version(unsigned int *flags
) {
1097 *flags
|= (DNS_SDLZFLAG_RELATIVEOWNER
|
1098 DNS_SDLZFLAG_RELATIVERDATA
|
1099 DNS_SDLZFLAG_THREADSAFE
);
1100 return (DLZ_DLOPEN_VERSION
);
1104 * Register a helper function from the bind9 dlz_dlopen driver
1107 b9_add_helper(mysql_instance_t
*db
, const char *helper_name
, void *ptr
) {
1108 if (strcmp(helper_name
, "log") == 0)
1109 db
->log
= (log_t
*)ptr
;
1110 if (strcmp(helper_name
, "putrr") == 0)
1111 db
->putrr
= (dns_sdlz_putrr_t
*)ptr
;
1112 if (strcmp(helper_name
, "putnamedrr") == 0)
1113 db
->putnamedrr
= (dns_sdlz_putnamedrr_t
*)ptr
;
1114 if (strcmp(helper_name
, "writeable_zone") == 0)
1115 db
->writeable_zone
= (dns_dlz_writeablezone_t
*)ptr
;