libopendbx1-dev
libopendbx1-sqlite3
libp11-kit-dev
+ libsqliteodbc
libtolua-dev
libtool
libyaml-cpp-dev
softhsm
time
unbound-host
+ unixodbc-dev
xmlto
- virtualenv $HOME/.venv
- source $HOME/.venv/bin/activate
- sudo chmod 0644 /etc/softhsm/softhsm.conf
- sudo chmod 0777 /var/lib/softhsm
- p11-kit -l # ensure it's ok
+ - echo -e "[pdns-sqlite3-1]\nDriver = SQLite3\nDatabase = ${PWD}/regression-tests/pdns.sqlite3\n\n[pdns-sqlite3-2]\nDriver = SQLite3\nDatabase = ${PWD}/regression-tests/pdns.sqlite32\n" > ${HOME}/.odbc.ini
script:
- ./bootstrap
#Build without --enable-botan1.10 option, Botan/SoftHSM conflict #2496
- source $HOME/.venv/bin/activate
- ./configure
- --with-dynmodules='bind gmysql geoip gpgsql gsqlite3 mydns tinydns pipe remote random opendbx ldap lua'
+ --with-dynmodules='bind gmysql geoip godbc gpgsql gsqlite3 mydns tinydns pipe remote random opendbx ldap lua'
--with-modules=''
--with-sqlite3
--enable-unit-tests
- ./timestamp ./start-test-stop 5300 gsqlite3-nsec3-narrow
- ./timestamp ./start-test-stop 5300 mydns
- ./timestamp ./start-test-stop 5300 opendbx-sqlite3
+ - GODBC_SQLITE3_DSN=pdns-sqlite3-1 ./timestamp ./start-test-stop 5300 godbc_sqlite3-nsec3
- travis_retry ./timestamp timeout 120s ./start-test-stop 5300 remotebackend-pipe
- travis_retry ./timestamp timeout 120s ./start-test-stop 5300 remotebackend-pipe-dnssec
- travis_retry ./timestamp timeout 120s ./start-test-stop 5300 remotebackend-unix
%description backend-postgresql
This package contains the gpgsql backend for %{name}
+%package backend-odbc
+Summary: UnixODBC backend for %{name}
+Group: System Environment/Daemons
+Requires: %{name}%{?_isa} = %{version}-%{release}
+BuildRequires: unixodbc-devel
+%global backends %{backends} godbc
+
+%description backend-odbc
+This package contains the godbc backend for %{name}
+
%package backend-pipe
Summary: Pipe backend for %{name}
Group: System Environment/Daemons
%doc modules/gpgsqlbackend/nodnssec-3.x_to_3.4.0_schema.pgsql.sql
%{_libdir}/%{name}/libgpgsqlbackend.so
+%files backend-odbc
+%doc modules/godbcbackend/schema.mssql.sql
+%{_libdir}/%{name}/libgodbcbackend.so
+
%files backend-pipe
%{_libdir}/%{name}/libpipebackend.so
--- /dev/null
+# godbc Configuration
+#
+# Uncomment to launch the godbc backend
+#launch+=godbc
+
+#################################
+# godbc-datasource Datasource (DSN) to use
+#
+# godbc-datasource=PowerDNS
+
+#################################
+# godbc-username User to connect as
+#
+# godbc-username=powerdns
+
+#################################
+# godbc-password Password to connect with
+#
+# godbc-password=
Standards-Version: 3.9.6
Maintainer: PowerDNS Autobuilder <powerdns.support@powerdns.com>
Origin: PowerDNS
-Build-Depends: debhelper (>= 9~), dh-autoreconf, dh-systemd, po-debconf, libtool, flex, bison, libmysqlclient-dev, libpq-dev, libssl-dev, libpolarssl-dev, libgdbm-dev, libldap2-dev, libsqlite3-dev, dpkg-dev (>= 1.17.0~), libboost-dev, libboost-serialization-dev, libboost-program-options-dev, libboost-test-dev, autotools-dev, automake, autoconf, liblua5.2-dev, pkg-config, libcrypto++-dev, ragel, libgmp-dev, libbotan1.10-dev, libcurl4-openssl-dev, libzmq-dev, libyaml-cpp-dev (>= 0.5), libgeoip-dev, libopendbx1-dev, libcdb-dev
+Build-Depends: debhelper (>= 9~), dh-autoreconf, dh-systemd, po-debconf, libtool, flex, bison, libmysqlclient-dev, libpq-dev, libssl-dev, libpolarssl-dev, libgdbm-dev, libldap2-dev, libsqlite3-dev, dpkg-dev (>= 1.17.0~), libboost-dev, libboost-serialization-dev, libboost-program-options-dev, libboost-test-dev, autotools-dev, automake, autoconf, liblua5.2-dev, pkg-config, libcrypto++-dev, ragel, libgmp-dev, libbotan1.10-dev, libcurl4-openssl-dev, libzmq-dev, libyaml-cpp-dev (>= 0.5), libgeoip-dev, libopendbx1-dev, libcdb-dev, unixodbc-dev (>= 2.3.1)
Homepage: http://www.powerdns.com/
Package: pdns-server
This package contains a generic MySQL backend for the PowerDNS
nameserver. It has configurable SQL statements.
+Package: pdns-backend-odbc
+Architecture: any
+Depends: pdns-server (>= ${source:Version}), ucf (>= 0.28), ${shlibs:Depends}, ${misc:Depends}
+Provides: pdns-backend
+Description: generic UnixODBC backend for PowerDNS
+ PowerDNS is a versatile nameserver which supports a large number
+ of different backends ranging from simple zonefiles to relational
+ databases and load balancing/failover algorithms.
+ PowerDNS tries to emphasize speed and security.
+ .
+ This package contains a generic UnixODBC backend for the PowerDNS
+ nameserver. It has configurable SQL statements.
+
Package: pdns-backend-pgsql
Architecture: any
Depends: pdns-server (>= ${source:Version}), ucf (>= 0.28), ${shlibs:Depends}, ${misc:Depends}
--- /dev/null
+modules/godbcbackend/schema.mssql.sql
--- /dev/null
+usr/lib/*/pdns/libgodbcbackend.so*
+debian/config/pdns.local.godbc.conf usr/share/pdns-backend-godbc
--- /dev/null
+#!/bin/sh
+#
+# postinst script for pdns-backend-mysql
+
+set -e
+
+if [ -n "$PDNSDEBUG" ]; then
+ echo "now debugging $0 $@"
+ set -x
+fi
+
+PKGNAME="pdns-backend-odbc"
+
+# rename ucf-conffile. This was mostly stolen from cacti.postinst after
+# a short discussion on debian-mentors, see
+# http://lists.debian.org/debian-mentors/2013/07/msg00027.html
+# and the following thread. Thanks to Paul Gevers
+renameconffile() {
+ oldname="$1"
+ newname="$2"
+ sourcefile="$3"
+ if [ -f $oldname ] ; then
+ if [ ! -e $newname ] ; then
+ mv $oldname $newname
+# else: Don't do anything, leave old file in place
+ fi
+ ucf --purge $oldname
+ ucfr --purge $PKGNAME $oldname
+ elif [ ! -e $newname ] ; then
+# The file was removed, we should respect that. Unfortunately, we don't
+# have a proper way to tell ucf that for the new location, so we need
+# to hack it a bit.
+# We only need to do this if the target does not already exist. If the
+# target already exists, we can later call ucf straight as there
+# is already a version of the file available, althought never
+# provided by this package, but we can just propose the new file anyway.
+ ucf --debconf-ok $sourcefile $newname
+ ucfr $PKGNAME $newname
+ rm -f $newname
+ fi
+}
+
+# Activate trigger
+dpkg-trigger pdns-server
+
+ucfr $PKGNAME /etc/powerdns/pdns.d/pdns.local.godbc.conf
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
+
--- /dev/null
+#!/bin/sh
+#
+# Post removal
+
+set -e
+
+if [ -n "$PDNSDEBUG" ]; then
+ echo "now debugging $0 $@"
+ set -x
+fi
+
+PKGNAME="pdns-backend-odbc"
+
+# Remove configuration file
+if [ "$1" = "purge" ]; then
+ # Remove files registered with ucf.
+ # this has been pulled from aide-common.postrm
+
+ UCF="ucf"
+ UCFR="ucfr"
+
+ if command -v ucfq >/dev/null; then
+ for file in $(ucfq --with-colons "$PKGNAME" | cut --delimiter=: --fields=1); do
+ for ext in '~' '%' .bak .dpkg-tmp .dpkg-new .dpkg-old .dpkg-dist; do
+ rm -f ${file}$ext
+ done
+ rm -f ${file}
+
+ if command -v $UCF >/dev/null; then
+ $UCF --purge ${file}
+ fi
+ if command -v $UCFR >/dev/null; then
+ $UCFR --purge $PKGNAME ${file}
+ fi
+ done
+ else
+ echo >&2 "ucf no longer installed, not cleaning up"
+ fi
+fi
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
+
--- /dev/null
+#!/bin/sh
+#
+# Pre removal
+
+set -e
+
+# Stop pdns.
+if [ -x "/etc/init.d/pdns" ]; then
+ invoke-rc.d pdns stop || exit $?
+fi
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
+
CXXFLAGS += -DPACKAGEVERSION='"$(version)"'
# Backends
-backends := bind ldap pipe gmysql gpgsql gsqlite3 geoip lua mydns remote random opendbx tinydns
+backends := bind ldap pipe gmysql godbc gpgsql gsqlite3 geoip lua mydns remote random opendbx tinydns
DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
#!/bin/sh
set -x
-[ -n "$1" ] && exit 0 # avoid running the whole suite on specifically targeted builders
+context=''
+# poor mans option parsing
+if [ -n "$1" ]; then
+ if [ "$1" != "odbc" ]; then
+ echo "invalid argument"
+ exit 1
+ fi
+ context=odbc
+ if [ -n "$2" ]; then
+ echo "too many arguments"
+ exit 1
+ fi
+fi
+
export PDNS=/usr/sbin/pdns_server
export PDNS2=$PDNS
export SDIG=/usr/bin/sdig
mkdir -p $GEM_HOME
export PATH="${GEM_HOME}/bin:$PATH"
-cd modules/remotebackend
-ruby -S bundle install
-cd ../../
+if [ -z "$context"]; then
+ cd modules/remotebackend
+ ruby -S bundle install
+ cd ../../
+fi
MODULES=""
EXITCODE=0
-export geoipregion=oc geoipregionip=1.2.3.4
-./timestamp ./start-test-stop 5300 bind-both || EXITCODE=1
-./timestamp ./start-test-stop 5300 bind-dnssec-both || EXITCODE=1
-
-# No PKCS#11 in packages
-#SETUP_SOFTHSM=y ./timestamp ./start-test-stop 5300 bind-dnssec-pkcs11 || EXITCODE=1
-./timestamp ./start-test-stop 5300 bind-dnssec-nsec3-both || EXITCODE=1
-./timestamp ./start-test-stop 5300 bind-dnssec-nsec3-optout-both || EXITCODE=1
-./timestamp ./start-test-stop 5300 bind-dnssec-nsec3-narrow || EXITCODE=1
-./timestamp ./start-test-stop 5300 bind-hybrid-nsec3 || EXITCODE=1
-
-# Adding extra IPs to docker containers in not supported :(
-#./timestamp ./start-test-stop 5300 geoipbackend || EXITCODE=1
-#./timestamp ./start-test-stop 5300 geoipbackend-nsec3-narrow || EXITCODE=1
-
-./timestamp ./start-test-stop 5300 gmysql-nodnssec-both || EXITCODE=1
-./timestamp ./start-test-stop 5300 gmysql-both || EXITCODE=1
-./timestamp ./start-test-stop 5300 gmysql-nsec3-both || EXITCODE=1
-./timestamp ./start-test-stop 5300 gmysql-nsec3-optout-both || EXITCODE=1
-./timestamp ./start-test-stop 5300 gmysql-nsec3-narrow || EXITCODE=1
-
-./timestamp ./start-test-stop 5300 gpgsql-nodnssec-both || EXITCODE=1
-./timestamp ./start-test-stop 5300 gpgsql-both || EXITCODE=1
-./timestamp ./start-test-stop 5300 gpgsql-nsec3-both || EXITCODE=1
-./timestamp ./start-test-stop 5300 gpgsql-nsec3-optout-both || EXITCODE=1
-./timestamp ./start-test-stop 5300 gpgsql-nsec3-narrow || EXITCODE=1
-
-./timestamp ./start-test-stop 5300 gsqlite3-nodnssec-both || EXITCODE=1
-./timestamp ./start-test-stop 5300 gsqlite3-both || EXITCODE=1
-./timestamp ./start-test-stop 5300 gsqlite3-nsec3-both || EXITCODE=1
-./timestamp ./start-test-stop 5300 gsqlite3-nsec3-optout-both || EXITCODE=1
-./timestamp ./start-test-stop 5300 gsqlite3-nsec3-narrow || EXITCODE=1
-
-./timestamp ./start-test-stop 5300 mydns || EXITCODE=1
-
-./timestamp ./start-test-stop 5300 opendbx-sqlite3 || EXITCODE=1
-
-./timestamp timeout 120s ./start-test-stop 5300 remotebackend-pipe || EXITCODE=1
-./timestamp timeout 120s ./start-test-stop 5300 remotebackend-pipe-dnssec || EXITCODE=1
-./timestamp timeout 120s ./start-test-stop 5300 remotebackend-unix || EXITCODE=1
-./timestamp timeout 120s ./start-test-stop 5300 remotebackend-unix-dnssec || EXITCODE=1
-./timestamp timeout 120s ./start-test-stop 5300 remotebackend-http || EXITCODE=1
-./timestamp timeout 120s ./start-test-stop 5300 remotebackend-http-dnssec || EXITCODE=1
-
-
-# No 0MQ in the PowerDNS packages
-#./timestamp timeout 120s ./start-test-stop 5300 remotebackend-zeromq || EXITCODE=1
-#./timestamp timeout 120s ./start-test-stop 5300 remotebackend-zeromq-dnssec || EXITCODE=1
-
-./timestamp ./start-test-stop 5300 tinydns || EXITCODE=1
-
-cd ../regression-tests.nobackend/
-
-# The package builds define other dirs, so the distconf test fails, so skip it
-touch pdnsconfdist/skip
-
-./runtests || EXITCODE=1
+if [ -z "$context" ]; then
+ export geoipregion=oc geoipregionip=1.2.3.4
+ ./timestamp ./start-test-stop 5300 bind-both || EXITCODE=1
+ ./timestamp ./start-test-stop 5300 bind-dnssec-both || EXITCODE=1
+
+ # No PKCS#11 in packages
+ #SETUP_SOFTHSM=y ./timestamp ./start-test-stop 5300 bind-dnssec-pkcs11 || EXITCODE=1
+ ./timestamp ./start-test-stop 5300 bind-dnssec-nsec3-both || EXITCODE=1
+ ./timestamp ./start-test-stop 5300 bind-dnssec-nsec3-optout-both || EXITCODE=1
+ ./timestamp ./start-test-stop 5300 bind-dnssec-nsec3-narrow || EXITCODE=1
+ ./timestamp ./start-test-stop 5300 bind-hybrid-nsec3 || EXITCODE=1
+
+ # Adding extra IPs to docker containers in not supported :(
+ #./timestamp ./start-test-stop 5300 geoipbackend || EXITCODE=1
+ #./timestamp ./start-test-stop 5300 geoipbackend-nsec3-narrow || EXITCODE=1
+
+ ./timestamp ./start-test-stop 5300 gmysql-nodnssec-both || EXITCODE=1
+ ./timestamp ./start-test-stop 5300 gmysql-both || EXITCODE=1
+ ./timestamp ./start-test-stop 5300 gmysql-nsec3-both || EXITCODE=1
+ ./timestamp ./start-test-stop 5300 gmysql-nsec3-optout-both || EXITCODE=1
+ ./timestamp ./start-test-stop 5300 gmysql-nsec3-narrow || EXITCODE=1
+
+ ./timestamp ./start-test-stop 5300 gpgsql-nodnssec-both || EXITCODE=1
+ ./timestamp ./start-test-stop 5300 gpgsql-both || EXITCODE=1
+ ./timestamp ./start-test-stop 5300 gpgsql-nsec3-both || EXITCODE=1
+ ./timestamp ./start-test-stop 5300 gpgsql-nsec3-optout-both || EXITCODE=1
+ ./timestamp ./start-test-stop 5300 gpgsql-nsec3-narrow || EXITCODE=1
+
+ ./timestamp ./start-test-stop 5300 gsqlite3-nodnssec-both || EXITCODE=1
+ ./timestamp ./start-test-stop 5300 gsqlite3-both || EXITCODE=1
+ ./timestamp ./start-test-stop 5300 gsqlite3-nsec3-both || EXITCODE=1
+ ./timestamp ./start-test-stop 5300 gsqlite3-nsec3-optout-both || EXITCODE=1
+ ./timestamp ./start-test-stop 5300 gsqlite3-nsec3-narrow || EXITCODE=1
+
+ ./timestamp ./start-test-stop 5300 mydns || EXITCODE=1
+
+ ./timestamp ./start-test-stop 5300 opendbx-sqlite3 || EXITCODE=1
+
+ ./timestamp timeout 120s ./start-test-stop 5300 remotebackend-pipe || EXITCODE=1
+ ./timestamp timeout 120s ./start-test-stop 5300 remotebackend-pipe-dnssec || EXITCODE=1
+ ./timestamp timeout 120s ./start-test-stop 5300 remotebackend-unix || EXITCODE=1
+ ./timestamp timeout 120s ./start-test-stop 5300 remotebackend-unix-dnssec || EXITCODE=1
+ ./timestamp timeout 120s ./start-test-stop 5300 remotebackend-http || EXITCODE=1
+ ./timestamp timeout 120s ./start-test-stop 5300 remotebackend-http-dnssec || EXITCODE=1
+
+
+ # No 0MQ in the PowerDNS packages
+ #./timestamp timeout 120s ./start-test-stop 5300 remotebackend-zeromq || EXITCODE=1
+ #./timestamp timeout 120s ./start-test-stop 5300 remotebackend-zeromq-dnssec || EXITCODE=1
+
+ ./timestamp ./start-test-stop 5300 tinydns || EXITCODE=1
+
+ cd ../regression-tests.nobackend/
+
+ # The package builds define other dirs, so the distconf test fails, so skip it
+ touch pdnsconfdist/skip
+
+ ./runtests || EXITCODE=1
+elif [ "$context" = "odbc" ]; then
+ cat > ~/.odbc.ini << __EOF__
+[pdns-sqlite3-1]
+Driver = SQLite3
+Database = $(pwd)/pdns.sqlite3
+
+[pdns-sqlite3-2]
+Driver = SQLite3
+Database = $(pwd)/pdns.sqlite32
+
+[pdns-mssql]
+Driver=FreeTDS
+Trace=No
+Server=pdns-odbc-regress-sql-1.database.windows.net
+Port=1433
+Database=pdns
+TDS_Version=7.1
+ClientCharset=UTF-8
+__EOF__
+
+ set +x
+ . ~/.mssql-credentials
+ set -x
+ export GODBC_SQLITE3_DSN=pdns-sqlite3-1
+ ./timestamp timeout 120s ./start-test-stop 5300 godbc_sqlite3-nodnssec || EXITCODE=1
+ export GODBC_MSSQL_DSN=pdns-mssql
+ export GODBC_MSSQL_USERNAME
+ export GODBC_MSSQL_PASSWORD
+ ./timestamp timeout 3600s ./start-test-stop 5300 godbc_mssql-nodnssec || EXITCODE=1
+ ./timestamp timeout 3600s ./start-test-stop 5300 godbc_mssql || EXITCODE=1
+ ./timestamp timeout 3600s ./start-test-stop 5300 godbc_mssql-nsec3 || EXITCODE=1
+ ./timestamp timeout 3600s ./start-test-stop 5300 godbc_mssql-nsec3-optout || EXITCODE=1
+ ./timestamp timeout 3600s ./start-test-stop 5300 godbc_mssql-nsec3-narrow || EXITCODE=1
+fi
exit $EXITCODE
PDNS_WITH_ORACLE
needoracle=yes
;;
+ godbc)
+ PDNS_WITH_UNIXODBC
+ ;;
mydns|gmysql|pdns)
PDNS_WITH_MYSQL
;;
modules/bindbackend/Makefile
modules/geoipbackend/Makefile
modules/gmysqlbackend/Makefile
+ modules/godbcbackend/Makefile
modules/goraclebackend/Makefile
modules/gpgsqlbackend/Makefile
modules/gsqlite3backend/Makefile
--- /dev/null
+# Generic ODBC Backend
+| | |
+|:--|:--|
+|Native|Yes|
+|Master|Yes|
+|Slave|Yes|
+|Superslave|Yes|
+|Autoserial|Yes|
+|Case|All lower|
+|DNSSEC|Yes|
+|Disabled data|Yes|
+|Comments|Yes|
+|Module name|godbc|
+|Launch name|godbc|
+
+The Generic ODBC Backend (godbc) is a child of the Generic SQL (gsql) backend,
+similar to the gmysql and gpgsql backends. It uses [UnixODBC](http://www.unixodbc.org/)
+and installed drivers to connect to the databases supported by said drivers.
+
+**Warning**: When there is a more specific generic sql backend (like goracle or
+gmysql), it is highly recommended to use that backend instead!
+
+# Enabling the backend
+When building PowerDNS yourself, append `godbc` to `--with-modules` or
+`--with-dynmodules`. It is expected that most pre-built packages contain this
+backend or be separately installable.
+
+# Configuration Parameters
+This section only details the configuration of PowerDNS for use with ODBC. For
+ODBC related configuration, please see UnixODBC website/documentation and the
+documentation for the driver you intend to use.
+
+## `godbc-datasource`
+
+* String
+* Default: PowerDNS
+
+The datasource (DSN) to use. This must be configured in the `odbc.ini` file,
+usually found in `/etc/`, but this depends your local setup.
+
+## `godbc-username`
+
+* String
+* Default: powerdns
+
+The user to connect to the datasource.
+
+## `godbc-password`
+
+* String
+* Default is empty
+
+The password to connect with the datasource.
+
+# Connecting to Microsoft SQL Server
+**note**: In order to connect to Microsoft SQL Server, you will need at least
+version 3.2.0 of UnixODBC. FreeDTS has been tested with versions 0.91 and 0.95.
+
+Install the [FreeTDS](http://www.freetds.org/) driver for UnixODBC, either by
+compiling or getting it from our distribution's repository and configure your
+`/etc/odbcinst.ini` with the driver, e.g.:
+
+```
+[FreeTDS]
+Description=v0.95.8 with protocol v7.1
+Driver=/usr/local/lib/libtdsodbc.so
+UsageCount=1
+```
+
+And add the datasource to your `/etc/odbc.ini`, e.g:
+```
+[pdns1]
+Driver=FreeTDS
+Trace=No
+Server=server.example.net
+Port=1433
+Database=pdns-1
+TDS_Version=7.1
+```
+
+(For our tests, we add `ClientCharset=UTF-8` as well. YMMV.)
+
+You can now test the connection with `isql pdns1 USERNAME PASSWORD`.
+
+## Loading the schema into the database
+For convenience, a schema for MS SQL Server has been created:
+(Note: This schema can also be found in the PowerDNS source as
+ `modules/godbcbackend/schema.mssql.sql`).
+
+```
+!!include=../modules/godbcbackend/schema.mssql.sql
+```
+
+Load this into the database as follows:
+`cat schema.mssql.sql | tr '\n' ' ' | isql pdns1 USERNAME PASSWORD -b`.
+
+## Loading records into the database
+Loading records is the same as with any SQL backend, just add them
+using SQL-queries. Should you want to use [`zone2sql`](migration.md#zone2sql),
+use the `--sqlite` option for correctly formatted SQL.
+
+## Configuring PowerDNS
+Add the options required to your `pdns.conf`:
+
+```
+launch=godbc
+godbc-datasource=pdns1
+godbc-username=USERNAME
+godbc-password=PASSWORD
+```
+
+Now restart PowerDNS and you're done. Just don't forget to add zones and
+records to the database.
+
+## Possible issues
+It might be that you need to compile FreeTDS with the `--tds-version=7.1` to
+connect to SQL Server.
+
+When connecting to a database hosted with Microsoft Azure, FreeTDS must be
+compiled with OpenSSL, use the `--with-openssl` configure flag.
| [LDAP](backend-ldap.md) | Unmaintained | Yes | No | No | No | No | No | Unknown (No) | Unknown (No) | Unknown |
| [MySQL](backend-generic-mypgsql.md) | Supported | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | `gmysql` |
| [MyDNS](backend-mydns.md) | Supported | Yes | No | No | No | No | No | No | No | `mydns` |
+| [ODBC](backend-godbc.md) | Supported | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes| `godbc` |
| [OpenDBX](backend-opendbx.md) | Supported | Yes | Yes | Yes | Yes | Unknown (No) | No | Unknown (No) | Unknown (No) | `opendbx` |
| [Oracle](backend-oracle.md) | Supported | Yes | Yes | Yes | Yes | Yes | Yes | Unknown (No) | No | `oracle` |
| [Pipe](backend-pipe.md) | Supported | Yes | No | No | No | No | Partial (no delegation, no key storage) | No | No | `pipe` |
- Authoritative Backends:
- BIND: authoritative/backend-bind.md
- Generic MySQL and PostgreSQL: authoritative/backend-generic-mypgsql.md
+ - Generic ODBC: authoritative/backend-godbc.md
- GeoIP: authoritative/backend-geoip.md
- Generic SQLite: authoritative/backend-gsqlite.md
- MyDNS: authoritative/backend-mydns.md
--- /dev/null
+AC_DEFUN([PDNS_WITH_UNIXODBC],[
+ AC_ARG_WITH([unixodbc],
+ [AS_HELP_STRING([--with-unixodbc=<path>], [root directory path of unixODBC installation])],
+ [
+ UNIXODBC_LIBS_check="$withval/lib/unixodbc $with_unixodbc/lib"
+ UNIXODBC_CFLAGS_check="$withval/include/unixodbc"
+ UNIXODBC_config_check="$withval/bin/odbc_config"
+ ],
+ [
+ UNIXODBC_LIBS_check="/usr/local/unixodbc/lib/unixodbc /usr/local/lib/unixodbc /opt/unixodbc/lib/unixodbc \
+ /usr/lib/unixodbc /usr/lib64/unixodbc /usr/local/unixodbc/lib /usr/local/lib /opt/unixodbc/lib /usr/lib \
+ /usr/sfw/lib/ /usr/lib/odbc /usr/lib/x86_64-linux-gnu $full_libdir"
+ UNIXODBC_CFLAGS_check="/usr/local/unixodbc/include/unixodbc /usr/local/include/unixodbc \
+ /opt/unixodbc/include/unixodbc /opt/unixodbc/include /usr/include/unixodbc /usr/sfw/include/unixodbc \
+ /usr/include /usr/local/include"
+ ]
+ )
+
+ AC_ARG_WITH([odbc-config],
+ [AS_HELP_STRING([--with-odbc-config=<path>], [file path to odbc_config])],
+ [UNIXODBC_config_check=$withval]
+ )
+
+ AC_ARG_WITH([unixodbc-lib],
+ [AS_HELP_STRING([--with-unixodbc-lib=<path>], [directory path of unixODBC library installation])],
+ [
+ UNIXODBC_LIBS_check="$withval/lib/unixodbc $withval/unixodbc $withval"
+ UNIXODBC_config_check="skip"
+ ]
+ )
+
+ AC_ARG_WITH([unixodbc-includes],
+ [AS_HELP_STRING([--with-unixodbc-includes=<path>], [directory path of unixODBC header installation])],
+ [
+ UNIXODBC_CFLAGS_check="$withval/include/unixodbc $withval/unixodbc $withval"
+ UNIXODBC_config_check="skip"
+ ]
+ )
+
+ UNIXODBC_config=""
+ if test "x$UNIXODBC_config_check" != "xskip"; then
+ if test "x$UNIXODBC_config_check" = "x"; then
+ AC_PATH_PROG([UNIXODBC_config], [odbc_config])
+ else
+ AC_MSG_CHECKING([for $UNIXODBC_config_check])
+ if test -x $UNIXODBC_config_check; then
+ UNIXODBC_config="$UNIXODBC_config_check"
+ AC_MSG_RESULT([yes])
+ else
+ UNIXODBC_config=""
+ AC_MSG_ERROR([not found])
+ fi
+ fi
+ fi
+
+ if test "x$UNIXODBC_config" != "x"; then
+ # use this to configure everything
+ UNIXODBC_LIBS=`$UNIXODBC_config --libs`
+ UNIXODBC_CFLAGS=-I`$UNIXODBC_config --include-prefix`
+ else
+ AC_MSG_CHECKING([for unixODBC library directory])
+ UNIXODBC_libdir=
+ for m in $UNIXODBC_LIBS_check; do
+ if test -d "$m" && \
+ (test -f "$m/libodbc.so" || test -f "$m/libodbc.a")
+ then
+ UNIXODBC_libdir=$m
+ break
+ fi
+ done
+ if test -z "$UNIXODBC_libdir"; then
+ AC_MSG_ERROR([Did not find the unixodbc library dir in '$UNIXODBC_LIBS_check'])
+ fi
+ case "$UNIXODBC_libdir" in
+ /*) UNIXODBC_LIBS="-L$UNIXODBC_libdir -lodbc"
+ ;;
+ *) AC_MSG_ERROR([The unixODBC library directory ($UNIXODBC_libdir) must be an absolute path.])
+ ;;
+ esac
+ AC_MSG_RESULT([$UNIXODBC_libdir])
+
+ AC_MSG_CHECKING([for unixODBC include directory])
+ UNIXODBC_CFLAGS=
+ for m in $UNIXODBC_CFLAGS_check; do
+ if test -d "$m" && test -f "$m/sql.h"
+ then
+ UNIXODBC_CFLAGS="$m"
+ break
+ fi
+ done
+ if test -z "$UNIXODBC_CFLAGS"; then
+ AC_MSG_ERROR([Did not find the unixodbc include dir in '$UNIXODBC_CFLAGS_check'])
+ fi
+
+ case "$UNIXODBC_CFLAGS" in
+ /*) AC_MSG_RESULT($UNIXODBC_CFLAGS)
+ ;;
+ *) AC_MSG_ERROR([The unixODBC include directory ($UNIXODBC_CFLAGS) must be an absolute path.])
+ ;;
+ esac
+ UNIXODBC_CFLAGS="-I$UNIXODBC_CFLAGS"
+ fi
+
+ AC_SUBST(UNIXODBC_CFLAGS)
+ AC_SUBST(UNIXODBC_LIBS)
+])
bindbackend \
geoipbackend \
gmysqlbackend \
+ godbcbackend \
goraclebackend \
gpgsqlbackend \
gsqlite3backend \
--- /dev/null
+AM_CPPFLAGS += $(UNIXODBC_CFLAGS)
+pkglib_LTLIBRARIES = libgodbcbackend.la
+
+EXTRA_DIST=OBJECTFILES OBJECTLIBS
+
+dist_doc_DATA=schema.mssql.sql
+
+libgodbcbackend_la_SOURCES=godbcbackend.cc godbcbackend.hh \
+ sodbc.hh sodbc.cc
+
+libgodbcbackend_la_LDFLAGS=-module -avoid-version
+libgodbcbackend_la_LIBADD=$(UNIXODBC_LIBS)
--- /dev/null
+godbcbackend.lo sodbc.lo
\ No newline at end of file
--- /dev/null
+-lodbc
\ No newline at end of file
--- /dev/null
+// The Generic ODBC Backend
+// By Michel Stol <michel@powerdns.com>
+
+#include "pdns/utility.hh"
+#include <map>
+#include <sstream>
+#include <string>
+
+#include "pdns/dns.hh"
+#include "pdns/dnsbackend.hh"
+#include "pdns/dnspacket.hh"
+#include "pdns/ueberbackend.hh"
+#include "pdns/pdnsexception.hh"
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+#include "sodbc.hh"
+#include "godbcbackend.hh"
+
+
+// Connects to the database.
+gODBCBackend::gODBCBackend (const std::string & mode, const std::string & suffix) : GSQLBackend( mode, suffix )
+{
+ try
+ {
+ setDB( new SODBC( getArg( "datasource" ), getArg( "username" ), getArg( "password" )));
+ }
+ catch( SSqlException & e )
+ {
+ L<<Logger::Error<< mode << " Connection failed: " << e.txtReason() << std::endl;
+ throw PDNSException( "Unable to launch " + mode + " connection: " + e.txtReason());
+ }
+
+ L << Logger::Warning << mode << " Connection successful" << std::endl;
+}
+
+
+//! Constructs a gODBCBackend
+class gODBCFactory : public BackendFactory
+{
+public:
+ //! Constructor.
+ gODBCFactory( const std::string & mode ) : BackendFactory( mode ), d_mode( mode )
+ {
+ }
+
+ //! Declares all needed arguments.
+ void declareArguments( const std::string & suffix = "" )
+ {
+ declare( suffix, "datasource", "Datasource (DSN) to use","PowerDNS");
+ declare( suffix, "username", "User to connect as","powerdns");
+ declare( suffix, "password", "Password to connect with","");
+ declare(suffix,"dnssec","Enable DNSSEC processing","no");
+
+ string record_query = "SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE";
+
+ declare(suffix, "basic-query", "Basic query", record_query+" disabled=0 and type=? and name=?");
+ declare(suffix, "id-query", "Basic with ID query", record_query+" disabled=0 and type=? and name=? and domain_id=?");
+ declare(suffix, "any-query", "Any query", record_query+" disabled=0 and name=?");
+ declare(suffix, "any-id-query", "Any with ID query", record_query+" disabled=0 and name=? and domain_id=?");
+
+ declare(suffix, "list-query", "AXFR query", record_query+" (disabled=0 OR disabled=?) and domain_id=? order by name, type");
+ declare(suffix, "list-subzone-query", "Subzone listing", record_query+" disabled=0 and (name=? OR name like ?) and domain_id=?");
+
+ declare(suffix, "remove-empty-non-terminals-from-zone-query", "remove all empty non-terminals from zone", "delete from records where domain_id=? and type is null");
+ declare(suffix, "insert-empty-non-terminal-query", "insert empty non-terminal in zone", "insert into records (domain_id,name,type,disabled,auth) values (?,?,null,0,1)");
+ declare(suffix, "delete-empty-non-terminal-query", "delete empty non-terminal from zone", "delete from records where domain_id=? and name=? and type is null");
+
+ declare(suffix,"master-zone-query","Data", "select master from domains where name=? and type='SLAVE'");
+
+ declare(suffix,"info-zone-query","","select id,name,master,last_check,notified_serial,type,account from domains where name=?");
+
+ declare(suffix,"info-all-slaves-query","","select id,name,master,last_check from domains where type='SLAVE'");
+ declare(suffix,"supermaster-query","", "select account from supermasters where ip=? and nameserver=?");
+ declare(suffix,"supermaster-name-to-ips", "", "select ip,account from supermasters where nameserver=? and account=?");
+
+ declare(suffix,"insert-zone-query","", "insert into domains (type,name) values('NATIVE',?)");
+ declare(suffix,"insert-slave-query","", "insert into domains (type,name,master,account) values('SLAVE',?,?,?)");
+
+ declare(suffix, "insert-record-query", "", "insert into records (content,ttl,prio,type,domain_id,disabled,name,auth) values (?,?,?,?,?,?,?,?)");
+ declare(suffix, "insert-record-order-query", "", "insert into records (content,ttl,prio,type,domain_id,disabled,name,ordername,auth) values (?,?,?,?,?,?,?,convert(varbinary(255),?),?)");
+ declare(suffix, "insert-ent-query", "insert empty non-terminal in zone", "insert into records (type,domain_id,disabled,name,auth) values (null,?,0,?,?)");
+ declare(suffix, "insert-ent-order-query", "insert empty non-terminal in zone", "insert into records (type,domain_id,disabled,name,ordername,auth) values (null,?,0,?,convert(varbinary(255),?),?)");
+
+ declare(suffix, "get-order-first-query", "DNSSEC Ordering Query, first", "select top 1 convert(varchar(255), ordername) from records where domain_id=? and disabled=0 and ordername is not null order by 1 asc");
+ declare(suffix, "get-order-before-query", "DNSSEC Ordering Query, before", "select top 1 convert(varchar(255), ordername), name from records where ordername <= convert(varbinary(255),?) and domain_id=? and disabled=0 and ordername is not null order by 1 desc");
+ declare(suffix, "get-order-after-query", "DNSSEC Ordering Query, after", "select convert(varchar(255), min(ordername)) from records where ordername > convert(varbinary(255),?) and domain_id=? and disabled=0 and ordername is not null");
+ declare(suffix, "get-order-last-query", "DNSSEC Ordering Query, last", "select top 1 convert(varchar(255), ordername), name from records where ordername != convert(varbinary(255),'') and domain_id=? and disabled=0 and ordername is not null order by 1 desc");
+
+ declare(suffix, "update-ordername-and-auth-query", "DNSSEC update ordername and auth for a qname query", "update records set ordername=convert(varbinary(255),?),auth=? where domain_id=? and name=? and disabled=0");
+ declare(suffix, "update-ordername-and-auth-type-query", "DNSSEC update ordername and auth for a rrset query", "update records set ordername=convert(varbinary(255),?),auth=? where domain_id=? and name=? and type=? and disabled=0");
+ declare(suffix, "nullify-ordername-and-update-auth-query", "DNSSEC nullify ordername and update auth for a qname query", "update records set ordername=NULL,auth=? where domain_id=? and name=? and disabled=0");
+ declare(suffix, "nullify-ordername-and-update-auth-type-query", "DNSSEC nullify ordername and update auth for a rrset query", "update records set ordername=NULL,auth=? where domain_id=? and name=? and type=? and disabled=0");
+
+ declare(suffix,"update-master-query","", "update domains set master=? where name=?");
+ declare(suffix,"update-kind-query","", "update domains set type=? where name=?");
+ declare(suffix,"update-account-query","", "update domains set account=? where name=?");
+ declare(suffix,"update-serial-query","", "update domains set notified_serial=? where id=?");
+ declare(suffix,"update-lastcheck-query","", "update domains set last_check=? where id=?");
+ declare(suffix,"zone-lastchange-query", "", "select max(change_date) from records where domain_id=?");
+ declare(suffix,"info-all-master-query","", "select id,name,master,last_check,notified_serial,type from domains where type='MASTER'");
+ declare(suffix,"delete-domain-query","", "delete from domains where name=?");
+ declare(suffix,"delete-zone-query","", "delete from records where domain_id=?");
+ declare(suffix,"delete-rrset-query","","delete from records where domain_id=? and name=? and type=?");
+ declare(suffix,"delete-names-query","","delete from records where domain_id=? and name=?");
+
+ declare(suffix,"add-domain-key-query","", "insert into cryptokeys (domain_id, flags, active, content) select id, ?, ?, ? from domains where name=?");
+ declare(suffix,"list-domain-keys-query","", "select cryptokeys.id, flags, active, content from domains, cryptokeys where cryptokeys.domain_id=domains.id and name=?");
+ declare(suffix,"get-all-domain-metadata-query","", "select kind,content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=?");
+ declare(suffix,"get-domain-metadata-query","", "select content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=? and domainmetadata.kind=?");
+ declare(suffix,"clear-domain-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name=?) and domainmetadata.kind=?");
+ declare(suffix,"clear-domain-all-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name=?)");
+ declare(suffix,"set-domain-metadata-query","", "insert into domainmetadata (domain_id, kind, content) select id, ?, ? from domains where name=?");
+ declare(suffix,"activate-domain-key-query","", "update cryptokeys set active=1 where domain_id=(select id from domains where name=?) and cryptokeys.id=?");
+ declare(suffix,"deactivate-domain-key-query","", "update cryptokeys set active=0 where domain_id=(select id from domains where name=?) and cryptokeys.id=?");
+ declare(suffix,"remove-domain-key-query","", "delete from cryptokeys where domain_id=(select id from domains where name=?) and cryptokeys.id=?");
+ declare(suffix,"clear-domain-all-keys-query","", "delete from cryptokeys where domain_id=(select id from domains where name=?)");
+ declare(suffix,"get-tsig-key-query","", "select algorithm, secret from tsigkeys where name=?");
+ /* FIXME: set-tsig-key-query only works on an empty database right now. For MySQL we use the "update into" statement..
+ According to the internet, we need to construct a pretty hefty "merge" query: https://msdn.microsoft.com/en-us/library/bb510625.aspx
+ */
+ declare(suffix,"set-tsig-key-query","", "insert into tsigkeys (name,algorithm,secret) values(?,?,?)");
+ declare(suffix,"delete-tsig-key-query","", "delete from tsigkeys where name=?");
+ declare(suffix,"get-tsig-keys-query","", "select name,algorithm, secret from tsigkeys");
+
+ declare(suffix, "get-all-domains-query", "Retrieve all domains", "select domains.id, domains.name, records.content, domains.type, domains.master, domains.notified_serial, domains.last_check, domains.account from domains LEFT JOIN records ON records.domain_id=domains.id AND records.type='SOA' AND records.name=domains.name WHERE records.disabled=0 OR records.disabled=?");
+
+ declare(suffix, "list-comments-query", "", "SELECT domain_id,name,type,modified_at,account,comment FROM comments WHERE domain_id=?");
+ declare(suffix, "insert-comment-query", "", "INSERT INTO comments (domain_id, name, type, modified_at, account, comment) VALUES (?, ?, ?, ?, ?, ?)");
+ declare(suffix, "delete-comment-rrset-query", "", "DELETE FROM comments WHERE domain_id=? AND name=? AND type=?");
+ declare(suffix, "delete-comments-query", "", "DELETE FROM comments WHERE domain_id=?");
+ declare(suffix, "search-records-query", "", record_query+" name LIKE ? OR content LIKE ? LIMIT ?");
+ declare(suffix, "search-comments-query", "", "SELECT domain_id,name,type,modified_at,account,comment FROM comments WHERE name LIKE ? OR comment LIKE ? LIMIT ?");
+ }
+
+ //! Constructs a new gODBCBackend object.
+ DNSBackend *make(const string & suffix = "" )
+ {
+ return new gODBCBackend( d_mode, suffix );
+ }
+
+private:
+ const string d_mode;
+};
+
+
+//! Magic class that is activated when the dynamic library is loaded
+class gODBCLoader
+{
+public:
+ //! This reports us to the main UeberBackend class
+ gODBCLoader()
+ {
+ BackendMakers().report( new gODBCFactory("godbc"));
+ L<<Logger::Warning << "This is module godbcbackend reporting" << std::endl;
+ }
+};
+
+//! Reports the backendloader to the UeberBackend.
+static gODBCLoader godbcloader;
--- /dev/null
+// The Generic ODBC Backend
+// By Michel Stol <michel@powerdns.com>
+
+#include <string>
+#include "pdns/backends/gsql/gsqlbackend.hh"
+
+class gODBCBackend : public GSQLBackend
+{
+public:
+ //! Constructor that connects to the database, throws an exception if something went wrong.
+ gODBCBackend( const std::string & mode, const std::string & suffix );
+
+};
+
--- /dev/null
+CREATE TABLE domains (
+ id INT IDENTITY,
+ name VARCHAR(255) NOT NULL,
+ master VARCHAR(128) DEFAULT NULL,
+ last_check INT DEFAULT NULL,
+ type VARCHAR(6) NOT NULL,
+ notified_serial INT DEFAULT NULL,
+ account VARCHAR(40) DEFAULT NULL,
+ PRIMARY KEY (id)
+);
+
+CREATE UNIQUE INDEX name_index ON domains(name);
+
+CREATE TABLE records (
+ id INT IDENTITY,
+ domain_id INT DEFAULT NULL,
+ name VARCHAR(255) DEFAULT NULL,
+ type VARCHAR(10) DEFAULT NULL,
+ content VARCHAR(MAX) DEFAULT NULL,
+ ttl INT DEFAULT NULL,
+ prio INT DEFAULT NULL,
+ change_date INT DEFAULT NULL,
+ disabled BIT DEFAULT 0,
+ ordername VARBINARY(255) DEFAULT NULL,
+ auth BIT DEFAULT 1,
+ PRIMARY KEY (id)
+);
+
+CREATE INDEX nametype_index ON records(name,type);
+CREATE INDEX domain_id ON records(domain_id);
+CREATE INDEX recordorder ON records (domain_id, ordername);
+
+
+CREATE TABLE supermasters (
+ ip VARCHAR(64) NOT NULL,
+ nameserver VARCHAR(255) NOT NULL,
+ account VARCHAR(40) NOT NULL,
+ PRIMARY KEY (ip, nameserver)
+);
+
+
+CREATE TABLE comments (
+ id INT IDENTITY,
+ domain_id INT NOT NULL,
+ name VARCHAR(255) NOT NULL,
+ type VARCHAR(10) NOT NULL,
+ modified_at INT NOT NULL,
+ account VARCHAR(40) NOT NULL,
+ comment VARCHAR(MAX) NOT NULL,
+ PRIMARY KEY (id)
+);
+
+CREATE INDEX comments_domain_id_idx ON comments (domain_id);
+CREATE INDEX comments_name_type_idx ON comments (name, type);
+CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);
+
+
+CREATE TABLE domainmetadata (
+ id INT IDENTITY,
+ domain_id INT NOT NULL,
+ kind VARCHAR(32),
+ content VARCHAR(MAX),
+ PRIMARY KEY (id)
+);
+
+CREATE INDEX domainmetadata_idx ON domainmetadata (domain_id, kind);
+
+CREATE TABLE cryptokeys (
+ id INT IDENTITY,
+ domain_id INT NOT NULL,
+ flags INT NOT NULL,
+ active BIT,
+ content VARCHAR(MAX),
+ PRIMARY KEY(id)
+);
+
+CREATE INDEX domainidindex ON cryptokeys(domain_id);
+
+
+CREATE TABLE tsigkeys (
+ id INT IDENTITY,
+ name VARCHAR(255),
+ algorithm VARCHAR(50),
+ secret VARCHAR(255),
+ PRIMARY KEY (id)
+);
+
+CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm);
--- /dev/null
+#include "pdns/utility.hh"
+#include <sstream>
+#include "sodbc.hh"
+#include <string.h>
+
+static void testResult( SQLRETURN result, SQLSMALLINT type, SQLHANDLE handle, const std::string & message )
+{
+ // cerr<<"result = "<<result<<endl;
+ if ( result == SQL_SUCCESS) // FIXME: testing only? || result == SQL_SUCCESS_WITH_INFO )
+ return;
+
+ ostringstream errmsg;
+
+ errmsg << message << ": ";
+
+ if ( result != SQL_ERROR && result != SQL_SUCCESS_WITH_INFO ) {
+ cerr<<"handle "<<handle<<" got result "<<result<<endl;
+ errmsg << "SQL function returned "<<result<<", no additional information available"<<endl;
+ throw SSqlException( errmsg.str() );
+ }
+
+ SQLINTEGER i = 0;
+ SQLINTEGER native;
+ SQLCHAR state[ 7 ];
+ SQLCHAR text[256];
+ SQLSMALLINT len;
+ SQLRETURN ret;
+
+ do
+ {
+ // cerr<<"getting sql diag record "<<i<<endl;
+ ret = SQLGetDiagRec(type, handle, ++i, state, &native, text,
+ sizeof(text), &len );
+ // cerr<<"getdiagrec said "<<ret<<endl;
+ if (SQL_SUCCEEDED(ret)) { // cerr<<"got it"<<endl;
+ errmsg<<state<<i<<native<<text<<"/";
+ }
+ }
+ while( ret == SQL_SUCCESS );
+ throw SSqlException( errmsg.str() );
+}
+
+class SODBCStatement: public SSqlStatement
+{
+public:
+ SODBCStatement(const string& query, bool dolog, int nparams, SQLHDBC connection)
+ {
+ SQLRETURN result;
+
+ d_query = query;
+ // d_nparams = nparams;
+ d_conn = connection;
+ d_dolog = dolog;
+ d_residx = 0;
+ d_paridx = 0;
+
+ // Allocate statement handle.
+ result = SQLAllocHandle( SQL_HANDLE_STMT, d_conn, &d_statement );
+ testResult( result, SQL_HANDLE_DBC, d_conn, "Could not allocate a statement handle." );
+
+ result = SQLPrepare(d_statement, (SQLCHAR *) query.c_str(), SQL_NTS);
+ testResult( result, SQL_HANDLE_STMT, d_statement, "Could not prepare query." );
+
+ SQLSMALLINT paramcount;
+ result = SQLNumParams(d_statement, ¶mcount);
+ testResult( result, SQL_HANDLE_STMT, d_statement, "Could not get parameter count." );
+
+ if (paramcount != nparams)
+ throw SSqlException("Provided parameter count does not match statement: " + d_query);
+
+ d_parnum = nparams;
+ // cerr<<"prepared ("<<query<<")"<<endl;
+ }
+
+ typedef struct {
+ SQLPOINTER ParameterValuePtr;
+ SQLLEN* LenPtr;
+ } ODBCParam;
+
+ vector<ODBCParam> d_req_bind;
+
+ SSqlStatement* bind(const string& name, bool value) { return bind(name, (long)value); }
+ SSqlStatement* bind(const string& name, long value) {
+
+ // cerr<<"asked to bind long "<<value<<endl;
+ // cerr<<"d_req_bind.size()="<<d_req_bind.size()<<endl;
+ // cerr<<"d_parnum="<<d_parnum<<endl;
+
+ if(d_req_bind.size() > (d_parnum+1)) throw SSqlException("Trying to bind too many parameters.");
+
+ ODBCParam p;
+
+ p.ParameterValuePtr = new long[1];
+ *((long*)p.ParameterValuePtr) = value;
+ p.LenPtr = new SQLLEN;
+ *(p.LenPtr) = sizeof(long);
+
+ d_req_bind.push_back(p);
+
+ SQLRETURN result = SQLBindParameter(
+ d_statement, // StatementHandle,
+ d_paridx+1, // ParameterNumber,
+ SQL_PARAM_INPUT, // InputOutputType,
+ SQL_C_SLONG, // ValueType,
+ SQL_BIGINT, // ParameterType,
+ 0, // ColumnSize,
+ 0, // DecimalDigits,
+ p.ParameterValuePtr, // ParameterValuePtr,
+ 0, // BufferLength,
+ p.LenPtr // StrLen_or_IndPtr
+ );
+ testResult( result, SQL_HANDLE_STMT, d_statement, "Could not bind parameter.");
+ d_paridx++;
+
+ return this;
+ }
+ SSqlStatement* bind(const string& name, uint32_t value) { return bind(name, (long)value); }
+ SSqlStatement* bind(const string& name, int value) { return bind(name, (long)value); }
+ SSqlStatement* bind(const string& name, unsigned long value) { return bind(name, (long)value);}
+ SSqlStatement* bind(const string& name, long long value) { return bind(name, (long)value); };
+ SSqlStatement* bind(const string& name, unsigned long long value) { return bind(name, (long)value); }
+ SSqlStatement* bind(const string& name, const std::string& value) {
+
+ // cerr<<"asked to bind string "<<value<<endl;
+
+ if(d_req_bind.size() > (d_parnum+1)) throw SSqlException("Trying to bind too many parameters.");
+
+ ODBCParam p;
+
+ p.ParameterValuePtr = (char*) new char[value.size()+1];
+ value.copy((char*)p.ParameterValuePtr, value.size());
+ ((char*)p.ParameterValuePtr)[value.size()]=0;
+ p.LenPtr=new SQLLEN;
+ *(p.LenPtr)=value.size();
+
+ d_req_bind.push_back(p);
+
+ SQLRETURN result = SQLBindParameter(
+ d_statement, // StatementHandle,
+ d_paridx+1, // ParameterNumber,
+ SQL_PARAM_INPUT, // InputOutputType,
+ SQL_C_CHAR, // ValueType,
+ SQL_VARCHAR, // ParameterType,
+ value.size(), // ColumnSize,
+ 0, // DecimalDigits,
+ p.ParameterValuePtr, // ParameterValuePtr,
+ value.size()+1, // BufferLength,
+ p.LenPtr // StrLen_or_IndPtr
+ );
+ testResult( result, SQL_HANDLE_STMT, d_statement, "Binding parameter.");
+ d_paridx++;
+
+ return this;
+ }
+
+ SSqlStatement* bindNull(const string& name) {
+ if(d_req_bind.size() > (d_parnum+1)) throw SSqlException("Trying to bind too many parameters.");
+
+ ODBCParam p;
+
+ p.ParameterValuePtr = NULL;
+ p.LenPtr=new SQLLEN;
+ *(p.LenPtr)=SQL_NULL_DATA;
+
+ d_req_bind.push_back(p);
+
+ SQLRETURN result = SQLBindParameter(
+ d_statement, // StatementHandle,
+ d_paridx+1, // ParameterNumber,
+ SQL_PARAM_INPUT, // InputOutputType,
+ SQL_C_CHAR, // ValueType,
+ SQL_VARCHAR, // ParameterType,
+ 0, // ColumnSize,
+ 0, // DecimalDigits,
+ p.ParameterValuePtr, // ParameterValuePtr,
+ 0, // BufferLength,
+ p.LenPtr // StrLen_or_IndPtr
+ );
+ testResult( result, SQL_HANDLE_STMT, d_statement, "Binding parameter.");
+ d_paridx++;
+
+ return this;
+ }
+
+ SSqlStatement* execute()
+ {
+ SQLRETURN result;
+ // cerr<<"execute("<<d_query<<")"<<endl;
+ if (d_dolog) {
+ // L<<Logger::Warning<<"Query: "<<d_query<<endl;
+ }
+
+ result = SQLExecute(d_statement);
+ if(result != SQL_NO_DATA) // odbc+sqlite returns this on 'no rows updated'
+ testResult( result, SQL_HANDLE_STMT, d_statement, "Could not execute query ("+d_query+")." );
+
+ // Determine the number of columns.
+ result = SQLNumResultCols( d_statement, &m_columncount );
+ testResult( result, SQL_HANDLE_STMT, d_statement, "Could not determine the number of columns." );
+ // cerr<<"got "<<m_columncount<<" columns"<<endl;
+
+ if(m_columncount) {
+ // cerr<<"first SQLFetch"<<endl;
+ d_result = SQLFetch(d_statement);
+ // cerr<<"first SQLFetch done, d_result="<<d_result<<endl;
+ }
+ else
+ d_result = SQL_NO_DATA;
+
+ if(d_result != SQL_NO_DATA)
+ testResult( d_result, SQL_HANDLE_STMT, d_statement, "Could not do first SQLFetch for ("+d_query+")." );
+ return this;
+ }
+
+ bool hasNextRow() {
+ // cerr<<"hasNextRow d_result="<<d_result<<endl;
+ return d_result!=SQL_NO_DATA;
+ }
+ SSqlStatement* nextRow(row_t& row);
+
+ SSqlStatement* getResult(result_t& result) {
+ result.clear();
+ // if (d_res == NULL) return this;
+ row_t row;
+ while(hasNextRow()) { nextRow(row); result.push_back(row); }
+ return this;
+ }
+
+ SSqlStatement* reset() {
+ SQLCloseCursor(d_statement); // hack, this probably violates some state transitions
+
+ for(auto &i: d_req_bind) { delete [] (char*) i.ParameterValuePtr; delete i.LenPtr; }
+ d_req_bind.clear();
+ d_residx = 0;
+ d_paridx = 0;
+ return this;
+ }
+ const std::string& getQuery() { return d_query; }
+
+private:
+ string d_query;
+ bool d_dolog;
+ bool d_havenextrow;
+ int d_residx, d_paridx, d_parnum;
+ SQLRETURN d_result;
+
+ SQLHDBC d_conn;
+ SQLHSTMT d_statement; //!< Database statement handle.
+
+ //! Column type.
+ struct column_t
+ {
+ SQLSMALLINT m_type; //!< Type of the column.
+ SQLULEN m_size; //!< Column size.
+ SQLPOINTER m_pData; //!< Pointer to the memory where to store the data.
+ bool m_canBeNull; //!< Can this column be null?
+ };
+
+ //! Column info.
+ SQLSMALLINT m_columncount;
+
+};
+
+SSqlStatement* SODBCStatement::nextRow(row_t& row)
+{
+ SQLRETURN result;
+
+ row.clear();
+
+ result = d_result;
+ // cerr<<"at start of nextRow, previous SQLFetch result is "<<result<<endl;
+ // FIXME handle errors (SQL_NO_DATA==100, anything other than the two SUCCESS options below is bad news)
+ if ( result == SQL_SUCCESS || result == SQL_SUCCESS_WITH_INFO )
+ {
+ // cerr<<"got row"<<endl;
+ // We've got a data row, now lets get the results.
+ SQLLEN len;
+ for ( int i = 0; i < m_columncount; i++ )
+ {
+ // Clear buffer.
+ // cerr<<"clearing m_pData of size "<<m_columnInfo[ i ].m_size<<endl;
+ SQLCHAR coldata[128*1024];
+
+ // FIXME: because we cap m_size to 128kbyte, this can truncate silently. see Retrieving Variable-Length Data in Parts at https://msdn.microsoft.com/en-us/library/ms715441(v=vs.85).aspx
+ result = SQLGetData( d_statement, i + 1, SQL_C_CHAR, (SQLPOINTER) coldata, 128*1024-1, &len );
+ // cerr<<"len="<<len<<endl;
+ testResult( result, SQL_HANDLE_STMT, d_statement, "Could not get data." );
+ if ( len == SQL_NULL_DATA ) {
+ // Column is NULL, so we can skip the converting part.
+ row.push_back( "" );
+ }
+ else
+ {
+ row.push_back(reinterpret_cast<char*>(coldata)); // FIXME: not NUL-safe, use len
+ }
+ }
+
+ // Done!
+ d_residx++;
+ // cerr<<"SQLFetch"<<endl;
+ d_result = SQLFetch(d_statement);
+ // cerr<<"subsequent SQLFetch done, d_result="<<d_result<<endl;
+ if(d_result == SQL_NO_DATA) {
+ SQLRETURN result = SQLMoreResults(d_statement);
+ // cerr<<"SQLMoreResults done, result="<<d_result<<endl;
+ if (result == SQL_NO_DATA) {
+ d_result = result;
+ }
+ else {
+ testResult( result, SQL_HANDLE_STMT, d_statement, "Could not fetch next result set for ("+d_query+").");
+ d_result = SQLFetch(d_statement);
+ }
+ }
+ testResult( result, SQL_HANDLE_STMT, d_statement, "Could not do subsequent SQLFetch for ("+d_query+")." );
+
+ return this;
+ }
+
+ SQLFreeStmt( d_statement, SQL_CLOSE );
+ throw SSqlException( "Should not get here." );
+ return this;
+}
+
+// Constructor.
+SODBC::SODBC(
+ const std::string & dsn,
+ const std::string & username,
+ const std::string & password
+ )
+{
+ SQLRETURN result;
+
+ // Allocate an environment handle.
+ result = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &m_environment );
+ testResult( result, SQL_NULL_HANDLE, NULL, "Could not allocate an environment handle." );
+
+ // Set ODBC version. (IEUW!)
+ result = SQLSetEnvAttr( m_environment, SQL_ATTR_ODBC_VERSION, reinterpret_cast< void * >( SQL_OV_ODBC3 ), 0 );
+ testResult( result, SQL_HANDLE_ENV, m_environment, "Could not set the ODBC version." );
+
+ // Allocate connection handle.
+ result = SQLAllocHandle( SQL_HANDLE_DBC, m_environment, &m_connection );
+ testResult( result, SQL_HANDLE_ENV, m_environment, "Could not allocate a connection handle." );
+
+ // Connect to the database.
+ char *l_dsn = strdup( dsn.c_str());
+ char *l_username = strdup( username.c_str());
+ char *l_password = strdup( password.c_str());
+
+ result = SQLConnect( m_connection,
+ reinterpret_cast< SQLTCHAR * >( l_dsn ), dsn.length(),
+ reinterpret_cast< SQLTCHAR * >( l_username ), username.length(),
+ reinterpret_cast< SQLTCHAR * >( l_password ), password.length());
+
+ free( l_dsn );
+ free( l_username );
+ free( l_password );
+
+ testResult( result, SQL_HANDLE_DBC, m_connection, "Could not connect to ODBC datasource." );
+
+
+ m_busy = false;
+ m_log = false;
+}
+
+
+// Destructor.
+SODBC::~SODBC( void )
+{
+ // Disconnect from database and free all used resources.
+ // SQLFreeHandle( SQL_HANDLE_STMT, m_statement );
+
+ SQLDisconnect( m_connection );
+
+ SQLFreeHandle( SQL_HANDLE_DBC, m_connection );
+ SQLFreeHandle( SQL_HANDLE_ENV, m_environment );
+
+ // Free all allocated column memory.
+ // for ( int i = 0; i < m_columnInfo.size(); i++ )
+ // {
+ // if ( m_columnInfo[ i ].m_pData )
+ // delete m_columnInfo[ i ].m_pData;
+ // }
+}
+
+// Executes a command.
+void SODBC::execute( const std::string & command )
+{
+ SQLRETURN result;
+ SODBCStatement stmt(command, false, 0, m_connection);
+
+ stmt.execute()->reset();
+}
+
+// Sets the log state.
+void SODBC::setLog( bool state )
+{
+ m_log = state;
+}
+
+// Returns an exception.
+SSqlException SODBC::sPerrorException( const std::string & reason )
+{
+ return SSqlException( reason );
+}
+
+SSqlStatement* SODBC::prepare(const string& query, int nparams)
+{
+ return new SODBCStatement(query, true, nparams, m_connection);
+}
+
+
+void SODBC::startTransaction() {
+ // cerr<<"starting transaction"<<endl;
+ SQLRETURN result;
+ result = SQLSetConnectAttr(m_connection, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF, 0);
+ testResult( result, SQL_HANDLE_DBC, m_connection, "startTransaction (enable autocommit) failed" );
+}
+
+void SODBC::commit() {
+ // cerr<<"commit!"<<endl;
+ SQLRETURN result;
+
+ result = SQLEndTran(SQL_HANDLE_DBC, m_connection, SQL_COMMIT); // don't really need this, AUTOCOMMIT_OFF below will also commit
+ testResult( result, SQL_HANDLE_DBC, m_connection, "commit failed" );
+
+ result = SQLSetConnectAttr(m_connection, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF, 0);
+ testResult( result, SQL_HANDLE_DBC, m_connection, "disabling autocommit after commit failed" );
+}
+
+void SODBC::rollback() {
+ // cerr<<"rollback!"<<endl;
+ SQLRETURN result;
+
+ result = SQLEndTran(SQL_HANDLE_DBC, m_connection, SQL_ROLLBACK);
+ testResult( result, SQL_HANDLE_DBC, m_connection, "rollback failed" );
+
+ result = SQLSetConnectAttr(m_connection, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF, 0);
+ testResult( result, SQL_HANDLE_DBC, m_connection, "disabling autocommit after rollback failed" );
+}
--- /dev/null
+// The Generic ODBC Backend
+// By Michel Stol <michel@powerdns.com>
+
+#ifndef SODBC_HH
+#define SODBC_HH
+
+#include <string>
+#include <vector>
+
+#include <sql.h>
+#include <sqlext.h>
+
+#include "pdns/backends/gsql/ssql.hh"
+
+//! ODBC SSql implementation for use with the Generic ODBC Backend.
+class SODBC : public SSql
+{
+private:
+
+
+ bool m_log; //!< Should we log?
+ bool m_busy; //!< Are we busy executing a query?
+
+ SQLHDBC m_connection; //!< Database connection handle.
+ SQLHENV m_environment; //!< Database environment handle
+
+
+
+public:
+ //! Default constructor.
+ /*!
+ This constructor connects to an ODBC datasource and makes sure it's ready to use.
+
+ \param dsn The ODBC DSN to use.
+ \param username Username to use.
+ \param password Password to use.
+ */
+ SODBC(
+ const std::string & dsn,
+ const std::string & username,
+ const std::string & password
+ );
+
+ //! Destructor.
+ virtual ~SODBC( void );
+
+ //! Sets the logging state.
+ void setLog( bool state );
+
+ SSqlStatement* prepare(const string& query, int nparams);
+ void execute(const string& query);
+ void startTransaction();
+ void rollback();
+ void commit();
+
+ //! Returns an exception.
+ SSqlException sPerrorException( const std::string & reason );
+
+};
+
+
+#endif // SODBC_HH
source ./backends/gmysql-master
;;
+ godbc_mssql*)
+ [ -z $GODBC_MSSQL_DSN ] && echo '$GODBC_MSSQL_DSN must be set' >&2 && exit 1
+ [ -z $GODBC_MSSQL_USERNAME ] && echo '$GODBC_MSSQL_USERNAME must be set' >&2 && exit 1
+ [ -z $GODBC_MSSQL_PASSWORD ] && echo '$GODBC_MSSQL_PASSWORD must be set' >&2 && exit 1
+ source ./backends/godbc_mssql-master
+ ;;
+
+ godbc_sqlite3*)
+ [ -z $GODBC_SQLITE3_DSN ] && echo '$GODBC_SQLITE3_DSN must be set' >&2 && exit 1
+ source ./backends/godbc_sqlite3-master
+ ;;
+
goracle*)
source ./backends/goracle-master
;;
source ./backends/gmysql-slave
;;
+ godbc_mssql*)
+ [ -z $GODBC_MSSQL2_DSN ] && echo '$GODBC_MSSQL2_DSN must be set' >&2 && exit 1
+ [ -z $GODBC_MSSQL2_USERNAME ] && echo '$GODBC_MSSQL2_USERNAME must be set' >&2 && exit 1
+ [ -z $GODBC_MSSQL2_PASSWORD ] && echo '$GODBC_MSSQL2_PASSWORD must be set' >&2 && exit 1
+ source ./backends/godbc_mssql-slave
+ ;;
+
goracle*)
source ./backends/goracle-slave
;;
--- /dev/null
+source ./backends/gsql-common
+ISQL="isql $GODBC_MSSQL_DSN $GODBC_MSSQL_USERNAME $GODBC_MSSQL_PASSWORD"
+BSQLODBC="bsqlodbc -S $GODBC_MSSQL_DSN -U $GODBC_MSSQL_USERNAME -P $GODBC_MSSQL_PASSWORD"
+case $context in
+ godbc_mssql-nodnssec | godbc_mssql | godbc_mssql-nsec3 | godbc_mssql-nsec3-optout | godbc_mssql-nsec3-narrow)
+ # Drop _ALL_ the tables!
+ for table in `echo "SELECT name FROM sysobjects WHERE OBJECTPROPERTY(id, N'IsUserTable') = 1" | $ISQL -b -d.`; do
+ echo "drop table $table" | $ISQL -b
+ done
+ cat ../modules/godbcbackend/schema.mssql.sql | tr '\n' ' ' | $ISQL -b
+
+ # Some context, the inserts are extremely slow for some reason
+ # This code removes the transactions from the sql because example.com is
+ # too large (and hangs/crashes).
+ # The 'sed' then adds 'go' after every 1000th line to batch-insert
+ # Then we send that to bsqlodbc with a final 'go' and an EOF so bdsqlodbc
+ # actually terminates
+ tosql gsqlite | grep -v -E '(COMMIT|TRANSACTION)' | awk '1;!(NR%98){print "go"}' | cat - <(echo go) /dev/null | $BSQLODBC
+ cat > pdns-godbc_mssql.conf << __EOF__
+module-dir=./modules
+launch=godbc
+godbc-datasource=$GODBC_MSSQL_DSN
+godbc-username=$GODBC_MSSQL_USERNAME
+godbc-password=$GODBC_MSSQL_PASSWORD
+godbc-dnssec=yes
+__EOF__
+
+ gsql_master godbc_mssql nodyndns
+ ;;
+
+ *)
+ nocontext=yes
+esac
--- /dev/null
+ context=${context}-presigned-godbc
+ ISQL="isql $GODBC_MSSQL2_DSN $GODBC_MSSQL2_USERNAME $GODBC_MSSQL2_PASSWORD"
+ # Drop _ALL_ the tables!
+ for table in `echo "SELECT name FROM sysobjects WHERE OBJECTPROPERTY(id, N'IsUserTable') = 1" | $ISQL -b -d.`; do
+ echo "drop table $table" | $ISQL -b
+ done
+ $ISQL < ../modules/godbcbackend/schema.mssql.sql
+ cat > pdns-godbc2.conf << __EOF__
+module-dir=./modules
+launch=godbc
+godbc-datasource=$GODBC_MSSQL2_DSN
+godbc-username=$GODBC_MSSQL2_USERNAME
+godbc-password=$GODBC_MSSQL2_PASSWORD
+__EOF__
+
+ for zone in $(grep 'zone ' named.conf | cut -f2 -d\" | tac)
+ do
+ echo "INSERT INTO domains (name, type, master) VALUES('$zone','SLAVE','127.0.0.1:$port');" | $ISQL -b
+ done
+
+ ../pdns/pdnssec --config-dir=. --config-name=godbc2 import-tsig-key test $ALGORITHM $KEY
+ ../pdns/pdnssec --config-dir=. --config-name=godbc2 activate-tsig-key tsig.com test slave
+ if [[ $skipreasons != *nolua* ]]
+ then
+ ../pdns/pdnssec --config-dir=. --config-name=godbc2 set-meta stest.com AXFR-SOURCE 127.0.0.2
+ fi
+
+ port=$((port+100))
+
+ $RUNWRAPPER $PDNS2 --daemon=no --local-port=$port --config-dir=. \
+ --config-name=godbc2 --socket-dir=./ --no-shuffle \
+ --send-root-referral --slave --retrieval-threads=4 \
+ --slave-cycle-interval=300 --experimental-dname-processing &
+
+ echo 'waiting for zones to be slaved'
+ set +e
+ loopcount=0
+ while [ $loopcount -lt 30 ]
+ do
+ sleep 5
+ todo=$(echo "SELECT COUNT(id) FROM domains WHERE last_check IS NULL" | $ISQL)
+ if [ $? -eq 0 ]
+ then
+ if [ $todo = 0 ]
+ then
+ break
+ fi
+ fi
+ let loopcount=loopcount+1
+ done
+ if [ $todo -ne 0 ]
+ then
+ echo "AXFR FAILED" >> failed_tests
+ exit
+ fi
+ set -e
--- /dev/null
+source ./backends/gsql-common
+case $context in
+ godbc_sqlite3-nodnssec | godbc_sqlite3 | godbc_sqlite3-nsec3 | godbc_sqlite3-nsec3-optout | godbc_sqlite3-nsec3-narrow)
+ rm -f pdns.sqlite3
+ sqlite3 pdns.sqlite3 < ../modules/gsqlite3backend/schema.sqlite3.sql
+ tosql gsqlite | sqlite3 pdns.sqlite3
+ echo 'ANALYZE; PRAGMA journal_mode=WAL;' | sqlite3 pdns.sqlite3
+
+ cat > pdns-godbc_sqlite3.conf << __EOF__
+module-dir=./modules
+launch=godbc
+godbc-datasource=$GODBC_SQLITE3_DSN
+
+godbc-activate-domain-key-query=update cryptokeys set active=1 where domain_id=(select id from domains where name=?) and cryptokeys.id=?
+godbc-add-domain-key-query=insert into cryptokeys (domain_id, flags, active, content) select id, ?,?, ? from domains where name=?
+godbc-any-id-query=SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE disabled=0 and name=? and domain_id=?
+godbc-any-query=SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE disabled=0 and name=?
+godbc-basic-query=SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE disabled=0 and type=? and name=?
+godbc-clear-domain-all-keys-query=delete from cryptokeys where domain_id=(select id from domains where name=?)
+godbc-clear-domain-all-metadata-query=delete from domainmetadata where domain_id=(select id from domains where name=?)
+godbc-clear-domain-metadata-query=delete from domainmetadata where domain_id=(select id from domains where name=?) and domainmetadata.kind=?
+godbc-deactivate-domain-key-query=update cryptokeys set active=0 where domain_id=(select id from domains where name=?) and cryptokeys.id=?
+godbc-delete-comment-rrset-query=DELETE FROM comments WHERE domain_id=? AND name=? AND type=?
+godbc-delete-comments-query=DELETE FROM comments WHERE domain_id=?
+godbc-delete-domain-query=delete from domains where name=?
+godbc-delete-empty-non-terminal-query=delete from records where domain_id=? and name=? and type is null
+godbc-delete-names-query=delete from records where domain_id=? and name=?
+godbc-delete-rrset-query=delete from records where domain_id=? and name=? and type=?
+godbc-delete-tsig-key-query=delete from tsigkeys where name=?
+godbc-delete-zone-query=delete from records where domain_id=?
+godbc-get-all-domain-metadata-query=select kind,content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=?
+godbc-get-all-domains-query=select domains.id, domains.name, records.content, domains.type, domains.master, domains.notified_serial, domains.last_check, domains.account from domains LEFT JOIN records ON records.domain_id=domains.id AND records.type='SOA' AND records.name=domains.name WHERE records.disabled=0 OR ?
+godbc-get-domain-metadata-query=select content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=? and domainmetadata.kind=?
+godbc-get-order-after-query=select min(ordername) from records where disabled=0 and ordername > ? and domain_id=? and ordername is not null
+godbc-get-order-before-query=select ordername, name from records where disabled=0 and ordername <= ? and domain_id=? and ordername is not null order by 1 desc limit 1
+godbc-get-order-first-query=select ordername from records where disabled=0 and domain_id=? and ordername is not null order by 1 asc limit 1
+godbc-get-order-last-query=select ordername from records where disabled=0 and ordername != '' and domain_id=? and ordername is not null order by 1 desc limit 1
+godbc-get-tsig-key-query=select algorithm, secret from tsigkeys where name=?
+godbc-get-tsig-keys-query=select name,algorithm, secret from tsigkeys
+godbc-id-query=SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE disabled=0 and type=? and name=? and domain_id=?
+godbc-info-all-master-query=select id,name,master,last_check,notified_serial,type from domains where type='MASTER'
+godbc-info-all-slaves-query=select id,name,master,last_check,type from domains where type='SLAVE'
+godbc-info-zone-query=select id,name,master,last_check,notified_serial,type,account from domains where name=?
+godbc-insert-comment-query=INSERT INTO comments (domain_id, name, type, modified_at, account, comment) VALUES (?, ?, ?, ?, ?, ?)
+godbc-insert-empty-non-terminal-query=insert into records (domain_id,name,type,disabled,auth) values (?,?,null,0,'1')
+godbc-insert-ent-order-query=insert into records (type,domain_id,disabled,name,ordername,auth) values (null,?,0,?,?,?)
+godbc-insert-ent-query=insert into records (type,domain_id,disabled,name,auth) values (null,?,0,?,?)
+godbc-insert-record-order-query=insert into records (content,ttl,prio,type,domain_id,disabled,name,ordername,auth) values (?,?,?,?,?,?,?,?,?)
+godbc-insert-record-query=insert into records (content,ttl,prio,type,domain_id,disabled,name,auth) values (?,?,?,?,?,?,?,?)
+godbc-insert-slave-query=insert into domains (type,name,master,account) values('SLAVE',?,?,?)
+godbc-insert-zone-query=insert into domains (type,name) values('NATIVE',?)
+godbc-list-comments-query=SELECT domain_id,name,type,modified_at,account,comment FROM comments WHERE domain_id=?
+godbc-list-domain-keys-query=select cryptokeys.id, flags, active, content from domains, cryptokeys where cryptokeys.domain_id=domains.id and name=?
+godbc-list-query=SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE (disabled=0 OR ?) and domain_id=? order by name, type
+godbc-list-subzone-query=SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE disabled=0 and (name=? OR name like ?) and domain_id=?
+godbc-master-zone-query=select master from domains where name=? and type='SLAVE'
+godbc-nullify-ordername-and-update-auth-query=update records set ordername=NULL,auth=? where domain_id=? and name=? and disabled=0
+godbc-remove-domain-key-query=delete from cryptokeys where domain_id=(select id from domains where name=?) and cryptokeys.id=?
+godbc-remove-empty-non-terminals-from-zone-query=delete from records where domain_id=? and type is null
+godbc-set-domain-metadata-query=insert into domainmetadata (domain_id, kind, content) select id, ?, ? from domains where name=?
+godbc-set-tsig-key-query=replace into tsigkeys (name,algorithm,secret) values(?,?,?)
+godbc-supermaster-name-to-ips=select ip,account from supermasters where nameserver=? and account=?
+godbc-supermaster-query=select account from supermasters where ip=? and nameserver=?
+godbc-update-account-query=update domains set account=? where name=?
+godbc-update-kind-query=update domains set type=? where name=?
+godbc-update-lastcheck-query=update domains set last_check=? where id=?
+godbc-update-master-query=update domains set master=? where name=?
+godbc-update-ordername-and-auth-query=update records set ordername=?,auth=? where domain_id=? and name=? and disabled=0
+godbc-update-ordername-and-auth-type-query=update records set ordername=?,auth=? where domain_id=? and name=? and type=? and disabled=0
+godbc-update-serial-query=update domains set notified_serial=? where id=?
+godbc-zone-lastchange-query=select max(change_date) from records where domain_id=?
+__EOF__
+
+ gsql_master godbc_sqlite3 nodyndns
+ ;;
+
+ *)
+ nocontext=yes
+esac
backend=$1
skipreasons=$2
+ real_backend=$backend
+ if `echo $backend | grep -q '_'`; then
+ real_backend=$(echo $backend | awk -F '_' '{print $1}')
+ fi
+
if [ $context != ${backend}-nodnssec ]
then
- echo "${backend}-dnssec" >> pdns-${backend}.conf
+ echo "${real_backend}-dnssec" >> pdns-${backend}.conf
fi
for zone in $(grep 'zone ' named.conf | cut -f2 -d\")
--- /dev/null
+../../modules/godbcbackend/.libs/libgodbcbackend.so
\ No newline at end of file
bind bind-dnssec bind-dnssec-nsec3 bind-dnssec-nsec3-optout bind-dnssec-nsec3-narrow
geoipbackend geoipbackend-nsec3-narrow
gmysql-nodnssec gmysql gmysql-nsec3 gmysql-nsec3-optout gmysql-nsec3-narrow
+godbc_mssql-nodnssec godbc_mssql godbc_mssql-nsec3 godbc_mssql-nsec3-optout godbc_mssql-nsec3-narrow
goracle-nodnssec goracle goracle-nsec3 goracle-nsec3-optout goracle-nsec3-narrow
gpgsql-nodnssec gpgsql gpgsql-nsec3 gpgsql-nsec3-optout gpgsql-nsec3-narrow
gsqlite3-nodnssec gsqlite3 gsqlite3-nsec3 gsqlite3-nsec3-optout gsqlite3-nsec3-narrow