summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 00:53:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 00:53:35 +0000
commit69c6a41ffb878ef98c9378ed4b1634a404cfaa7f (patch)
treeb2a4f704565d62fbb129ab9dc3b35977c50e6e7f /src
parentInitial commit. (diff)
downloadknot-69c6a41ffb878ef98c9378ed4b1634a404cfaa7f.tar.xz
knot-69c6a41ffb878ef98c9378ed4b1634a404cfaa7f.zip
Adding upstream version 2.7.6.upstream/2.7.6upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--src/Makefile.am21
-rw-r--r--src/Makefile.in5499
-rw-r--r--src/config.h.in208
-rw-r--r--src/contrib/Makefile.inc103
-rw-r--r--src/contrib/asan.h37
-rw-r--r--src/contrib/base32hex.c353
-rw-r--r--src/contrib/base32hex.h103
-rw-r--r--src/contrib/base64.c272
-rw-r--r--src/contrib/base64.h102
-rw-r--r--src/contrib/ctype.h192
-rw-r--r--src/contrib/dnstap/convert.c142
-rw-r--r--src/contrib/dnstap/convert.h59
-rw-r--r--src/contrib/dnstap/dnstap.c40
-rw-r--r--src/contrib/dnstap/dnstap.h46
-rw-r--r--src/contrib/dnstap/dnstap.proto270
-rw-r--r--src/contrib/dnstap/message.c130
-rw-r--r--src/contrib/dnstap/message.h62
-rw-r--r--src/contrib/dnstap/reader.c105
-rw-r--r--src/contrib/dnstap/reader.h72
-rw-r--r--src/contrib/dnstap/writer.c120
-rw-r--r--src/contrib/dnstap/writer.h70
-rw-r--r--src/contrib/dynarray.h123
-rw-r--r--src/contrib/files.c134
-rw-r--r--src/contrib/files.h43
-rw-r--r--src/contrib/getline.c60
-rw-r--r--src/contrib/getline.h38
-rw-r--r--src/contrib/licenses/0BSD12
-rw-r--r--src/contrib/licenses/BSD-3-Clause21
-rw-r--r--src/contrib/licenses/LGPL-2.0339
-rw-r--r--src/contrib/licenses/OLDAP-2.847
-rw-r--r--src/contrib/lmdb/LICENSE1
-rw-r--r--src/contrib/lmdb/lmdb.h1604
-rw-r--r--src/contrib/lmdb/mdb.c10266
-rw-r--r--src/contrib/lmdb/midl.c359
-rw-r--r--src/contrib/lmdb/midl.h186
-rw-r--r--src/contrib/macros.h43
-rw-r--r--src/contrib/mempattern.c122
-rw-r--r--src/contrib/mempattern.h46
-rw-r--r--src/contrib/net.c598
-rw-r--r--src/contrib/net.h185
-rw-r--r--src/contrib/openbsd/LICENSE2
-rw-r--r--src/contrib/openbsd/siphash.c176
-rw-r--r--src/contrib/openbsd/siphash.h83
-rw-r--r--src/contrib/openbsd/strlcat.c48
-rw-r--r--src/contrib/openbsd/strlcat.h31
-rw-r--r--src/contrib/openbsd/strlcpy.c46
-rw-r--r--src/contrib/openbsd/strlcpy.h29
-rw-r--r--src/contrib/qp-trie/trie.c835
-rw-r--r--src/contrib/qp-trie/trie.h112
-rw-r--r--src/contrib/sockaddr.c351
-rw-r--r--src/contrib/sockaddr.h160
-rw-r--r--src/contrib/string.c112
-rw-r--r--src/contrib/string.h82
-rw-r--r--src/contrib/strtonum.h120
-rw-r--r--src/contrib/time.c405
-rw-r--r--src/contrib/time.h171
-rw-r--r--src/contrib/tolower.h51
-rw-r--r--src/contrib/trim.h35
-rw-r--r--src/contrib/ucw/LICENSE1
-rw-r--r--src/contrib/ucw/array-sort.h195
-rw-r--r--src/contrib/ucw/binsearch.h50
-rw-r--r--src/contrib/ucw/heap.c166
-rw-r--r--src/contrib/ucw/heap.h46
-rw-r--r--src/contrib/ucw/lists.c235
-rw-r--r--src/contrib/ucw/lists.h84
-rw-r--r--src/contrib/ucw/mempool.c322
-rw-r--r--src/contrib/ucw/mempool.h124
-rw-r--r--src/contrib/wire_ctx.h361
-rw-r--r--src/knot/Makefile.inc196
-rw-r--r--src/knot/common/evsched.c267
-rw-r--r--src/knot/common/evsched.h153
-rw-r--r--src/knot/common/fdset.c151
-rw-r--r--src/knot/common/fdset.h112
-rw-r--r--src/knot/common/log.c491
-rw-r--r--src/knot/common/log.h185
-rw-r--r--src/knot/common/process.c189
-rw-r--r--src/knot/common/process.h59
-rw-r--r--src/knot/common/ref.c44
-rw-r--r--src/knot/common/ref.h78
-rw-r--r--src/knot/common/stats.c295
-rw-r--r--src/knot/common/stats.h47
-rw-r--r--src/knot/conf/base.c924
-rw-r--r--src/knot/conf/base.h279
-rw-r--r--src/knot/conf/conf.c1216
-rw-r--r--src/knot/conf/conf.h715
-rw-r--r--src/knot/conf/confdb.c951
-rw-r--r--src/knot/conf/confdb.h230
-rw-r--r--src/knot/conf/confio.c1514
-rw-r--r--src/knot/conf/confio.h218
-rw-r--r--src/knot/conf/migration.c81
-rw-r--r--src/knot/conf/migration.h30
-rw-r--r--src/knot/conf/module.c460
-rw-r--r--src/knot/conf/module.h110
-rw-r--r--src/knot/conf/schema.c344
-rw-r--r--src/knot/conf/schema.h154
-rw-r--r--src/knot/conf/tools.c551
-rw-r--r--src/knot/conf/tools.h107
-rw-r--r--src/knot/ctl/commands.c1841
-rw-r--r--src/knot/ctl/commands.h135
-rw-r--r--src/knot/ctl/process.c128
-rw-r--r--src/knot/ctl/process.h30
-rw-r--r--src/knot/dnssec/context.c218
-rw-r--r--src/knot/dnssec/context.h62
-rw-r--r--src/knot/dnssec/ds_query.c244
-rw-r--r--src/knot/dnssec/ds_query.h22
-rw-r--r--src/knot/dnssec/kasp/kasp_db.c751
-rw-r--r--src/knot/dnssec/kasp/kasp_db.h235
-rw-r--r--src/knot/dnssec/kasp/kasp_zone.c296
-rw-r--r--src/knot/dnssec/kasp/kasp_zone.h45
-rw-r--r--src/knot/dnssec/kasp/keystate.c70
-rw-r--r--src/knot/dnssec/kasp/keystate.h34
-rw-r--r--src/knot/dnssec/kasp/keystore.c89
-rw-r--r--src/knot/dnssec/kasp/keystore.h22
-rw-r--r--src/knot/dnssec/kasp/policy.h112
-rw-r--r--src/knot/dnssec/key-events.c713
-rw-r--r--src/knot/dnssec/key-events.h57
-rw-r--r--src/knot/dnssec/nsec-chain.c444
-rw-r--r--src/knot/dnssec/nsec-chain.h151
-rw-r--r--src/knot/dnssec/nsec3-chain.c830
-rw-r--r--src/knot/dnssec/nsec3-chain.h57
-rw-r--r--src/knot/dnssec/policy.c47
-rw-r--r--src/knot/dnssec/policy.h26
-rw-r--r--src/knot/dnssec/rrset-sign.c395
-rw-r--r--src/knot/dnssec/rrset-sign.h112
-rw-r--r--src/knot/dnssec/zone-events.c312
-rw-r--r--src/knot/dnssec/zone-events.h95
-rw-r--r--src/knot/dnssec/zone-keys.c529
-rw-r--r--src/knot/dnssec/zone-keys.h176
-rw-r--r--src/knot/dnssec/zone-nsec.c409
-rw-r--r--src/knot/dnssec/zone-nsec.h95
-rw-r--r--src/knot/dnssec/zone-sign.c1196
-rw-r--r--src/knot/dnssec/zone-sign.h135
-rw-r--r--src/knot/events/events.c475
-rw-r--r--src/knot/events/events.h190
-rw-r--r--src/knot/events/handlers.h47
-rw-r--r--src/knot/events/handlers/dnssec.c116
-rw-r--r--src/knot/events/handlers/expire.c46
-rw-r--r--src/knot/events/handlers/flush.c38
-rw-r--r--src/knot/events/handlers/freeze_thaw.c49
-rw-r--r--src/knot/events/handlers/load.c307
-rw-r--r--src/knot/events/handlers/notify.c158
-rw-r--r--src/knot/events/handlers/nsec3resalt.c46
-rw-r--r--src/knot/events/handlers/parent_ds_query.c53
-rw-r--r--src/knot/events/handlers/refresh.c1169
-rw-r--r--src/knot/events/handlers/update.c33
-rw-r--r--src/knot/events/replan.c175
-rw-r--r--src/knot/events/replan.h35
-rw-r--r--src/knot/include/module.h549
-rw-r--r--src/knot/journal/chgset_ctx.c88
-rw-r--r--src/knot/journal/chgset_ctx.h63
-rw-r--r--src/knot/journal/journal.c2197
-rw-r--r--src/knot/journal/journal.h244
-rw-r--r--src/knot/journal/serialization.c380
-rw-r--r--src/knot/journal/serialization.h98
-rw-r--r--src/knot/modules/cookies/Makefile.inc13
-rw-r--r--src/knot/modules/cookies/cookies.c269
-rw-r--r--src/knot/modules/cookies/cookies.rst78
-rw-r--r--src/knot/modules/dnsproxy/Makefile.inc13
-rw-r--r--src/knot/modules/dnsproxy/dnsproxy.c165
-rw-r--r--src/knot/modules/dnsproxy/dnsproxy.rst102
-rw-r--r--src/knot/modules/dnstap/Makefile.inc15
-rw-r--r--src/knot/modules/dnstap/dnstap.c320
-rw-r--r--src/knot/modules/dnstap/dnstap.rst106
-rw-r--r--src/knot/modules/geoip/Makefile.inc16
-rw-r--r--src/knot/modules/geoip/geodb.c222
-rw-r--r--src/knot/modules/geoip/geodb.h65
-rw-r--r--src/knot/modules/geoip/geoip.c779
-rw-r--r--src/knot/modules/geoip/geoip.rst211
-rw-r--r--src/knot/modules/noudp/Makefile.inc12
-rw-r--r--src/knot/modules/noudp/noudp.c43
-rw-r--r--src/knot/modules/noudp/noudp.rst20
-rw-r--r--src/knot/modules/onlinesign/Makefile.inc15
-rw-r--r--src/knot/modules/onlinesign/nsec_next.c113
-rw-r--r--src/knot/modules/onlinesign/nsec_next.h29
-rw-r--r--src/knot/modules/onlinesign/onlinesign.c776
-rw-r--r--src/knot/modules/onlinesign/onlinesign.rst152
-rw-r--r--src/knot/modules/queryacl/Makefile.inc12
-rw-r--r--src/knot/modules/queryacl/queryacl.c98
-rw-r--r--src/knot/modules/queryacl/queryacl.rst60
-rw-r--r--src/knot/modules/rrl/Makefile.inc15
-rw-r--r--src/knot/modules/rrl/functions.c525
-rw-r--r--src/knot/modules/rrl/functions.h114
-rw-r--r--src/knot/modules/rrl/rrl.c209
-rw-r--r--src/knot/modules/rrl/rrl.rst133
-rw-r--r--src/knot/modules/static_modules.h.in25
-rw-r--r--src/knot/modules/stats/Makefile.inc12
-rw-r--r--src/knot/modules/stats/stats.c622
-rw-r--r--src/knot/modules/stats/stats.rst266
-rw-r--r--src/knot/modules/synthrecord/Makefile.inc13
-rw-r--r--src/knot/modules/synthrecord/synthrecord.c498
-rw-r--r--src/knot/modules/synthrecord/synthrecord.rst161
-rw-r--r--src/knot/modules/whoami/Makefile.inc12
-rw-r--r--src/knot/modules/whoami/whoami.c114
-rw-r--r--src/knot/modules/whoami/whoami.rst97
-rw-r--r--src/knot/nameserver/axfr.c214
-rw-r--r--src/knot/nameserver/axfr.h27
-rw-r--r--src/knot/nameserver/chaos.c145
-rw-r--r--src/knot/nameserver/chaos.h34
-rw-r--r--src/knot/nameserver/internet.c664
-rw-r--r--src/knot/nameserver/internet.h76
-rw-r--r--src/knot/nameserver/ixfr.c298
-rw-r--r--src/knot/nameserver/ixfr.h60
-rw-r--r--src/knot/nameserver/log.h90
-rw-r--r--src/knot/nameserver/notify.c93
-rw-r--r--src/knot/nameserver/notify.h30
-rw-r--r--src/knot/nameserver/nsec_proofs.c677
-rw-r--r--src/knot/nameserver/nsec_proofs.h38
-rw-r--r--src/knot/nameserver/process_query.c891
-rw-r--r--src/knot/nameserver/process_query.h133
-rw-r--r--src/knot/nameserver/query_module.c641
-rw-r--r--src/knot/nameserver/query_module.h98
-rw-r--r--src/knot/nameserver/tsig_ctx.c188
-rw-r--r--src/knot/nameserver/tsig_ctx.h97
-rw-r--r--src/knot/nameserver/update.c477
-rw-r--r--src/knot/nameserver/update.h34
-rw-r--r--src/knot/nameserver/xfr.c96
-rw-r--r--src/knot/nameserver/xfr.h69
-rw-r--r--src/knot/query/capture.c72
-rw-r--r--src/knot/query/capture.h33
-rw-r--r--src/knot/query/layer.h135
-rw-r--r--src/knot/query/query.c118
-rw-r--r--src/knot/query/query.h67
-rw-r--r--src/knot/query/requestor.c328
-rw-r--r--src/knot/query/requestor.h119
-rw-r--r--src/knot/server/dthreads.c766
-rw-r--r--src/knot/server/dthreads.h294
-rw-r--r--src/knot/server/server.c932
-rw-r--r--src/knot/server/server.h181
-rw-r--r--src/knot/server/tcp-handler.c373
-rw-r--r--src/knot/server/tcp-handler.h42
-rw-r--r--src/knot/server/udp-handler.c495
-rw-r--r--src/knot/server/udp-handler.h42
-rw-r--r--src/knot/updates/acl.c104
-rw-r--r--src/knot/updates/acl.h57
-rw-r--r--src/knot/updates/apply.c485
-rw-r--r--src/knot/updates/apply.h150
-rw-r--r--src/knot/updates/changesets.c822
-rw-r--r--src/knot/updates/changesets.h314
-rw-r--r--src/knot/updates/ddns.c769
-rw-r--r--src/knot/updates/ddns.h57
-rw-r--r--src/knot/updates/zone-update.c895
-rw-r--r--src/knot/updates/zone-update.h321
-rw-r--r--src/knot/worker/pool.c242
-rw-r--r--src/knot/worker/pool.h82
-rw-r--r--src/knot/worker/queue.c67
-rw-r--r--src/knot/worker/queue.h65
-rw-r--r--src/knot/zone/contents.c1197
-rw-r--r--src/knot/zone/contents.h288
-rw-r--r--src/knot/zone/node.c312
-rw-r--r--src/knot/zone/node.h276
-rw-r--r--src/knot/zone/semantic-check.c1193
-rw-r--r--src/knot/zone/semantic-check.h123
-rw-r--r--src/knot/zone/serial.c84
-rw-r--r--src/knot/zone/serial.h72
-rw-r--r--src/knot/zone/timers.c288
-rw-r--r--src/knot/zone/timers.h119
-rw-r--r--src/knot/zone/zone-diff.c389
-rw-r--r--src/knot/zone/zone-diff.h31
-rw-r--r--src/knot/zone/zone-dump.c226
-rw-r--r--src/knot/zone/zone-dump.h41
-rw-r--r--src/knot/zone/zone-load.c154
-rw-r--r--src/knot/zone/zone-load.h63
-rw-r--r--src/knot/zone/zone-tree.c209
-rw-r--r--src/knot/zone/zone-tree.h142
-rw-r--r--src/knot/zone/zone.c731
-rw-r--r--src/knot/zone/zone.h177
-rw-r--r--src/knot/zone/zonedb-load.c346
-rw-r--r--src/knot/zone/zonedb-load.h28
-rw-r--r--src/knot/zone/zonedb.c167
-rw-r--r--src/knot/zone/zonedb.h123
-rw-r--r--src/knot/zone/zonefile.c343
-rw-r--r--src/knot/zone/zonefile.h104
-rw-r--r--src/knotd.pc.in9
-rw-r--r--src/libdnssec.pc.in13
-rw-r--r--src/libdnssec/Makefile.inc87
-rw-r--r--src/libdnssec/binary.c169
-rw-r--r--src/libdnssec/binary.h133
-rw-r--r--src/libdnssec/contrib/vpool.c241
-rw-r--r--src/libdnssec/contrib/vpool.h60
-rw-r--r--src/libdnssec/crypto.c42
-rw-r--r--src/libdnssec/crypto.h74
-rw-r--r--src/libdnssec/dnssec.h35
-rw-r--r--src/libdnssec/error.c84
-rw-r--r--src/libdnssec/error.h112
-rw-r--r--src/libdnssec/key.h318
-rw-r--r--src/libdnssec/key/algorithm.c163
-rw-r--r--src/libdnssec/key/algorithm.h30
-rw-r--r--src/libdnssec/key/convert.c375
-rw-r--r--src/libdnssec/key/convert.h44
-rw-r--r--src/libdnssec/key/dnskey.c82
-rw-r--r--src/libdnssec/key/dnskey.h46
-rw-r--r--src/libdnssec/key/ds.c115
-rw-r--r--src/libdnssec/key/internal.h35
-rw-r--r--src/libdnssec/key/key.c440
-rw-r--r--src/libdnssec/key/keytag.c88
-rw-r--r--src/libdnssec/key/privkey.c140
-rw-r--r--src/libdnssec/key/privkey.h35
-rw-r--r--src/libdnssec/key/simple.c55
-rw-r--r--src/libdnssec/keyid.c87
-rw-r--r--src/libdnssec/keyid.h80
-rw-r--r--src/libdnssec/keystore.h297
-rw-r--r--src/libdnssec/keystore/internal.h52
-rw-r--r--src/libdnssec/keystore/keystore.c183
-rw-r--r--src/libdnssec/keystore/pkcs11.c440
-rw-r--r--src/libdnssec/keystore/pkcs8.c211
-rw-r--r--src/libdnssec/keystore/pkcs8_dir.c379
-rw-r--r--src/libdnssec/keytag.h63
-rw-r--r--src/libdnssec/list.h85
-rw-r--r--src/libdnssec/list/list.c298
-rw-r--r--src/libdnssec/list/ucw_clists.h260
-rw-r--r--src/libdnssec/nsec.h214
-rw-r--r--src/libdnssec/nsec/bitmap.c142
-rw-r--r--src/libdnssec/nsec/hash.c125
-rw-r--r--src/libdnssec/nsec/nsec.c116
-rw-r--r--src/libdnssec/p11/p11.c113
-rw-r--r--src/libdnssec/p11/p11.h41
-rw-r--r--src/libdnssec/random.c53
-rw-r--r--src/libdnssec/random.h85
-rw-r--r--src/libdnssec/shared/bignum.c64
-rw-r--r--src/libdnssec/shared/bignum.h41
-rw-r--r--src/libdnssec/shared/binary_wire.h53
-rw-r--r--src/libdnssec/shared/dname.c165
-rw-r--r--src/libdnssec/shared/dname.h57
-rw-r--r--src/libdnssec/shared/fs.c47
-rw-r--r--src/libdnssec/shared/fs.h25
-rw-r--r--src/libdnssec/shared/hex.c167
-rw-r--r--src/libdnssec/shared/hex.h39
-rw-r--r--src/libdnssec/shared/keyid_gnutls.c94
-rw-r--r--src/libdnssec/shared/keyid_gnutls.h30
-rw-r--r--src/libdnssec/shared/pem.c198
-rw-r--r--src/libdnssec/shared/pem.h74
-rw-r--r--src/libdnssec/shared/shared.h129
-rw-r--r--src/libdnssec/sign.h137
-rw-r--r--src/libdnssec/sign/der.c229
-rw-r--r--src/libdnssec/sign/der.h56
-rw-r--r--src/libdnssec/sign/sign.c408
-rw-r--r--src/libdnssec/tsig.c242
-rw-r--r--src/libdnssec/tsig.h207
-rw-r--r--src/libdnssec/version.h25
-rw-r--r--src/libdnssec/version.h.in25
-rw-r--r--src/libknot.pc.in14
-rw-r--r--src/libknot/Makefile.inc78
-rw-r--r--src/libknot/attribute.h46
-rw-r--r--src/libknot/codes.c80
-rw-r--r--src/libknot/codes.h49
-rw-r--r--src/libknot/consts.h157
-rw-r--r--src/libknot/control/control.c561
-rw-r--r--src/libknot/control/control.h158
-rw-r--r--src/libknot/cookies.c130
-rw-r--r--src/libknot/cookies.h97
-rw-r--r--src/libknot/db/db.h91
-rw-r--r--src/libknot/db/db_lmdb.c568
-rw-r--r--src/libknot/db/db_lmdb.h71
-rw-r--r--src/libknot/db/db_trie.c178
-rw-r--r--src/libknot/db/db_trie.h39
-rw-r--r--src/libknot/descriptor.c411
-rw-r--r--src/libknot/descriptor.h298
-rw-r--r--src/libknot/dname.c755
-rw-r--r--src/libknot/dname.h328
-rw-r--r--src/libknot/endian.h50
-rw-r--r--src/libknot/errcode.h203
-rw-r--r--src/libknot/error.c206
-rw-r--r--src/libknot/error.h49
-rw-r--r--src/libknot/libknot.h65
-rw-r--r--src/libknot/lookup.h88
-rw-r--r--src/libknot/mm_ctx.h40
-rw-r--r--src/libknot/packet/compr.h100
-rw-r--r--src/libknot/packet/pkt.c826
-rw-r--r--src/libknot/packet/pkt.h402
-rw-r--r--src/libknot/packet/rrset-wire.c727
-rw-r--r--src/libknot/packet/rrset-wire.h73
-rw-r--r--src/libknot/packet/wire.h980
-rw-r--r--src/libknot/rdata.h97
-rw-r--r--src/libknot/rdataset.c368
-rw-r--r--src/libknot/rdataset.h201
-rw-r--r--src/libknot/rrset-dump.c2014
-rw-r--r--src/libknot/rrset-dump.h112
-rw-r--r--src/libknot/rrset.c227
-rw-r--r--src/libknot/rrset.h200
-rw-r--r--src/libknot/rrtype/dnskey.h71
-rw-r--r--src/libknot/rrtype/ds.h63
-rw-r--r--src/libknot/rrtype/naptr.c47
-rw-r--r--src/libknot/rrtype/naptr.h40
-rw-r--r--src/libknot/rrtype/nsec.h49
-rw-r--r--src/libknot/rrtype/nsec3.h97
-rw-r--r--src/libknot/rrtype/nsec3param.h63
-rw-r--r--src/libknot/rrtype/opt.c675
-rw-r--r--src/libknot/rrtype/opt.h574
-rw-r--r--src/libknot/rrtype/rdname.h84
-rw-r--r--src/libknot/rrtype/rrsig.h99
-rw-r--r--src/libknot/rrtype/soa.h93
-rw-r--r--src/libknot/rrtype/tsig.c404
-rw-r--r--src/libknot/rrtype/tsig.h121
-rw-r--r--src/libknot/tsig-op.c683
-rw-r--r--src/libknot/tsig-op.h186
-rw-r--r--src/libknot/tsig.c186
-rw-r--r--src/libknot/tsig.h92
-rw-r--r--src/libknot/version.h25
-rw-r--r--src/libknot/version.h.in25
-rw-r--r--src/libknot/wire.h153
-rw-r--r--src/libknot/yparser/yparser.c172
-rw-r--r--src/libknot/yparser/yparser.h148
-rw-r--r--src/libknot/yparser/ypbody.c456
-rw-r--r--src/libknot/yparser/ypformat.c121
-rw-r--r--src/libknot/yparser/ypformat.h100
-rw-r--r--src/libknot/yparser/ypschema.c575
-rw-r--r--src/libknot/yparser/ypschema.h347
-rw-r--r--src/libknot/yparser/yptrafo.c1094
-rw-r--r--src/libknot/yparser/yptrafo.h310
-rw-r--r--src/libzscanner.pc.in13
-rw-r--r--src/libzscanner/Makefile.inc39
-rw-r--r--src/libzscanner/error.c188
-rw-r--r--src/libzscanner/error.h111
-rw-r--r--src/libzscanner/functions.c821
-rw-r--r--src/libzscanner/functions.h110
-rw-r--r--src/libzscanner/scanner.c.g285519
-rw-r--r--src/libzscanner/scanner.c.t08509
-rw-r--r--src/libzscanner/scanner.h370
-rw-r--r--src/libzscanner/scanner.rl541
-rw-r--r--src/libzscanner/scanner_body.rl2088
-rw-r--r--src/libzscanner/version.h25
-rw-r--r--src/libzscanner/version.h.in25
-rw-r--r--src/utils/Makefile.inc139
-rw-r--r--src/utils/common/cert.c61
-rw-r--r--src/utils/common/cert.h36
-rw-r--r--src/utils/common/exec.c692
-rw-r--r--src/utils/common/exec.h97
-rw-r--r--src/utils/common/hex.c82
-rw-r--r--src/utils/common/hex.h42
-rw-r--r--src/utils/common/lookup.c279
-rw-r--r--src/utils/common/lookup.h122
-rw-r--r--src/utils/common/msg.c40
-rw-r--r--src/utils/common/msg.h50
-rw-r--r--src/utils/common/netio.c593
-rw-r--r--src/utils/common/netio.h229
-rw-r--r--src/utils/common/params.c347
-rw-r--r--src/utils/common/params.h172
-rw-r--r--src/utils/common/resolv.c208
-rw-r--r--src/utils/common/resolv.h36
-rw-r--r--src/utils/common/sign.c109
-rw-r--r--src/utils/common/sign.h63
-rw-r--r--src/utils/common/tls.c495
-rw-r--r--src/utils/common/tls.h64
-rw-r--r--src/utils/common/token.c115
-rw-r--r--src/utils/common/token.h77
-rw-r--r--src/utils/kdig/kdig_exec.c1181
-rw-r--r--src/utils/kdig/kdig_exec.h21
-rw-r--r--src/utils/kdig/kdig_main.c43
-rw-r--r--src/utils/kdig/kdig_params.c2317
-rw-r--r--src/utils/kdig/kdig_params.h176
-rw-r--r--src/utils/keymgr/bind_privkey.c352
-rw-r--r--src/utils/keymgr/bind_privkey.h72
-rw-r--r--src/utils/keymgr/functions.c879
-rw-r--r--src/utils/keymgr/functions.h45
-rw-r--r--src/utils/keymgr/main.c373
-rw-r--r--src/utils/khost/khost_main.c43
-rw-r--r--src/utils/khost/khost_params.c365
-rw-r--r--src/utils/khost/khost_params.h22
-rw-r--r--src/utils/kjournalprint/main.c412
-rw-r--r--src/utils/knotc/commands.c1168
-rw-r--r--src/utils/knotc/commands.h68
-rw-r--r--src/utils/knotc/estimator.c147
-rw-r--r--src/utils/knotc/estimator.h64
-rw-r--r--src/utils/knotc/interactive.c433
-rw-r--r--src/utils/knotc/interactive.h26
-rw-r--r--src/utils/knotc/main.c145
-rw-r--r--src/utils/knotc/process.c238
-rw-r--r--src/utils/knotc/process.h69
-rw-r--r--src/utils/knotd/main.c620
-rw-r--r--src/utils/knsec3hash/knsec3hash.c184
-rw-r--r--src/utils/knsupdate/knsupdate_exec.c1058
-rw-r--r--src/utils/knsupdate/knsupdate_exec.h21
-rw-r--r--src/utils/knsupdate/knsupdate_main.c44
-rw-r--r--src/utils/knsupdate/knsupdate_params.c314
-rw-r--r--src/utils/knsupdate/knsupdate_params.h74
-rw-r--r--src/utils/kzonecheck/main.c148
-rw-r--r--src/utils/kzonecheck/zone_check.c91
-rw-r--r--src/utils/kzonecheck/zone_check.h22
478 files changed, 221722 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..247cea9
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,21 @@
+AM_CPPFLAGS = \
+ -include $(top_builddir)/src/config.h \
+ -DCONFIG_DIR='"${config_dir}"' \
+ -DSTORAGE_DIR='"${storage_dir}"' \
+ -DRUN_DIR='"${run_dir}"' \
+ -DMODULE_DIR='"${module_dir}"' \
+ -DMODULE_INSTDIR='"${module_instdir}"'
+
+EXTRA_DIST =
+CLEANFILES =
+BUILT_SOURCES =
+lib_LTLIBRARIES =
+noinst_LTLIBRARIES =
+pkgconfig_DATA =
+
+include $(srcdir)/contrib/Makefile.inc
+include $(srcdir)/libdnssec/Makefile.inc
+include $(srcdir)/libknot/Makefile.inc
+include $(srcdir)/libzscanner/Makefile.inc
+include $(srcdir)/knot/Makefile.inc
+include $(srcdir)/utils/Makefile.inc
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..88f9f97
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,5499 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@HAVE_LMDB_FALSE@am__append_1 = $(pthread_LIBS)
+@HAVE_LMDB_FALSE@am__append_2 = \
+@HAVE_LMDB_FALSE@ contrib/lmdb/lmdb.h \
+@HAVE_LMDB_FALSE@ contrib/lmdb/mdb.c \
+@HAVE_LMDB_FALSE@ contrib/lmdb/midl.c \
+@HAVE_LMDB_FALSE@ contrib/lmdb/midl.h
+
+@HAVE_LIBDNSTAP_TRUE@am__append_3 = libdnstap.la
+@HAVE_LIBDNSTAP_TRUE@am__append_4 = $(nodist_libdnstap_la_SOURCES)
+@HAVE_LIBDNSTAP_TRUE@am__append_5 = $(nodist_libdnstap_la_SOURCES)
+@EXCLUDE_LIBS_LIBDNSSEC_TRUE@am__append_6 = $(LDFLAG_EXCLUDE_LIBS)
+@ENABLE_PKCS11_TRUE@am__append_7 = $(pthread_LIBS)
+@HAVE_DAEMON_TRUE@am__append_8 = libknotd.la
+@HAVE_DAEMON_TRUE@am__append_9 = knotd.pc
+@STATIC_MODULE_cookies_TRUE@am__append_10 = $(knot_modules_cookies_la_SOURCES)
+@SHARED_MODULE_cookies_TRUE@am__append_11 = knot/modules/cookies.la
+@STATIC_MODULE_dnsproxy_TRUE@am__append_12 = $(knot_modules_dnsproxy_la_SOURCES)
+@SHARED_MODULE_dnsproxy_TRUE@am__append_13 = knot/modules/dnsproxy.la
+@STATIC_MODULE_dnstap_TRUE@am__append_14 = $(knot_modules_dnstap_la_SOURCES)
+@STATIC_MODULE_dnstap_TRUE@am__append_15 = $(DNSTAP_CFLAGS)
+@STATIC_MODULE_dnstap_TRUE@am__append_16 = $(DNSTAP_LIBS) libdnstap.la
+@SHARED_MODULE_dnstap_TRUE@am__append_17 = knot/modules/dnstap.la
+@STATIC_MODULE_geoip_TRUE@am__append_18 = $(knot_modules_geoip_la_SOURCES)
+@STATIC_MODULE_geoip_TRUE@am__append_19 = $(libmaxminddb_CFLAGS)
+@STATIC_MODULE_geoip_TRUE@am__append_20 = $(libmaxminddb_LIBS)
+@SHARED_MODULE_geoip_TRUE@am__append_21 = knot/modules/geoip.la
+@STATIC_MODULE_noudp_TRUE@am__append_22 = $(knot_modules_noudp_la_SOURCES)
+@SHARED_MODULE_noudp_TRUE@am__append_23 = knot/modules/noudp.la
+@STATIC_MODULE_onlinesign_TRUE@am__append_24 = $(knot_modules_onlinesign_la_SOURCES)
+@SHARED_MODULE_onlinesign_TRUE@am__append_25 = knot/modules/onlinesign.la
+@STATIC_MODULE_queryacl_TRUE@am__append_26 = $(knot_modules_queryacl_la_SOURCES)
+@SHARED_MODULE_queryacl_TRUE@am__append_27 = knot/modules/queryacl.la
+@STATIC_MODULE_rrl_TRUE@am__append_28 = $(knot_modules_rrl_la_SOURCES)
+@SHARED_MODULE_rrl_TRUE@am__append_29 = knot/modules/rrl.la
+@STATIC_MODULE_stats_TRUE@am__append_30 = $(knot_modules_stats_la_SOURCES)
+@SHARED_MODULE_stats_TRUE@am__append_31 = knot/modules/stats.la
+@STATIC_MODULE_synthrecord_TRUE@am__append_32 = $(knot_modules_synthrecord_la_SOURCES)
+@SHARED_MODULE_synthrecord_TRUE@am__append_33 = knot/modules/synthrecord.la
+@STATIC_MODULE_whoami_TRUE@am__append_34 = $(knot_modules_whoami_la_SOURCES)
+@SHARED_MODULE_whoami_TRUE@am__append_35 = knot/modules/whoami.la
+@HAVE_LIBUTILS_TRUE@am__append_36 = libknotus.la
+@HAVE_UTILS_TRUE@bin_PROGRAMS = kdig$(EXEEXT) khost$(EXEEXT) \
+@HAVE_UTILS_TRUE@ knsec3hash$(EXEEXT) knsupdate$(EXEEXT) \
+@HAVE_UTILS_TRUE@ $(am__EXEEXT_1)
+@HAVE_DNSTAP_TRUE@@HAVE_UTILS_TRUE@am__append_37 = $(DNSTAP_LIBS) libdnstap.la
+@HAVE_DNSTAP_TRUE@@HAVE_UTILS_TRUE@am__append_38 = $(DNSTAP_LIBS) libdnstap.la
+@HAVE_DNSTAP_TRUE@@HAVE_UTILS_TRUE@am__append_39 = $(DNSTAP_CFLAGS)
+@HAVE_DNSTAP_TRUE@@HAVE_UTILS_TRUE@am__append_40 = $(DNSTAP_CFLAGS)
+@HAVE_DAEMON_TRUE@sbin_PROGRAMS = knotc$(EXEEXT) knotd$(EXEEXT) \
+@HAVE_DAEMON_TRUE@ $(am__EXEEXT_2)
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@am__append_41 = kzonecheck
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@am__append_42 = keymgr kjournalprint
+subdir = src
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cc_clang.m4 \
+ $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_compare_version.m4 \
+ $(top_srcdir)/m4/code-coverage.m4 \
+ $(top_srcdir)/m4/knot-lib-version.m4 \
+ $(top_srcdir)/m4/knot-module.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/sanitizer.m4 $(top_srcdir)/m4/visibility.m4 \
+ $(top_srcdir)/m4/knot-version.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(include_libdnssec_HEADERS) \
+ $(include_libknotd_HEADERS) $(include_libzscanner_HEADERS) \
+ $(nobase_include_libknot_HEADERS) $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES = knotd.pc libknot.pc libdnssec.pc libzscanner.pc
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkglibdir)" \
+ "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" \
+ "$(DESTDIR)$(pkgconfigdir)" \
+ "$(DESTDIR)$(include_libdnssecdir)" \
+ "$(DESTDIR)$(include_libknotddir)" \
+ "$(DESTDIR)$(include_libzscannerdir)" \
+ "$(DESTDIR)$(include_libknotdir)"
+LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) \
+ $(pkglib_LTLIBRARIES)
+@SHARED_MODULE_cookies_TRUE@knot_modules_cookies_la_DEPENDENCIES = \
+@SHARED_MODULE_cookies_TRUE@ libcontrib.la
+am__dirstamp = $(am__leading_dot)dirstamp
+am_knot_modules_cookies_la_OBJECTS = \
+ knot/modules/cookies/knot_modules_cookies_la-cookies.lo
+knot_modules_cookies_la_OBJECTS = \
+ $(am_knot_modules_cookies_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+knot_modules_cookies_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(knot_modules_cookies_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@SHARED_MODULE_cookies_TRUE@am_knot_modules_cookies_la_rpath = -rpath \
+@SHARED_MODULE_cookies_TRUE@ $(pkglibdir)
+@SHARED_MODULE_dnsproxy_TRUE@knot_modules_dnsproxy_la_DEPENDENCIES = \
+@SHARED_MODULE_dnsproxy_TRUE@ libcontrib.la
+am_knot_modules_dnsproxy_la_OBJECTS = \
+ knot/modules/dnsproxy/knot_modules_dnsproxy_la-dnsproxy.lo
+knot_modules_dnsproxy_la_OBJECTS = \
+ $(am_knot_modules_dnsproxy_la_OBJECTS)
+knot_modules_dnsproxy_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(knot_modules_dnsproxy_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@SHARED_MODULE_dnsproxy_TRUE@am_knot_modules_dnsproxy_la_rpath = \
+@SHARED_MODULE_dnsproxy_TRUE@ -rpath $(pkglibdir)
+am__DEPENDENCIES_1 =
+@SHARED_MODULE_dnstap_TRUE@knot_modules_dnstap_la_DEPENDENCIES = \
+@SHARED_MODULE_dnstap_TRUE@ $(am__DEPENDENCIES_1) libdnstap.la
+am_knot_modules_dnstap_la_OBJECTS = \
+ knot/modules/dnstap/knot_modules_dnstap_la-dnstap.lo
+knot_modules_dnstap_la_OBJECTS = $(am_knot_modules_dnstap_la_OBJECTS)
+knot_modules_dnstap_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(knot_modules_dnstap_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@SHARED_MODULE_dnstap_TRUE@am_knot_modules_dnstap_la_rpath = -rpath \
+@SHARED_MODULE_dnstap_TRUE@ $(pkglibdir)
+knot_modules_geoip_la_LIBADD =
+am_knot_modules_geoip_la_OBJECTS = \
+ knot/modules/geoip/knot_modules_geoip_la-geoip.lo \
+ knot/modules/geoip/knot_modules_geoip_la-geodb.lo
+knot_modules_geoip_la_OBJECTS = $(am_knot_modules_geoip_la_OBJECTS)
+knot_modules_geoip_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(knot_modules_geoip_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@SHARED_MODULE_geoip_TRUE@am_knot_modules_geoip_la_rpath = -rpath \
+@SHARED_MODULE_geoip_TRUE@ $(pkglibdir)
+knot_modules_noudp_la_LIBADD =
+am_knot_modules_noudp_la_OBJECTS = \
+ knot/modules/noudp/knot_modules_noudp_la-noudp.lo
+knot_modules_noudp_la_OBJECTS = $(am_knot_modules_noudp_la_OBJECTS)
+knot_modules_noudp_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(knot_modules_noudp_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@SHARED_MODULE_noudp_TRUE@am_knot_modules_noudp_la_rpath = -rpath \
+@SHARED_MODULE_noudp_TRUE@ $(pkglibdir)
+@SHARED_MODULE_onlinesign_TRUE@knot_modules_onlinesign_la_DEPENDENCIES = \
+@SHARED_MODULE_onlinesign_TRUE@ libcontrib.la
+am_knot_modules_onlinesign_la_OBJECTS = knot/modules/onlinesign/knot_modules_onlinesign_la-onlinesign.lo \
+ knot/modules/onlinesign/knot_modules_onlinesign_la-nsec_next.lo
+knot_modules_onlinesign_la_OBJECTS = \
+ $(am_knot_modules_onlinesign_la_OBJECTS)
+knot_modules_onlinesign_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(knot_modules_onlinesign_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@SHARED_MODULE_onlinesign_TRUE@am_knot_modules_onlinesign_la_rpath = \
+@SHARED_MODULE_onlinesign_TRUE@ -rpath $(pkglibdir)
+knot_modules_queryacl_la_LIBADD =
+am_knot_modules_queryacl_la_OBJECTS = \
+ knot/modules/queryacl/knot_modules_queryacl_la-queryacl.lo
+knot_modules_queryacl_la_OBJECTS = \
+ $(am_knot_modules_queryacl_la_OBJECTS)
+knot_modules_queryacl_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(knot_modules_queryacl_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@SHARED_MODULE_queryacl_TRUE@am_knot_modules_queryacl_la_rpath = \
+@SHARED_MODULE_queryacl_TRUE@ -rpath $(pkglibdir)
+@SHARED_MODULE_rrl_TRUE@knot_modules_rrl_la_DEPENDENCIES = \
+@SHARED_MODULE_rrl_TRUE@ libcontrib.la
+am_knot_modules_rrl_la_OBJECTS = \
+ knot/modules/rrl/knot_modules_rrl_la-rrl.lo \
+ knot/modules/rrl/knot_modules_rrl_la-functions.lo
+knot_modules_rrl_la_OBJECTS = $(am_knot_modules_rrl_la_OBJECTS)
+knot_modules_rrl_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(knot_modules_rrl_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@SHARED_MODULE_rrl_TRUE@am_knot_modules_rrl_la_rpath = -rpath \
+@SHARED_MODULE_rrl_TRUE@ $(pkglibdir)
+knot_modules_stats_la_LIBADD =
+am_knot_modules_stats_la_OBJECTS = \
+ knot/modules/stats/knot_modules_stats_la-stats.lo
+knot_modules_stats_la_OBJECTS = $(am_knot_modules_stats_la_OBJECTS)
+knot_modules_stats_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(knot_modules_stats_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@SHARED_MODULE_stats_TRUE@am_knot_modules_stats_la_rpath = -rpath \
+@SHARED_MODULE_stats_TRUE@ $(pkglibdir)
+@SHARED_MODULE_synthrecord_TRUE@knot_modules_synthrecord_la_DEPENDENCIES = \
+@SHARED_MODULE_synthrecord_TRUE@ libcontrib.la
+am_knot_modules_synthrecord_la_OBJECTS = knot/modules/synthrecord/knot_modules_synthrecord_la-synthrecord.lo
+knot_modules_synthrecord_la_OBJECTS = \
+ $(am_knot_modules_synthrecord_la_OBJECTS)
+knot_modules_synthrecord_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(knot_modules_synthrecord_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@SHARED_MODULE_synthrecord_TRUE@am_knot_modules_synthrecord_la_rpath = \
+@SHARED_MODULE_synthrecord_TRUE@ -rpath $(pkglibdir)
+knot_modules_whoami_la_LIBADD =
+am_knot_modules_whoami_la_OBJECTS = \
+ knot/modules/whoami/knot_modules_whoami_la-whoami.lo
+knot_modules_whoami_la_OBJECTS = $(am_knot_modules_whoami_la_OBJECTS)
+knot_modules_whoami_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(knot_modules_whoami_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@SHARED_MODULE_whoami_TRUE@am_knot_modules_whoami_la_rpath = -rpath \
+@SHARED_MODULE_whoami_TRUE@ $(pkglibdir)
+libcontrib_la_LIBADD =
+am__libcontrib_la_SOURCES_DIST = contrib/asan.h contrib/base32hex.c \
+ contrib/base32hex.h contrib/base64.c contrib/base64.h \
+ contrib/ctype.h contrib/dynarray.h contrib/files.c \
+ contrib/files.h contrib/getline.c contrib/getline.h \
+ contrib/macros.h contrib/mempattern.c contrib/mempattern.h \
+ contrib/net.c contrib/net.h contrib/qp-trie/trie.c \
+ contrib/qp-trie/trie.h contrib/sockaddr.c contrib/sockaddr.h \
+ contrib/string.c contrib/string.h contrib/strtonum.h \
+ contrib/time.c contrib/time.h contrib/tolower.h contrib/trim.h \
+ contrib/wire_ctx.h contrib/openbsd/siphash.c \
+ contrib/openbsd/siphash.h contrib/openbsd/strlcat.c \
+ contrib/openbsd/strlcat.h contrib/openbsd/strlcpy.c \
+ contrib/openbsd/strlcpy.h contrib/ucw/array-sort.h \
+ contrib/ucw/binsearch.h contrib/ucw/heap.c contrib/ucw/heap.h \
+ contrib/ucw/lists.c contrib/ucw/lists.h contrib/ucw/mempool.c \
+ contrib/ucw/mempool.h contrib/lmdb/lmdb.h contrib/lmdb/mdb.c \
+ contrib/lmdb/midl.c contrib/lmdb/midl.h
+@HAVE_LMDB_FALSE@am__objects_1 = contrib/lmdb/libcontrib_la-mdb.lo \
+@HAVE_LMDB_FALSE@ contrib/lmdb/libcontrib_la-midl.lo
+am_libcontrib_la_OBJECTS = contrib/libcontrib_la-base32hex.lo \
+ contrib/libcontrib_la-base64.lo contrib/libcontrib_la-files.lo \
+ contrib/libcontrib_la-getline.lo \
+ contrib/libcontrib_la-mempattern.lo \
+ contrib/libcontrib_la-net.lo \
+ contrib/qp-trie/libcontrib_la-trie.lo \
+ contrib/libcontrib_la-sockaddr.lo \
+ contrib/libcontrib_la-string.lo contrib/libcontrib_la-time.lo \
+ contrib/openbsd/libcontrib_la-siphash.lo \
+ contrib/openbsd/libcontrib_la-strlcat.lo \
+ contrib/openbsd/libcontrib_la-strlcpy.lo \
+ contrib/ucw/libcontrib_la-heap.lo \
+ contrib/ucw/libcontrib_la-lists.lo \
+ contrib/ucw/libcontrib_la-mempool.lo $(am__objects_1)
+libcontrib_la_OBJECTS = $(am_libcontrib_la_OBJECTS)
+libcontrib_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libcontrib_la_LDFLAGS) $(LDFLAGS) -o $@
+@ENABLE_PKCS11_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
+libdnssec_la_DEPENDENCIES = libshared.la $(am__DEPENDENCIES_2)
+am_libdnssec_la_OBJECTS = libdnssec/contrib/libdnssec_la-vpool.lo \
+ libdnssec/libdnssec_la-binary.lo \
+ libdnssec/libdnssec_la-crypto.lo \
+ libdnssec/libdnssec_la-error.lo \
+ libdnssec/key/libdnssec_la-algorithm.lo \
+ libdnssec/key/libdnssec_la-convert.lo \
+ libdnssec/key/libdnssec_la-dnskey.lo \
+ libdnssec/key/libdnssec_la-ds.lo \
+ libdnssec/key/libdnssec_la-key.lo \
+ libdnssec/key/libdnssec_la-keytag.lo \
+ libdnssec/key/libdnssec_la-privkey.lo \
+ libdnssec/key/libdnssec_la-simple.lo \
+ libdnssec/libdnssec_la-keyid.lo \
+ libdnssec/keystore/libdnssec_la-keystore.lo \
+ libdnssec/keystore/libdnssec_la-pkcs11.lo \
+ libdnssec/keystore/libdnssec_la-pkcs8.lo \
+ libdnssec/keystore/libdnssec_la-pkcs8_dir.lo \
+ libdnssec/list/libdnssec_la-list.lo \
+ libdnssec/nsec/libdnssec_la-bitmap.lo \
+ libdnssec/nsec/libdnssec_la-hash.lo \
+ libdnssec/nsec/libdnssec_la-nsec.lo \
+ libdnssec/p11/libdnssec_la-p11.lo \
+ libdnssec/libdnssec_la-random.lo \
+ libdnssec/sign/libdnssec_la-der.lo \
+ libdnssec/sign/libdnssec_la-sign.lo \
+ libdnssec/libdnssec_la-tsig.lo
+libdnssec_la_OBJECTS = $(am_libdnssec_la_OBJECTS)
+libdnssec_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libdnssec_la_LDFLAGS) $(LDFLAGS) -o $@
+libdnstap_la_LIBADD =
+am__libdnstap_la_SOURCES_DIST = contrib/dnstap/convert.c \
+ contrib/dnstap/convert.h contrib/dnstap/dnstap.c \
+ contrib/dnstap/dnstap.h contrib/dnstap/message.c \
+ contrib/dnstap/message.h contrib/dnstap/reader.c \
+ contrib/dnstap/reader.h contrib/dnstap/writer.c \
+ contrib/dnstap/writer.h
+@HAVE_LIBDNSTAP_TRUE@am_libdnstap_la_OBJECTS = \
+@HAVE_LIBDNSTAP_TRUE@ contrib/dnstap/libdnstap_la-convert.lo \
+@HAVE_LIBDNSTAP_TRUE@ contrib/dnstap/libdnstap_la-dnstap.lo \
+@HAVE_LIBDNSTAP_TRUE@ contrib/dnstap/libdnstap_la-message.lo \
+@HAVE_LIBDNSTAP_TRUE@ contrib/dnstap/libdnstap_la-reader.lo \
+@HAVE_LIBDNSTAP_TRUE@ contrib/dnstap/libdnstap_la-writer.lo
+@HAVE_LIBDNSTAP_TRUE@nodist_libdnstap_la_OBJECTS = contrib/dnstap/libdnstap_la-dnstap.pb-c.lo
+libdnstap_la_OBJECTS = $(am_libdnstap_la_OBJECTS) \
+ $(nodist_libdnstap_la_OBJECTS)
+libdnstap_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libdnstap_la_LDFLAGS) $(LDFLAGS) -o $@
+@HAVE_LIBDNSTAP_TRUE@am_libdnstap_la_rpath =
+libknot_la_DEPENDENCIES = libcontrib.la libdnssec.la \
+ $(am__DEPENDENCIES_1)
+am_libknot_la_OBJECTS = libknot/libknot_la-codes.lo \
+ libknot/control/libknot_la-control.lo \
+ libknot/libknot_la-cookies.lo libknot/libknot_la-descriptor.lo \
+ libknot/libknot_la-dname.lo libknot/libknot_la-error.lo \
+ libknot/db/libknot_la-db_lmdb.lo \
+ libknot/db/libknot_la-db_trie.lo \
+ libknot/packet/libknot_la-pkt.lo \
+ libknot/packet/libknot_la-rrset-wire.lo \
+ libknot/libknot_la-rdataset.lo \
+ libknot/libknot_la-rrset-dump.lo libknot/libknot_la-rrset.lo \
+ libknot/rrtype/libknot_la-naptr.lo \
+ libknot/rrtype/libknot_la-opt.lo \
+ libknot/rrtype/libknot_la-tsig.lo \
+ libknot/libknot_la-tsig-op.lo libknot/libknot_la-tsig.lo \
+ libknot/yparser/libknot_la-yparser.lo \
+ libknot/yparser/libknot_la-ypbody.lo \
+ libknot/yparser/libknot_la-ypformat.lo \
+ libknot/yparser/libknot_la-ypschema.lo \
+ libknot/yparser/libknot_la-yptrafo.lo
+libknot_la_OBJECTS = $(am_libknot_la_OBJECTS)
+libknot_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libknot_la_LDFLAGS) $(LDFLAGS) -o $@
+@STATIC_MODULE_dnstap_TRUE@am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1) \
+@STATIC_MODULE_dnstap_TRUE@ libdnstap.la
+@STATIC_MODULE_geoip_TRUE@am__DEPENDENCIES_4 = $(am__DEPENDENCIES_1)
+libknotd_la_DEPENDENCIES = libcontrib.la libknot.la libzscanner.la \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_4)
+am__libknotd_la_SOURCES_DIST = knot/conf/base.c knot/conf/base.h \
+ knot/conf/conf.c knot/conf/conf.h knot/conf/confdb.c \
+ knot/conf/confdb.h knot/conf/confio.c knot/conf/confio.h \
+ knot/conf/migration.c knot/conf/migration.h knot/conf/module.h \
+ knot/conf/module.c knot/conf/schema.c knot/conf/schema.h \
+ knot/conf/tools.c knot/conf/tools.h knot/ctl/commands.c \
+ knot/ctl/commands.h knot/ctl/process.c knot/ctl/process.h \
+ knot/dnssec/context.c knot/dnssec/context.h \
+ knot/dnssec/ds_query.c knot/dnssec/ds_query.h \
+ knot/dnssec/kasp/kasp_db.c knot/dnssec/kasp/kasp_db.h \
+ knot/dnssec/kasp/kasp_zone.c knot/dnssec/kasp/kasp_zone.h \
+ knot/dnssec/kasp/keystate.c knot/dnssec/kasp/keystate.h \
+ knot/dnssec/kasp/keystore.c knot/dnssec/kasp/keystore.h \
+ knot/dnssec/kasp/policy.h knot/dnssec/key-events.c \
+ knot/dnssec/key-events.h knot/dnssec/nsec-chain.c \
+ knot/dnssec/nsec-chain.h knot/dnssec/nsec3-chain.c \
+ knot/dnssec/nsec3-chain.h knot/dnssec/policy.c \
+ knot/dnssec/policy.h knot/dnssec/rrset-sign.c \
+ knot/dnssec/rrset-sign.h knot/dnssec/zone-events.c \
+ knot/dnssec/zone-events.h knot/dnssec/zone-keys.c \
+ knot/dnssec/zone-keys.h knot/dnssec/zone-nsec.c \
+ knot/dnssec/zone-nsec.h knot/dnssec/zone-sign.c \
+ knot/dnssec/zone-sign.h knot/events/events.c \
+ knot/events/events.h knot/events/handlers.h \
+ knot/events/handlers/dnssec.c knot/events/handlers/expire.c \
+ knot/events/handlers/flush.c \
+ knot/events/handlers/freeze_thaw.c knot/events/handlers/load.c \
+ knot/events/handlers/notify.c \
+ knot/events/handlers/nsec3resalt.c \
+ knot/events/handlers/refresh.c knot/events/handlers/update.c \
+ knot/events/handlers/parent_ds_query.c knot/events/replan.c \
+ knot/events/replan.h knot/nameserver/axfr.c \
+ knot/nameserver/axfr.h knot/nameserver/chaos.c \
+ knot/nameserver/chaos.h knot/nameserver/internet.c \
+ knot/nameserver/internet.h knot/nameserver/ixfr.c \
+ knot/nameserver/ixfr.h knot/nameserver/log.h \
+ knot/nameserver/notify.c knot/nameserver/notify.h \
+ knot/nameserver/nsec_proofs.c knot/nameserver/nsec_proofs.h \
+ knot/nameserver/process_query.c \
+ knot/nameserver/process_query.h knot/nameserver/query_module.c \
+ knot/nameserver/query_module.h knot/nameserver/tsig_ctx.c \
+ knot/nameserver/tsig_ctx.h knot/nameserver/update.c \
+ knot/nameserver/update.h knot/nameserver/xfr.c \
+ knot/nameserver/xfr.h knot/query/capture.c \
+ knot/query/capture.h knot/query/layer.h knot/query/query.c \
+ knot/query/query.h knot/query/requestor.c \
+ knot/query/requestor.h knot/common/evsched.c \
+ knot/common/evsched.h knot/common/fdset.c knot/common/fdset.h \
+ knot/common/log.c knot/common/log.h knot/common/process.c \
+ knot/common/process.h knot/common/ref.c knot/common/ref.h \
+ knot/common/stats.c knot/common/stats.h knot/server/dthreads.c \
+ knot/server/dthreads.h knot/journal/chgset_ctx.c \
+ knot/journal/chgset_ctx.h knot/journal/journal.c \
+ knot/journal/journal.h knot/journal/serialization.c \
+ knot/journal/serialization.h knot/server/server.c \
+ knot/server/server.h knot/server/tcp-handler.c \
+ knot/server/tcp-handler.h knot/server/udp-handler.c \
+ knot/server/udp-handler.h knot/updates/acl.c \
+ knot/updates/acl.h knot/updates/apply.c knot/updates/apply.h \
+ knot/updates/changesets.c knot/updates/changesets.h \
+ knot/updates/ddns.c knot/updates/ddns.h \
+ knot/updates/zone-update.c knot/updates/zone-update.h \
+ knot/worker/pool.c knot/worker/pool.h knot/worker/queue.c \
+ knot/worker/queue.h knot/zone/contents.c knot/zone/contents.h \
+ knot/zone/node.c knot/zone/node.h knot/zone/semantic-check.c \
+ knot/zone/semantic-check.h knot/zone/serial.c \
+ knot/zone/serial.h knot/zone/timers.c knot/zone/timers.h \
+ knot/zone/zone-diff.c knot/zone/zone-diff.h \
+ knot/zone/zone-dump.c knot/zone/zone-dump.h \
+ knot/zone/zone-load.c knot/zone/zone-load.h \
+ knot/zone/zone-tree.c knot/zone/zone-tree.h knot/zone/zone.c \
+ knot/zone/zone.h knot/zone/zonedb-load.c \
+ knot/zone/zonedb-load.h knot/zone/zonedb.c knot/zone/zonedb.h \
+ knot/zone/zonefile.c knot/zone/zonefile.h \
+ knot/modules/cookies/cookies.c \
+ knot/modules/dnsproxy/dnsproxy.c knot/modules/dnstap/dnstap.c \
+ knot/modules/geoip/geoip.c knot/modules/geoip/geodb.c \
+ knot/modules/geoip/geodb.h knot/modules/noudp/noudp.c \
+ knot/modules/onlinesign/onlinesign.c \
+ knot/modules/onlinesign/nsec_next.c \
+ knot/modules/onlinesign/nsec_next.h \
+ knot/modules/queryacl/queryacl.c knot/modules/rrl/rrl.c \
+ knot/modules/rrl/functions.c knot/modules/rrl/functions.h \
+ knot/modules/stats/stats.c \
+ knot/modules/synthrecord/synthrecord.c \
+ knot/modules/whoami/whoami.c
+am__objects_2 = knot/modules/cookies/libknotd_la-cookies.lo
+@STATIC_MODULE_cookies_TRUE@am__objects_3 = $(am__objects_2)
+am__objects_4 = knot/modules/dnsproxy/libknotd_la-dnsproxy.lo
+@STATIC_MODULE_dnsproxy_TRUE@am__objects_5 = $(am__objects_4)
+am__objects_6 = knot/modules/dnstap/libknotd_la-dnstap.lo
+@STATIC_MODULE_dnstap_TRUE@am__objects_7 = $(am__objects_6)
+am__objects_8 = knot/modules/geoip/libknotd_la-geoip.lo \
+ knot/modules/geoip/libknotd_la-geodb.lo
+@STATIC_MODULE_geoip_TRUE@am__objects_9 = $(am__objects_8)
+am__objects_10 = knot/modules/noudp/libknotd_la-noudp.lo
+@STATIC_MODULE_noudp_TRUE@am__objects_11 = $(am__objects_10)
+am__objects_12 = knot/modules/onlinesign/libknotd_la-onlinesign.lo \
+ knot/modules/onlinesign/libknotd_la-nsec_next.lo
+@STATIC_MODULE_onlinesign_TRUE@am__objects_13 = $(am__objects_12)
+am__objects_14 = knot/modules/queryacl/libknotd_la-queryacl.lo
+@STATIC_MODULE_queryacl_TRUE@am__objects_15 = $(am__objects_14)
+am__objects_16 = knot/modules/rrl/libknotd_la-rrl.lo \
+ knot/modules/rrl/libknotd_la-functions.lo
+@STATIC_MODULE_rrl_TRUE@am__objects_17 = $(am__objects_16)
+am__objects_18 = knot/modules/stats/libknotd_la-stats.lo
+@STATIC_MODULE_stats_TRUE@am__objects_19 = $(am__objects_18)
+am__objects_20 = knot/modules/synthrecord/libknotd_la-synthrecord.lo
+@STATIC_MODULE_synthrecord_TRUE@am__objects_21 = $(am__objects_20)
+am__objects_22 = knot/modules/whoami/libknotd_la-whoami.lo
+@STATIC_MODULE_whoami_TRUE@am__objects_23 = $(am__objects_22)
+am_libknotd_la_OBJECTS = knot/conf/libknotd_la-base.lo \
+ knot/conf/libknotd_la-conf.lo knot/conf/libknotd_la-confdb.lo \
+ knot/conf/libknotd_la-confio.lo \
+ knot/conf/libknotd_la-migration.lo \
+ knot/conf/libknotd_la-module.lo \
+ knot/conf/libknotd_la-schema.lo knot/conf/libknotd_la-tools.lo \
+ knot/ctl/libknotd_la-commands.lo \
+ knot/ctl/libknotd_la-process.lo \
+ knot/dnssec/libknotd_la-context.lo \
+ knot/dnssec/libknotd_la-ds_query.lo \
+ knot/dnssec/kasp/libknotd_la-kasp_db.lo \
+ knot/dnssec/kasp/libknotd_la-kasp_zone.lo \
+ knot/dnssec/kasp/libknotd_la-keystate.lo \
+ knot/dnssec/kasp/libknotd_la-keystore.lo \
+ knot/dnssec/libknotd_la-key-events.lo \
+ knot/dnssec/libknotd_la-nsec-chain.lo \
+ knot/dnssec/libknotd_la-nsec3-chain.lo \
+ knot/dnssec/libknotd_la-policy.lo \
+ knot/dnssec/libknotd_la-rrset-sign.lo \
+ knot/dnssec/libknotd_la-zone-events.lo \
+ knot/dnssec/libknotd_la-zone-keys.lo \
+ knot/dnssec/libknotd_la-zone-nsec.lo \
+ knot/dnssec/libknotd_la-zone-sign.lo \
+ knot/events/libknotd_la-events.lo \
+ knot/events/handlers/libknotd_la-dnssec.lo \
+ knot/events/handlers/libknotd_la-expire.lo \
+ knot/events/handlers/libknotd_la-flush.lo \
+ knot/events/handlers/libknotd_la-freeze_thaw.lo \
+ knot/events/handlers/libknotd_la-load.lo \
+ knot/events/handlers/libknotd_la-notify.lo \
+ knot/events/handlers/libknotd_la-nsec3resalt.lo \
+ knot/events/handlers/libknotd_la-refresh.lo \
+ knot/events/handlers/libknotd_la-update.lo \
+ knot/events/handlers/libknotd_la-parent_ds_query.lo \
+ knot/events/libknotd_la-replan.lo \
+ knot/nameserver/libknotd_la-axfr.lo \
+ knot/nameserver/libknotd_la-chaos.lo \
+ knot/nameserver/libknotd_la-internet.lo \
+ knot/nameserver/libknotd_la-ixfr.lo \
+ knot/nameserver/libknotd_la-notify.lo \
+ knot/nameserver/libknotd_la-nsec_proofs.lo \
+ knot/nameserver/libknotd_la-process_query.lo \
+ knot/nameserver/libknotd_la-query_module.lo \
+ knot/nameserver/libknotd_la-tsig_ctx.lo \
+ knot/nameserver/libknotd_la-update.lo \
+ knot/nameserver/libknotd_la-xfr.lo \
+ knot/query/libknotd_la-capture.lo \
+ knot/query/libknotd_la-query.lo \
+ knot/query/libknotd_la-requestor.lo \
+ knot/common/libknotd_la-evsched.lo \
+ knot/common/libknotd_la-fdset.lo \
+ knot/common/libknotd_la-log.lo \
+ knot/common/libknotd_la-process.lo \
+ knot/common/libknotd_la-ref.lo \
+ knot/common/libknotd_la-stats.lo \
+ knot/server/libknotd_la-dthreads.lo \
+ knot/journal/libknotd_la-chgset_ctx.lo \
+ knot/journal/libknotd_la-journal.lo \
+ knot/journal/libknotd_la-serialization.lo \
+ knot/server/libknotd_la-server.lo \
+ knot/server/libknotd_la-tcp-handler.lo \
+ knot/server/libknotd_la-udp-handler.lo \
+ knot/updates/libknotd_la-acl.lo \
+ knot/updates/libknotd_la-apply.lo \
+ knot/updates/libknotd_la-changesets.lo \
+ knot/updates/libknotd_la-ddns.lo \
+ knot/updates/libknotd_la-zone-update.lo \
+ knot/worker/libknotd_la-pool.lo \
+ knot/worker/libknotd_la-queue.lo \
+ knot/zone/libknotd_la-contents.lo \
+ knot/zone/libknotd_la-node.lo \
+ knot/zone/libknotd_la-semantic-check.lo \
+ knot/zone/libknotd_la-serial.lo \
+ knot/zone/libknotd_la-timers.lo \
+ knot/zone/libknotd_la-zone-diff.lo \
+ knot/zone/libknotd_la-zone-dump.lo \
+ knot/zone/libknotd_la-zone-load.lo \
+ knot/zone/libknotd_la-zone-tree.lo \
+ knot/zone/libknotd_la-zone.lo \
+ knot/zone/libknotd_la-zonedb-load.lo \
+ knot/zone/libknotd_la-zonedb.lo \
+ knot/zone/libknotd_la-zonefile.lo $(am__objects_3) \
+ $(am__objects_5) $(am__objects_7) $(am__objects_9) \
+ $(am__objects_11) $(am__objects_13) $(am__objects_15) \
+ $(am__objects_17) $(am__objects_19) $(am__objects_21) \
+ $(am__objects_23)
+libknotd_la_OBJECTS = $(am_libknotd_la_OBJECTS)
+libknotd_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libknotd_la_LDFLAGS) $(LDFLAGS) -o $@
+@HAVE_DAEMON_TRUE@am_libknotd_la_rpath =
+@HAVE_LIBUTILS_TRUE@libknotus_la_DEPENDENCIES = libcontrib.la \
+@HAVE_LIBUTILS_TRUE@ libknot.la $(am__DEPENDENCIES_1) \
+@HAVE_LIBUTILS_TRUE@ $(am__DEPENDENCIES_1) \
+@HAVE_LIBUTILS_TRUE@ $(am__DEPENDENCIES_1) \
+@HAVE_LIBUTILS_TRUE@ $(am__DEPENDENCIES_1)
+am__libknotus_la_SOURCES_DIST = utils/common/cert.c \
+ utils/common/cert.h utils/common/exec.c utils/common/exec.h \
+ utils/common/hex.c utils/common/hex.h utils/common/lookup.c \
+ utils/common/lookup.h utils/common/msg.c utils/common/msg.h \
+ utils/common/netio.c utils/common/netio.h \
+ utils/common/params.c utils/common/params.h \
+ utils/common/resolv.c utils/common/resolv.h \
+ utils/common/sign.c utils/common/sign.h utils/common/tls.c \
+ utils/common/tls.h utils/common/token.c utils/common/token.h
+@HAVE_LIBUTILS_TRUE@am_libknotus_la_OBJECTS = \
+@HAVE_LIBUTILS_TRUE@ utils/common/libknotus_la-cert.lo \
+@HAVE_LIBUTILS_TRUE@ utils/common/libknotus_la-exec.lo \
+@HAVE_LIBUTILS_TRUE@ utils/common/libknotus_la-hex.lo \
+@HAVE_LIBUTILS_TRUE@ utils/common/libknotus_la-lookup.lo \
+@HAVE_LIBUTILS_TRUE@ utils/common/libknotus_la-msg.lo \
+@HAVE_LIBUTILS_TRUE@ utils/common/libknotus_la-netio.lo \
+@HAVE_LIBUTILS_TRUE@ utils/common/libknotus_la-params.lo \
+@HAVE_LIBUTILS_TRUE@ utils/common/libknotus_la-resolv.lo \
+@HAVE_LIBUTILS_TRUE@ utils/common/libknotus_la-sign.lo \
+@HAVE_LIBUTILS_TRUE@ utils/common/libknotus_la-tls.lo \
+@HAVE_LIBUTILS_TRUE@ utils/common/libknotus_la-token.lo
+libknotus_la_OBJECTS = $(am_libknotus_la_OBJECTS)
+libknotus_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libknotus_la_LDFLAGS) $(LDFLAGS) -o $@
+@HAVE_LIBUTILS_TRUE@am_libknotus_la_rpath =
+libshared_la_LIBADD =
+am_libshared_la_OBJECTS = libdnssec/shared/libshared_la-bignum.lo \
+ libdnssec/shared/libshared_la-dname.lo \
+ libdnssec/shared/libshared_la-fs.lo \
+ libdnssec/shared/libshared_la-hex.lo \
+ libdnssec/shared/libshared_la-keyid_gnutls.lo \
+ libdnssec/shared/libshared_la-pem.lo
+libshared_la_OBJECTS = $(am_libshared_la_OBJECTS)
+libzscanner_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am__objects_24 =
+am_libzscanner_la_OBJECTS = libzscanner/libzscanner_la-error.lo \
+ libzscanner/libzscanner_la-functions.lo $(am__objects_24)
+nodist_libzscanner_la_OBJECTS = libzscanner/libzscanner_la-scanner.lo
+libzscanner_la_OBJECTS = $(am_libzscanner_la_OBJECTS) \
+ $(nodist_libzscanner_la_OBJECTS)
+libzscanner_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(libzscanner_la_LDFLAGS) $(LDFLAGS) -o \
+ $@
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@am__EXEEXT_1 = kzonecheck$(EXEEXT)
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@am__EXEEXT_2 = keymgr$(EXEEXT) \
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ kjournalprint$(EXEEXT)
+PROGRAMS = $(bin_PROGRAMS) $(sbin_PROGRAMS)
+am__kdig_SOURCES_DIST = utils/kdig/kdig_exec.c utils/kdig/kdig_exec.h \
+ utils/kdig/kdig_main.c utils/kdig/kdig_params.c \
+ utils/kdig/kdig_params.h
+@HAVE_UTILS_TRUE@am_kdig_OBJECTS = \
+@HAVE_UTILS_TRUE@ utils/kdig/kdig-kdig_exec.$(OBJEXT) \
+@HAVE_UTILS_TRUE@ utils/kdig/kdig-kdig_main.$(OBJEXT) \
+@HAVE_UTILS_TRUE@ utils/kdig/kdig-kdig_params.$(OBJEXT)
+kdig_OBJECTS = $(am_kdig_OBJECTS)
+@HAVE_DNSTAP_TRUE@@HAVE_UTILS_TRUE@am__DEPENDENCIES_5 = \
+@HAVE_DNSTAP_TRUE@@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_1) \
+@HAVE_DNSTAP_TRUE@@HAVE_UTILS_TRUE@ libdnstap.la
+@HAVE_UTILS_TRUE@kdig_DEPENDENCIES = libknotus.la \
+@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_5)
+am__keymgr_SOURCES_DIST = utils/keymgr/bind_privkey.c \
+ utils/keymgr/bind_privkey.h utils/keymgr/functions.c \
+ utils/keymgr/functions.h utils/keymgr/main.c
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@am_keymgr_OBJECTS = utils/keymgr/keymgr-bind_privkey.$(OBJEXT) \
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ utils/keymgr/keymgr-functions.$(OBJEXT) \
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ utils/keymgr/keymgr-main.$(OBJEXT)
+keymgr_OBJECTS = $(am_keymgr_OBJECTS)
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@keymgr_DEPENDENCIES = \
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ libcontrib.la libknotd.la \
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ libknotus.la libdnssec.la \
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ libshared.la libzscanner.la
+am__khost_SOURCES_DIST = utils/kdig/kdig_exec.c utils/kdig/kdig_exec.h \
+ utils/kdig/kdig_params.c utils/kdig/kdig_params.h \
+ utils/khost/khost_main.c utils/khost/khost_params.c \
+ utils/khost/khost_params.h
+@HAVE_UTILS_TRUE@am_khost_OBJECTS = \
+@HAVE_UTILS_TRUE@ utils/kdig/khost-kdig_exec.$(OBJEXT) \
+@HAVE_UTILS_TRUE@ utils/kdig/khost-kdig_params.$(OBJEXT) \
+@HAVE_UTILS_TRUE@ utils/khost/khost-khost_main.$(OBJEXT) \
+@HAVE_UTILS_TRUE@ utils/khost/khost-khost_params.$(OBJEXT)
+khost_OBJECTS = $(am_khost_OBJECTS)
+@HAVE_UTILS_TRUE@khost_DEPENDENCIES = libknotus.la \
+@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_5)
+am__kjournalprint_SOURCES_DIST = utils/kjournalprint/main.c
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@am_kjournalprint_OBJECTS = utils/kjournalprint/kjournalprint-main.$(OBJEXT)
+kjournalprint_OBJECTS = $(am_kjournalprint_OBJECTS)
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@kjournalprint_DEPENDENCIES = \
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ libcontrib.la libknotd.la
+am__knotc_SOURCES_DIST = utils/knotc/commands.c utils/knotc/commands.h \
+ utils/knotc/estimator.c utils/knotc/estimator.h \
+ utils/knotc/interactive.c utils/knotc/interactive.h \
+ utils/knotc/process.c utils/knotc/process.h utils/knotc/main.c
+@HAVE_DAEMON_TRUE@am_knotc_OBJECTS = \
+@HAVE_DAEMON_TRUE@ utils/knotc/knotc-commands.$(OBJEXT) \
+@HAVE_DAEMON_TRUE@ utils/knotc/knotc-estimator.$(OBJEXT) \
+@HAVE_DAEMON_TRUE@ utils/knotc/knotc-interactive.$(OBJEXT) \
+@HAVE_DAEMON_TRUE@ utils/knotc/knotc-process.$(OBJEXT) \
+@HAVE_DAEMON_TRUE@ utils/knotc/knotc-main.$(OBJEXT)
+knotc_OBJECTS = $(am_knotc_OBJECTS)
+@HAVE_DAEMON_TRUE@knotc_DEPENDENCIES = libcontrib.la libknotd.la \
+@HAVE_DAEMON_TRUE@ libknotus.la $(am__DEPENDENCIES_1)
+knotc_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(knotc_LDFLAGS) $(LDFLAGS) -o $@
+am__knotd_SOURCES_DIST = utils/knotd/main.c
+@HAVE_DAEMON_TRUE@am_knotd_OBJECTS = utils/knotd/knotd-main.$(OBJEXT)
+knotd_OBJECTS = $(am_knotd_OBJECTS)
+@HAVE_DAEMON_TRUE@knotd_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+@HAVE_DAEMON_TRUE@ libcontrib.la libknotd.la \
+@HAVE_DAEMON_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+knotd_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(knotd_LDFLAGS) $(LDFLAGS) -o $@
+am__knsec3hash_SOURCES_DIST = utils/knsec3hash/knsec3hash.c
+@HAVE_UTILS_TRUE@am_knsec3hash_OBJECTS = utils/knsec3hash/knsec3hash-knsec3hash.$(OBJEXT)
+knsec3hash_OBJECTS = $(am_knsec3hash_OBJECTS)
+@HAVE_UTILS_TRUE@knsec3hash_DEPENDENCIES = libcontrib.la libdnssec.la \
+@HAVE_UTILS_TRUE@ libknot.la libshared.la
+am__knsupdate_SOURCES_DIST = utils/knsupdate/knsupdate_exec.c \
+ utils/knsupdate/knsupdate_exec.h \
+ utils/knsupdate/knsupdate_main.c \
+ utils/knsupdate/knsupdate_params.c \
+ utils/knsupdate/knsupdate_params.h
+@HAVE_UTILS_TRUE@am_knsupdate_OBJECTS = utils/knsupdate/knsupdate-knsupdate_exec.$(OBJEXT) \
+@HAVE_UTILS_TRUE@ utils/knsupdate/knsupdate-knsupdate_main.$(OBJEXT) \
+@HAVE_UTILS_TRUE@ utils/knsupdate/knsupdate-knsupdate_params.$(OBJEXT)
+knsupdate_OBJECTS = $(am_knsupdate_OBJECTS)
+@HAVE_UTILS_TRUE@knsupdate_DEPENDENCIES = libknotus.la libzscanner.la
+am__kzonecheck_SOURCES_DIST = utils/kzonecheck/main.c \
+ utils/kzonecheck/zone_check.c utils/kzonecheck/zone_check.h
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@am_kzonecheck_OBJECTS = utils/kzonecheck/kzonecheck-main.$(OBJEXT) \
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ utils/kzonecheck/kzonecheck-zone_check.$(OBJEXT)
+kzonecheck_OBJECTS = $(am_kzonecheck_OBJECTS)
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@kzonecheck_DEPENDENCIES = \
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ libcontrib.la libknotd.la
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(knot_modules_cookies_la_SOURCES) \
+ $(knot_modules_dnsproxy_la_SOURCES) \
+ $(knot_modules_dnstap_la_SOURCES) \
+ $(knot_modules_geoip_la_SOURCES) \
+ $(knot_modules_noudp_la_SOURCES) \
+ $(knot_modules_onlinesign_la_SOURCES) \
+ $(knot_modules_queryacl_la_SOURCES) \
+ $(knot_modules_rrl_la_SOURCES) \
+ $(knot_modules_stats_la_SOURCES) \
+ $(knot_modules_synthrecord_la_SOURCES) \
+ $(knot_modules_whoami_la_SOURCES) $(libcontrib_la_SOURCES) \
+ $(libdnssec_la_SOURCES) $(libdnstap_la_SOURCES) \
+ $(nodist_libdnstap_la_SOURCES) $(libknot_la_SOURCES) \
+ $(libknotd_la_SOURCES) $(libknotus_la_SOURCES) \
+ $(libshared_la_SOURCES) $(libzscanner_la_SOURCES) \
+ $(nodist_libzscanner_la_SOURCES) $(kdig_SOURCES) \
+ $(keymgr_SOURCES) $(khost_SOURCES) $(kjournalprint_SOURCES) \
+ $(knotc_SOURCES) $(knotd_SOURCES) $(knsec3hash_SOURCES) \
+ $(knsupdate_SOURCES) $(kzonecheck_SOURCES)
+DIST_SOURCES = $(knot_modules_cookies_la_SOURCES) \
+ $(knot_modules_dnsproxy_la_SOURCES) \
+ $(knot_modules_dnstap_la_SOURCES) \
+ $(knot_modules_geoip_la_SOURCES) \
+ $(knot_modules_noudp_la_SOURCES) \
+ $(knot_modules_onlinesign_la_SOURCES) \
+ $(knot_modules_queryacl_la_SOURCES) \
+ $(knot_modules_rrl_la_SOURCES) \
+ $(knot_modules_stats_la_SOURCES) \
+ $(knot_modules_synthrecord_la_SOURCES) \
+ $(knot_modules_whoami_la_SOURCES) \
+ $(am__libcontrib_la_SOURCES_DIST) $(libdnssec_la_SOURCES) \
+ $(am__libdnstap_la_SOURCES_DIST) $(libknot_la_SOURCES) \
+ $(am__libknotd_la_SOURCES_DIST) \
+ $(am__libknotus_la_SOURCES_DIST) $(libshared_la_SOURCES) \
+ $(libzscanner_la_SOURCES) $(am__kdig_SOURCES_DIST) \
+ $(am__keymgr_SOURCES_DIST) $(am__khost_SOURCES_DIST) \
+ $(am__kjournalprint_SOURCES_DIST) $(am__knotc_SOURCES_DIST) \
+ $(am__knotd_SOURCES_DIST) $(am__knsec3hash_SOURCES_DIST) \
+ $(am__knsupdate_SOURCES_DIST) $(am__kzonecheck_SOURCES_DIST)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+DATA = $(pkgconfig_DATA)
+HEADERS = $(include_libdnssec_HEADERS) $(include_libknotd_HEADERS) \
+ $(include_libzscanner_HEADERS) \
+ $(nobase_include_libknot_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \
+ $(LISP)config.h.in
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \
+ $(srcdir)/contrib/Makefile.inc $(srcdir)/knot/Makefile.inc \
+ $(srcdir)/knot/modules/cookies/Makefile.inc \
+ $(srcdir)/knot/modules/dnsproxy/Makefile.inc \
+ $(srcdir)/knot/modules/dnstap/Makefile.inc \
+ $(srcdir)/knot/modules/geoip/Makefile.inc \
+ $(srcdir)/knot/modules/noudp/Makefile.inc \
+ $(srcdir)/knot/modules/onlinesign/Makefile.inc \
+ $(srcdir)/knot/modules/queryacl/Makefile.inc \
+ $(srcdir)/knot/modules/rrl/Makefile.inc \
+ $(srcdir)/knot/modules/stats/Makefile.inc \
+ $(srcdir)/knot/modules/synthrecord/Makefile.inc \
+ $(srcdir)/knot/modules/whoami/Makefile.inc \
+ $(srcdir)/knotd.pc.in $(srcdir)/libdnssec.pc.in \
+ $(srcdir)/libdnssec/Makefile.inc $(srcdir)/libknot.pc.in \
+ $(srcdir)/libknot/Makefile.inc $(srcdir)/libzscanner.pc.in \
+ $(srcdir)/libzscanner/Makefile.inc \
+ $(srcdir)/utils/Makefile.inc $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+pkglibdir = $(module_instdir)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CC_CLANG_VERSION = @CC_CLANG_VERSION@
+CFLAGS = @CFLAGS@
+CFLAG_VISIBILITY = @CFLAG_VISIBILITY@
+CODE_COVERAGE_ENABLED = @CODE_COVERAGE_ENABLED@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DNSTAP_CFLAGS = @DNSTAP_CFLAGS@
+DNSTAP_LIBS = @DNSTAP_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GENHTML = @GENHTML@
+GREP = @GREP@
+HAVE_VISIBILITY = @HAVE_VISIBILITY@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+KNOT_VERSION_MAJOR = @KNOT_VERSION_MAJOR@
+KNOT_VERSION_MINOR = @KNOT_VERSION_MINOR@
+KNOT_VERSION_PATCH = @KNOT_VERSION_PATCH@
+LCOV = @LCOV@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LDFLAG_EXCLUDE_LIBS = @LDFLAG_EXCLUDE_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PDFLATEX = @PDFLATEX@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROTOC_C = @PROTOC_C@
+RANLIB = @RANLIB@
+RELEASE_DATE = @RELEASE_DATE@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPHINXBUILD = @SPHINXBUILD@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cap_ng_CFLAGS = @cap_ng_CFLAGS@
+cap_ng_LIBS = @cap_ng_LIBS@
+conf_mapsize = @conf_mapsize@
+config_dir = @config_dir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+dlopen_LIBS = @dlopen_LIBS@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+external_lmdb_LIBS = @external_lmdb_LIBS@
+fuzzer_CFLAGS = @fuzzer_CFLAGS@
+fuzzer_LDFLAGS = @fuzzer_LDFLAGS@
+gnutls_CFLAGS = @gnutls_CFLAGS@
+gnutls_LIBS = @gnutls_LIBS@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libdnssec_SONAME = @libdnssec_SONAME@
+libdnssec_SOVERSION = @libdnssec_SOVERSION@
+libdnssec_VERSION_INFO = @libdnssec_VERSION_INFO@
+libedit_CFLAGS = @libedit_CFLAGS@
+libedit_LIBS = @libedit_LIBS@
+libexecdir = @libexecdir@
+libfstrm_CFLAGS = @libfstrm_CFLAGS@
+libfstrm_LIBS = @libfstrm_LIBS@
+libidn2_CFLAGS = @libidn2_CFLAGS@
+libidn2_LIBS = @libidn2_LIBS@
+libidn_CFLAGS = @libidn_CFLAGS@
+libidn_LIBS = @libidn_LIBS@
+libknot_SONAME = @libknot_SONAME@
+libknot_SOVERSION = @libknot_SOVERSION@
+libknot_VERSION_INFO = @libknot_VERSION_INFO@
+libmaxminddb_CFLAGS = @libmaxminddb_CFLAGS@
+libmaxminddb_LIBS = @libmaxminddb_LIBS@
+libprotobuf_c_CFLAGS = @libprotobuf_c_CFLAGS@
+libprotobuf_c_LIBS = @libprotobuf_c_LIBS@
+liburcu_CFLAGS = @liburcu_CFLAGS@
+liburcu_LIBS = @liburcu_LIBS@
+liburcu_PKGCONFIG = @liburcu_PKGCONFIG@
+libzscanner_SONAME = @libzscanner_SONAME@
+libzscanner_SOVERSION = @libzscanner_SOVERSION@
+libzscanner_VERSION_INFO = @libzscanner_VERSION_INFO@
+lmdb_CFLAGS = @lmdb_CFLAGS@
+lmdb_LIBS = @lmdb_LIBS@
+localedir = @localedir@
+localstatedir = @localstatedir@
+malloc_LIBS = @malloc_LIBS@
+mandir = @mandir@
+math_LIBS = @math_LIBS@
+mkdir_p = @mkdir_p@
+module_dir = @module_dir@
+module_instdir = @module_instdir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgconfigdir = @pkgconfigdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pthread_LIBS = @pthread_LIBS@
+run_dir = @run_dir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+storage_dir = @storage_dir@
+sysconfdir = @sysconfdir@
+systemd_CFLAGS = @systemd_CFLAGS@
+systemd_LIBS = @systemd_LIBS@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = \
+ -include $(top_builddir)/src/config.h \
+ -DCONFIG_DIR='"${config_dir}"' \
+ -DSTORAGE_DIR='"${storage_dir}"' \
+ -DRUN_DIR='"${run_dir}"' \
+ -DMODULE_DIR='"${module_dir}"' \
+ -DMODULE_INSTDIR='"${module_instdir}"'
+
+EXTRA_DIST = contrib/licenses/0BSD contrib/licenses/BSD-3-Clause \
+ contrib/licenses/LGPL-2.0 contrib/licenses/OLDAP-2.8 \
+ contrib/lmdb/LICENSE contrib/openbsd/LICENSE \
+ contrib/ucw/LICENSE contrib/dnstap/dnstap.proto \
+ libzscanner/scanner.rl libzscanner/scanner_body.rl \
+ libzscanner/scanner.c.g2 libzscanner/scanner.c.t0 \
+ knot/modules/cookies/cookies.rst \
+ knot/modules/dnsproxy/dnsproxy.rst \
+ knot/modules/dnstap/dnstap.rst knot/modules/geoip/geoip.rst \
+ knot/modules/noudp/noudp.rst \
+ knot/modules/onlinesign/onlinesign.rst \
+ knot/modules/queryacl/queryacl.rst knot/modules/rrl/rrl.rst \
+ knot/modules/stats/stats.rst \
+ knot/modules/synthrecord/synthrecord.rst \
+ knot/modules/whoami/whoami.rst
+CLEANFILES = $(am__append_5) libzscanner/scanner.c
+BUILT_SOURCES = $(am__append_4) libzscanner/scanner.c
+lib_LTLIBRARIES = libdnssec.la libknot.la libzscanner.la
+noinst_LTLIBRARIES = libcontrib.la $(am__append_3) libshared.la \
+ $(am__append_8) $(am__append_36)
+pkgconfig_DATA = libdnssec.pc libknot.pc libzscanner.pc \
+ $(am__append_9)
+libcontrib_la_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAG_VISIBILITY)
+libcontrib_la_LDFLAGS = $(AM_LDFLAGS) $(LDFLAG_EXCLUDE_LIBS) \
+ $(am__append_1)
+libcontrib_la_SOURCES = contrib/asan.h contrib/base32hex.c \
+ contrib/base32hex.h contrib/base64.c contrib/base64.h \
+ contrib/ctype.h contrib/dynarray.h contrib/files.c \
+ contrib/files.h contrib/getline.c contrib/getline.h \
+ contrib/macros.h contrib/mempattern.c contrib/mempattern.h \
+ contrib/net.c contrib/net.h contrib/qp-trie/trie.c \
+ contrib/qp-trie/trie.h contrib/sockaddr.c contrib/sockaddr.h \
+ contrib/string.c contrib/string.h contrib/strtonum.h \
+ contrib/time.c contrib/time.h contrib/tolower.h contrib/trim.h \
+ contrib/wire_ctx.h contrib/openbsd/siphash.c \
+ contrib/openbsd/siphash.h contrib/openbsd/strlcat.c \
+ contrib/openbsd/strlcat.h contrib/openbsd/strlcpy.c \
+ contrib/openbsd/strlcpy.h contrib/ucw/array-sort.h \
+ contrib/ucw/binsearch.h contrib/ucw/heap.c contrib/ucw/heap.h \
+ contrib/ucw/lists.c contrib/ucw/lists.h contrib/ucw/mempool.c \
+ contrib/ucw/mempool.h $(am__append_2)
+@HAVE_LIBDNSTAP_TRUE@libdnstap_la_CPPFLAGS = $(AM_CPPFLAGS) $(DNSTAP_CFLAGS)
+@HAVE_LIBDNSTAP_TRUE@libdnstap_la_LDFLAGS = $(AM_LDFLAGS) $(DNSTAP_LIBS)
+@HAVE_LIBDNSTAP_TRUE@SUFFIXES = .proto .pb-c.c .pb-c.h
+@HAVE_LIBDNSTAP_TRUE@libdnstap_la_SOURCES = \
+@HAVE_LIBDNSTAP_TRUE@ contrib/dnstap/convert.c \
+@HAVE_LIBDNSTAP_TRUE@ contrib/dnstap/convert.h \
+@HAVE_LIBDNSTAP_TRUE@ contrib/dnstap/dnstap.c \
+@HAVE_LIBDNSTAP_TRUE@ contrib/dnstap/dnstap.h \
+@HAVE_LIBDNSTAP_TRUE@ contrib/dnstap/message.c \
+@HAVE_LIBDNSTAP_TRUE@ contrib/dnstap/message.h \
+@HAVE_LIBDNSTAP_TRUE@ contrib/dnstap/reader.c \
+@HAVE_LIBDNSTAP_TRUE@ contrib/dnstap/reader.h \
+@HAVE_LIBDNSTAP_TRUE@ contrib/dnstap/writer.c \
+@HAVE_LIBDNSTAP_TRUE@ contrib/dnstap/writer.h
+
+@HAVE_LIBDNSTAP_TRUE@nodist_libdnstap_la_SOURCES = \
+@HAVE_LIBDNSTAP_TRUE@ contrib/dnstap/dnstap.pb-c.c \
+@HAVE_LIBDNSTAP_TRUE@ contrib/dnstap/dnstap.pb-c.h
+
+libshared_la_CPPFLAGS = $(AM_CPPFLAGS) $(gnutls_CFLAGS)
+libshared_la_SOURCES = \
+ libdnssec/shared/bignum.c \
+ libdnssec/shared/bignum.h \
+ libdnssec/shared/binary_wire.h \
+ libdnssec/shared/dname.c \
+ libdnssec/shared/dname.h \
+ libdnssec/shared/fs.c \
+ libdnssec/shared/fs.h \
+ libdnssec/shared/hex.c \
+ libdnssec/shared/hex.h \
+ libdnssec/shared/keyid_gnutls.c \
+ libdnssec/shared/keyid_gnutls.h \
+ libdnssec/shared/pem.c \
+ libdnssec/shared/pem.h \
+ libdnssec/shared/shared.h
+
+libdnssec_la_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAG_VISIBILITY) $(gnutls_CFLAGS)
+libdnssec_la_LDFLAGS = $(AM_LDFLAGS) $(libdnssec_VERSION_INFO) \
+ $(gnutls_LIBS) $(am__append_6)
+libdnssec_la_LIBADD = libshared.la $(am__append_7)
+include_libdnssecdir = $(includedir)/libdnssec
+include_libdnssec_HEADERS = \
+ libdnssec/binary.h \
+ libdnssec/crypto.h \
+ libdnssec/dnssec.h \
+ libdnssec/error.h \
+ libdnssec/key.h \
+ libdnssec/keyid.h \
+ libdnssec/keystore.h \
+ libdnssec/keytag.h \
+ libdnssec/list.h \
+ libdnssec/nsec.h \
+ libdnssec/random.h \
+ libdnssec/sign.h \
+ libdnssec/tsig.h \
+ libdnssec/version.h
+
+libdnssec_la_SOURCES = \
+ libdnssec/contrib/vpool.c \
+ libdnssec/contrib/vpool.h \
+ libdnssec/binary.c \
+ libdnssec/crypto.c \
+ libdnssec/error.c \
+ libdnssec/key/algorithm.c \
+ libdnssec/key/algorithm.h \
+ libdnssec/key/convert.c \
+ libdnssec/key/convert.h \
+ libdnssec/key/dnskey.c \
+ libdnssec/key/dnskey.h \
+ libdnssec/key/ds.c \
+ libdnssec/key/internal.h \
+ libdnssec/key/key.c \
+ libdnssec/key/keytag.c \
+ libdnssec/key/privkey.c \
+ libdnssec/key/privkey.h \
+ libdnssec/key/simple.c \
+ libdnssec/keyid.c \
+ libdnssec/keystore/internal.h \
+ libdnssec/keystore/keystore.c \
+ libdnssec/keystore/pkcs11.c \
+ libdnssec/keystore/pkcs8.c \
+ libdnssec/keystore/pkcs8_dir.c \
+ libdnssec/list/list.c \
+ libdnssec/list/ucw_clists.h \
+ libdnssec/nsec/bitmap.c \
+ libdnssec/nsec/hash.c \
+ libdnssec/nsec/nsec.c \
+ libdnssec/p11/p11.c \
+ libdnssec/p11/p11.h \
+ libdnssec/random.c \
+ libdnssec/sign/der.c \
+ libdnssec/sign/der.h \
+ libdnssec/sign/sign.c \
+ libdnssec/tsig.c
+
+libknot_la_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAG_VISIBILITY) $(lmdb_CFLAGS)
+libknot_la_LDFLAGS = $(AM_LDFLAGS) $(libknot_VERSION_INFO) $(lmdb_LIBS) \
+ $(LDFLAG_EXCLUDE_LIBS)
+
+libknot_la_LIBADD = libcontrib.la libdnssec.la $(math_LIBS)
+include_libknotdir = $(includedir)
+nobase_include_libknot_HEADERS = \
+ libknot/attribute.h \
+ libknot/codes.h \
+ libknot/consts.h \
+ libknot/control/control.h \
+ libknot/cookies.h \
+ libknot/descriptor.h \
+ libknot/dname.h \
+ libknot/endian.h \
+ libknot/errcode.h \
+ libknot/error.h \
+ libknot/libknot.h \
+ libknot/lookup.h \
+ libknot/mm_ctx.h \
+ libknot/db/db.h \
+ libknot/db/db_lmdb.h \
+ libknot/db/db_trie.h \
+ libknot/packet/compr.h \
+ libknot/packet/pkt.h \
+ libknot/packet/rrset-wire.h \
+ libknot/packet/wire.h \
+ libknot/rdata.h \
+ libknot/rdataset.h \
+ libknot/rrset-dump.h \
+ libknot/rrset.h \
+ libknot/rrtype/dnskey.h \
+ libknot/rrtype/ds.h \
+ libknot/rrtype/naptr.h \
+ libknot/rrtype/nsec.h \
+ libknot/rrtype/nsec3.h \
+ libknot/rrtype/nsec3param.h \
+ libknot/rrtype/opt.h \
+ libknot/rrtype/rdname.h \
+ libknot/rrtype/rrsig.h \
+ libknot/rrtype/soa.h \
+ libknot/rrtype/tsig.h \
+ libknot/tsig-op.h \
+ libknot/tsig.h \
+ libknot/wire.h \
+ libknot/yparser/yparser.h \
+ libknot/yparser/ypformat.h \
+ libknot/yparser/ypschema.h \
+ libknot/yparser/yptrafo.h \
+ libknot/version.h
+
+libknot_la_SOURCES = \
+ libknot/codes.c \
+ libknot/control/control.c \
+ libknot/cookies.c \
+ libknot/descriptor.c \
+ libknot/dname.c \
+ libknot/error.c \
+ libknot/db/db_lmdb.c \
+ libknot/db/db_trie.c \
+ libknot/packet/pkt.c \
+ libknot/packet/rrset-wire.c \
+ libknot/rdataset.c \
+ libknot/rrset-dump.c \
+ libknot/rrset.c \
+ libknot/rrtype/naptr.c \
+ libknot/rrtype/opt.c \
+ libknot/rrtype/tsig.c \
+ libknot/tsig-op.c \
+ libknot/tsig.c \
+ libknot/yparser/yparser.c \
+ libknot/yparser/ypbody.c \
+ libknot/yparser/ypformat.c \
+ libknot/yparser/ypschema.c \
+ libknot/yparser/yptrafo.c
+
+libzscanner_la_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAG_VISIBILITY)
+libzscanner_la_LDFLAGS = $(AM_LDFLAGS) $(libzscanner_VERSION_INFO) $(LDFLAG_EXCLUDE_LIBS)
+libzscanner_la_LIBADD = $(math_LIBS)
+include_libzscannerdir = $(includedir)/libzscanner
+include_libzscanner_HEADERS = \
+ libzscanner/error.h \
+ libzscanner/scanner.h \
+ libzscanner/version.h
+
+libzscanner_la_SOURCES = \
+ libzscanner/error.c \
+ libzscanner/functions.h \
+ libzscanner/functions.c \
+ $(include_libzscanner_HEADERS)
+
+nodist_libzscanner_la_SOURCES = \
+ libzscanner/scanner.c
+
+libknotd_la_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAG_VISIBILITY) \
+ $(systemd_CFLAGS) $(liburcu_CFLAGS) -DKNOTD_MOD_STATIC \
+ $(am__append_15) $(am__append_19)
+libknotd_la_LDFLAGS = $(AM_LDFLAGS) -export-symbols-regex '^knotd_'
+libknotd_la_LIBADD = libcontrib.la libknot.la libzscanner.la \
+ $(systemd_LIBS) $(liburcu_LIBS) $(pthread_LIBS) $(dlopen_LIBS) \
+ $(am__append_16) $(am__append_20)
+include_libknotddir = $(includedir)/knot
+include_libknotd_HEADERS = \
+ knot/include/module.h
+
+libknotd_la_SOURCES = knot/conf/base.c knot/conf/base.h \
+ knot/conf/conf.c knot/conf/conf.h knot/conf/confdb.c \
+ knot/conf/confdb.h knot/conf/confio.c knot/conf/confio.h \
+ knot/conf/migration.c knot/conf/migration.h knot/conf/module.h \
+ knot/conf/module.c knot/conf/schema.c knot/conf/schema.h \
+ knot/conf/tools.c knot/conf/tools.h knot/ctl/commands.c \
+ knot/ctl/commands.h knot/ctl/process.c knot/ctl/process.h \
+ knot/dnssec/context.c knot/dnssec/context.h \
+ knot/dnssec/ds_query.c knot/dnssec/ds_query.h \
+ knot/dnssec/kasp/kasp_db.c knot/dnssec/kasp/kasp_db.h \
+ knot/dnssec/kasp/kasp_zone.c knot/dnssec/kasp/kasp_zone.h \
+ knot/dnssec/kasp/keystate.c knot/dnssec/kasp/keystate.h \
+ knot/dnssec/kasp/keystore.c knot/dnssec/kasp/keystore.h \
+ knot/dnssec/kasp/policy.h knot/dnssec/key-events.c \
+ knot/dnssec/key-events.h knot/dnssec/nsec-chain.c \
+ knot/dnssec/nsec-chain.h knot/dnssec/nsec3-chain.c \
+ knot/dnssec/nsec3-chain.h knot/dnssec/policy.c \
+ knot/dnssec/policy.h knot/dnssec/rrset-sign.c \
+ knot/dnssec/rrset-sign.h knot/dnssec/zone-events.c \
+ knot/dnssec/zone-events.h knot/dnssec/zone-keys.c \
+ knot/dnssec/zone-keys.h knot/dnssec/zone-nsec.c \
+ knot/dnssec/zone-nsec.h knot/dnssec/zone-sign.c \
+ knot/dnssec/zone-sign.h knot/events/events.c \
+ knot/events/events.h knot/events/handlers.h \
+ knot/events/handlers/dnssec.c knot/events/handlers/expire.c \
+ knot/events/handlers/flush.c \
+ knot/events/handlers/freeze_thaw.c knot/events/handlers/load.c \
+ knot/events/handlers/notify.c \
+ knot/events/handlers/nsec3resalt.c \
+ knot/events/handlers/refresh.c knot/events/handlers/update.c \
+ knot/events/handlers/parent_ds_query.c knot/events/replan.c \
+ knot/events/replan.h knot/nameserver/axfr.c \
+ knot/nameserver/axfr.h knot/nameserver/chaos.c \
+ knot/nameserver/chaos.h knot/nameserver/internet.c \
+ knot/nameserver/internet.h knot/nameserver/ixfr.c \
+ knot/nameserver/ixfr.h knot/nameserver/log.h \
+ knot/nameserver/notify.c knot/nameserver/notify.h \
+ knot/nameserver/nsec_proofs.c knot/nameserver/nsec_proofs.h \
+ knot/nameserver/process_query.c \
+ knot/nameserver/process_query.h knot/nameserver/query_module.c \
+ knot/nameserver/query_module.h knot/nameserver/tsig_ctx.c \
+ knot/nameserver/tsig_ctx.h knot/nameserver/update.c \
+ knot/nameserver/update.h knot/nameserver/xfr.c \
+ knot/nameserver/xfr.h knot/query/capture.c \
+ knot/query/capture.h knot/query/layer.h knot/query/query.c \
+ knot/query/query.h knot/query/requestor.c \
+ knot/query/requestor.h knot/common/evsched.c \
+ knot/common/evsched.h knot/common/fdset.c knot/common/fdset.h \
+ knot/common/log.c knot/common/log.h knot/common/process.c \
+ knot/common/process.h knot/common/ref.c knot/common/ref.h \
+ knot/common/stats.c knot/common/stats.h knot/server/dthreads.c \
+ knot/server/dthreads.h knot/journal/chgset_ctx.c \
+ knot/journal/chgset_ctx.h knot/journal/journal.c \
+ knot/journal/journal.h knot/journal/serialization.c \
+ knot/journal/serialization.h knot/server/server.c \
+ knot/server/server.h knot/server/tcp-handler.c \
+ knot/server/tcp-handler.h knot/server/udp-handler.c \
+ knot/server/udp-handler.h knot/updates/acl.c \
+ knot/updates/acl.h knot/updates/apply.c knot/updates/apply.h \
+ knot/updates/changesets.c knot/updates/changesets.h \
+ knot/updates/ddns.c knot/updates/ddns.h \
+ knot/updates/zone-update.c knot/updates/zone-update.h \
+ knot/worker/pool.c knot/worker/pool.h knot/worker/queue.c \
+ knot/worker/queue.h knot/zone/contents.c knot/zone/contents.h \
+ knot/zone/node.c knot/zone/node.h knot/zone/semantic-check.c \
+ knot/zone/semantic-check.h knot/zone/serial.c \
+ knot/zone/serial.h knot/zone/timers.c knot/zone/timers.h \
+ knot/zone/zone-diff.c knot/zone/zone-diff.h \
+ knot/zone/zone-dump.c knot/zone/zone-dump.h \
+ knot/zone/zone-load.c knot/zone/zone-load.h \
+ knot/zone/zone-tree.c knot/zone/zone-tree.h knot/zone/zone.c \
+ knot/zone/zone.h knot/zone/zonedb-load.c \
+ knot/zone/zonedb-load.h knot/zone/zonedb.c knot/zone/zonedb.h \
+ knot/zone/zonefile.c knot/zone/zonefile.h $(am__append_10) \
+ $(am__append_12) $(am__append_14) $(am__append_18) \
+ $(am__append_22) $(am__append_24) $(am__append_26) \
+ $(am__append_28) $(am__append_30) $(am__append_32) \
+ $(am__append_34)
+KNOTD_MOD_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAG_VISIBILITY)
+KNOTD_MOD_LDFLAGS = $(AM_LDFLAGS) -module -shared -avoid-version
+pkglib_LTLIBRARIES = $(am__append_11) $(am__append_13) \
+ $(am__append_17) $(am__append_21) $(am__append_23) \
+ $(am__append_25) $(am__append_27) $(am__append_29) \
+ $(am__append_31) $(am__append_33) $(am__append_35)
+knot_modules_cookies_la_SOURCES = knot/modules/cookies/cookies.c
+@SHARED_MODULE_cookies_TRUE@knot_modules_cookies_la_LDFLAGS = $(KNOTD_MOD_LDFLAGS)
+@SHARED_MODULE_cookies_TRUE@knot_modules_cookies_la_CPPFLAGS = $(KNOTD_MOD_CPPFLAGS)
+@SHARED_MODULE_cookies_TRUE@knot_modules_cookies_la_LIBADD = libcontrib.la
+knot_modules_dnsproxy_la_SOURCES = knot/modules/dnsproxy/dnsproxy.c
+@SHARED_MODULE_dnsproxy_TRUE@knot_modules_dnsproxy_la_LDFLAGS = $(KNOTD_MOD_LDFLAGS)
+@SHARED_MODULE_dnsproxy_TRUE@knot_modules_dnsproxy_la_CPPFLAGS = $(KNOTD_MOD_CPPFLAGS)
+@SHARED_MODULE_dnsproxy_TRUE@knot_modules_dnsproxy_la_LIBADD = libcontrib.la
+knot_modules_dnstap_la_SOURCES = knot/modules/dnstap/dnstap.c
+@SHARED_MODULE_dnstap_TRUE@knot_modules_dnstap_la_LDFLAGS = $(KNOTD_MOD_LDFLAGS)
+@SHARED_MODULE_dnstap_TRUE@knot_modules_dnstap_la_CPPFLAGS = $(KNOTD_MOD_CPPFLAGS) $(DNSTAP_CFLAGS)
+@SHARED_MODULE_dnstap_TRUE@knot_modules_dnstap_la_LIBADD = $(DNSTAP_LIBS) libdnstap.la
+knot_modules_geoip_la_SOURCES = knot/modules/geoip/geoip.c \
+ knot/modules/geoip/geodb.c \
+ knot/modules/geoip/geodb.h
+
+@SHARED_MODULE_geoip_TRUE@knot_modules_geoip_la_LDFLAGS = $(KNOTD_MOD_LDFLAGS)
+@SHARED_MODULE_geoip_TRUE@knot_modules_geoip_la_CPPFLAGS = $(KNOTD_MOD_CPPFLAGS)
+knot_modules_noudp_la_SOURCES = knot/modules/noudp/noudp.c
+@SHARED_MODULE_noudp_TRUE@knot_modules_noudp_la_LDFLAGS = $(KNOTD_MOD_LDFLAGS)
+@SHARED_MODULE_noudp_TRUE@knot_modules_noudp_la_CPPFLAGS = $(KNOTD_MOD_CPPFLAGS)
+knot_modules_onlinesign_la_SOURCES = knot/modules/onlinesign/onlinesign.c \
+ knot/modules/onlinesign/nsec_next.c \
+ knot/modules/onlinesign/nsec_next.h
+
+@SHARED_MODULE_onlinesign_TRUE@knot_modules_onlinesign_la_LDFLAGS = $(KNOTD_MOD_LDFLAGS)
+@SHARED_MODULE_onlinesign_TRUE@knot_modules_onlinesign_la_CPPFLAGS = $(KNOTD_MOD_CPPFLAGS)
+@SHARED_MODULE_onlinesign_TRUE@knot_modules_onlinesign_la_LIBADD = libcontrib.la
+knot_modules_queryacl_la_SOURCES = knot/modules/queryacl/queryacl.c
+@SHARED_MODULE_queryacl_TRUE@knot_modules_queryacl_la_LDFLAGS = $(KNOTD_MOD_LDFLAGS)
+@SHARED_MODULE_queryacl_TRUE@knot_modules_queryacl_la_CPPFLAGS = $(KNOTD_MOD_CPPFLAGS)
+knot_modules_rrl_la_SOURCES = knot/modules/rrl/rrl.c \
+ knot/modules/rrl/functions.c \
+ knot/modules/rrl/functions.h
+
+@SHARED_MODULE_rrl_TRUE@knot_modules_rrl_la_LDFLAGS = $(KNOTD_MOD_LDFLAGS)
+@SHARED_MODULE_rrl_TRUE@knot_modules_rrl_la_CPPFLAGS = $(KNOTD_MOD_CPPFLAGS)
+@SHARED_MODULE_rrl_TRUE@knot_modules_rrl_la_LIBADD = libcontrib.la
+knot_modules_stats_la_SOURCES = knot/modules/stats/stats.c
+@SHARED_MODULE_stats_TRUE@knot_modules_stats_la_LDFLAGS = $(KNOTD_MOD_LDFLAGS)
+@SHARED_MODULE_stats_TRUE@knot_modules_stats_la_CPPFLAGS = $(KNOTD_MOD_CPPFLAGS)
+knot_modules_synthrecord_la_SOURCES = knot/modules/synthrecord/synthrecord.c
+@SHARED_MODULE_synthrecord_TRUE@knot_modules_synthrecord_la_LDFLAGS = $(KNOTD_MOD_LDFLAGS)
+@SHARED_MODULE_synthrecord_TRUE@knot_modules_synthrecord_la_CPPFLAGS = $(KNOTD_MOD_CPPFLAGS)
+@SHARED_MODULE_synthrecord_TRUE@knot_modules_synthrecord_la_LIBADD = libcontrib.la
+knot_modules_whoami_la_SOURCES = knot/modules/whoami/whoami.c
+@SHARED_MODULE_whoami_TRUE@knot_modules_whoami_la_LDFLAGS = $(KNOTD_MOD_LDFLAGS)
+@SHARED_MODULE_whoami_TRUE@knot_modules_whoami_la_CPPFLAGS = $(KNOTD_MOD_CPPFLAGS)
+@HAVE_LIBUTILS_TRUE@libknotus_la_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAG_VISIBILITY) $(libidn2_CFLAGS) \
+@HAVE_LIBUTILS_TRUE@ $(libidn_CFLAGS) $(libedit_CFLAGS) $(gnutls_CFLAGS)
+
+@HAVE_LIBUTILS_TRUE@libknotus_la_LDFLAGS = $(AM_LDFLAGS) $(LDFLAG_EXCLUDE_LIBS)
+@HAVE_LIBUTILS_TRUE@libknotus_la_LIBADD = libcontrib.la libknot.la $(libidn2_LIBS) $(libidn_LIBS) \
+@HAVE_LIBUTILS_TRUE@ $(libedit_LIBS) $(gnutls_LIBS)
+
+@HAVE_LIBUTILS_TRUE@libknotus_la_SOURCES = \
+@HAVE_LIBUTILS_TRUE@ utils/common/cert.c \
+@HAVE_LIBUTILS_TRUE@ utils/common/cert.h \
+@HAVE_LIBUTILS_TRUE@ utils/common/exec.c \
+@HAVE_LIBUTILS_TRUE@ utils/common/exec.h \
+@HAVE_LIBUTILS_TRUE@ utils/common/hex.c \
+@HAVE_LIBUTILS_TRUE@ utils/common/hex.h \
+@HAVE_LIBUTILS_TRUE@ utils/common/lookup.c \
+@HAVE_LIBUTILS_TRUE@ utils/common/lookup.h \
+@HAVE_LIBUTILS_TRUE@ utils/common/msg.c \
+@HAVE_LIBUTILS_TRUE@ utils/common/msg.h \
+@HAVE_LIBUTILS_TRUE@ utils/common/netio.c \
+@HAVE_LIBUTILS_TRUE@ utils/common/netio.h \
+@HAVE_LIBUTILS_TRUE@ utils/common/params.c \
+@HAVE_LIBUTILS_TRUE@ utils/common/params.h \
+@HAVE_LIBUTILS_TRUE@ utils/common/resolv.c \
+@HAVE_LIBUTILS_TRUE@ utils/common/resolv.h \
+@HAVE_LIBUTILS_TRUE@ utils/common/sign.c \
+@HAVE_LIBUTILS_TRUE@ utils/common/sign.h \
+@HAVE_LIBUTILS_TRUE@ utils/common/tls.c \
+@HAVE_LIBUTILS_TRUE@ utils/common/tls.h \
+@HAVE_LIBUTILS_TRUE@ utils/common/token.c \
+@HAVE_LIBUTILS_TRUE@ utils/common/token.h
+
+@HAVE_UTILS_TRUE@kdig_SOURCES = \
+@HAVE_UTILS_TRUE@ utils/kdig/kdig_exec.c \
+@HAVE_UTILS_TRUE@ utils/kdig/kdig_exec.h \
+@HAVE_UTILS_TRUE@ utils/kdig/kdig_main.c \
+@HAVE_UTILS_TRUE@ utils/kdig/kdig_params.c \
+@HAVE_UTILS_TRUE@ utils/kdig/kdig_params.h
+
+@HAVE_UTILS_TRUE@khost_SOURCES = \
+@HAVE_UTILS_TRUE@ utils/kdig/kdig_exec.c \
+@HAVE_UTILS_TRUE@ utils/kdig/kdig_exec.h \
+@HAVE_UTILS_TRUE@ utils/kdig/kdig_params.c \
+@HAVE_UTILS_TRUE@ utils/kdig/kdig_params.h \
+@HAVE_UTILS_TRUE@ utils/khost/khost_main.c \
+@HAVE_UTILS_TRUE@ utils/khost/khost_params.c \
+@HAVE_UTILS_TRUE@ utils/khost/khost_params.h
+
+@HAVE_UTILS_TRUE@knsec3hash_SOURCES = \
+@HAVE_UTILS_TRUE@ utils/knsec3hash/knsec3hash.c
+
+@HAVE_UTILS_TRUE@knsupdate_SOURCES = \
+@HAVE_UTILS_TRUE@ utils/knsupdate/knsupdate_exec.c \
+@HAVE_UTILS_TRUE@ utils/knsupdate/knsupdate_exec.h \
+@HAVE_UTILS_TRUE@ utils/knsupdate/knsupdate_main.c \
+@HAVE_UTILS_TRUE@ utils/knsupdate/knsupdate_params.c \
+@HAVE_UTILS_TRUE@ utils/knsupdate/knsupdate_params.h
+
+@HAVE_UTILS_TRUE@kdig_CPPFLAGS = $(AM_CPPFLAGS) $(gnutls_CFLAGS) \
+@HAVE_UTILS_TRUE@ $(am__append_39)
+@HAVE_UTILS_TRUE@kdig_LDADD = libknotus.la $(am__append_37)
+@HAVE_UTILS_TRUE@khost_CPPFLAGS = $(AM_CPPFLAGS) $(gnutls_CFLAGS) \
+@HAVE_UTILS_TRUE@ $(am__append_40)
+@HAVE_UTILS_TRUE@khost_LDADD = libknotus.la $(am__append_38)
+@HAVE_UTILS_TRUE@knsec3hash_CPPFLAGS = $(AM_CPPFLAGS)
+@HAVE_UTILS_TRUE@knsec3hash_LDADD = libcontrib.la libdnssec.la libknot.la libshared.la
+@HAVE_UTILS_TRUE@knsupdate_CPPFLAGS = $(AM_CPPFLAGS) $(gnutls_CFLAGS)
+@HAVE_UTILS_TRUE@knsupdate_LDADD = libknotus.la libzscanner.la
+@HAVE_DAEMON_TRUE@knotc_SOURCES = \
+@HAVE_DAEMON_TRUE@ utils/knotc/commands.c \
+@HAVE_DAEMON_TRUE@ utils/knotc/commands.h \
+@HAVE_DAEMON_TRUE@ utils/knotc/estimator.c \
+@HAVE_DAEMON_TRUE@ utils/knotc/estimator.h \
+@HAVE_DAEMON_TRUE@ utils/knotc/interactive.c \
+@HAVE_DAEMON_TRUE@ utils/knotc/interactive.h \
+@HAVE_DAEMON_TRUE@ utils/knotc/process.c \
+@HAVE_DAEMON_TRUE@ utils/knotc/process.h \
+@HAVE_DAEMON_TRUE@ utils/knotc/main.c
+
+@HAVE_DAEMON_TRUE@knotd_SOURCES = \
+@HAVE_DAEMON_TRUE@ utils/knotd/main.c
+
+@HAVE_DAEMON_TRUE@knotc_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAG_VISIBILITY) $(libedit_CFLAGS)
+@HAVE_DAEMON_TRUE@knotc_LDADD = libcontrib.la libknotd.la libknotus.la $(libedit_LIBS)
+@HAVE_DAEMON_TRUE@knotc_LDFLAGS = $(AM_LDFLAGS) -rdynamic
+@HAVE_DAEMON_TRUE@knotd_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAG_VISIBILITY) $(liburcu_CFLAGS)
+@HAVE_DAEMON_TRUE@knotd_LDADD = $(malloc_LIBS) libcontrib.la libknotd.la $(liburcu_LIBS) \
+@HAVE_DAEMON_TRUE@ $(cap_ng_LIBS)
+
+@HAVE_DAEMON_TRUE@knotd_LDFLAGS = $(AM_LDFLAGS) -rdynamic
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@kzonecheck_SOURCES = \
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ utils/kzonecheck/main.c \
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ utils/kzonecheck/zone_check.c \
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ utils/kzonecheck/zone_check.h
+
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@keymgr_SOURCES = \
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ utils/keymgr/bind_privkey.c \
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ utils/keymgr/bind_privkey.h \
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ utils/keymgr/functions.c \
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ utils/keymgr/functions.h \
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ utils/keymgr/main.c
+
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@kjournalprint_SOURCES = \
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ utils/kjournalprint/main.c
+
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@kzonecheck_CPPFLAGS = $(AM_CPPFLAGS)
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@kzonecheck_LDADD = libcontrib.la libknotd.la
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@keymgr_CPPFLAGS = $(AM_CPPFLAGS) $(gnutls_CFLAGS)
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@keymgr_LDADD = libcontrib.la libknotd.la libknotus.la libdnssec.la \
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ libshared.la libzscanner.la
+
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@kjournalprint_CPPFLAGS = $(AM_CPPFLAGS) $(gnutls_CFLAGS)
+@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@kjournalprint_LDADD = libcontrib.la libknotd.la
+all: $(BUILT_SOURCES) config.h
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .proto .pb-c.c .pb-c.h .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(srcdir)/contrib/Makefile.inc $(srcdir)/libdnssec/Makefile.inc $(srcdir)/libknot/Makefile.inc $(srcdir)/libzscanner/Makefile.inc $(srcdir)/knot/Makefile.inc $(srcdir)/knot/modules/cookies/Makefile.inc $(srcdir)/knot/modules/dnsproxy/Makefile.inc $(srcdir)/knot/modules/dnstap/Makefile.inc $(srcdir)/knot/modules/geoip/Makefile.inc $(srcdir)/knot/modules/noudp/Makefile.inc $(srcdir)/knot/modules/onlinesign/Makefile.inc $(srcdir)/knot/modules/queryacl/Makefile.inc $(srcdir)/knot/modules/rrl/Makefile.inc $(srcdir)/knot/modules/stats/Makefile.inc $(srcdir)/knot/modules/synthrecord/Makefile.inc $(srcdir)/knot/modules/whoami/Makefile.inc $(srcdir)/utils/Makefile.inc $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+$(srcdir)/contrib/Makefile.inc $(srcdir)/libdnssec/Makefile.inc $(srcdir)/libknot/Makefile.inc $(srcdir)/libzscanner/Makefile.inc $(srcdir)/knot/Makefile.inc $(srcdir)/knot/modules/cookies/Makefile.inc $(srcdir)/knot/modules/dnsproxy/Makefile.inc $(srcdir)/knot/modules/dnstap/Makefile.inc $(srcdir)/knot/modules/geoip/Makefile.inc $(srcdir)/knot/modules/noudp/Makefile.inc $(srcdir)/knot/modules/onlinesign/Makefile.inc $(srcdir)/knot/modules/queryacl/Makefile.inc $(srcdir)/knot/modules/rrl/Makefile.inc $(srcdir)/knot/modules/stats/Makefile.inc $(srcdir)/knot/modules/synthrecord/Makefile.inc $(srcdir)/knot/modules/whoami/Makefile.inc $(srcdir)/utils/Makefile.inc $(am__empty):
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+config.h: stamp-h1
+ @test -f $@ || rm -f stamp-h1
+ @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+ @rm -f stamp-h1
+ cd $(top_builddir) && $(SHELL) ./config.status src/config.h
+$(srcdir)/config.h.in: $(am__configure_deps)
+ ($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+ rm -f stamp-h1
+ touch $@
+
+distclean-hdr:
+ -rm -f config.h stamp-h1
+knotd.pc: $(top_builddir)/config.status $(srcdir)/knotd.pc.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+libknot.pc: $(top_builddir)/config.status $(srcdir)/libknot.pc.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+libdnssec.pc: $(top_builddir)/config.status $(srcdir)/libdnssec.pc.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+libzscanner.pc: $(top_builddir)/config.status $(srcdir)/libzscanner.pc.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+ }
+
+uninstall-pkglibLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+ done
+
+clean-pkglibLTLIBRARIES:
+ -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+ @list='$(pkglib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+knot/modules/cookies/$(am__dirstamp):
+ @$(MKDIR_P) knot/modules/cookies
+ @: > knot/modules/cookies/$(am__dirstamp)
+knot/modules/cookies/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) knot/modules/cookies/$(DEPDIR)
+ @: > knot/modules/cookies/$(DEPDIR)/$(am__dirstamp)
+knot/modules/cookies/knot_modules_cookies_la-cookies.lo: \
+ knot/modules/cookies/$(am__dirstamp) \
+ knot/modules/cookies/$(DEPDIR)/$(am__dirstamp)
+knot/modules/$(am__dirstamp):
+ @$(MKDIR_P) knot/modules
+ @: > knot/modules/$(am__dirstamp)
+
+knot/modules/cookies.la: $(knot_modules_cookies_la_OBJECTS) $(knot_modules_cookies_la_DEPENDENCIES) $(EXTRA_knot_modules_cookies_la_DEPENDENCIES) knot/modules/$(am__dirstamp)
+ $(AM_V_CCLD)$(knot_modules_cookies_la_LINK) $(am_knot_modules_cookies_la_rpath) $(knot_modules_cookies_la_OBJECTS) $(knot_modules_cookies_la_LIBADD) $(LIBS)
+knot/modules/dnsproxy/$(am__dirstamp):
+ @$(MKDIR_P) knot/modules/dnsproxy
+ @: > knot/modules/dnsproxy/$(am__dirstamp)
+knot/modules/dnsproxy/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) knot/modules/dnsproxy/$(DEPDIR)
+ @: > knot/modules/dnsproxy/$(DEPDIR)/$(am__dirstamp)
+knot/modules/dnsproxy/knot_modules_dnsproxy_la-dnsproxy.lo: \
+ knot/modules/dnsproxy/$(am__dirstamp) \
+ knot/modules/dnsproxy/$(DEPDIR)/$(am__dirstamp)
+
+knot/modules/dnsproxy.la: $(knot_modules_dnsproxy_la_OBJECTS) $(knot_modules_dnsproxy_la_DEPENDENCIES) $(EXTRA_knot_modules_dnsproxy_la_DEPENDENCIES) knot/modules/$(am__dirstamp)
+ $(AM_V_CCLD)$(knot_modules_dnsproxy_la_LINK) $(am_knot_modules_dnsproxy_la_rpath) $(knot_modules_dnsproxy_la_OBJECTS) $(knot_modules_dnsproxy_la_LIBADD) $(LIBS)
+knot/modules/dnstap/$(am__dirstamp):
+ @$(MKDIR_P) knot/modules/dnstap
+ @: > knot/modules/dnstap/$(am__dirstamp)
+knot/modules/dnstap/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) knot/modules/dnstap/$(DEPDIR)
+ @: > knot/modules/dnstap/$(DEPDIR)/$(am__dirstamp)
+knot/modules/dnstap/knot_modules_dnstap_la-dnstap.lo: \
+ knot/modules/dnstap/$(am__dirstamp) \
+ knot/modules/dnstap/$(DEPDIR)/$(am__dirstamp)
+
+knot/modules/dnstap.la: $(knot_modules_dnstap_la_OBJECTS) $(knot_modules_dnstap_la_DEPENDENCIES) $(EXTRA_knot_modules_dnstap_la_DEPENDENCIES) knot/modules/$(am__dirstamp)
+ $(AM_V_CCLD)$(knot_modules_dnstap_la_LINK) $(am_knot_modules_dnstap_la_rpath) $(knot_modules_dnstap_la_OBJECTS) $(knot_modules_dnstap_la_LIBADD) $(LIBS)
+knot/modules/geoip/$(am__dirstamp):
+ @$(MKDIR_P) knot/modules/geoip
+ @: > knot/modules/geoip/$(am__dirstamp)
+knot/modules/geoip/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) knot/modules/geoip/$(DEPDIR)
+ @: > knot/modules/geoip/$(DEPDIR)/$(am__dirstamp)
+knot/modules/geoip/knot_modules_geoip_la-geoip.lo: \
+ knot/modules/geoip/$(am__dirstamp) \
+ knot/modules/geoip/$(DEPDIR)/$(am__dirstamp)
+knot/modules/geoip/knot_modules_geoip_la-geodb.lo: \
+ knot/modules/geoip/$(am__dirstamp) \
+ knot/modules/geoip/$(DEPDIR)/$(am__dirstamp)
+
+knot/modules/geoip.la: $(knot_modules_geoip_la_OBJECTS) $(knot_modules_geoip_la_DEPENDENCIES) $(EXTRA_knot_modules_geoip_la_DEPENDENCIES) knot/modules/$(am__dirstamp)
+ $(AM_V_CCLD)$(knot_modules_geoip_la_LINK) $(am_knot_modules_geoip_la_rpath) $(knot_modules_geoip_la_OBJECTS) $(knot_modules_geoip_la_LIBADD) $(LIBS)
+knot/modules/noudp/$(am__dirstamp):
+ @$(MKDIR_P) knot/modules/noudp
+ @: > knot/modules/noudp/$(am__dirstamp)
+knot/modules/noudp/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) knot/modules/noudp/$(DEPDIR)
+ @: > knot/modules/noudp/$(DEPDIR)/$(am__dirstamp)
+knot/modules/noudp/knot_modules_noudp_la-noudp.lo: \
+ knot/modules/noudp/$(am__dirstamp) \
+ knot/modules/noudp/$(DEPDIR)/$(am__dirstamp)
+
+knot/modules/noudp.la: $(knot_modules_noudp_la_OBJECTS) $(knot_modules_noudp_la_DEPENDENCIES) $(EXTRA_knot_modules_noudp_la_DEPENDENCIES) knot/modules/$(am__dirstamp)
+ $(AM_V_CCLD)$(knot_modules_noudp_la_LINK) $(am_knot_modules_noudp_la_rpath) $(knot_modules_noudp_la_OBJECTS) $(knot_modules_noudp_la_LIBADD) $(LIBS)
+knot/modules/onlinesign/$(am__dirstamp):
+ @$(MKDIR_P) knot/modules/onlinesign
+ @: > knot/modules/onlinesign/$(am__dirstamp)
+knot/modules/onlinesign/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) knot/modules/onlinesign/$(DEPDIR)
+ @: > knot/modules/onlinesign/$(DEPDIR)/$(am__dirstamp)
+knot/modules/onlinesign/knot_modules_onlinesign_la-onlinesign.lo: \
+ knot/modules/onlinesign/$(am__dirstamp) \
+ knot/modules/onlinesign/$(DEPDIR)/$(am__dirstamp)
+knot/modules/onlinesign/knot_modules_onlinesign_la-nsec_next.lo: \
+ knot/modules/onlinesign/$(am__dirstamp) \
+ knot/modules/onlinesign/$(DEPDIR)/$(am__dirstamp)
+
+knot/modules/onlinesign.la: $(knot_modules_onlinesign_la_OBJECTS) $(knot_modules_onlinesign_la_DEPENDENCIES) $(EXTRA_knot_modules_onlinesign_la_DEPENDENCIES) knot/modules/$(am__dirstamp)
+ $(AM_V_CCLD)$(knot_modules_onlinesign_la_LINK) $(am_knot_modules_onlinesign_la_rpath) $(knot_modules_onlinesign_la_OBJECTS) $(knot_modules_onlinesign_la_LIBADD) $(LIBS)
+knot/modules/queryacl/$(am__dirstamp):
+ @$(MKDIR_P) knot/modules/queryacl
+ @: > knot/modules/queryacl/$(am__dirstamp)
+knot/modules/queryacl/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) knot/modules/queryacl/$(DEPDIR)
+ @: > knot/modules/queryacl/$(DEPDIR)/$(am__dirstamp)
+knot/modules/queryacl/knot_modules_queryacl_la-queryacl.lo: \
+ knot/modules/queryacl/$(am__dirstamp) \
+ knot/modules/queryacl/$(DEPDIR)/$(am__dirstamp)
+
+knot/modules/queryacl.la: $(knot_modules_queryacl_la_OBJECTS) $(knot_modules_queryacl_la_DEPENDENCIES) $(EXTRA_knot_modules_queryacl_la_DEPENDENCIES) knot/modules/$(am__dirstamp)
+ $(AM_V_CCLD)$(knot_modules_queryacl_la_LINK) $(am_knot_modules_queryacl_la_rpath) $(knot_modules_queryacl_la_OBJECTS) $(knot_modules_queryacl_la_LIBADD) $(LIBS)
+knot/modules/rrl/$(am__dirstamp):
+ @$(MKDIR_P) knot/modules/rrl
+ @: > knot/modules/rrl/$(am__dirstamp)
+knot/modules/rrl/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) knot/modules/rrl/$(DEPDIR)
+ @: > knot/modules/rrl/$(DEPDIR)/$(am__dirstamp)
+knot/modules/rrl/knot_modules_rrl_la-rrl.lo: \
+ knot/modules/rrl/$(am__dirstamp) \
+ knot/modules/rrl/$(DEPDIR)/$(am__dirstamp)
+knot/modules/rrl/knot_modules_rrl_la-functions.lo: \
+ knot/modules/rrl/$(am__dirstamp) \
+ knot/modules/rrl/$(DEPDIR)/$(am__dirstamp)
+
+knot/modules/rrl.la: $(knot_modules_rrl_la_OBJECTS) $(knot_modules_rrl_la_DEPENDENCIES) $(EXTRA_knot_modules_rrl_la_DEPENDENCIES) knot/modules/$(am__dirstamp)
+ $(AM_V_CCLD)$(knot_modules_rrl_la_LINK) $(am_knot_modules_rrl_la_rpath) $(knot_modules_rrl_la_OBJECTS) $(knot_modules_rrl_la_LIBADD) $(LIBS)
+knot/modules/stats/$(am__dirstamp):
+ @$(MKDIR_P) knot/modules/stats
+ @: > knot/modules/stats/$(am__dirstamp)
+knot/modules/stats/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) knot/modules/stats/$(DEPDIR)
+ @: > knot/modules/stats/$(DEPDIR)/$(am__dirstamp)
+knot/modules/stats/knot_modules_stats_la-stats.lo: \
+ knot/modules/stats/$(am__dirstamp) \
+ knot/modules/stats/$(DEPDIR)/$(am__dirstamp)
+
+knot/modules/stats.la: $(knot_modules_stats_la_OBJECTS) $(knot_modules_stats_la_DEPENDENCIES) $(EXTRA_knot_modules_stats_la_DEPENDENCIES) knot/modules/$(am__dirstamp)
+ $(AM_V_CCLD)$(knot_modules_stats_la_LINK) $(am_knot_modules_stats_la_rpath) $(knot_modules_stats_la_OBJECTS) $(knot_modules_stats_la_LIBADD) $(LIBS)
+knot/modules/synthrecord/$(am__dirstamp):
+ @$(MKDIR_P) knot/modules/synthrecord
+ @: > knot/modules/synthrecord/$(am__dirstamp)
+knot/modules/synthrecord/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) knot/modules/synthrecord/$(DEPDIR)
+ @: > knot/modules/synthrecord/$(DEPDIR)/$(am__dirstamp)
+knot/modules/synthrecord/knot_modules_synthrecord_la-synthrecord.lo: \
+ knot/modules/synthrecord/$(am__dirstamp) \
+ knot/modules/synthrecord/$(DEPDIR)/$(am__dirstamp)
+
+knot/modules/synthrecord.la: $(knot_modules_synthrecord_la_OBJECTS) $(knot_modules_synthrecord_la_DEPENDENCIES) $(EXTRA_knot_modules_synthrecord_la_DEPENDENCIES) knot/modules/$(am__dirstamp)
+ $(AM_V_CCLD)$(knot_modules_synthrecord_la_LINK) $(am_knot_modules_synthrecord_la_rpath) $(knot_modules_synthrecord_la_OBJECTS) $(knot_modules_synthrecord_la_LIBADD) $(LIBS)
+knot/modules/whoami/$(am__dirstamp):
+ @$(MKDIR_P) knot/modules/whoami
+ @: > knot/modules/whoami/$(am__dirstamp)
+knot/modules/whoami/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) knot/modules/whoami/$(DEPDIR)
+ @: > knot/modules/whoami/$(DEPDIR)/$(am__dirstamp)
+knot/modules/whoami/knot_modules_whoami_la-whoami.lo: \
+ knot/modules/whoami/$(am__dirstamp) \
+ knot/modules/whoami/$(DEPDIR)/$(am__dirstamp)
+
+knot/modules/whoami.la: $(knot_modules_whoami_la_OBJECTS) $(knot_modules_whoami_la_DEPENDENCIES) $(EXTRA_knot_modules_whoami_la_DEPENDENCIES) knot/modules/$(am__dirstamp)
+ $(AM_V_CCLD)$(knot_modules_whoami_la_LINK) $(am_knot_modules_whoami_la_rpath) $(knot_modules_whoami_la_OBJECTS) $(knot_modules_whoami_la_LIBADD) $(LIBS)
+contrib/$(am__dirstamp):
+ @$(MKDIR_P) contrib
+ @: > contrib/$(am__dirstamp)
+contrib/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) contrib/$(DEPDIR)
+ @: > contrib/$(DEPDIR)/$(am__dirstamp)
+contrib/libcontrib_la-base32hex.lo: contrib/$(am__dirstamp) \
+ contrib/$(DEPDIR)/$(am__dirstamp)
+contrib/libcontrib_la-base64.lo: contrib/$(am__dirstamp) \
+ contrib/$(DEPDIR)/$(am__dirstamp)
+contrib/libcontrib_la-files.lo: contrib/$(am__dirstamp) \
+ contrib/$(DEPDIR)/$(am__dirstamp)
+contrib/libcontrib_la-getline.lo: contrib/$(am__dirstamp) \
+ contrib/$(DEPDIR)/$(am__dirstamp)
+contrib/libcontrib_la-mempattern.lo: contrib/$(am__dirstamp) \
+ contrib/$(DEPDIR)/$(am__dirstamp)
+contrib/libcontrib_la-net.lo: contrib/$(am__dirstamp) \
+ contrib/$(DEPDIR)/$(am__dirstamp)
+contrib/qp-trie/$(am__dirstamp):
+ @$(MKDIR_P) contrib/qp-trie
+ @: > contrib/qp-trie/$(am__dirstamp)
+contrib/qp-trie/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) contrib/qp-trie/$(DEPDIR)
+ @: > contrib/qp-trie/$(DEPDIR)/$(am__dirstamp)
+contrib/qp-trie/libcontrib_la-trie.lo: \
+ contrib/qp-trie/$(am__dirstamp) \
+ contrib/qp-trie/$(DEPDIR)/$(am__dirstamp)
+contrib/libcontrib_la-sockaddr.lo: contrib/$(am__dirstamp) \
+ contrib/$(DEPDIR)/$(am__dirstamp)
+contrib/libcontrib_la-string.lo: contrib/$(am__dirstamp) \
+ contrib/$(DEPDIR)/$(am__dirstamp)
+contrib/libcontrib_la-time.lo: contrib/$(am__dirstamp) \
+ contrib/$(DEPDIR)/$(am__dirstamp)
+contrib/openbsd/$(am__dirstamp):
+ @$(MKDIR_P) contrib/openbsd
+ @: > contrib/openbsd/$(am__dirstamp)
+contrib/openbsd/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) contrib/openbsd/$(DEPDIR)
+ @: > contrib/openbsd/$(DEPDIR)/$(am__dirstamp)
+contrib/openbsd/libcontrib_la-siphash.lo: \
+ contrib/openbsd/$(am__dirstamp) \
+ contrib/openbsd/$(DEPDIR)/$(am__dirstamp)
+contrib/openbsd/libcontrib_la-strlcat.lo: \
+ contrib/openbsd/$(am__dirstamp) \
+ contrib/openbsd/$(DEPDIR)/$(am__dirstamp)
+contrib/openbsd/libcontrib_la-strlcpy.lo: \
+ contrib/openbsd/$(am__dirstamp) \
+ contrib/openbsd/$(DEPDIR)/$(am__dirstamp)
+contrib/ucw/$(am__dirstamp):
+ @$(MKDIR_P) contrib/ucw
+ @: > contrib/ucw/$(am__dirstamp)
+contrib/ucw/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) contrib/ucw/$(DEPDIR)
+ @: > contrib/ucw/$(DEPDIR)/$(am__dirstamp)
+contrib/ucw/libcontrib_la-heap.lo: contrib/ucw/$(am__dirstamp) \
+ contrib/ucw/$(DEPDIR)/$(am__dirstamp)
+contrib/ucw/libcontrib_la-lists.lo: contrib/ucw/$(am__dirstamp) \
+ contrib/ucw/$(DEPDIR)/$(am__dirstamp)
+contrib/ucw/libcontrib_la-mempool.lo: contrib/ucw/$(am__dirstamp) \
+ contrib/ucw/$(DEPDIR)/$(am__dirstamp)
+contrib/lmdb/$(am__dirstamp):
+ @$(MKDIR_P) contrib/lmdb
+ @: > contrib/lmdb/$(am__dirstamp)
+contrib/lmdb/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) contrib/lmdb/$(DEPDIR)
+ @: > contrib/lmdb/$(DEPDIR)/$(am__dirstamp)
+contrib/lmdb/libcontrib_la-mdb.lo: contrib/lmdb/$(am__dirstamp) \
+ contrib/lmdb/$(DEPDIR)/$(am__dirstamp)
+contrib/lmdb/libcontrib_la-midl.lo: contrib/lmdb/$(am__dirstamp) \
+ contrib/lmdb/$(DEPDIR)/$(am__dirstamp)
+
+libcontrib.la: $(libcontrib_la_OBJECTS) $(libcontrib_la_DEPENDENCIES) $(EXTRA_libcontrib_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libcontrib_la_LINK) $(libcontrib_la_OBJECTS) $(libcontrib_la_LIBADD) $(LIBS)
+libdnssec/contrib/$(am__dirstamp):
+ @$(MKDIR_P) libdnssec/contrib
+ @: > libdnssec/contrib/$(am__dirstamp)
+libdnssec/contrib/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) libdnssec/contrib/$(DEPDIR)
+ @: > libdnssec/contrib/$(DEPDIR)/$(am__dirstamp)
+libdnssec/contrib/libdnssec_la-vpool.lo: \
+ libdnssec/contrib/$(am__dirstamp) \
+ libdnssec/contrib/$(DEPDIR)/$(am__dirstamp)
+libdnssec/$(am__dirstamp):
+ @$(MKDIR_P) libdnssec
+ @: > libdnssec/$(am__dirstamp)
+libdnssec/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) libdnssec/$(DEPDIR)
+ @: > libdnssec/$(DEPDIR)/$(am__dirstamp)
+libdnssec/libdnssec_la-binary.lo: libdnssec/$(am__dirstamp) \
+ libdnssec/$(DEPDIR)/$(am__dirstamp)
+libdnssec/libdnssec_la-crypto.lo: libdnssec/$(am__dirstamp) \
+ libdnssec/$(DEPDIR)/$(am__dirstamp)
+libdnssec/libdnssec_la-error.lo: libdnssec/$(am__dirstamp) \
+ libdnssec/$(DEPDIR)/$(am__dirstamp)
+libdnssec/key/$(am__dirstamp):
+ @$(MKDIR_P) libdnssec/key
+ @: > libdnssec/key/$(am__dirstamp)
+libdnssec/key/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) libdnssec/key/$(DEPDIR)
+ @: > libdnssec/key/$(DEPDIR)/$(am__dirstamp)
+libdnssec/key/libdnssec_la-algorithm.lo: \
+ libdnssec/key/$(am__dirstamp) \
+ libdnssec/key/$(DEPDIR)/$(am__dirstamp)
+libdnssec/key/libdnssec_la-convert.lo: libdnssec/key/$(am__dirstamp) \
+ libdnssec/key/$(DEPDIR)/$(am__dirstamp)
+libdnssec/key/libdnssec_la-dnskey.lo: libdnssec/key/$(am__dirstamp) \
+ libdnssec/key/$(DEPDIR)/$(am__dirstamp)
+libdnssec/key/libdnssec_la-ds.lo: libdnssec/key/$(am__dirstamp) \
+ libdnssec/key/$(DEPDIR)/$(am__dirstamp)
+libdnssec/key/libdnssec_la-key.lo: libdnssec/key/$(am__dirstamp) \
+ libdnssec/key/$(DEPDIR)/$(am__dirstamp)
+libdnssec/key/libdnssec_la-keytag.lo: libdnssec/key/$(am__dirstamp) \
+ libdnssec/key/$(DEPDIR)/$(am__dirstamp)
+libdnssec/key/libdnssec_la-privkey.lo: libdnssec/key/$(am__dirstamp) \
+ libdnssec/key/$(DEPDIR)/$(am__dirstamp)
+libdnssec/key/libdnssec_la-simple.lo: libdnssec/key/$(am__dirstamp) \
+ libdnssec/key/$(DEPDIR)/$(am__dirstamp)
+libdnssec/libdnssec_la-keyid.lo: libdnssec/$(am__dirstamp) \
+ libdnssec/$(DEPDIR)/$(am__dirstamp)
+libdnssec/keystore/$(am__dirstamp):
+ @$(MKDIR_P) libdnssec/keystore
+ @: > libdnssec/keystore/$(am__dirstamp)
+libdnssec/keystore/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) libdnssec/keystore/$(DEPDIR)
+ @: > libdnssec/keystore/$(DEPDIR)/$(am__dirstamp)
+libdnssec/keystore/libdnssec_la-keystore.lo: \
+ libdnssec/keystore/$(am__dirstamp) \
+ libdnssec/keystore/$(DEPDIR)/$(am__dirstamp)
+libdnssec/keystore/libdnssec_la-pkcs11.lo: \
+ libdnssec/keystore/$(am__dirstamp) \
+ libdnssec/keystore/$(DEPDIR)/$(am__dirstamp)
+libdnssec/keystore/libdnssec_la-pkcs8.lo: \
+ libdnssec/keystore/$(am__dirstamp) \
+ libdnssec/keystore/$(DEPDIR)/$(am__dirstamp)
+libdnssec/keystore/libdnssec_la-pkcs8_dir.lo: \
+ libdnssec/keystore/$(am__dirstamp) \
+ libdnssec/keystore/$(DEPDIR)/$(am__dirstamp)
+libdnssec/list/$(am__dirstamp):
+ @$(MKDIR_P) libdnssec/list
+ @: > libdnssec/list/$(am__dirstamp)
+libdnssec/list/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) libdnssec/list/$(DEPDIR)
+ @: > libdnssec/list/$(DEPDIR)/$(am__dirstamp)
+libdnssec/list/libdnssec_la-list.lo: libdnssec/list/$(am__dirstamp) \
+ libdnssec/list/$(DEPDIR)/$(am__dirstamp)
+libdnssec/nsec/$(am__dirstamp):
+ @$(MKDIR_P) libdnssec/nsec
+ @: > libdnssec/nsec/$(am__dirstamp)
+libdnssec/nsec/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) libdnssec/nsec/$(DEPDIR)
+ @: > libdnssec/nsec/$(DEPDIR)/$(am__dirstamp)
+libdnssec/nsec/libdnssec_la-bitmap.lo: libdnssec/nsec/$(am__dirstamp) \
+ libdnssec/nsec/$(DEPDIR)/$(am__dirstamp)
+libdnssec/nsec/libdnssec_la-hash.lo: libdnssec/nsec/$(am__dirstamp) \
+ libdnssec/nsec/$(DEPDIR)/$(am__dirstamp)
+libdnssec/nsec/libdnssec_la-nsec.lo: libdnssec/nsec/$(am__dirstamp) \
+ libdnssec/nsec/$(DEPDIR)/$(am__dirstamp)
+libdnssec/p11/$(am__dirstamp):
+ @$(MKDIR_P) libdnssec/p11
+ @: > libdnssec/p11/$(am__dirstamp)
+libdnssec/p11/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) libdnssec/p11/$(DEPDIR)
+ @: > libdnssec/p11/$(DEPDIR)/$(am__dirstamp)
+libdnssec/p11/libdnssec_la-p11.lo: libdnssec/p11/$(am__dirstamp) \
+ libdnssec/p11/$(DEPDIR)/$(am__dirstamp)
+libdnssec/libdnssec_la-random.lo: libdnssec/$(am__dirstamp) \
+ libdnssec/$(DEPDIR)/$(am__dirstamp)
+libdnssec/sign/$(am__dirstamp):
+ @$(MKDIR_P) libdnssec/sign
+ @: > libdnssec/sign/$(am__dirstamp)
+libdnssec/sign/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) libdnssec/sign/$(DEPDIR)
+ @: > libdnssec/sign/$(DEPDIR)/$(am__dirstamp)
+libdnssec/sign/libdnssec_la-der.lo: libdnssec/sign/$(am__dirstamp) \
+ libdnssec/sign/$(DEPDIR)/$(am__dirstamp)
+libdnssec/sign/libdnssec_la-sign.lo: libdnssec/sign/$(am__dirstamp) \
+ libdnssec/sign/$(DEPDIR)/$(am__dirstamp)
+libdnssec/libdnssec_la-tsig.lo: libdnssec/$(am__dirstamp) \
+ libdnssec/$(DEPDIR)/$(am__dirstamp)
+
+libdnssec.la: $(libdnssec_la_OBJECTS) $(libdnssec_la_DEPENDENCIES) $(EXTRA_libdnssec_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libdnssec_la_LINK) -rpath $(libdir) $(libdnssec_la_OBJECTS) $(libdnssec_la_LIBADD) $(LIBS)
+contrib/dnstap/$(am__dirstamp):
+ @$(MKDIR_P) contrib/dnstap
+ @: > contrib/dnstap/$(am__dirstamp)
+contrib/dnstap/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) contrib/dnstap/$(DEPDIR)
+ @: > contrib/dnstap/$(DEPDIR)/$(am__dirstamp)
+contrib/dnstap/libdnstap_la-convert.lo: \
+ contrib/dnstap/$(am__dirstamp) \
+ contrib/dnstap/$(DEPDIR)/$(am__dirstamp)
+contrib/dnstap/libdnstap_la-dnstap.lo: contrib/dnstap/$(am__dirstamp) \
+ contrib/dnstap/$(DEPDIR)/$(am__dirstamp)
+contrib/dnstap/libdnstap_la-message.lo: \
+ contrib/dnstap/$(am__dirstamp) \
+ contrib/dnstap/$(DEPDIR)/$(am__dirstamp)
+contrib/dnstap/libdnstap_la-reader.lo: contrib/dnstap/$(am__dirstamp) \
+ contrib/dnstap/$(DEPDIR)/$(am__dirstamp)
+contrib/dnstap/libdnstap_la-writer.lo: contrib/dnstap/$(am__dirstamp) \
+ contrib/dnstap/$(DEPDIR)/$(am__dirstamp)
+contrib/dnstap/libdnstap_la-dnstap.pb-c.lo: \
+ contrib/dnstap/$(am__dirstamp) \
+ contrib/dnstap/$(DEPDIR)/$(am__dirstamp)
+
+libdnstap.la: $(libdnstap_la_OBJECTS) $(libdnstap_la_DEPENDENCIES) $(EXTRA_libdnstap_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libdnstap_la_LINK) $(am_libdnstap_la_rpath) $(libdnstap_la_OBJECTS) $(libdnstap_la_LIBADD) $(LIBS)
+libknot/$(am__dirstamp):
+ @$(MKDIR_P) libknot
+ @: > libknot/$(am__dirstamp)
+libknot/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) libknot/$(DEPDIR)
+ @: > libknot/$(DEPDIR)/$(am__dirstamp)
+libknot/libknot_la-codes.lo: libknot/$(am__dirstamp) \
+ libknot/$(DEPDIR)/$(am__dirstamp)
+libknot/control/$(am__dirstamp):
+ @$(MKDIR_P) libknot/control
+ @: > libknot/control/$(am__dirstamp)
+libknot/control/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) libknot/control/$(DEPDIR)
+ @: > libknot/control/$(DEPDIR)/$(am__dirstamp)
+libknot/control/libknot_la-control.lo: \
+ libknot/control/$(am__dirstamp) \
+ libknot/control/$(DEPDIR)/$(am__dirstamp)
+libknot/libknot_la-cookies.lo: libknot/$(am__dirstamp) \
+ libknot/$(DEPDIR)/$(am__dirstamp)
+libknot/libknot_la-descriptor.lo: libknot/$(am__dirstamp) \
+ libknot/$(DEPDIR)/$(am__dirstamp)
+libknot/libknot_la-dname.lo: libknot/$(am__dirstamp) \
+ libknot/$(DEPDIR)/$(am__dirstamp)
+libknot/libknot_la-error.lo: libknot/$(am__dirstamp) \
+ libknot/$(DEPDIR)/$(am__dirstamp)
+libknot/db/$(am__dirstamp):
+ @$(MKDIR_P) libknot/db
+ @: > libknot/db/$(am__dirstamp)
+libknot/db/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) libknot/db/$(DEPDIR)
+ @: > libknot/db/$(DEPDIR)/$(am__dirstamp)
+libknot/db/libknot_la-db_lmdb.lo: libknot/db/$(am__dirstamp) \
+ libknot/db/$(DEPDIR)/$(am__dirstamp)
+libknot/db/libknot_la-db_trie.lo: libknot/db/$(am__dirstamp) \
+ libknot/db/$(DEPDIR)/$(am__dirstamp)
+libknot/packet/$(am__dirstamp):
+ @$(MKDIR_P) libknot/packet
+ @: > libknot/packet/$(am__dirstamp)
+libknot/packet/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) libknot/packet/$(DEPDIR)
+ @: > libknot/packet/$(DEPDIR)/$(am__dirstamp)
+libknot/packet/libknot_la-pkt.lo: libknot/packet/$(am__dirstamp) \
+ libknot/packet/$(DEPDIR)/$(am__dirstamp)
+libknot/packet/libknot_la-rrset-wire.lo: \
+ libknot/packet/$(am__dirstamp) \
+ libknot/packet/$(DEPDIR)/$(am__dirstamp)
+libknot/libknot_la-rdataset.lo: libknot/$(am__dirstamp) \
+ libknot/$(DEPDIR)/$(am__dirstamp)
+libknot/libknot_la-rrset-dump.lo: libknot/$(am__dirstamp) \
+ libknot/$(DEPDIR)/$(am__dirstamp)
+libknot/libknot_la-rrset.lo: libknot/$(am__dirstamp) \
+ libknot/$(DEPDIR)/$(am__dirstamp)
+libknot/rrtype/$(am__dirstamp):
+ @$(MKDIR_P) libknot/rrtype
+ @: > libknot/rrtype/$(am__dirstamp)
+libknot/rrtype/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) libknot/rrtype/$(DEPDIR)
+ @: > libknot/rrtype/$(DEPDIR)/$(am__dirstamp)
+libknot/rrtype/libknot_la-naptr.lo: libknot/rrtype/$(am__dirstamp) \
+ libknot/rrtype/$(DEPDIR)/$(am__dirstamp)
+libknot/rrtype/libknot_la-opt.lo: libknot/rrtype/$(am__dirstamp) \
+ libknot/rrtype/$(DEPDIR)/$(am__dirstamp)
+libknot/rrtype/libknot_la-tsig.lo: libknot/rrtype/$(am__dirstamp) \
+ libknot/rrtype/$(DEPDIR)/$(am__dirstamp)
+libknot/libknot_la-tsig-op.lo: libknot/$(am__dirstamp) \
+ libknot/$(DEPDIR)/$(am__dirstamp)
+libknot/libknot_la-tsig.lo: libknot/$(am__dirstamp) \
+ libknot/$(DEPDIR)/$(am__dirstamp)
+libknot/yparser/$(am__dirstamp):
+ @$(MKDIR_P) libknot/yparser
+ @: > libknot/yparser/$(am__dirstamp)
+libknot/yparser/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) libknot/yparser/$(DEPDIR)
+ @: > libknot/yparser/$(DEPDIR)/$(am__dirstamp)
+libknot/yparser/libknot_la-yparser.lo: \
+ libknot/yparser/$(am__dirstamp) \
+ libknot/yparser/$(DEPDIR)/$(am__dirstamp)
+libknot/yparser/libknot_la-ypbody.lo: libknot/yparser/$(am__dirstamp) \
+ libknot/yparser/$(DEPDIR)/$(am__dirstamp)
+libknot/yparser/libknot_la-ypformat.lo: \
+ libknot/yparser/$(am__dirstamp) \
+ libknot/yparser/$(DEPDIR)/$(am__dirstamp)
+libknot/yparser/libknot_la-ypschema.lo: \
+ libknot/yparser/$(am__dirstamp) \
+ libknot/yparser/$(DEPDIR)/$(am__dirstamp)
+libknot/yparser/libknot_la-yptrafo.lo: \
+ libknot/yparser/$(am__dirstamp) \
+ libknot/yparser/$(DEPDIR)/$(am__dirstamp)
+
+libknot.la: $(libknot_la_OBJECTS) $(libknot_la_DEPENDENCIES) $(EXTRA_libknot_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libknot_la_LINK) -rpath $(libdir) $(libknot_la_OBJECTS) $(libknot_la_LIBADD) $(LIBS)
+knot/conf/$(am__dirstamp):
+ @$(MKDIR_P) knot/conf
+ @: > knot/conf/$(am__dirstamp)
+knot/conf/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) knot/conf/$(DEPDIR)
+ @: > knot/conf/$(DEPDIR)/$(am__dirstamp)
+knot/conf/libknotd_la-base.lo: knot/conf/$(am__dirstamp) \
+ knot/conf/$(DEPDIR)/$(am__dirstamp)
+knot/conf/libknotd_la-conf.lo: knot/conf/$(am__dirstamp) \
+ knot/conf/$(DEPDIR)/$(am__dirstamp)
+knot/conf/libknotd_la-confdb.lo: knot/conf/$(am__dirstamp) \
+ knot/conf/$(DEPDIR)/$(am__dirstamp)
+knot/conf/libknotd_la-confio.lo: knot/conf/$(am__dirstamp) \
+ knot/conf/$(DEPDIR)/$(am__dirstamp)
+knot/conf/libknotd_la-migration.lo: knot/conf/$(am__dirstamp) \
+ knot/conf/$(DEPDIR)/$(am__dirstamp)
+knot/conf/libknotd_la-module.lo: knot/conf/$(am__dirstamp) \
+ knot/conf/$(DEPDIR)/$(am__dirstamp)
+knot/conf/libknotd_la-schema.lo: knot/conf/$(am__dirstamp) \
+ knot/conf/$(DEPDIR)/$(am__dirstamp)
+knot/conf/libknotd_la-tools.lo: knot/conf/$(am__dirstamp) \
+ knot/conf/$(DEPDIR)/$(am__dirstamp)
+knot/ctl/$(am__dirstamp):
+ @$(MKDIR_P) knot/ctl
+ @: > knot/ctl/$(am__dirstamp)
+knot/ctl/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) knot/ctl/$(DEPDIR)
+ @: > knot/ctl/$(DEPDIR)/$(am__dirstamp)
+knot/ctl/libknotd_la-commands.lo: knot/ctl/$(am__dirstamp) \
+ knot/ctl/$(DEPDIR)/$(am__dirstamp)
+knot/ctl/libknotd_la-process.lo: knot/ctl/$(am__dirstamp) \
+ knot/ctl/$(DEPDIR)/$(am__dirstamp)
+knot/dnssec/$(am__dirstamp):
+ @$(MKDIR_P) knot/dnssec
+ @: > knot/dnssec/$(am__dirstamp)
+knot/dnssec/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) knot/dnssec/$(DEPDIR)
+ @: > knot/dnssec/$(DEPDIR)/$(am__dirstamp)
+knot/dnssec/libknotd_la-context.lo: knot/dnssec/$(am__dirstamp) \
+ knot/dnssec/$(DEPDIR)/$(am__dirstamp)
+knot/dnssec/libknotd_la-ds_query.lo: knot/dnssec/$(am__dirstamp) \
+ knot/dnssec/$(DEPDIR)/$(am__dirstamp)
+knot/dnssec/kasp/$(am__dirstamp):
+ @$(MKDIR_P) knot/dnssec/kasp
+ @: > knot/dnssec/kasp/$(am__dirstamp)
+knot/dnssec/kasp/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) knot/dnssec/kasp/$(DEPDIR)
+ @: > knot/dnssec/kasp/$(DEPDIR)/$(am__dirstamp)
+knot/dnssec/kasp/libknotd_la-kasp_db.lo: \
+ knot/dnssec/kasp/$(am__dirstamp) \
+ knot/dnssec/kasp/$(DEPDIR)/$(am__dirstamp)
+knot/dnssec/kasp/libknotd_la-kasp_zone.lo: \
+ knot/dnssec/kasp/$(am__dirstamp) \
+ knot/dnssec/kasp/$(DEPDIR)/$(am__dirstamp)
+knot/dnssec/kasp/libknotd_la-keystate.lo: \
+ knot/dnssec/kasp/$(am__dirstamp) \
+ knot/dnssec/kasp/$(DEPDIR)/$(am__dirstamp)
+knot/dnssec/kasp/libknotd_la-keystore.lo: \
+ knot/dnssec/kasp/$(am__dirstamp) \
+ knot/dnssec/kasp/$(DEPDIR)/$(am__dirstamp)
+knot/dnssec/libknotd_la-key-events.lo: knot/dnssec/$(am__dirstamp) \
+ knot/dnssec/$(DEPDIR)/$(am__dirstamp)
+knot/dnssec/libknotd_la-nsec-chain.lo: knot/dnssec/$(am__dirstamp) \
+ knot/dnssec/$(DEPDIR)/$(am__dirstamp)
+knot/dnssec/libknotd_la-nsec3-chain.lo: knot/dnssec/$(am__dirstamp) \
+ knot/dnssec/$(DEPDIR)/$(am__dirstamp)
+knot/dnssec/libknotd_la-policy.lo: knot/dnssec/$(am__dirstamp) \
+ knot/dnssec/$(DEPDIR)/$(am__dirstamp)
+knot/dnssec/libknotd_la-rrset-sign.lo: knot/dnssec/$(am__dirstamp) \
+ knot/dnssec/$(DEPDIR)/$(am__dirstamp)
+knot/dnssec/libknotd_la-zone-events.lo: knot/dnssec/$(am__dirstamp) \
+ knot/dnssec/$(DEPDIR)/$(am__dirstamp)
+knot/dnssec/libknotd_la-zone-keys.lo: knot/dnssec/$(am__dirstamp) \
+ knot/dnssec/$(DEPDIR)/$(am__dirstamp)
+knot/dnssec/libknotd_la-zone-nsec.lo: knot/dnssec/$(am__dirstamp) \
+ knot/dnssec/$(DEPDIR)/$(am__dirstamp)
+knot/dnssec/libknotd_la-zone-sign.lo: knot/dnssec/$(am__dirstamp) \
+ knot/dnssec/$(DEPDIR)/$(am__dirstamp)
+knot/events/$(am__dirstamp):
+ @$(MKDIR_P) knot/events
+ @: > knot/events/$(am__dirstamp)
+knot/events/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) knot/events/$(DEPDIR)
+ @: > knot/events/$(DEPDIR)/$(am__dirstamp)
+knot/events/libknotd_la-events.lo: knot/events/$(am__dirstamp) \
+ knot/events/$(DEPDIR)/$(am__dirstamp)
+knot/events/handlers/$(am__dirstamp):
+ @$(MKDIR_P) knot/events/handlers
+ @: > knot/events/handlers/$(am__dirstamp)
+knot/events/handlers/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) knot/events/handlers/$(DEPDIR)
+ @: > knot/events/handlers/$(DEPDIR)/$(am__dirstamp)
+knot/events/handlers/libknotd_la-dnssec.lo: \
+ knot/events/handlers/$(am__dirstamp) \
+ knot/events/handlers/$(DEPDIR)/$(am__dirstamp)
+knot/events/handlers/libknotd_la-expire.lo: \
+ knot/events/handlers/$(am__dirstamp) \
+ knot/events/handlers/$(DEPDIR)/$(am__dirstamp)
+knot/events/handlers/libknotd_la-flush.lo: \
+ knot/events/handlers/$(am__dirstamp) \
+ knot/events/handlers/$(DEPDIR)/$(am__dirstamp)
+knot/events/handlers/libknotd_la-freeze_thaw.lo: \
+ knot/events/handlers/$(am__dirstamp) \
+ knot/events/handlers/$(DEPDIR)/$(am__dirstamp)
+knot/events/handlers/libknotd_la-load.lo: \
+ knot/events/handlers/$(am__dirstamp) \
+ knot/events/handlers/$(DEPDIR)/$(am__dirstamp)
+knot/events/handlers/libknotd_la-notify.lo: \
+ knot/events/handlers/$(am__dirstamp) \
+ knot/events/handlers/$(DEPDIR)/$(am__dirstamp)
+knot/events/handlers/libknotd_la-nsec3resalt.lo: \
+ knot/events/handlers/$(am__dirstamp) \
+ knot/events/handlers/$(DEPDIR)/$(am__dirstamp)
+knot/events/handlers/libknotd_la-refresh.lo: \
+ knot/events/handlers/$(am__dirstamp) \
+ knot/events/handlers/$(DEPDIR)/$(am__dirstamp)
+knot/events/handlers/libknotd_la-update.lo: \
+ knot/events/handlers/$(am__dirstamp) \
+ knot/events/handlers/$(DEPDIR)/$(am__dirstamp)
+knot/events/handlers/libknotd_la-parent_ds_query.lo: \
+ knot/events/handlers/$(am__dirstamp) \
+ knot/events/handlers/$(DEPDIR)/$(am__dirstamp)
+knot/events/libknotd_la-replan.lo: knot/events/$(am__dirstamp) \
+ knot/events/$(DEPDIR)/$(am__dirstamp)
+knot/nameserver/$(am__dirstamp):
+ @$(MKDIR_P) knot/nameserver
+ @: > knot/nameserver/$(am__dirstamp)
+knot/nameserver/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) knot/nameserver/$(DEPDIR)
+ @: > knot/nameserver/$(DEPDIR)/$(am__dirstamp)
+knot/nameserver/libknotd_la-axfr.lo: knot/nameserver/$(am__dirstamp) \
+ knot/nameserver/$(DEPDIR)/$(am__dirstamp)
+knot/nameserver/libknotd_la-chaos.lo: knot/nameserver/$(am__dirstamp) \
+ knot/nameserver/$(DEPDIR)/$(am__dirstamp)
+knot/nameserver/libknotd_la-internet.lo: \
+ knot/nameserver/$(am__dirstamp) \
+ knot/nameserver/$(DEPDIR)/$(am__dirstamp)
+knot/nameserver/libknotd_la-ixfr.lo: knot/nameserver/$(am__dirstamp) \
+ knot/nameserver/$(DEPDIR)/$(am__dirstamp)
+knot/nameserver/libknotd_la-notify.lo: \
+ knot/nameserver/$(am__dirstamp) \
+ knot/nameserver/$(DEPDIR)/$(am__dirstamp)
+knot/nameserver/libknotd_la-nsec_proofs.lo: \
+ knot/nameserver/$(am__dirstamp) \
+ knot/nameserver/$(DEPDIR)/$(am__dirstamp)
+knot/nameserver/libknotd_la-process_query.lo: \
+ knot/nameserver/$(am__dirstamp) \
+ knot/nameserver/$(DEPDIR)/$(am__dirstamp)
+knot/nameserver/libknotd_la-query_module.lo: \
+ knot/nameserver/$(am__dirstamp) \
+ knot/nameserver/$(DEPDIR)/$(am__dirstamp)
+knot/nameserver/libknotd_la-tsig_ctx.lo: \
+ knot/nameserver/$(am__dirstamp) \
+ knot/nameserver/$(DEPDIR)/$(am__dirstamp)
+knot/nameserver/libknotd_la-update.lo: \
+ knot/nameserver/$(am__dirstamp) \
+ knot/nameserver/$(DEPDIR)/$(am__dirstamp)
+knot/nameserver/libknotd_la-xfr.lo: knot/nameserver/$(am__dirstamp) \
+ knot/nameserver/$(DEPDIR)/$(am__dirstamp)
+knot/query/$(am__dirstamp):
+ @$(MKDIR_P) knot/query
+ @: > knot/query/$(am__dirstamp)
+knot/query/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) knot/query/$(DEPDIR)
+ @: > knot/query/$(DEPDIR)/$(am__dirstamp)
+knot/query/libknotd_la-capture.lo: knot/query/$(am__dirstamp) \
+ knot/query/$(DEPDIR)/$(am__dirstamp)
+knot/query/libknotd_la-query.lo: knot/query/$(am__dirstamp) \
+ knot/query/$(DEPDIR)/$(am__dirstamp)
+knot/query/libknotd_la-requestor.lo: knot/query/$(am__dirstamp) \
+ knot/query/$(DEPDIR)/$(am__dirstamp)
+knot/common/$(am__dirstamp):
+ @$(MKDIR_P) knot/common
+ @: > knot/common/$(am__dirstamp)
+knot/common/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) knot/common/$(DEPDIR)
+ @: > knot/common/$(DEPDIR)/$(am__dirstamp)
+knot/common/libknotd_la-evsched.lo: knot/common/$(am__dirstamp) \
+ knot/common/$(DEPDIR)/$(am__dirstamp)
+knot/common/libknotd_la-fdset.lo: knot/common/$(am__dirstamp) \
+ knot/common/$(DEPDIR)/$(am__dirstamp)
+knot/common/libknotd_la-log.lo: knot/common/$(am__dirstamp) \
+ knot/common/$(DEPDIR)/$(am__dirstamp)
+knot/common/libknotd_la-process.lo: knot/common/$(am__dirstamp) \
+ knot/common/$(DEPDIR)/$(am__dirstamp)
+knot/common/libknotd_la-ref.lo: knot/common/$(am__dirstamp) \
+ knot/common/$(DEPDIR)/$(am__dirstamp)
+knot/common/libknotd_la-stats.lo: knot/common/$(am__dirstamp) \
+ knot/common/$(DEPDIR)/$(am__dirstamp)
+knot/server/$(am__dirstamp):
+ @$(MKDIR_P) knot/server
+ @: > knot/server/$(am__dirstamp)
+knot/server/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) knot/server/$(DEPDIR)
+ @: > knot/server/$(DEPDIR)/$(am__dirstamp)
+knot/server/libknotd_la-dthreads.lo: knot/server/$(am__dirstamp) \
+ knot/server/$(DEPDIR)/$(am__dirstamp)
+knot/journal/$(am__dirstamp):
+ @$(MKDIR_P) knot/journal
+ @: > knot/journal/$(am__dirstamp)
+knot/journal/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) knot/journal/$(DEPDIR)
+ @: > knot/journal/$(DEPDIR)/$(am__dirstamp)
+knot/journal/libknotd_la-chgset_ctx.lo: knot/journal/$(am__dirstamp) \
+ knot/journal/$(DEPDIR)/$(am__dirstamp)
+knot/journal/libknotd_la-journal.lo: knot/journal/$(am__dirstamp) \
+ knot/journal/$(DEPDIR)/$(am__dirstamp)
+knot/journal/libknotd_la-serialization.lo: \
+ knot/journal/$(am__dirstamp) \
+ knot/journal/$(DEPDIR)/$(am__dirstamp)
+knot/server/libknotd_la-server.lo: knot/server/$(am__dirstamp) \
+ knot/server/$(DEPDIR)/$(am__dirstamp)
+knot/server/libknotd_la-tcp-handler.lo: knot/server/$(am__dirstamp) \
+ knot/server/$(DEPDIR)/$(am__dirstamp)
+knot/server/libknotd_la-udp-handler.lo: knot/server/$(am__dirstamp) \
+ knot/server/$(DEPDIR)/$(am__dirstamp)
+knot/updates/$(am__dirstamp):
+ @$(MKDIR_P) knot/updates
+ @: > knot/updates/$(am__dirstamp)
+knot/updates/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) knot/updates/$(DEPDIR)
+ @: > knot/updates/$(DEPDIR)/$(am__dirstamp)
+knot/updates/libknotd_la-acl.lo: knot/updates/$(am__dirstamp) \
+ knot/updates/$(DEPDIR)/$(am__dirstamp)
+knot/updates/libknotd_la-apply.lo: knot/updates/$(am__dirstamp) \
+ knot/updates/$(DEPDIR)/$(am__dirstamp)
+knot/updates/libknotd_la-changesets.lo: knot/updates/$(am__dirstamp) \
+ knot/updates/$(DEPDIR)/$(am__dirstamp)
+knot/updates/libknotd_la-ddns.lo: knot/updates/$(am__dirstamp) \
+ knot/updates/$(DEPDIR)/$(am__dirstamp)
+knot/updates/libknotd_la-zone-update.lo: knot/updates/$(am__dirstamp) \
+ knot/updates/$(DEPDIR)/$(am__dirstamp)
+knot/worker/$(am__dirstamp):
+ @$(MKDIR_P) knot/worker
+ @: > knot/worker/$(am__dirstamp)
+knot/worker/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) knot/worker/$(DEPDIR)
+ @: > knot/worker/$(DEPDIR)/$(am__dirstamp)
+knot/worker/libknotd_la-pool.lo: knot/worker/$(am__dirstamp) \
+ knot/worker/$(DEPDIR)/$(am__dirstamp)
+knot/worker/libknotd_la-queue.lo: knot/worker/$(am__dirstamp) \
+ knot/worker/$(DEPDIR)/$(am__dirstamp)
+knot/zone/$(am__dirstamp):
+ @$(MKDIR_P) knot/zone
+ @: > knot/zone/$(am__dirstamp)
+knot/zone/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) knot/zone/$(DEPDIR)
+ @: > knot/zone/$(DEPDIR)/$(am__dirstamp)
+knot/zone/libknotd_la-contents.lo: knot/zone/$(am__dirstamp) \
+ knot/zone/$(DEPDIR)/$(am__dirstamp)
+knot/zone/libknotd_la-node.lo: knot/zone/$(am__dirstamp) \
+ knot/zone/$(DEPDIR)/$(am__dirstamp)
+knot/zone/libknotd_la-semantic-check.lo: knot/zone/$(am__dirstamp) \
+ knot/zone/$(DEPDIR)/$(am__dirstamp)
+knot/zone/libknotd_la-serial.lo: knot/zone/$(am__dirstamp) \
+ knot/zone/$(DEPDIR)/$(am__dirstamp)
+knot/zone/libknotd_la-timers.lo: knot/zone/$(am__dirstamp) \
+ knot/zone/$(DEPDIR)/$(am__dirstamp)
+knot/zone/libknotd_la-zone-diff.lo: knot/zone/$(am__dirstamp) \
+ knot/zone/$(DEPDIR)/$(am__dirstamp)
+knot/zone/libknotd_la-zone-dump.lo: knot/zone/$(am__dirstamp) \
+ knot/zone/$(DEPDIR)/$(am__dirstamp)
+knot/zone/libknotd_la-zone-load.lo: knot/zone/$(am__dirstamp) \
+ knot/zone/$(DEPDIR)/$(am__dirstamp)
+knot/zone/libknotd_la-zone-tree.lo: knot/zone/$(am__dirstamp) \
+ knot/zone/$(DEPDIR)/$(am__dirstamp)
+knot/zone/libknotd_la-zone.lo: knot/zone/$(am__dirstamp) \
+ knot/zone/$(DEPDIR)/$(am__dirstamp)
+knot/zone/libknotd_la-zonedb-load.lo: knot/zone/$(am__dirstamp) \
+ knot/zone/$(DEPDIR)/$(am__dirstamp)
+knot/zone/libknotd_la-zonedb.lo: knot/zone/$(am__dirstamp) \
+ knot/zone/$(DEPDIR)/$(am__dirstamp)
+knot/zone/libknotd_la-zonefile.lo: knot/zone/$(am__dirstamp) \
+ knot/zone/$(DEPDIR)/$(am__dirstamp)
+knot/modules/cookies/libknotd_la-cookies.lo: \
+ knot/modules/cookies/$(am__dirstamp) \
+ knot/modules/cookies/$(DEPDIR)/$(am__dirstamp)
+knot/modules/dnsproxy/libknotd_la-dnsproxy.lo: \
+ knot/modules/dnsproxy/$(am__dirstamp) \
+ knot/modules/dnsproxy/$(DEPDIR)/$(am__dirstamp)
+knot/modules/dnstap/libknotd_la-dnstap.lo: \
+ knot/modules/dnstap/$(am__dirstamp) \
+ knot/modules/dnstap/$(DEPDIR)/$(am__dirstamp)
+knot/modules/geoip/libknotd_la-geoip.lo: \
+ knot/modules/geoip/$(am__dirstamp) \
+ knot/modules/geoip/$(DEPDIR)/$(am__dirstamp)
+knot/modules/geoip/libknotd_la-geodb.lo: \
+ knot/modules/geoip/$(am__dirstamp) \
+ knot/modules/geoip/$(DEPDIR)/$(am__dirstamp)
+knot/modules/noudp/libknotd_la-noudp.lo: \
+ knot/modules/noudp/$(am__dirstamp) \
+ knot/modules/noudp/$(DEPDIR)/$(am__dirstamp)
+knot/modules/onlinesign/libknotd_la-onlinesign.lo: \
+ knot/modules/onlinesign/$(am__dirstamp) \
+ knot/modules/onlinesign/$(DEPDIR)/$(am__dirstamp)
+knot/modules/onlinesign/libknotd_la-nsec_next.lo: \
+ knot/modules/onlinesign/$(am__dirstamp) \
+ knot/modules/onlinesign/$(DEPDIR)/$(am__dirstamp)
+knot/modules/queryacl/libknotd_la-queryacl.lo: \
+ knot/modules/queryacl/$(am__dirstamp) \
+ knot/modules/queryacl/$(DEPDIR)/$(am__dirstamp)
+knot/modules/rrl/libknotd_la-rrl.lo: knot/modules/rrl/$(am__dirstamp) \
+ knot/modules/rrl/$(DEPDIR)/$(am__dirstamp)
+knot/modules/rrl/libknotd_la-functions.lo: \
+ knot/modules/rrl/$(am__dirstamp) \
+ knot/modules/rrl/$(DEPDIR)/$(am__dirstamp)
+knot/modules/stats/libknotd_la-stats.lo: \
+ knot/modules/stats/$(am__dirstamp) \
+ knot/modules/stats/$(DEPDIR)/$(am__dirstamp)
+knot/modules/synthrecord/libknotd_la-synthrecord.lo: \
+ knot/modules/synthrecord/$(am__dirstamp) \
+ knot/modules/synthrecord/$(DEPDIR)/$(am__dirstamp)
+knot/modules/whoami/libknotd_la-whoami.lo: \
+ knot/modules/whoami/$(am__dirstamp) \
+ knot/modules/whoami/$(DEPDIR)/$(am__dirstamp)
+
+libknotd.la: $(libknotd_la_OBJECTS) $(libknotd_la_DEPENDENCIES) $(EXTRA_libknotd_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libknotd_la_LINK) $(am_libknotd_la_rpath) $(libknotd_la_OBJECTS) $(libknotd_la_LIBADD) $(LIBS)
+utils/common/$(am__dirstamp):
+ @$(MKDIR_P) utils/common
+ @: > utils/common/$(am__dirstamp)
+utils/common/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) utils/common/$(DEPDIR)
+ @: > utils/common/$(DEPDIR)/$(am__dirstamp)
+utils/common/libknotus_la-cert.lo: utils/common/$(am__dirstamp) \
+ utils/common/$(DEPDIR)/$(am__dirstamp)
+utils/common/libknotus_la-exec.lo: utils/common/$(am__dirstamp) \
+ utils/common/$(DEPDIR)/$(am__dirstamp)
+utils/common/libknotus_la-hex.lo: utils/common/$(am__dirstamp) \
+ utils/common/$(DEPDIR)/$(am__dirstamp)
+utils/common/libknotus_la-lookup.lo: utils/common/$(am__dirstamp) \
+ utils/common/$(DEPDIR)/$(am__dirstamp)
+utils/common/libknotus_la-msg.lo: utils/common/$(am__dirstamp) \
+ utils/common/$(DEPDIR)/$(am__dirstamp)
+utils/common/libknotus_la-netio.lo: utils/common/$(am__dirstamp) \
+ utils/common/$(DEPDIR)/$(am__dirstamp)
+utils/common/libknotus_la-params.lo: utils/common/$(am__dirstamp) \
+ utils/common/$(DEPDIR)/$(am__dirstamp)
+utils/common/libknotus_la-resolv.lo: utils/common/$(am__dirstamp) \
+ utils/common/$(DEPDIR)/$(am__dirstamp)
+utils/common/libknotus_la-sign.lo: utils/common/$(am__dirstamp) \
+ utils/common/$(DEPDIR)/$(am__dirstamp)
+utils/common/libknotus_la-tls.lo: utils/common/$(am__dirstamp) \
+ utils/common/$(DEPDIR)/$(am__dirstamp)
+utils/common/libknotus_la-token.lo: utils/common/$(am__dirstamp) \
+ utils/common/$(DEPDIR)/$(am__dirstamp)
+
+libknotus.la: $(libknotus_la_OBJECTS) $(libknotus_la_DEPENDENCIES) $(EXTRA_libknotus_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libknotus_la_LINK) $(am_libknotus_la_rpath) $(libknotus_la_OBJECTS) $(libknotus_la_LIBADD) $(LIBS)
+libdnssec/shared/$(am__dirstamp):
+ @$(MKDIR_P) libdnssec/shared
+ @: > libdnssec/shared/$(am__dirstamp)
+libdnssec/shared/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) libdnssec/shared/$(DEPDIR)
+ @: > libdnssec/shared/$(DEPDIR)/$(am__dirstamp)
+libdnssec/shared/libshared_la-bignum.lo: \
+ libdnssec/shared/$(am__dirstamp) \
+ libdnssec/shared/$(DEPDIR)/$(am__dirstamp)
+libdnssec/shared/libshared_la-dname.lo: \
+ libdnssec/shared/$(am__dirstamp) \
+ libdnssec/shared/$(DEPDIR)/$(am__dirstamp)
+libdnssec/shared/libshared_la-fs.lo: libdnssec/shared/$(am__dirstamp) \
+ libdnssec/shared/$(DEPDIR)/$(am__dirstamp)
+libdnssec/shared/libshared_la-hex.lo: \
+ libdnssec/shared/$(am__dirstamp) \
+ libdnssec/shared/$(DEPDIR)/$(am__dirstamp)
+libdnssec/shared/libshared_la-keyid_gnutls.lo: \
+ libdnssec/shared/$(am__dirstamp) \
+ libdnssec/shared/$(DEPDIR)/$(am__dirstamp)
+libdnssec/shared/libshared_la-pem.lo: \
+ libdnssec/shared/$(am__dirstamp) \
+ libdnssec/shared/$(DEPDIR)/$(am__dirstamp)
+
+libshared.la: $(libshared_la_OBJECTS) $(libshared_la_DEPENDENCIES) $(EXTRA_libshared_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libshared_la_OBJECTS) $(libshared_la_LIBADD) $(LIBS)
+libzscanner/$(am__dirstamp):
+ @$(MKDIR_P) libzscanner
+ @: > libzscanner/$(am__dirstamp)
+libzscanner/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) libzscanner/$(DEPDIR)
+ @: > libzscanner/$(DEPDIR)/$(am__dirstamp)
+libzscanner/libzscanner_la-error.lo: libzscanner/$(am__dirstamp) \
+ libzscanner/$(DEPDIR)/$(am__dirstamp)
+libzscanner/libzscanner_la-functions.lo: libzscanner/$(am__dirstamp) \
+ libzscanner/$(DEPDIR)/$(am__dirstamp)
+libzscanner/libzscanner_la-scanner.lo: libzscanner/$(am__dirstamp) \
+ libzscanner/$(DEPDIR)/$(am__dirstamp)
+
+libzscanner.la: $(libzscanner_la_OBJECTS) $(libzscanner_la_DEPENDENCIES) $(EXTRA_libzscanner_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libzscanner_la_LINK) -rpath $(libdir) $(libzscanner_la_OBJECTS) $(libzscanner_la_LIBADD) $(LIBS)
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ || test -f $$p1 \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+installcheck-binPROGRAMS: $(bin_PROGRAMS)
+ bad=0; pid=$$$$; list="$(bin_PROGRAMS)"; for p in $$list; do \
+ case ' $(AM_INSTALLCHECK_STD_OPTIONS_EXEMPT) ' in \
+ *" $$p "* | *" $(srcdir)/$$p "*) continue;; \
+ esac; \
+ f=`echo "$$p" | \
+ sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ for opt in --help --version; do \
+ if "$(DESTDIR)$(bindir)/$$f" $$opt >c$${pid}_.out \
+ 2>c$${pid}_.err </dev/null \
+ && test -n "`cat c$${pid}_.out`" \
+ && test -z "`cat c$${pid}_.err`"; then :; \
+ else echo "$$f does not support $$opt" 1>&2; bad=1; fi; \
+ done; \
+ done; rm -f c$${pid}_.???; exit $$bad
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ || test -f $$p1 \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-sbinPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(sbindir)" && rm -f $$files
+
+clean-sbinPROGRAMS:
+ @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+installcheck-sbinPROGRAMS: $(sbin_PROGRAMS)
+ bad=0; pid=$$$$; list="$(sbin_PROGRAMS)"; for p in $$list; do \
+ case ' $(AM_INSTALLCHECK_STD_OPTIONS_EXEMPT) ' in \
+ *" $$p "* | *" $(srcdir)/$$p "*) continue;; \
+ esac; \
+ f=`echo "$$p" | \
+ sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ for opt in --help --version; do \
+ if "$(DESTDIR)$(sbindir)/$$f" $$opt >c$${pid}_.out \
+ 2>c$${pid}_.err </dev/null \
+ && test -n "`cat c$${pid}_.out`" \
+ && test -z "`cat c$${pid}_.err`"; then :; \
+ else echo "$$f does not support $$opt" 1>&2; bad=1; fi; \
+ done; \
+ done; rm -f c$${pid}_.???; exit $$bad
+utils/kdig/$(am__dirstamp):
+ @$(MKDIR_P) utils/kdig
+ @: > utils/kdig/$(am__dirstamp)
+utils/kdig/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) utils/kdig/$(DEPDIR)
+ @: > utils/kdig/$(DEPDIR)/$(am__dirstamp)
+utils/kdig/kdig-kdig_exec.$(OBJEXT): utils/kdig/$(am__dirstamp) \
+ utils/kdig/$(DEPDIR)/$(am__dirstamp)
+utils/kdig/kdig-kdig_main.$(OBJEXT): utils/kdig/$(am__dirstamp) \
+ utils/kdig/$(DEPDIR)/$(am__dirstamp)
+utils/kdig/kdig-kdig_params.$(OBJEXT): utils/kdig/$(am__dirstamp) \
+ utils/kdig/$(DEPDIR)/$(am__dirstamp)
+
+kdig$(EXEEXT): $(kdig_OBJECTS) $(kdig_DEPENDENCIES) $(EXTRA_kdig_DEPENDENCIES)
+ @rm -f kdig$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(kdig_OBJECTS) $(kdig_LDADD) $(LIBS)
+utils/keymgr/$(am__dirstamp):
+ @$(MKDIR_P) utils/keymgr
+ @: > utils/keymgr/$(am__dirstamp)
+utils/keymgr/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) utils/keymgr/$(DEPDIR)
+ @: > utils/keymgr/$(DEPDIR)/$(am__dirstamp)
+utils/keymgr/keymgr-bind_privkey.$(OBJEXT): \
+ utils/keymgr/$(am__dirstamp) \
+ utils/keymgr/$(DEPDIR)/$(am__dirstamp)
+utils/keymgr/keymgr-functions.$(OBJEXT): utils/keymgr/$(am__dirstamp) \
+ utils/keymgr/$(DEPDIR)/$(am__dirstamp)
+utils/keymgr/keymgr-main.$(OBJEXT): utils/keymgr/$(am__dirstamp) \
+ utils/keymgr/$(DEPDIR)/$(am__dirstamp)
+
+keymgr$(EXEEXT): $(keymgr_OBJECTS) $(keymgr_DEPENDENCIES) $(EXTRA_keymgr_DEPENDENCIES)
+ @rm -f keymgr$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(keymgr_OBJECTS) $(keymgr_LDADD) $(LIBS)
+utils/kdig/khost-kdig_exec.$(OBJEXT): utils/kdig/$(am__dirstamp) \
+ utils/kdig/$(DEPDIR)/$(am__dirstamp)
+utils/kdig/khost-kdig_params.$(OBJEXT): utils/kdig/$(am__dirstamp) \
+ utils/kdig/$(DEPDIR)/$(am__dirstamp)
+utils/khost/$(am__dirstamp):
+ @$(MKDIR_P) utils/khost
+ @: > utils/khost/$(am__dirstamp)
+utils/khost/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) utils/khost/$(DEPDIR)
+ @: > utils/khost/$(DEPDIR)/$(am__dirstamp)
+utils/khost/khost-khost_main.$(OBJEXT): utils/khost/$(am__dirstamp) \
+ utils/khost/$(DEPDIR)/$(am__dirstamp)
+utils/khost/khost-khost_params.$(OBJEXT): utils/khost/$(am__dirstamp) \
+ utils/khost/$(DEPDIR)/$(am__dirstamp)
+
+khost$(EXEEXT): $(khost_OBJECTS) $(khost_DEPENDENCIES) $(EXTRA_khost_DEPENDENCIES)
+ @rm -f khost$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(khost_OBJECTS) $(khost_LDADD) $(LIBS)
+utils/kjournalprint/$(am__dirstamp):
+ @$(MKDIR_P) utils/kjournalprint
+ @: > utils/kjournalprint/$(am__dirstamp)
+utils/kjournalprint/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) utils/kjournalprint/$(DEPDIR)
+ @: > utils/kjournalprint/$(DEPDIR)/$(am__dirstamp)
+utils/kjournalprint/kjournalprint-main.$(OBJEXT): \
+ utils/kjournalprint/$(am__dirstamp) \
+ utils/kjournalprint/$(DEPDIR)/$(am__dirstamp)
+
+kjournalprint$(EXEEXT): $(kjournalprint_OBJECTS) $(kjournalprint_DEPENDENCIES) $(EXTRA_kjournalprint_DEPENDENCIES)
+ @rm -f kjournalprint$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(kjournalprint_OBJECTS) $(kjournalprint_LDADD) $(LIBS)
+utils/knotc/$(am__dirstamp):
+ @$(MKDIR_P) utils/knotc
+ @: > utils/knotc/$(am__dirstamp)
+utils/knotc/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) utils/knotc/$(DEPDIR)
+ @: > utils/knotc/$(DEPDIR)/$(am__dirstamp)
+utils/knotc/knotc-commands.$(OBJEXT): utils/knotc/$(am__dirstamp) \
+ utils/knotc/$(DEPDIR)/$(am__dirstamp)
+utils/knotc/knotc-estimator.$(OBJEXT): utils/knotc/$(am__dirstamp) \
+ utils/knotc/$(DEPDIR)/$(am__dirstamp)
+utils/knotc/knotc-interactive.$(OBJEXT): utils/knotc/$(am__dirstamp) \
+ utils/knotc/$(DEPDIR)/$(am__dirstamp)
+utils/knotc/knotc-process.$(OBJEXT): utils/knotc/$(am__dirstamp) \
+ utils/knotc/$(DEPDIR)/$(am__dirstamp)
+utils/knotc/knotc-main.$(OBJEXT): utils/knotc/$(am__dirstamp) \
+ utils/knotc/$(DEPDIR)/$(am__dirstamp)
+
+knotc$(EXEEXT): $(knotc_OBJECTS) $(knotc_DEPENDENCIES) $(EXTRA_knotc_DEPENDENCIES)
+ @rm -f knotc$(EXEEXT)
+ $(AM_V_CCLD)$(knotc_LINK) $(knotc_OBJECTS) $(knotc_LDADD) $(LIBS)
+utils/knotd/$(am__dirstamp):
+ @$(MKDIR_P) utils/knotd
+ @: > utils/knotd/$(am__dirstamp)
+utils/knotd/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) utils/knotd/$(DEPDIR)
+ @: > utils/knotd/$(DEPDIR)/$(am__dirstamp)
+utils/knotd/knotd-main.$(OBJEXT): utils/knotd/$(am__dirstamp) \
+ utils/knotd/$(DEPDIR)/$(am__dirstamp)
+
+knotd$(EXEEXT): $(knotd_OBJECTS) $(knotd_DEPENDENCIES) $(EXTRA_knotd_DEPENDENCIES)
+ @rm -f knotd$(EXEEXT)
+ $(AM_V_CCLD)$(knotd_LINK) $(knotd_OBJECTS) $(knotd_LDADD) $(LIBS)
+utils/knsec3hash/$(am__dirstamp):
+ @$(MKDIR_P) utils/knsec3hash
+ @: > utils/knsec3hash/$(am__dirstamp)
+utils/knsec3hash/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) utils/knsec3hash/$(DEPDIR)
+ @: > utils/knsec3hash/$(DEPDIR)/$(am__dirstamp)
+utils/knsec3hash/knsec3hash-knsec3hash.$(OBJEXT): \
+ utils/knsec3hash/$(am__dirstamp) \
+ utils/knsec3hash/$(DEPDIR)/$(am__dirstamp)
+
+knsec3hash$(EXEEXT): $(knsec3hash_OBJECTS) $(knsec3hash_DEPENDENCIES) $(EXTRA_knsec3hash_DEPENDENCIES)
+ @rm -f knsec3hash$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(knsec3hash_OBJECTS) $(knsec3hash_LDADD) $(LIBS)
+utils/knsupdate/$(am__dirstamp):
+ @$(MKDIR_P) utils/knsupdate
+ @: > utils/knsupdate/$(am__dirstamp)
+utils/knsupdate/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) utils/knsupdate/$(DEPDIR)
+ @: > utils/knsupdate/$(DEPDIR)/$(am__dirstamp)
+utils/knsupdate/knsupdate-knsupdate_exec.$(OBJEXT): \
+ utils/knsupdate/$(am__dirstamp) \
+ utils/knsupdate/$(DEPDIR)/$(am__dirstamp)
+utils/knsupdate/knsupdate-knsupdate_main.$(OBJEXT): \
+ utils/knsupdate/$(am__dirstamp) \
+ utils/knsupdate/$(DEPDIR)/$(am__dirstamp)
+utils/knsupdate/knsupdate-knsupdate_params.$(OBJEXT): \
+ utils/knsupdate/$(am__dirstamp) \
+ utils/knsupdate/$(DEPDIR)/$(am__dirstamp)
+
+knsupdate$(EXEEXT): $(knsupdate_OBJECTS) $(knsupdate_DEPENDENCIES) $(EXTRA_knsupdate_DEPENDENCIES)
+ @rm -f knsupdate$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(knsupdate_OBJECTS) $(knsupdate_LDADD) $(LIBS)
+utils/kzonecheck/$(am__dirstamp):
+ @$(MKDIR_P) utils/kzonecheck
+ @: > utils/kzonecheck/$(am__dirstamp)
+utils/kzonecheck/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) utils/kzonecheck/$(DEPDIR)
+ @: > utils/kzonecheck/$(DEPDIR)/$(am__dirstamp)
+utils/kzonecheck/kzonecheck-main.$(OBJEXT): \
+ utils/kzonecheck/$(am__dirstamp) \
+ utils/kzonecheck/$(DEPDIR)/$(am__dirstamp)
+utils/kzonecheck/kzonecheck-zone_check.$(OBJEXT): \
+ utils/kzonecheck/$(am__dirstamp) \
+ utils/kzonecheck/$(DEPDIR)/$(am__dirstamp)
+
+kzonecheck$(EXEEXT): $(kzonecheck_OBJECTS) $(kzonecheck_DEPENDENCIES) $(EXTRA_kzonecheck_DEPENDENCIES)
+ @rm -f kzonecheck$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(kzonecheck_OBJECTS) $(kzonecheck_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+ -rm -f contrib/*.$(OBJEXT)
+ -rm -f contrib/*.lo
+ -rm -f contrib/dnstap/*.$(OBJEXT)
+ -rm -f contrib/dnstap/*.lo
+ -rm -f contrib/lmdb/*.$(OBJEXT)
+ -rm -f contrib/lmdb/*.lo
+ -rm -f contrib/openbsd/*.$(OBJEXT)
+ -rm -f contrib/openbsd/*.lo
+ -rm -f contrib/qp-trie/*.$(OBJEXT)
+ -rm -f contrib/qp-trie/*.lo
+ -rm -f contrib/ucw/*.$(OBJEXT)
+ -rm -f contrib/ucw/*.lo
+ -rm -f knot/common/*.$(OBJEXT)
+ -rm -f knot/common/*.lo
+ -rm -f knot/conf/*.$(OBJEXT)
+ -rm -f knot/conf/*.lo
+ -rm -f knot/ctl/*.$(OBJEXT)
+ -rm -f knot/ctl/*.lo
+ -rm -f knot/dnssec/*.$(OBJEXT)
+ -rm -f knot/dnssec/*.lo
+ -rm -f knot/dnssec/kasp/*.$(OBJEXT)
+ -rm -f knot/dnssec/kasp/*.lo
+ -rm -f knot/events/*.$(OBJEXT)
+ -rm -f knot/events/*.lo
+ -rm -f knot/events/handlers/*.$(OBJEXT)
+ -rm -f knot/events/handlers/*.lo
+ -rm -f knot/journal/*.$(OBJEXT)
+ -rm -f knot/journal/*.lo
+ -rm -f knot/modules/cookies/*.$(OBJEXT)
+ -rm -f knot/modules/cookies/*.lo
+ -rm -f knot/modules/dnsproxy/*.$(OBJEXT)
+ -rm -f knot/modules/dnsproxy/*.lo
+ -rm -f knot/modules/dnstap/*.$(OBJEXT)
+ -rm -f knot/modules/dnstap/*.lo
+ -rm -f knot/modules/geoip/*.$(OBJEXT)
+ -rm -f knot/modules/geoip/*.lo
+ -rm -f knot/modules/noudp/*.$(OBJEXT)
+ -rm -f knot/modules/noudp/*.lo
+ -rm -f knot/modules/onlinesign/*.$(OBJEXT)
+ -rm -f knot/modules/onlinesign/*.lo
+ -rm -f knot/modules/queryacl/*.$(OBJEXT)
+ -rm -f knot/modules/queryacl/*.lo
+ -rm -f knot/modules/rrl/*.$(OBJEXT)
+ -rm -f knot/modules/rrl/*.lo
+ -rm -f knot/modules/stats/*.$(OBJEXT)
+ -rm -f knot/modules/stats/*.lo
+ -rm -f knot/modules/synthrecord/*.$(OBJEXT)
+ -rm -f knot/modules/synthrecord/*.lo
+ -rm -f knot/modules/whoami/*.$(OBJEXT)
+ -rm -f knot/modules/whoami/*.lo
+ -rm -f knot/nameserver/*.$(OBJEXT)
+ -rm -f knot/nameserver/*.lo
+ -rm -f knot/query/*.$(OBJEXT)
+ -rm -f knot/query/*.lo
+ -rm -f knot/server/*.$(OBJEXT)
+ -rm -f knot/server/*.lo
+ -rm -f knot/updates/*.$(OBJEXT)
+ -rm -f knot/updates/*.lo
+ -rm -f knot/worker/*.$(OBJEXT)
+ -rm -f knot/worker/*.lo
+ -rm -f knot/zone/*.$(OBJEXT)
+ -rm -f knot/zone/*.lo
+ -rm -f libdnssec/*.$(OBJEXT)
+ -rm -f libdnssec/*.lo
+ -rm -f libdnssec/contrib/*.$(OBJEXT)
+ -rm -f libdnssec/contrib/*.lo
+ -rm -f libdnssec/key/*.$(OBJEXT)
+ -rm -f libdnssec/key/*.lo
+ -rm -f libdnssec/keystore/*.$(OBJEXT)
+ -rm -f libdnssec/keystore/*.lo
+ -rm -f libdnssec/list/*.$(OBJEXT)
+ -rm -f libdnssec/list/*.lo
+ -rm -f libdnssec/nsec/*.$(OBJEXT)
+ -rm -f libdnssec/nsec/*.lo
+ -rm -f libdnssec/p11/*.$(OBJEXT)
+ -rm -f libdnssec/p11/*.lo
+ -rm -f libdnssec/shared/*.$(OBJEXT)
+ -rm -f libdnssec/shared/*.lo
+ -rm -f libdnssec/sign/*.$(OBJEXT)
+ -rm -f libdnssec/sign/*.lo
+ -rm -f libknot/*.$(OBJEXT)
+ -rm -f libknot/*.lo
+ -rm -f libknot/control/*.$(OBJEXT)
+ -rm -f libknot/control/*.lo
+ -rm -f libknot/db/*.$(OBJEXT)
+ -rm -f libknot/db/*.lo
+ -rm -f libknot/packet/*.$(OBJEXT)
+ -rm -f libknot/packet/*.lo
+ -rm -f libknot/rrtype/*.$(OBJEXT)
+ -rm -f libknot/rrtype/*.lo
+ -rm -f libknot/yparser/*.$(OBJEXT)
+ -rm -f libknot/yparser/*.lo
+ -rm -f libzscanner/*.$(OBJEXT)
+ -rm -f libzscanner/*.lo
+ -rm -f utils/common/*.$(OBJEXT)
+ -rm -f utils/common/*.lo
+ -rm -f utils/kdig/*.$(OBJEXT)
+ -rm -f utils/keymgr/*.$(OBJEXT)
+ -rm -f utils/khost/*.$(OBJEXT)
+ -rm -f utils/kjournalprint/*.$(OBJEXT)
+ -rm -f utils/knotc/*.$(OBJEXT)
+ -rm -f utils/knotd/*.$(OBJEXT)
+ -rm -f utils/knsec3hash/*.$(OBJEXT)
+ -rm -f utils/knsupdate/*.$(OBJEXT)
+ -rm -f utils/kzonecheck/*.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@contrib/$(DEPDIR)/libcontrib_la-base32hex.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@contrib/$(DEPDIR)/libcontrib_la-base64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@contrib/$(DEPDIR)/libcontrib_la-files.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@contrib/$(DEPDIR)/libcontrib_la-getline.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@contrib/$(DEPDIR)/libcontrib_la-mempattern.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@contrib/$(DEPDIR)/libcontrib_la-net.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@contrib/$(DEPDIR)/libcontrib_la-sockaddr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@contrib/$(DEPDIR)/libcontrib_la-string.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@contrib/$(DEPDIR)/libcontrib_la-time.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@contrib/dnstap/$(DEPDIR)/libdnstap_la-convert.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@contrib/dnstap/$(DEPDIR)/libdnstap_la-dnstap.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@contrib/dnstap/$(DEPDIR)/libdnstap_la-dnstap.pb-c.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@contrib/dnstap/$(DEPDIR)/libdnstap_la-message.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@contrib/dnstap/$(DEPDIR)/libdnstap_la-reader.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@contrib/dnstap/$(DEPDIR)/libdnstap_la-writer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@contrib/lmdb/$(DEPDIR)/libcontrib_la-mdb.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@contrib/lmdb/$(DEPDIR)/libcontrib_la-midl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@contrib/openbsd/$(DEPDIR)/libcontrib_la-siphash.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@contrib/openbsd/$(DEPDIR)/libcontrib_la-strlcat.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@contrib/openbsd/$(DEPDIR)/libcontrib_la-strlcpy.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@contrib/qp-trie/$(DEPDIR)/libcontrib_la-trie.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@contrib/ucw/$(DEPDIR)/libcontrib_la-heap.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@contrib/ucw/$(DEPDIR)/libcontrib_la-lists.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@contrib/ucw/$(DEPDIR)/libcontrib_la-mempool.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/common/$(DEPDIR)/libknotd_la-evsched.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/common/$(DEPDIR)/libknotd_la-fdset.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/common/$(DEPDIR)/libknotd_la-log.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/common/$(DEPDIR)/libknotd_la-process.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/common/$(DEPDIR)/libknotd_la-ref.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/common/$(DEPDIR)/libknotd_la-stats.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/conf/$(DEPDIR)/libknotd_la-base.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/conf/$(DEPDIR)/libknotd_la-conf.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/conf/$(DEPDIR)/libknotd_la-confdb.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/conf/$(DEPDIR)/libknotd_la-confio.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/conf/$(DEPDIR)/libknotd_la-migration.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/conf/$(DEPDIR)/libknotd_la-module.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/conf/$(DEPDIR)/libknotd_la-schema.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/conf/$(DEPDIR)/libknotd_la-tools.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/ctl/$(DEPDIR)/libknotd_la-commands.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/ctl/$(DEPDIR)/libknotd_la-process.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/dnssec/$(DEPDIR)/libknotd_la-context.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/dnssec/$(DEPDIR)/libknotd_la-ds_query.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/dnssec/$(DEPDIR)/libknotd_la-key-events.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/dnssec/$(DEPDIR)/libknotd_la-nsec-chain.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/dnssec/$(DEPDIR)/libknotd_la-nsec3-chain.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/dnssec/$(DEPDIR)/libknotd_la-policy.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/dnssec/$(DEPDIR)/libknotd_la-rrset-sign.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/dnssec/$(DEPDIR)/libknotd_la-zone-events.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/dnssec/$(DEPDIR)/libknotd_la-zone-keys.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/dnssec/$(DEPDIR)/libknotd_la-zone-nsec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/dnssec/$(DEPDIR)/libknotd_la-zone-sign.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/dnssec/kasp/$(DEPDIR)/libknotd_la-kasp_db.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/dnssec/kasp/$(DEPDIR)/libknotd_la-kasp_zone.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/dnssec/kasp/$(DEPDIR)/libknotd_la-keystate.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/dnssec/kasp/$(DEPDIR)/libknotd_la-keystore.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/events/$(DEPDIR)/libknotd_la-events.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/events/$(DEPDIR)/libknotd_la-replan.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/events/handlers/$(DEPDIR)/libknotd_la-dnssec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/events/handlers/$(DEPDIR)/libknotd_la-expire.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/events/handlers/$(DEPDIR)/libknotd_la-flush.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/events/handlers/$(DEPDIR)/libknotd_la-freeze_thaw.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/events/handlers/$(DEPDIR)/libknotd_la-load.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/events/handlers/$(DEPDIR)/libknotd_la-notify.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/events/handlers/$(DEPDIR)/libknotd_la-nsec3resalt.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/events/handlers/$(DEPDIR)/libknotd_la-parent_ds_query.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/events/handlers/$(DEPDIR)/libknotd_la-refresh.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/events/handlers/$(DEPDIR)/libknotd_la-update.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/journal/$(DEPDIR)/libknotd_la-chgset_ctx.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/journal/$(DEPDIR)/libknotd_la-journal.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/journal/$(DEPDIR)/libknotd_la-serialization.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/cookies/$(DEPDIR)/knot_modules_cookies_la-cookies.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/cookies/$(DEPDIR)/libknotd_la-cookies.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/dnsproxy/$(DEPDIR)/knot_modules_dnsproxy_la-dnsproxy.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/dnsproxy/$(DEPDIR)/libknotd_la-dnsproxy.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/dnstap/$(DEPDIR)/knot_modules_dnstap_la-dnstap.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/dnstap/$(DEPDIR)/libknotd_la-dnstap.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/geoip/$(DEPDIR)/knot_modules_geoip_la-geodb.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/geoip/$(DEPDIR)/knot_modules_geoip_la-geoip.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/geoip/$(DEPDIR)/libknotd_la-geodb.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/geoip/$(DEPDIR)/libknotd_la-geoip.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/noudp/$(DEPDIR)/knot_modules_noudp_la-noudp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/noudp/$(DEPDIR)/libknotd_la-noudp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/onlinesign/$(DEPDIR)/knot_modules_onlinesign_la-nsec_next.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/onlinesign/$(DEPDIR)/knot_modules_onlinesign_la-onlinesign.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/onlinesign/$(DEPDIR)/libknotd_la-nsec_next.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/onlinesign/$(DEPDIR)/libknotd_la-onlinesign.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/queryacl/$(DEPDIR)/knot_modules_queryacl_la-queryacl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/queryacl/$(DEPDIR)/libknotd_la-queryacl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/rrl/$(DEPDIR)/knot_modules_rrl_la-functions.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/rrl/$(DEPDIR)/knot_modules_rrl_la-rrl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/rrl/$(DEPDIR)/libknotd_la-functions.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/rrl/$(DEPDIR)/libknotd_la-rrl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/stats/$(DEPDIR)/knot_modules_stats_la-stats.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/stats/$(DEPDIR)/libknotd_la-stats.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/synthrecord/$(DEPDIR)/knot_modules_synthrecord_la-synthrecord.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/synthrecord/$(DEPDIR)/libknotd_la-synthrecord.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/whoami/$(DEPDIR)/knot_modules_whoami_la-whoami.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/whoami/$(DEPDIR)/libknotd_la-whoami.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/nameserver/$(DEPDIR)/libknotd_la-axfr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/nameserver/$(DEPDIR)/libknotd_la-chaos.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/nameserver/$(DEPDIR)/libknotd_la-internet.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/nameserver/$(DEPDIR)/libknotd_la-ixfr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/nameserver/$(DEPDIR)/libknotd_la-notify.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/nameserver/$(DEPDIR)/libknotd_la-nsec_proofs.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/nameserver/$(DEPDIR)/libknotd_la-process_query.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/nameserver/$(DEPDIR)/libknotd_la-query_module.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/nameserver/$(DEPDIR)/libknotd_la-tsig_ctx.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/nameserver/$(DEPDIR)/libknotd_la-update.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/nameserver/$(DEPDIR)/libknotd_la-xfr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/query/$(DEPDIR)/libknotd_la-capture.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/query/$(DEPDIR)/libknotd_la-query.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/query/$(DEPDIR)/libknotd_la-requestor.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/server/$(DEPDIR)/libknotd_la-dthreads.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/server/$(DEPDIR)/libknotd_la-server.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/server/$(DEPDIR)/libknotd_la-tcp-handler.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/server/$(DEPDIR)/libknotd_la-udp-handler.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/updates/$(DEPDIR)/libknotd_la-acl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/updates/$(DEPDIR)/libknotd_la-apply.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/updates/$(DEPDIR)/libknotd_la-changesets.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/updates/$(DEPDIR)/libknotd_la-ddns.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/updates/$(DEPDIR)/libknotd_la-zone-update.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/worker/$(DEPDIR)/libknotd_la-pool.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/worker/$(DEPDIR)/libknotd_la-queue.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/zone/$(DEPDIR)/libknotd_la-contents.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/zone/$(DEPDIR)/libknotd_la-node.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/zone/$(DEPDIR)/libknotd_la-semantic-check.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/zone/$(DEPDIR)/libknotd_la-serial.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/zone/$(DEPDIR)/libknotd_la-timers.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/zone/$(DEPDIR)/libknotd_la-zone-diff.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/zone/$(DEPDIR)/libknotd_la-zone-dump.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/zone/$(DEPDIR)/libknotd_la-zone-load.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/zone/$(DEPDIR)/libknotd_la-zone-tree.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/zone/$(DEPDIR)/libknotd_la-zone.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/zone/$(DEPDIR)/libknotd_la-zonedb-load.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/zone/$(DEPDIR)/libknotd_la-zonedb.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@knot/zone/$(DEPDIR)/libknotd_la-zonefile.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/$(DEPDIR)/libdnssec_la-binary.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/$(DEPDIR)/libdnssec_la-crypto.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/$(DEPDIR)/libdnssec_la-error.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/$(DEPDIR)/libdnssec_la-keyid.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/$(DEPDIR)/libdnssec_la-random.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/$(DEPDIR)/libdnssec_la-tsig.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/contrib/$(DEPDIR)/libdnssec_la-vpool.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/key/$(DEPDIR)/libdnssec_la-algorithm.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/key/$(DEPDIR)/libdnssec_la-convert.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/key/$(DEPDIR)/libdnssec_la-dnskey.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/key/$(DEPDIR)/libdnssec_la-ds.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/key/$(DEPDIR)/libdnssec_la-key.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/key/$(DEPDIR)/libdnssec_la-keytag.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/key/$(DEPDIR)/libdnssec_la-privkey.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/key/$(DEPDIR)/libdnssec_la-simple.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/keystore/$(DEPDIR)/libdnssec_la-keystore.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/keystore/$(DEPDIR)/libdnssec_la-pkcs11.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/keystore/$(DEPDIR)/libdnssec_la-pkcs8.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/keystore/$(DEPDIR)/libdnssec_la-pkcs8_dir.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/list/$(DEPDIR)/libdnssec_la-list.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/nsec/$(DEPDIR)/libdnssec_la-bitmap.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/nsec/$(DEPDIR)/libdnssec_la-hash.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/nsec/$(DEPDIR)/libdnssec_la-nsec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/p11/$(DEPDIR)/libdnssec_la-p11.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/shared/$(DEPDIR)/libshared_la-bignum.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/shared/$(DEPDIR)/libshared_la-dname.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/shared/$(DEPDIR)/libshared_la-fs.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/shared/$(DEPDIR)/libshared_la-hex.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/shared/$(DEPDIR)/libshared_la-keyid_gnutls.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/shared/$(DEPDIR)/libshared_la-pem.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/sign/$(DEPDIR)/libdnssec_la-der.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libdnssec/sign/$(DEPDIR)/libdnssec_la-sign.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libknot/$(DEPDIR)/libknot_la-codes.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libknot/$(DEPDIR)/libknot_la-cookies.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libknot/$(DEPDIR)/libknot_la-descriptor.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libknot/$(DEPDIR)/libknot_la-dname.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libknot/$(DEPDIR)/libknot_la-error.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libknot/$(DEPDIR)/libknot_la-rdataset.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libknot/$(DEPDIR)/libknot_la-rrset-dump.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libknot/$(DEPDIR)/libknot_la-rrset.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libknot/$(DEPDIR)/libknot_la-tsig-op.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libknot/$(DEPDIR)/libknot_la-tsig.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libknot/control/$(DEPDIR)/libknot_la-control.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libknot/db/$(DEPDIR)/libknot_la-db_lmdb.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libknot/db/$(DEPDIR)/libknot_la-db_trie.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libknot/packet/$(DEPDIR)/libknot_la-pkt.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libknot/packet/$(DEPDIR)/libknot_la-rrset-wire.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libknot/rrtype/$(DEPDIR)/libknot_la-naptr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libknot/rrtype/$(DEPDIR)/libknot_la-opt.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libknot/rrtype/$(DEPDIR)/libknot_la-tsig.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libknot/yparser/$(DEPDIR)/libknot_la-yparser.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libknot/yparser/$(DEPDIR)/libknot_la-ypbody.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libknot/yparser/$(DEPDIR)/libknot_la-ypformat.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libknot/yparser/$(DEPDIR)/libknot_la-ypschema.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libknot/yparser/$(DEPDIR)/libknot_la-yptrafo.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libzscanner/$(DEPDIR)/libzscanner_la-error.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libzscanner/$(DEPDIR)/libzscanner_la-functions.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@libzscanner/$(DEPDIR)/libzscanner_la-scanner.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/common/$(DEPDIR)/libknotus_la-cert.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/common/$(DEPDIR)/libknotus_la-exec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/common/$(DEPDIR)/libknotus_la-hex.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/common/$(DEPDIR)/libknotus_la-lookup.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/common/$(DEPDIR)/libknotus_la-msg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/common/$(DEPDIR)/libknotus_la-netio.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/common/$(DEPDIR)/libknotus_la-params.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/common/$(DEPDIR)/libknotus_la-resolv.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/common/$(DEPDIR)/libknotus_la-sign.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/common/$(DEPDIR)/libknotus_la-tls.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/common/$(DEPDIR)/libknotus_la-token.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/kdig/$(DEPDIR)/kdig-kdig_exec.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/kdig/$(DEPDIR)/kdig-kdig_main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/kdig/$(DEPDIR)/kdig-kdig_params.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/kdig/$(DEPDIR)/khost-kdig_exec.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/kdig/$(DEPDIR)/khost-kdig_params.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/keymgr/$(DEPDIR)/keymgr-bind_privkey.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/keymgr/$(DEPDIR)/keymgr-functions.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/keymgr/$(DEPDIR)/keymgr-main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/khost/$(DEPDIR)/khost-khost_main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/khost/$(DEPDIR)/khost-khost_params.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/kjournalprint/$(DEPDIR)/kjournalprint-main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/knotc/$(DEPDIR)/knotc-commands.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/knotc/$(DEPDIR)/knotc-estimator.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/knotc/$(DEPDIR)/knotc-interactive.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/knotc/$(DEPDIR)/knotc-main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/knotc/$(DEPDIR)/knotc-process.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/knotd/$(DEPDIR)/knotd-main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/knsec3hash/$(DEPDIR)/knsec3hash-knsec3hash.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/knsupdate/$(DEPDIR)/knsupdate-knsupdate_exec.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/knsupdate/$(DEPDIR)/knsupdate-knsupdate_main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/knsupdate/$(DEPDIR)/knsupdate-knsupdate_params.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/kzonecheck/$(DEPDIR)/kzonecheck-main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@utils/kzonecheck/$(DEPDIR)/kzonecheck-zone_check.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+knot/modules/cookies/knot_modules_cookies_la-cookies.lo: knot/modules/cookies/cookies.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_cookies_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/cookies/knot_modules_cookies_la-cookies.lo -MD -MP -MF knot/modules/cookies/$(DEPDIR)/knot_modules_cookies_la-cookies.Tpo -c -o knot/modules/cookies/knot_modules_cookies_la-cookies.lo `test -f 'knot/modules/cookies/cookies.c' || echo '$(srcdir)/'`knot/modules/cookies/cookies.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/cookies/$(DEPDIR)/knot_modules_cookies_la-cookies.Tpo knot/modules/cookies/$(DEPDIR)/knot_modules_cookies_la-cookies.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/cookies/cookies.c' object='knot/modules/cookies/knot_modules_cookies_la-cookies.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_cookies_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/cookies/knot_modules_cookies_la-cookies.lo `test -f 'knot/modules/cookies/cookies.c' || echo '$(srcdir)/'`knot/modules/cookies/cookies.c
+
+knot/modules/dnsproxy/knot_modules_dnsproxy_la-dnsproxy.lo: knot/modules/dnsproxy/dnsproxy.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_dnsproxy_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/dnsproxy/knot_modules_dnsproxy_la-dnsproxy.lo -MD -MP -MF knot/modules/dnsproxy/$(DEPDIR)/knot_modules_dnsproxy_la-dnsproxy.Tpo -c -o knot/modules/dnsproxy/knot_modules_dnsproxy_la-dnsproxy.lo `test -f 'knot/modules/dnsproxy/dnsproxy.c' || echo '$(srcdir)/'`knot/modules/dnsproxy/dnsproxy.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/dnsproxy/$(DEPDIR)/knot_modules_dnsproxy_la-dnsproxy.Tpo knot/modules/dnsproxy/$(DEPDIR)/knot_modules_dnsproxy_la-dnsproxy.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/dnsproxy/dnsproxy.c' object='knot/modules/dnsproxy/knot_modules_dnsproxy_la-dnsproxy.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_dnsproxy_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/dnsproxy/knot_modules_dnsproxy_la-dnsproxy.lo `test -f 'knot/modules/dnsproxy/dnsproxy.c' || echo '$(srcdir)/'`knot/modules/dnsproxy/dnsproxy.c
+
+knot/modules/dnstap/knot_modules_dnstap_la-dnstap.lo: knot/modules/dnstap/dnstap.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_dnstap_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/dnstap/knot_modules_dnstap_la-dnstap.lo -MD -MP -MF knot/modules/dnstap/$(DEPDIR)/knot_modules_dnstap_la-dnstap.Tpo -c -o knot/modules/dnstap/knot_modules_dnstap_la-dnstap.lo `test -f 'knot/modules/dnstap/dnstap.c' || echo '$(srcdir)/'`knot/modules/dnstap/dnstap.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/dnstap/$(DEPDIR)/knot_modules_dnstap_la-dnstap.Tpo knot/modules/dnstap/$(DEPDIR)/knot_modules_dnstap_la-dnstap.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/dnstap/dnstap.c' object='knot/modules/dnstap/knot_modules_dnstap_la-dnstap.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_dnstap_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/dnstap/knot_modules_dnstap_la-dnstap.lo `test -f 'knot/modules/dnstap/dnstap.c' || echo '$(srcdir)/'`knot/modules/dnstap/dnstap.c
+
+knot/modules/geoip/knot_modules_geoip_la-geoip.lo: knot/modules/geoip/geoip.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_geoip_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/geoip/knot_modules_geoip_la-geoip.lo -MD -MP -MF knot/modules/geoip/$(DEPDIR)/knot_modules_geoip_la-geoip.Tpo -c -o knot/modules/geoip/knot_modules_geoip_la-geoip.lo `test -f 'knot/modules/geoip/geoip.c' || echo '$(srcdir)/'`knot/modules/geoip/geoip.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/geoip/$(DEPDIR)/knot_modules_geoip_la-geoip.Tpo knot/modules/geoip/$(DEPDIR)/knot_modules_geoip_la-geoip.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/geoip/geoip.c' object='knot/modules/geoip/knot_modules_geoip_la-geoip.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_geoip_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/geoip/knot_modules_geoip_la-geoip.lo `test -f 'knot/modules/geoip/geoip.c' || echo '$(srcdir)/'`knot/modules/geoip/geoip.c
+
+knot/modules/geoip/knot_modules_geoip_la-geodb.lo: knot/modules/geoip/geodb.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_geoip_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/geoip/knot_modules_geoip_la-geodb.lo -MD -MP -MF knot/modules/geoip/$(DEPDIR)/knot_modules_geoip_la-geodb.Tpo -c -o knot/modules/geoip/knot_modules_geoip_la-geodb.lo `test -f 'knot/modules/geoip/geodb.c' || echo '$(srcdir)/'`knot/modules/geoip/geodb.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/geoip/$(DEPDIR)/knot_modules_geoip_la-geodb.Tpo knot/modules/geoip/$(DEPDIR)/knot_modules_geoip_la-geodb.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/geoip/geodb.c' object='knot/modules/geoip/knot_modules_geoip_la-geodb.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_geoip_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/geoip/knot_modules_geoip_la-geodb.lo `test -f 'knot/modules/geoip/geodb.c' || echo '$(srcdir)/'`knot/modules/geoip/geodb.c
+
+knot/modules/noudp/knot_modules_noudp_la-noudp.lo: knot/modules/noudp/noudp.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_noudp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/noudp/knot_modules_noudp_la-noudp.lo -MD -MP -MF knot/modules/noudp/$(DEPDIR)/knot_modules_noudp_la-noudp.Tpo -c -o knot/modules/noudp/knot_modules_noudp_la-noudp.lo `test -f 'knot/modules/noudp/noudp.c' || echo '$(srcdir)/'`knot/modules/noudp/noudp.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/noudp/$(DEPDIR)/knot_modules_noudp_la-noudp.Tpo knot/modules/noudp/$(DEPDIR)/knot_modules_noudp_la-noudp.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/noudp/noudp.c' object='knot/modules/noudp/knot_modules_noudp_la-noudp.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_noudp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/noudp/knot_modules_noudp_la-noudp.lo `test -f 'knot/modules/noudp/noudp.c' || echo '$(srcdir)/'`knot/modules/noudp/noudp.c
+
+knot/modules/onlinesign/knot_modules_onlinesign_la-onlinesign.lo: knot/modules/onlinesign/onlinesign.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_onlinesign_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/onlinesign/knot_modules_onlinesign_la-onlinesign.lo -MD -MP -MF knot/modules/onlinesign/$(DEPDIR)/knot_modules_onlinesign_la-onlinesign.Tpo -c -o knot/modules/onlinesign/knot_modules_onlinesign_la-onlinesign.lo `test -f 'knot/modules/onlinesign/onlinesign.c' || echo '$(srcdir)/'`knot/modules/onlinesign/onlinesign.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/onlinesign/$(DEPDIR)/knot_modules_onlinesign_la-onlinesign.Tpo knot/modules/onlinesign/$(DEPDIR)/knot_modules_onlinesign_la-onlinesign.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/onlinesign/onlinesign.c' object='knot/modules/onlinesign/knot_modules_onlinesign_la-onlinesign.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_onlinesign_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/onlinesign/knot_modules_onlinesign_la-onlinesign.lo `test -f 'knot/modules/onlinesign/onlinesign.c' || echo '$(srcdir)/'`knot/modules/onlinesign/onlinesign.c
+
+knot/modules/onlinesign/knot_modules_onlinesign_la-nsec_next.lo: knot/modules/onlinesign/nsec_next.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_onlinesign_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/onlinesign/knot_modules_onlinesign_la-nsec_next.lo -MD -MP -MF knot/modules/onlinesign/$(DEPDIR)/knot_modules_onlinesign_la-nsec_next.Tpo -c -o knot/modules/onlinesign/knot_modules_onlinesign_la-nsec_next.lo `test -f 'knot/modules/onlinesign/nsec_next.c' || echo '$(srcdir)/'`knot/modules/onlinesign/nsec_next.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/onlinesign/$(DEPDIR)/knot_modules_onlinesign_la-nsec_next.Tpo knot/modules/onlinesign/$(DEPDIR)/knot_modules_onlinesign_la-nsec_next.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/onlinesign/nsec_next.c' object='knot/modules/onlinesign/knot_modules_onlinesign_la-nsec_next.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_onlinesign_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/onlinesign/knot_modules_onlinesign_la-nsec_next.lo `test -f 'knot/modules/onlinesign/nsec_next.c' || echo '$(srcdir)/'`knot/modules/onlinesign/nsec_next.c
+
+knot/modules/queryacl/knot_modules_queryacl_la-queryacl.lo: knot/modules/queryacl/queryacl.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_queryacl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/queryacl/knot_modules_queryacl_la-queryacl.lo -MD -MP -MF knot/modules/queryacl/$(DEPDIR)/knot_modules_queryacl_la-queryacl.Tpo -c -o knot/modules/queryacl/knot_modules_queryacl_la-queryacl.lo `test -f 'knot/modules/queryacl/queryacl.c' || echo '$(srcdir)/'`knot/modules/queryacl/queryacl.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/queryacl/$(DEPDIR)/knot_modules_queryacl_la-queryacl.Tpo knot/modules/queryacl/$(DEPDIR)/knot_modules_queryacl_la-queryacl.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/queryacl/queryacl.c' object='knot/modules/queryacl/knot_modules_queryacl_la-queryacl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_queryacl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/queryacl/knot_modules_queryacl_la-queryacl.lo `test -f 'knot/modules/queryacl/queryacl.c' || echo '$(srcdir)/'`knot/modules/queryacl/queryacl.c
+
+knot/modules/rrl/knot_modules_rrl_la-rrl.lo: knot/modules/rrl/rrl.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_rrl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/rrl/knot_modules_rrl_la-rrl.lo -MD -MP -MF knot/modules/rrl/$(DEPDIR)/knot_modules_rrl_la-rrl.Tpo -c -o knot/modules/rrl/knot_modules_rrl_la-rrl.lo `test -f 'knot/modules/rrl/rrl.c' || echo '$(srcdir)/'`knot/modules/rrl/rrl.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/rrl/$(DEPDIR)/knot_modules_rrl_la-rrl.Tpo knot/modules/rrl/$(DEPDIR)/knot_modules_rrl_la-rrl.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/rrl/rrl.c' object='knot/modules/rrl/knot_modules_rrl_la-rrl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_rrl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/rrl/knot_modules_rrl_la-rrl.lo `test -f 'knot/modules/rrl/rrl.c' || echo '$(srcdir)/'`knot/modules/rrl/rrl.c
+
+knot/modules/rrl/knot_modules_rrl_la-functions.lo: knot/modules/rrl/functions.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_rrl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/rrl/knot_modules_rrl_la-functions.lo -MD -MP -MF knot/modules/rrl/$(DEPDIR)/knot_modules_rrl_la-functions.Tpo -c -o knot/modules/rrl/knot_modules_rrl_la-functions.lo `test -f 'knot/modules/rrl/functions.c' || echo '$(srcdir)/'`knot/modules/rrl/functions.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/rrl/$(DEPDIR)/knot_modules_rrl_la-functions.Tpo knot/modules/rrl/$(DEPDIR)/knot_modules_rrl_la-functions.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/rrl/functions.c' object='knot/modules/rrl/knot_modules_rrl_la-functions.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_rrl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/rrl/knot_modules_rrl_la-functions.lo `test -f 'knot/modules/rrl/functions.c' || echo '$(srcdir)/'`knot/modules/rrl/functions.c
+
+knot/modules/stats/knot_modules_stats_la-stats.lo: knot/modules/stats/stats.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_stats_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/stats/knot_modules_stats_la-stats.lo -MD -MP -MF knot/modules/stats/$(DEPDIR)/knot_modules_stats_la-stats.Tpo -c -o knot/modules/stats/knot_modules_stats_la-stats.lo `test -f 'knot/modules/stats/stats.c' || echo '$(srcdir)/'`knot/modules/stats/stats.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/stats/$(DEPDIR)/knot_modules_stats_la-stats.Tpo knot/modules/stats/$(DEPDIR)/knot_modules_stats_la-stats.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/stats/stats.c' object='knot/modules/stats/knot_modules_stats_la-stats.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_stats_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/stats/knot_modules_stats_la-stats.lo `test -f 'knot/modules/stats/stats.c' || echo '$(srcdir)/'`knot/modules/stats/stats.c
+
+knot/modules/synthrecord/knot_modules_synthrecord_la-synthrecord.lo: knot/modules/synthrecord/synthrecord.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_synthrecord_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/synthrecord/knot_modules_synthrecord_la-synthrecord.lo -MD -MP -MF knot/modules/synthrecord/$(DEPDIR)/knot_modules_synthrecord_la-synthrecord.Tpo -c -o knot/modules/synthrecord/knot_modules_synthrecord_la-synthrecord.lo `test -f 'knot/modules/synthrecord/synthrecord.c' || echo '$(srcdir)/'`knot/modules/synthrecord/synthrecord.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/synthrecord/$(DEPDIR)/knot_modules_synthrecord_la-synthrecord.Tpo knot/modules/synthrecord/$(DEPDIR)/knot_modules_synthrecord_la-synthrecord.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/synthrecord/synthrecord.c' object='knot/modules/synthrecord/knot_modules_synthrecord_la-synthrecord.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_synthrecord_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/synthrecord/knot_modules_synthrecord_la-synthrecord.lo `test -f 'knot/modules/synthrecord/synthrecord.c' || echo '$(srcdir)/'`knot/modules/synthrecord/synthrecord.c
+
+knot/modules/whoami/knot_modules_whoami_la-whoami.lo: knot/modules/whoami/whoami.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_whoami_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/whoami/knot_modules_whoami_la-whoami.lo -MD -MP -MF knot/modules/whoami/$(DEPDIR)/knot_modules_whoami_la-whoami.Tpo -c -o knot/modules/whoami/knot_modules_whoami_la-whoami.lo `test -f 'knot/modules/whoami/whoami.c' || echo '$(srcdir)/'`knot/modules/whoami/whoami.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/whoami/$(DEPDIR)/knot_modules_whoami_la-whoami.Tpo knot/modules/whoami/$(DEPDIR)/knot_modules_whoami_la-whoami.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/whoami/whoami.c' object='knot/modules/whoami/knot_modules_whoami_la-whoami.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_whoami_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/whoami/knot_modules_whoami_la-whoami.lo `test -f 'knot/modules/whoami/whoami.c' || echo '$(srcdir)/'`knot/modules/whoami/whoami.c
+
+contrib/libcontrib_la-base32hex.lo: contrib/base32hex.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT contrib/libcontrib_la-base32hex.lo -MD -MP -MF contrib/$(DEPDIR)/libcontrib_la-base32hex.Tpo -c -o contrib/libcontrib_la-base32hex.lo `test -f 'contrib/base32hex.c' || echo '$(srcdir)/'`contrib/base32hex.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) contrib/$(DEPDIR)/libcontrib_la-base32hex.Tpo contrib/$(DEPDIR)/libcontrib_la-base32hex.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='contrib/base32hex.c' object='contrib/libcontrib_la-base32hex.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o contrib/libcontrib_la-base32hex.lo `test -f 'contrib/base32hex.c' || echo '$(srcdir)/'`contrib/base32hex.c
+
+contrib/libcontrib_la-base64.lo: contrib/base64.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT contrib/libcontrib_la-base64.lo -MD -MP -MF contrib/$(DEPDIR)/libcontrib_la-base64.Tpo -c -o contrib/libcontrib_la-base64.lo `test -f 'contrib/base64.c' || echo '$(srcdir)/'`contrib/base64.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) contrib/$(DEPDIR)/libcontrib_la-base64.Tpo contrib/$(DEPDIR)/libcontrib_la-base64.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='contrib/base64.c' object='contrib/libcontrib_la-base64.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o contrib/libcontrib_la-base64.lo `test -f 'contrib/base64.c' || echo '$(srcdir)/'`contrib/base64.c
+
+contrib/libcontrib_la-files.lo: contrib/files.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT contrib/libcontrib_la-files.lo -MD -MP -MF contrib/$(DEPDIR)/libcontrib_la-files.Tpo -c -o contrib/libcontrib_la-files.lo `test -f 'contrib/files.c' || echo '$(srcdir)/'`contrib/files.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) contrib/$(DEPDIR)/libcontrib_la-files.Tpo contrib/$(DEPDIR)/libcontrib_la-files.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='contrib/files.c' object='contrib/libcontrib_la-files.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o contrib/libcontrib_la-files.lo `test -f 'contrib/files.c' || echo '$(srcdir)/'`contrib/files.c
+
+contrib/libcontrib_la-getline.lo: contrib/getline.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT contrib/libcontrib_la-getline.lo -MD -MP -MF contrib/$(DEPDIR)/libcontrib_la-getline.Tpo -c -o contrib/libcontrib_la-getline.lo `test -f 'contrib/getline.c' || echo '$(srcdir)/'`contrib/getline.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) contrib/$(DEPDIR)/libcontrib_la-getline.Tpo contrib/$(DEPDIR)/libcontrib_la-getline.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='contrib/getline.c' object='contrib/libcontrib_la-getline.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o contrib/libcontrib_la-getline.lo `test -f 'contrib/getline.c' || echo '$(srcdir)/'`contrib/getline.c
+
+contrib/libcontrib_la-mempattern.lo: contrib/mempattern.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT contrib/libcontrib_la-mempattern.lo -MD -MP -MF contrib/$(DEPDIR)/libcontrib_la-mempattern.Tpo -c -o contrib/libcontrib_la-mempattern.lo `test -f 'contrib/mempattern.c' || echo '$(srcdir)/'`contrib/mempattern.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) contrib/$(DEPDIR)/libcontrib_la-mempattern.Tpo contrib/$(DEPDIR)/libcontrib_la-mempattern.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='contrib/mempattern.c' object='contrib/libcontrib_la-mempattern.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o contrib/libcontrib_la-mempattern.lo `test -f 'contrib/mempattern.c' || echo '$(srcdir)/'`contrib/mempattern.c
+
+contrib/libcontrib_la-net.lo: contrib/net.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT contrib/libcontrib_la-net.lo -MD -MP -MF contrib/$(DEPDIR)/libcontrib_la-net.Tpo -c -o contrib/libcontrib_la-net.lo `test -f 'contrib/net.c' || echo '$(srcdir)/'`contrib/net.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) contrib/$(DEPDIR)/libcontrib_la-net.Tpo contrib/$(DEPDIR)/libcontrib_la-net.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='contrib/net.c' object='contrib/libcontrib_la-net.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o contrib/libcontrib_la-net.lo `test -f 'contrib/net.c' || echo '$(srcdir)/'`contrib/net.c
+
+contrib/qp-trie/libcontrib_la-trie.lo: contrib/qp-trie/trie.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT contrib/qp-trie/libcontrib_la-trie.lo -MD -MP -MF contrib/qp-trie/$(DEPDIR)/libcontrib_la-trie.Tpo -c -o contrib/qp-trie/libcontrib_la-trie.lo `test -f 'contrib/qp-trie/trie.c' || echo '$(srcdir)/'`contrib/qp-trie/trie.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) contrib/qp-trie/$(DEPDIR)/libcontrib_la-trie.Tpo contrib/qp-trie/$(DEPDIR)/libcontrib_la-trie.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='contrib/qp-trie/trie.c' object='contrib/qp-trie/libcontrib_la-trie.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o contrib/qp-trie/libcontrib_la-trie.lo `test -f 'contrib/qp-trie/trie.c' || echo '$(srcdir)/'`contrib/qp-trie/trie.c
+
+contrib/libcontrib_la-sockaddr.lo: contrib/sockaddr.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT contrib/libcontrib_la-sockaddr.lo -MD -MP -MF contrib/$(DEPDIR)/libcontrib_la-sockaddr.Tpo -c -o contrib/libcontrib_la-sockaddr.lo `test -f 'contrib/sockaddr.c' || echo '$(srcdir)/'`contrib/sockaddr.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) contrib/$(DEPDIR)/libcontrib_la-sockaddr.Tpo contrib/$(DEPDIR)/libcontrib_la-sockaddr.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='contrib/sockaddr.c' object='contrib/libcontrib_la-sockaddr.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o contrib/libcontrib_la-sockaddr.lo `test -f 'contrib/sockaddr.c' || echo '$(srcdir)/'`contrib/sockaddr.c
+
+contrib/libcontrib_la-string.lo: contrib/string.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT contrib/libcontrib_la-string.lo -MD -MP -MF contrib/$(DEPDIR)/libcontrib_la-string.Tpo -c -o contrib/libcontrib_la-string.lo `test -f 'contrib/string.c' || echo '$(srcdir)/'`contrib/string.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) contrib/$(DEPDIR)/libcontrib_la-string.Tpo contrib/$(DEPDIR)/libcontrib_la-string.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='contrib/string.c' object='contrib/libcontrib_la-string.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o contrib/libcontrib_la-string.lo `test -f 'contrib/string.c' || echo '$(srcdir)/'`contrib/string.c
+
+contrib/libcontrib_la-time.lo: contrib/time.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT contrib/libcontrib_la-time.lo -MD -MP -MF contrib/$(DEPDIR)/libcontrib_la-time.Tpo -c -o contrib/libcontrib_la-time.lo `test -f 'contrib/time.c' || echo '$(srcdir)/'`contrib/time.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) contrib/$(DEPDIR)/libcontrib_la-time.Tpo contrib/$(DEPDIR)/libcontrib_la-time.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='contrib/time.c' object='contrib/libcontrib_la-time.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o contrib/libcontrib_la-time.lo `test -f 'contrib/time.c' || echo '$(srcdir)/'`contrib/time.c
+
+contrib/openbsd/libcontrib_la-siphash.lo: contrib/openbsd/siphash.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT contrib/openbsd/libcontrib_la-siphash.lo -MD -MP -MF contrib/openbsd/$(DEPDIR)/libcontrib_la-siphash.Tpo -c -o contrib/openbsd/libcontrib_la-siphash.lo `test -f 'contrib/openbsd/siphash.c' || echo '$(srcdir)/'`contrib/openbsd/siphash.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) contrib/openbsd/$(DEPDIR)/libcontrib_la-siphash.Tpo contrib/openbsd/$(DEPDIR)/libcontrib_la-siphash.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='contrib/openbsd/siphash.c' object='contrib/openbsd/libcontrib_la-siphash.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o contrib/openbsd/libcontrib_la-siphash.lo `test -f 'contrib/openbsd/siphash.c' || echo '$(srcdir)/'`contrib/openbsd/siphash.c
+
+contrib/openbsd/libcontrib_la-strlcat.lo: contrib/openbsd/strlcat.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT contrib/openbsd/libcontrib_la-strlcat.lo -MD -MP -MF contrib/openbsd/$(DEPDIR)/libcontrib_la-strlcat.Tpo -c -o contrib/openbsd/libcontrib_la-strlcat.lo `test -f 'contrib/openbsd/strlcat.c' || echo '$(srcdir)/'`contrib/openbsd/strlcat.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) contrib/openbsd/$(DEPDIR)/libcontrib_la-strlcat.Tpo contrib/openbsd/$(DEPDIR)/libcontrib_la-strlcat.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='contrib/openbsd/strlcat.c' object='contrib/openbsd/libcontrib_la-strlcat.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o contrib/openbsd/libcontrib_la-strlcat.lo `test -f 'contrib/openbsd/strlcat.c' || echo '$(srcdir)/'`contrib/openbsd/strlcat.c
+
+contrib/openbsd/libcontrib_la-strlcpy.lo: contrib/openbsd/strlcpy.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT contrib/openbsd/libcontrib_la-strlcpy.lo -MD -MP -MF contrib/openbsd/$(DEPDIR)/libcontrib_la-strlcpy.Tpo -c -o contrib/openbsd/libcontrib_la-strlcpy.lo `test -f 'contrib/openbsd/strlcpy.c' || echo '$(srcdir)/'`contrib/openbsd/strlcpy.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) contrib/openbsd/$(DEPDIR)/libcontrib_la-strlcpy.Tpo contrib/openbsd/$(DEPDIR)/libcontrib_la-strlcpy.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='contrib/openbsd/strlcpy.c' object='contrib/openbsd/libcontrib_la-strlcpy.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o contrib/openbsd/libcontrib_la-strlcpy.lo `test -f 'contrib/openbsd/strlcpy.c' || echo '$(srcdir)/'`contrib/openbsd/strlcpy.c
+
+contrib/ucw/libcontrib_la-heap.lo: contrib/ucw/heap.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT contrib/ucw/libcontrib_la-heap.lo -MD -MP -MF contrib/ucw/$(DEPDIR)/libcontrib_la-heap.Tpo -c -o contrib/ucw/libcontrib_la-heap.lo `test -f 'contrib/ucw/heap.c' || echo '$(srcdir)/'`contrib/ucw/heap.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) contrib/ucw/$(DEPDIR)/libcontrib_la-heap.Tpo contrib/ucw/$(DEPDIR)/libcontrib_la-heap.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='contrib/ucw/heap.c' object='contrib/ucw/libcontrib_la-heap.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o contrib/ucw/libcontrib_la-heap.lo `test -f 'contrib/ucw/heap.c' || echo '$(srcdir)/'`contrib/ucw/heap.c
+
+contrib/ucw/libcontrib_la-lists.lo: contrib/ucw/lists.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT contrib/ucw/libcontrib_la-lists.lo -MD -MP -MF contrib/ucw/$(DEPDIR)/libcontrib_la-lists.Tpo -c -o contrib/ucw/libcontrib_la-lists.lo `test -f 'contrib/ucw/lists.c' || echo '$(srcdir)/'`contrib/ucw/lists.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) contrib/ucw/$(DEPDIR)/libcontrib_la-lists.Tpo contrib/ucw/$(DEPDIR)/libcontrib_la-lists.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='contrib/ucw/lists.c' object='contrib/ucw/libcontrib_la-lists.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o contrib/ucw/libcontrib_la-lists.lo `test -f 'contrib/ucw/lists.c' || echo '$(srcdir)/'`contrib/ucw/lists.c
+
+contrib/ucw/libcontrib_la-mempool.lo: contrib/ucw/mempool.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT contrib/ucw/libcontrib_la-mempool.lo -MD -MP -MF contrib/ucw/$(DEPDIR)/libcontrib_la-mempool.Tpo -c -o contrib/ucw/libcontrib_la-mempool.lo `test -f 'contrib/ucw/mempool.c' || echo '$(srcdir)/'`contrib/ucw/mempool.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) contrib/ucw/$(DEPDIR)/libcontrib_la-mempool.Tpo contrib/ucw/$(DEPDIR)/libcontrib_la-mempool.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='contrib/ucw/mempool.c' object='contrib/ucw/libcontrib_la-mempool.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o contrib/ucw/libcontrib_la-mempool.lo `test -f 'contrib/ucw/mempool.c' || echo '$(srcdir)/'`contrib/ucw/mempool.c
+
+contrib/lmdb/libcontrib_la-mdb.lo: contrib/lmdb/mdb.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT contrib/lmdb/libcontrib_la-mdb.lo -MD -MP -MF contrib/lmdb/$(DEPDIR)/libcontrib_la-mdb.Tpo -c -o contrib/lmdb/libcontrib_la-mdb.lo `test -f 'contrib/lmdb/mdb.c' || echo '$(srcdir)/'`contrib/lmdb/mdb.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) contrib/lmdb/$(DEPDIR)/libcontrib_la-mdb.Tpo contrib/lmdb/$(DEPDIR)/libcontrib_la-mdb.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='contrib/lmdb/mdb.c' object='contrib/lmdb/libcontrib_la-mdb.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o contrib/lmdb/libcontrib_la-mdb.lo `test -f 'contrib/lmdb/mdb.c' || echo '$(srcdir)/'`contrib/lmdb/mdb.c
+
+contrib/lmdb/libcontrib_la-midl.lo: contrib/lmdb/midl.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT contrib/lmdb/libcontrib_la-midl.lo -MD -MP -MF contrib/lmdb/$(DEPDIR)/libcontrib_la-midl.Tpo -c -o contrib/lmdb/libcontrib_la-midl.lo `test -f 'contrib/lmdb/midl.c' || echo '$(srcdir)/'`contrib/lmdb/midl.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) contrib/lmdb/$(DEPDIR)/libcontrib_la-midl.Tpo contrib/lmdb/$(DEPDIR)/libcontrib_la-midl.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='contrib/lmdb/midl.c' object='contrib/lmdb/libcontrib_la-midl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcontrib_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o contrib/lmdb/libcontrib_la-midl.lo `test -f 'contrib/lmdb/midl.c' || echo '$(srcdir)/'`contrib/lmdb/midl.c
+
+libdnssec/contrib/libdnssec_la-vpool.lo: libdnssec/contrib/vpool.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/contrib/libdnssec_la-vpool.lo -MD -MP -MF libdnssec/contrib/$(DEPDIR)/libdnssec_la-vpool.Tpo -c -o libdnssec/contrib/libdnssec_la-vpool.lo `test -f 'libdnssec/contrib/vpool.c' || echo '$(srcdir)/'`libdnssec/contrib/vpool.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/contrib/$(DEPDIR)/libdnssec_la-vpool.Tpo libdnssec/contrib/$(DEPDIR)/libdnssec_la-vpool.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/contrib/vpool.c' object='libdnssec/contrib/libdnssec_la-vpool.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/contrib/libdnssec_la-vpool.lo `test -f 'libdnssec/contrib/vpool.c' || echo '$(srcdir)/'`libdnssec/contrib/vpool.c
+
+libdnssec/libdnssec_la-binary.lo: libdnssec/binary.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/libdnssec_la-binary.lo -MD -MP -MF libdnssec/$(DEPDIR)/libdnssec_la-binary.Tpo -c -o libdnssec/libdnssec_la-binary.lo `test -f 'libdnssec/binary.c' || echo '$(srcdir)/'`libdnssec/binary.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/$(DEPDIR)/libdnssec_la-binary.Tpo libdnssec/$(DEPDIR)/libdnssec_la-binary.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/binary.c' object='libdnssec/libdnssec_la-binary.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/libdnssec_la-binary.lo `test -f 'libdnssec/binary.c' || echo '$(srcdir)/'`libdnssec/binary.c
+
+libdnssec/libdnssec_la-crypto.lo: libdnssec/crypto.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/libdnssec_la-crypto.lo -MD -MP -MF libdnssec/$(DEPDIR)/libdnssec_la-crypto.Tpo -c -o libdnssec/libdnssec_la-crypto.lo `test -f 'libdnssec/crypto.c' || echo '$(srcdir)/'`libdnssec/crypto.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/$(DEPDIR)/libdnssec_la-crypto.Tpo libdnssec/$(DEPDIR)/libdnssec_la-crypto.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/crypto.c' object='libdnssec/libdnssec_la-crypto.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/libdnssec_la-crypto.lo `test -f 'libdnssec/crypto.c' || echo '$(srcdir)/'`libdnssec/crypto.c
+
+libdnssec/libdnssec_la-error.lo: libdnssec/error.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/libdnssec_la-error.lo -MD -MP -MF libdnssec/$(DEPDIR)/libdnssec_la-error.Tpo -c -o libdnssec/libdnssec_la-error.lo `test -f 'libdnssec/error.c' || echo '$(srcdir)/'`libdnssec/error.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/$(DEPDIR)/libdnssec_la-error.Tpo libdnssec/$(DEPDIR)/libdnssec_la-error.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/error.c' object='libdnssec/libdnssec_la-error.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/libdnssec_la-error.lo `test -f 'libdnssec/error.c' || echo '$(srcdir)/'`libdnssec/error.c
+
+libdnssec/key/libdnssec_la-algorithm.lo: libdnssec/key/algorithm.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/key/libdnssec_la-algorithm.lo -MD -MP -MF libdnssec/key/$(DEPDIR)/libdnssec_la-algorithm.Tpo -c -o libdnssec/key/libdnssec_la-algorithm.lo `test -f 'libdnssec/key/algorithm.c' || echo '$(srcdir)/'`libdnssec/key/algorithm.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/key/$(DEPDIR)/libdnssec_la-algorithm.Tpo libdnssec/key/$(DEPDIR)/libdnssec_la-algorithm.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/key/algorithm.c' object='libdnssec/key/libdnssec_la-algorithm.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/key/libdnssec_la-algorithm.lo `test -f 'libdnssec/key/algorithm.c' || echo '$(srcdir)/'`libdnssec/key/algorithm.c
+
+libdnssec/key/libdnssec_la-convert.lo: libdnssec/key/convert.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/key/libdnssec_la-convert.lo -MD -MP -MF libdnssec/key/$(DEPDIR)/libdnssec_la-convert.Tpo -c -o libdnssec/key/libdnssec_la-convert.lo `test -f 'libdnssec/key/convert.c' || echo '$(srcdir)/'`libdnssec/key/convert.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/key/$(DEPDIR)/libdnssec_la-convert.Tpo libdnssec/key/$(DEPDIR)/libdnssec_la-convert.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/key/convert.c' object='libdnssec/key/libdnssec_la-convert.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/key/libdnssec_la-convert.lo `test -f 'libdnssec/key/convert.c' || echo '$(srcdir)/'`libdnssec/key/convert.c
+
+libdnssec/key/libdnssec_la-dnskey.lo: libdnssec/key/dnskey.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/key/libdnssec_la-dnskey.lo -MD -MP -MF libdnssec/key/$(DEPDIR)/libdnssec_la-dnskey.Tpo -c -o libdnssec/key/libdnssec_la-dnskey.lo `test -f 'libdnssec/key/dnskey.c' || echo '$(srcdir)/'`libdnssec/key/dnskey.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/key/$(DEPDIR)/libdnssec_la-dnskey.Tpo libdnssec/key/$(DEPDIR)/libdnssec_la-dnskey.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/key/dnskey.c' object='libdnssec/key/libdnssec_la-dnskey.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/key/libdnssec_la-dnskey.lo `test -f 'libdnssec/key/dnskey.c' || echo '$(srcdir)/'`libdnssec/key/dnskey.c
+
+libdnssec/key/libdnssec_la-ds.lo: libdnssec/key/ds.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/key/libdnssec_la-ds.lo -MD -MP -MF libdnssec/key/$(DEPDIR)/libdnssec_la-ds.Tpo -c -o libdnssec/key/libdnssec_la-ds.lo `test -f 'libdnssec/key/ds.c' || echo '$(srcdir)/'`libdnssec/key/ds.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/key/$(DEPDIR)/libdnssec_la-ds.Tpo libdnssec/key/$(DEPDIR)/libdnssec_la-ds.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/key/ds.c' object='libdnssec/key/libdnssec_la-ds.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/key/libdnssec_la-ds.lo `test -f 'libdnssec/key/ds.c' || echo '$(srcdir)/'`libdnssec/key/ds.c
+
+libdnssec/key/libdnssec_la-key.lo: libdnssec/key/key.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/key/libdnssec_la-key.lo -MD -MP -MF libdnssec/key/$(DEPDIR)/libdnssec_la-key.Tpo -c -o libdnssec/key/libdnssec_la-key.lo `test -f 'libdnssec/key/key.c' || echo '$(srcdir)/'`libdnssec/key/key.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/key/$(DEPDIR)/libdnssec_la-key.Tpo libdnssec/key/$(DEPDIR)/libdnssec_la-key.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/key/key.c' object='libdnssec/key/libdnssec_la-key.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/key/libdnssec_la-key.lo `test -f 'libdnssec/key/key.c' || echo '$(srcdir)/'`libdnssec/key/key.c
+
+libdnssec/key/libdnssec_la-keytag.lo: libdnssec/key/keytag.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/key/libdnssec_la-keytag.lo -MD -MP -MF libdnssec/key/$(DEPDIR)/libdnssec_la-keytag.Tpo -c -o libdnssec/key/libdnssec_la-keytag.lo `test -f 'libdnssec/key/keytag.c' || echo '$(srcdir)/'`libdnssec/key/keytag.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/key/$(DEPDIR)/libdnssec_la-keytag.Tpo libdnssec/key/$(DEPDIR)/libdnssec_la-keytag.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/key/keytag.c' object='libdnssec/key/libdnssec_la-keytag.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/key/libdnssec_la-keytag.lo `test -f 'libdnssec/key/keytag.c' || echo '$(srcdir)/'`libdnssec/key/keytag.c
+
+libdnssec/key/libdnssec_la-privkey.lo: libdnssec/key/privkey.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/key/libdnssec_la-privkey.lo -MD -MP -MF libdnssec/key/$(DEPDIR)/libdnssec_la-privkey.Tpo -c -o libdnssec/key/libdnssec_la-privkey.lo `test -f 'libdnssec/key/privkey.c' || echo '$(srcdir)/'`libdnssec/key/privkey.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/key/$(DEPDIR)/libdnssec_la-privkey.Tpo libdnssec/key/$(DEPDIR)/libdnssec_la-privkey.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/key/privkey.c' object='libdnssec/key/libdnssec_la-privkey.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/key/libdnssec_la-privkey.lo `test -f 'libdnssec/key/privkey.c' || echo '$(srcdir)/'`libdnssec/key/privkey.c
+
+libdnssec/key/libdnssec_la-simple.lo: libdnssec/key/simple.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/key/libdnssec_la-simple.lo -MD -MP -MF libdnssec/key/$(DEPDIR)/libdnssec_la-simple.Tpo -c -o libdnssec/key/libdnssec_la-simple.lo `test -f 'libdnssec/key/simple.c' || echo '$(srcdir)/'`libdnssec/key/simple.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/key/$(DEPDIR)/libdnssec_la-simple.Tpo libdnssec/key/$(DEPDIR)/libdnssec_la-simple.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/key/simple.c' object='libdnssec/key/libdnssec_la-simple.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/key/libdnssec_la-simple.lo `test -f 'libdnssec/key/simple.c' || echo '$(srcdir)/'`libdnssec/key/simple.c
+
+libdnssec/libdnssec_la-keyid.lo: libdnssec/keyid.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/libdnssec_la-keyid.lo -MD -MP -MF libdnssec/$(DEPDIR)/libdnssec_la-keyid.Tpo -c -o libdnssec/libdnssec_la-keyid.lo `test -f 'libdnssec/keyid.c' || echo '$(srcdir)/'`libdnssec/keyid.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/$(DEPDIR)/libdnssec_la-keyid.Tpo libdnssec/$(DEPDIR)/libdnssec_la-keyid.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/keyid.c' object='libdnssec/libdnssec_la-keyid.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/libdnssec_la-keyid.lo `test -f 'libdnssec/keyid.c' || echo '$(srcdir)/'`libdnssec/keyid.c
+
+libdnssec/keystore/libdnssec_la-keystore.lo: libdnssec/keystore/keystore.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/keystore/libdnssec_la-keystore.lo -MD -MP -MF libdnssec/keystore/$(DEPDIR)/libdnssec_la-keystore.Tpo -c -o libdnssec/keystore/libdnssec_la-keystore.lo `test -f 'libdnssec/keystore/keystore.c' || echo '$(srcdir)/'`libdnssec/keystore/keystore.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/keystore/$(DEPDIR)/libdnssec_la-keystore.Tpo libdnssec/keystore/$(DEPDIR)/libdnssec_la-keystore.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/keystore/keystore.c' object='libdnssec/keystore/libdnssec_la-keystore.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/keystore/libdnssec_la-keystore.lo `test -f 'libdnssec/keystore/keystore.c' || echo '$(srcdir)/'`libdnssec/keystore/keystore.c
+
+libdnssec/keystore/libdnssec_la-pkcs11.lo: libdnssec/keystore/pkcs11.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/keystore/libdnssec_la-pkcs11.lo -MD -MP -MF libdnssec/keystore/$(DEPDIR)/libdnssec_la-pkcs11.Tpo -c -o libdnssec/keystore/libdnssec_la-pkcs11.lo `test -f 'libdnssec/keystore/pkcs11.c' || echo '$(srcdir)/'`libdnssec/keystore/pkcs11.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/keystore/$(DEPDIR)/libdnssec_la-pkcs11.Tpo libdnssec/keystore/$(DEPDIR)/libdnssec_la-pkcs11.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/keystore/pkcs11.c' object='libdnssec/keystore/libdnssec_la-pkcs11.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/keystore/libdnssec_la-pkcs11.lo `test -f 'libdnssec/keystore/pkcs11.c' || echo '$(srcdir)/'`libdnssec/keystore/pkcs11.c
+
+libdnssec/keystore/libdnssec_la-pkcs8.lo: libdnssec/keystore/pkcs8.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/keystore/libdnssec_la-pkcs8.lo -MD -MP -MF libdnssec/keystore/$(DEPDIR)/libdnssec_la-pkcs8.Tpo -c -o libdnssec/keystore/libdnssec_la-pkcs8.lo `test -f 'libdnssec/keystore/pkcs8.c' || echo '$(srcdir)/'`libdnssec/keystore/pkcs8.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/keystore/$(DEPDIR)/libdnssec_la-pkcs8.Tpo libdnssec/keystore/$(DEPDIR)/libdnssec_la-pkcs8.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/keystore/pkcs8.c' object='libdnssec/keystore/libdnssec_la-pkcs8.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/keystore/libdnssec_la-pkcs8.lo `test -f 'libdnssec/keystore/pkcs8.c' || echo '$(srcdir)/'`libdnssec/keystore/pkcs8.c
+
+libdnssec/keystore/libdnssec_la-pkcs8_dir.lo: libdnssec/keystore/pkcs8_dir.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/keystore/libdnssec_la-pkcs8_dir.lo -MD -MP -MF libdnssec/keystore/$(DEPDIR)/libdnssec_la-pkcs8_dir.Tpo -c -o libdnssec/keystore/libdnssec_la-pkcs8_dir.lo `test -f 'libdnssec/keystore/pkcs8_dir.c' || echo '$(srcdir)/'`libdnssec/keystore/pkcs8_dir.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/keystore/$(DEPDIR)/libdnssec_la-pkcs8_dir.Tpo libdnssec/keystore/$(DEPDIR)/libdnssec_la-pkcs8_dir.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/keystore/pkcs8_dir.c' object='libdnssec/keystore/libdnssec_la-pkcs8_dir.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/keystore/libdnssec_la-pkcs8_dir.lo `test -f 'libdnssec/keystore/pkcs8_dir.c' || echo '$(srcdir)/'`libdnssec/keystore/pkcs8_dir.c
+
+libdnssec/list/libdnssec_la-list.lo: libdnssec/list/list.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/list/libdnssec_la-list.lo -MD -MP -MF libdnssec/list/$(DEPDIR)/libdnssec_la-list.Tpo -c -o libdnssec/list/libdnssec_la-list.lo `test -f 'libdnssec/list/list.c' || echo '$(srcdir)/'`libdnssec/list/list.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/list/$(DEPDIR)/libdnssec_la-list.Tpo libdnssec/list/$(DEPDIR)/libdnssec_la-list.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/list/list.c' object='libdnssec/list/libdnssec_la-list.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/list/libdnssec_la-list.lo `test -f 'libdnssec/list/list.c' || echo '$(srcdir)/'`libdnssec/list/list.c
+
+libdnssec/nsec/libdnssec_la-bitmap.lo: libdnssec/nsec/bitmap.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/nsec/libdnssec_la-bitmap.lo -MD -MP -MF libdnssec/nsec/$(DEPDIR)/libdnssec_la-bitmap.Tpo -c -o libdnssec/nsec/libdnssec_la-bitmap.lo `test -f 'libdnssec/nsec/bitmap.c' || echo '$(srcdir)/'`libdnssec/nsec/bitmap.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/nsec/$(DEPDIR)/libdnssec_la-bitmap.Tpo libdnssec/nsec/$(DEPDIR)/libdnssec_la-bitmap.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/nsec/bitmap.c' object='libdnssec/nsec/libdnssec_la-bitmap.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/nsec/libdnssec_la-bitmap.lo `test -f 'libdnssec/nsec/bitmap.c' || echo '$(srcdir)/'`libdnssec/nsec/bitmap.c
+
+libdnssec/nsec/libdnssec_la-hash.lo: libdnssec/nsec/hash.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/nsec/libdnssec_la-hash.lo -MD -MP -MF libdnssec/nsec/$(DEPDIR)/libdnssec_la-hash.Tpo -c -o libdnssec/nsec/libdnssec_la-hash.lo `test -f 'libdnssec/nsec/hash.c' || echo '$(srcdir)/'`libdnssec/nsec/hash.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/nsec/$(DEPDIR)/libdnssec_la-hash.Tpo libdnssec/nsec/$(DEPDIR)/libdnssec_la-hash.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/nsec/hash.c' object='libdnssec/nsec/libdnssec_la-hash.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/nsec/libdnssec_la-hash.lo `test -f 'libdnssec/nsec/hash.c' || echo '$(srcdir)/'`libdnssec/nsec/hash.c
+
+libdnssec/nsec/libdnssec_la-nsec.lo: libdnssec/nsec/nsec.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/nsec/libdnssec_la-nsec.lo -MD -MP -MF libdnssec/nsec/$(DEPDIR)/libdnssec_la-nsec.Tpo -c -o libdnssec/nsec/libdnssec_la-nsec.lo `test -f 'libdnssec/nsec/nsec.c' || echo '$(srcdir)/'`libdnssec/nsec/nsec.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/nsec/$(DEPDIR)/libdnssec_la-nsec.Tpo libdnssec/nsec/$(DEPDIR)/libdnssec_la-nsec.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/nsec/nsec.c' object='libdnssec/nsec/libdnssec_la-nsec.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/nsec/libdnssec_la-nsec.lo `test -f 'libdnssec/nsec/nsec.c' || echo '$(srcdir)/'`libdnssec/nsec/nsec.c
+
+libdnssec/p11/libdnssec_la-p11.lo: libdnssec/p11/p11.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/p11/libdnssec_la-p11.lo -MD -MP -MF libdnssec/p11/$(DEPDIR)/libdnssec_la-p11.Tpo -c -o libdnssec/p11/libdnssec_la-p11.lo `test -f 'libdnssec/p11/p11.c' || echo '$(srcdir)/'`libdnssec/p11/p11.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/p11/$(DEPDIR)/libdnssec_la-p11.Tpo libdnssec/p11/$(DEPDIR)/libdnssec_la-p11.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/p11/p11.c' object='libdnssec/p11/libdnssec_la-p11.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/p11/libdnssec_la-p11.lo `test -f 'libdnssec/p11/p11.c' || echo '$(srcdir)/'`libdnssec/p11/p11.c
+
+libdnssec/libdnssec_la-random.lo: libdnssec/random.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/libdnssec_la-random.lo -MD -MP -MF libdnssec/$(DEPDIR)/libdnssec_la-random.Tpo -c -o libdnssec/libdnssec_la-random.lo `test -f 'libdnssec/random.c' || echo '$(srcdir)/'`libdnssec/random.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/$(DEPDIR)/libdnssec_la-random.Tpo libdnssec/$(DEPDIR)/libdnssec_la-random.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/random.c' object='libdnssec/libdnssec_la-random.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/libdnssec_la-random.lo `test -f 'libdnssec/random.c' || echo '$(srcdir)/'`libdnssec/random.c
+
+libdnssec/sign/libdnssec_la-der.lo: libdnssec/sign/der.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/sign/libdnssec_la-der.lo -MD -MP -MF libdnssec/sign/$(DEPDIR)/libdnssec_la-der.Tpo -c -o libdnssec/sign/libdnssec_la-der.lo `test -f 'libdnssec/sign/der.c' || echo '$(srcdir)/'`libdnssec/sign/der.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/sign/$(DEPDIR)/libdnssec_la-der.Tpo libdnssec/sign/$(DEPDIR)/libdnssec_la-der.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/sign/der.c' object='libdnssec/sign/libdnssec_la-der.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/sign/libdnssec_la-der.lo `test -f 'libdnssec/sign/der.c' || echo '$(srcdir)/'`libdnssec/sign/der.c
+
+libdnssec/sign/libdnssec_la-sign.lo: libdnssec/sign/sign.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/sign/libdnssec_la-sign.lo -MD -MP -MF libdnssec/sign/$(DEPDIR)/libdnssec_la-sign.Tpo -c -o libdnssec/sign/libdnssec_la-sign.lo `test -f 'libdnssec/sign/sign.c' || echo '$(srcdir)/'`libdnssec/sign/sign.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/sign/$(DEPDIR)/libdnssec_la-sign.Tpo libdnssec/sign/$(DEPDIR)/libdnssec_la-sign.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/sign/sign.c' object='libdnssec/sign/libdnssec_la-sign.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/sign/libdnssec_la-sign.lo `test -f 'libdnssec/sign/sign.c' || echo '$(srcdir)/'`libdnssec/sign/sign.c
+
+libdnssec/libdnssec_la-tsig.lo: libdnssec/tsig.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/libdnssec_la-tsig.lo -MD -MP -MF libdnssec/$(DEPDIR)/libdnssec_la-tsig.Tpo -c -o libdnssec/libdnssec_la-tsig.lo `test -f 'libdnssec/tsig.c' || echo '$(srcdir)/'`libdnssec/tsig.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/$(DEPDIR)/libdnssec_la-tsig.Tpo libdnssec/$(DEPDIR)/libdnssec_la-tsig.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/tsig.c' object='libdnssec/libdnssec_la-tsig.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnssec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/libdnssec_la-tsig.lo `test -f 'libdnssec/tsig.c' || echo '$(srcdir)/'`libdnssec/tsig.c
+
+contrib/dnstap/libdnstap_la-convert.lo: contrib/dnstap/convert.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnstap_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT contrib/dnstap/libdnstap_la-convert.lo -MD -MP -MF contrib/dnstap/$(DEPDIR)/libdnstap_la-convert.Tpo -c -o contrib/dnstap/libdnstap_la-convert.lo `test -f 'contrib/dnstap/convert.c' || echo '$(srcdir)/'`contrib/dnstap/convert.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) contrib/dnstap/$(DEPDIR)/libdnstap_la-convert.Tpo contrib/dnstap/$(DEPDIR)/libdnstap_la-convert.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='contrib/dnstap/convert.c' object='contrib/dnstap/libdnstap_la-convert.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnstap_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o contrib/dnstap/libdnstap_la-convert.lo `test -f 'contrib/dnstap/convert.c' || echo '$(srcdir)/'`contrib/dnstap/convert.c
+
+contrib/dnstap/libdnstap_la-dnstap.lo: contrib/dnstap/dnstap.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnstap_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT contrib/dnstap/libdnstap_la-dnstap.lo -MD -MP -MF contrib/dnstap/$(DEPDIR)/libdnstap_la-dnstap.Tpo -c -o contrib/dnstap/libdnstap_la-dnstap.lo `test -f 'contrib/dnstap/dnstap.c' || echo '$(srcdir)/'`contrib/dnstap/dnstap.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) contrib/dnstap/$(DEPDIR)/libdnstap_la-dnstap.Tpo contrib/dnstap/$(DEPDIR)/libdnstap_la-dnstap.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='contrib/dnstap/dnstap.c' object='contrib/dnstap/libdnstap_la-dnstap.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnstap_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o contrib/dnstap/libdnstap_la-dnstap.lo `test -f 'contrib/dnstap/dnstap.c' || echo '$(srcdir)/'`contrib/dnstap/dnstap.c
+
+contrib/dnstap/libdnstap_la-message.lo: contrib/dnstap/message.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnstap_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT contrib/dnstap/libdnstap_la-message.lo -MD -MP -MF contrib/dnstap/$(DEPDIR)/libdnstap_la-message.Tpo -c -o contrib/dnstap/libdnstap_la-message.lo `test -f 'contrib/dnstap/message.c' || echo '$(srcdir)/'`contrib/dnstap/message.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) contrib/dnstap/$(DEPDIR)/libdnstap_la-message.Tpo contrib/dnstap/$(DEPDIR)/libdnstap_la-message.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='contrib/dnstap/message.c' object='contrib/dnstap/libdnstap_la-message.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnstap_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o contrib/dnstap/libdnstap_la-message.lo `test -f 'contrib/dnstap/message.c' || echo '$(srcdir)/'`contrib/dnstap/message.c
+
+contrib/dnstap/libdnstap_la-reader.lo: contrib/dnstap/reader.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnstap_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT contrib/dnstap/libdnstap_la-reader.lo -MD -MP -MF contrib/dnstap/$(DEPDIR)/libdnstap_la-reader.Tpo -c -o contrib/dnstap/libdnstap_la-reader.lo `test -f 'contrib/dnstap/reader.c' || echo '$(srcdir)/'`contrib/dnstap/reader.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) contrib/dnstap/$(DEPDIR)/libdnstap_la-reader.Tpo contrib/dnstap/$(DEPDIR)/libdnstap_la-reader.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='contrib/dnstap/reader.c' object='contrib/dnstap/libdnstap_la-reader.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnstap_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o contrib/dnstap/libdnstap_la-reader.lo `test -f 'contrib/dnstap/reader.c' || echo '$(srcdir)/'`contrib/dnstap/reader.c
+
+contrib/dnstap/libdnstap_la-writer.lo: contrib/dnstap/writer.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnstap_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT contrib/dnstap/libdnstap_la-writer.lo -MD -MP -MF contrib/dnstap/$(DEPDIR)/libdnstap_la-writer.Tpo -c -o contrib/dnstap/libdnstap_la-writer.lo `test -f 'contrib/dnstap/writer.c' || echo '$(srcdir)/'`contrib/dnstap/writer.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) contrib/dnstap/$(DEPDIR)/libdnstap_la-writer.Tpo contrib/dnstap/$(DEPDIR)/libdnstap_la-writer.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='contrib/dnstap/writer.c' object='contrib/dnstap/libdnstap_la-writer.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnstap_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o contrib/dnstap/libdnstap_la-writer.lo `test -f 'contrib/dnstap/writer.c' || echo '$(srcdir)/'`contrib/dnstap/writer.c
+
+contrib/dnstap/libdnstap_la-dnstap.pb-c.lo: contrib/dnstap/dnstap.pb-c.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnstap_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT contrib/dnstap/libdnstap_la-dnstap.pb-c.lo -MD -MP -MF contrib/dnstap/$(DEPDIR)/libdnstap_la-dnstap.pb-c.Tpo -c -o contrib/dnstap/libdnstap_la-dnstap.pb-c.lo `test -f 'contrib/dnstap/dnstap.pb-c.c' || echo '$(srcdir)/'`contrib/dnstap/dnstap.pb-c.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) contrib/dnstap/$(DEPDIR)/libdnstap_la-dnstap.pb-c.Tpo contrib/dnstap/$(DEPDIR)/libdnstap_la-dnstap.pb-c.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='contrib/dnstap/dnstap.pb-c.c' object='contrib/dnstap/libdnstap_la-dnstap.pb-c.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdnstap_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o contrib/dnstap/libdnstap_la-dnstap.pb-c.lo `test -f 'contrib/dnstap/dnstap.pb-c.c' || echo '$(srcdir)/'`contrib/dnstap/dnstap.pb-c.c
+
+libknot/libknot_la-codes.lo: libknot/codes.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot/libknot_la-codes.lo -MD -MP -MF libknot/$(DEPDIR)/libknot_la-codes.Tpo -c -o libknot/libknot_la-codes.lo `test -f 'libknot/codes.c' || echo '$(srcdir)/'`libknot/codes.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libknot/$(DEPDIR)/libknot_la-codes.Tpo libknot/$(DEPDIR)/libknot_la-codes.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libknot/codes.c' object='libknot/libknot_la-codes.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot/libknot_la-codes.lo `test -f 'libknot/codes.c' || echo '$(srcdir)/'`libknot/codes.c
+
+libknot/control/libknot_la-control.lo: libknot/control/control.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot/control/libknot_la-control.lo -MD -MP -MF libknot/control/$(DEPDIR)/libknot_la-control.Tpo -c -o libknot/control/libknot_la-control.lo `test -f 'libknot/control/control.c' || echo '$(srcdir)/'`libknot/control/control.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libknot/control/$(DEPDIR)/libknot_la-control.Tpo libknot/control/$(DEPDIR)/libknot_la-control.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libknot/control/control.c' object='libknot/control/libknot_la-control.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot/control/libknot_la-control.lo `test -f 'libknot/control/control.c' || echo '$(srcdir)/'`libknot/control/control.c
+
+libknot/libknot_la-cookies.lo: libknot/cookies.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot/libknot_la-cookies.lo -MD -MP -MF libknot/$(DEPDIR)/libknot_la-cookies.Tpo -c -o libknot/libknot_la-cookies.lo `test -f 'libknot/cookies.c' || echo '$(srcdir)/'`libknot/cookies.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libknot/$(DEPDIR)/libknot_la-cookies.Tpo libknot/$(DEPDIR)/libknot_la-cookies.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libknot/cookies.c' object='libknot/libknot_la-cookies.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot/libknot_la-cookies.lo `test -f 'libknot/cookies.c' || echo '$(srcdir)/'`libknot/cookies.c
+
+libknot/libknot_la-descriptor.lo: libknot/descriptor.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot/libknot_la-descriptor.lo -MD -MP -MF libknot/$(DEPDIR)/libknot_la-descriptor.Tpo -c -o libknot/libknot_la-descriptor.lo `test -f 'libknot/descriptor.c' || echo '$(srcdir)/'`libknot/descriptor.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libknot/$(DEPDIR)/libknot_la-descriptor.Tpo libknot/$(DEPDIR)/libknot_la-descriptor.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libknot/descriptor.c' object='libknot/libknot_la-descriptor.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot/libknot_la-descriptor.lo `test -f 'libknot/descriptor.c' || echo '$(srcdir)/'`libknot/descriptor.c
+
+libknot/libknot_la-dname.lo: libknot/dname.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot/libknot_la-dname.lo -MD -MP -MF libknot/$(DEPDIR)/libknot_la-dname.Tpo -c -o libknot/libknot_la-dname.lo `test -f 'libknot/dname.c' || echo '$(srcdir)/'`libknot/dname.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libknot/$(DEPDIR)/libknot_la-dname.Tpo libknot/$(DEPDIR)/libknot_la-dname.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libknot/dname.c' object='libknot/libknot_la-dname.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot/libknot_la-dname.lo `test -f 'libknot/dname.c' || echo '$(srcdir)/'`libknot/dname.c
+
+libknot/libknot_la-error.lo: libknot/error.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot/libknot_la-error.lo -MD -MP -MF libknot/$(DEPDIR)/libknot_la-error.Tpo -c -o libknot/libknot_la-error.lo `test -f 'libknot/error.c' || echo '$(srcdir)/'`libknot/error.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libknot/$(DEPDIR)/libknot_la-error.Tpo libknot/$(DEPDIR)/libknot_la-error.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libknot/error.c' object='libknot/libknot_la-error.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot/libknot_la-error.lo `test -f 'libknot/error.c' || echo '$(srcdir)/'`libknot/error.c
+
+libknot/db/libknot_la-db_lmdb.lo: libknot/db/db_lmdb.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot/db/libknot_la-db_lmdb.lo -MD -MP -MF libknot/db/$(DEPDIR)/libknot_la-db_lmdb.Tpo -c -o libknot/db/libknot_la-db_lmdb.lo `test -f 'libknot/db/db_lmdb.c' || echo '$(srcdir)/'`libknot/db/db_lmdb.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libknot/db/$(DEPDIR)/libknot_la-db_lmdb.Tpo libknot/db/$(DEPDIR)/libknot_la-db_lmdb.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libknot/db/db_lmdb.c' object='libknot/db/libknot_la-db_lmdb.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot/db/libknot_la-db_lmdb.lo `test -f 'libknot/db/db_lmdb.c' || echo '$(srcdir)/'`libknot/db/db_lmdb.c
+
+libknot/db/libknot_la-db_trie.lo: libknot/db/db_trie.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot/db/libknot_la-db_trie.lo -MD -MP -MF libknot/db/$(DEPDIR)/libknot_la-db_trie.Tpo -c -o libknot/db/libknot_la-db_trie.lo `test -f 'libknot/db/db_trie.c' || echo '$(srcdir)/'`libknot/db/db_trie.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libknot/db/$(DEPDIR)/libknot_la-db_trie.Tpo libknot/db/$(DEPDIR)/libknot_la-db_trie.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libknot/db/db_trie.c' object='libknot/db/libknot_la-db_trie.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot/db/libknot_la-db_trie.lo `test -f 'libknot/db/db_trie.c' || echo '$(srcdir)/'`libknot/db/db_trie.c
+
+libknot/packet/libknot_la-pkt.lo: libknot/packet/pkt.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot/packet/libknot_la-pkt.lo -MD -MP -MF libknot/packet/$(DEPDIR)/libknot_la-pkt.Tpo -c -o libknot/packet/libknot_la-pkt.lo `test -f 'libknot/packet/pkt.c' || echo '$(srcdir)/'`libknot/packet/pkt.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libknot/packet/$(DEPDIR)/libknot_la-pkt.Tpo libknot/packet/$(DEPDIR)/libknot_la-pkt.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libknot/packet/pkt.c' object='libknot/packet/libknot_la-pkt.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot/packet/libknot_la-pkt.lo `test -f 'libknot/packet/pkt.c' || echo '$(srcdir)/'`libknot/packet/pkt.c
+
+libknot/packet/libknot_la-rrset-wire.lo: libknot/packet/rrset-wire.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot/packet/libknot_la-rrset-wire.lo -MD -MP -MF libknot/packet/$(DEPDIR)/libknot_la-rrset-wire.Tpo -c -o libknot/packet/libknot_la-rrset-wire.lo `test -f 'libknot/packet/rrset-wire.c' || echo '$(srcdir)/'`libknot/packet/rrset-wire.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libknot/packet/$(DEPDIR)/libknot_la-rrset-wire.Tpo libknot/packet/$(DEPDIR)/libknot_la-rrset-wire.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libknot/packet/rrset-wire.c' object='libknot/packet/libknot_la-rrset-wire.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot/packet/libknot_la-rrset-wire.lo `test -f 'libknot/packet/rrset-wire.c' || echo '$(srcdir)/'`libknot/packet/rrset-wire.c
+
+libknot/libknot_la-rdataset.lo: libknot/rdataset.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot/libknot_la-rdataset.lo -MD -MP -MF libknot/$(DEPDIR)/libknot_la-rdataset.Tpo -c -o libknot/libknot_la-rdataset.lo `test -f 'libknot/rdataset.c' || echo '$(srcdir)/'`libknot/rdataset.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libknot/$(DEPDIR)/libknot_la-rdataset.Tpo libknot/$(DEPDIR)/libknot_la-rdataset.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libknot/rdataset.c' object='libknot/libknot_la-rdataset.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot/libknot_la-rdataset.lo `test -f 'libknot/rdataset.c' || echo '$(srcdir)/'`libknot/rdataset.c
+
+libknot/libknot_la-rrset-dump.lo: libknot/rrset-dump.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot/libknot_la-rrset-dump.lo -MD -MP -MF libknot/$(DEPDIR)/libknot_la-rrset-dump.Tpo -c -o libknot/libknot_la-rrset-dump.lo `test -f 'libknot/rrset-dump.c' || echo '$(srcdir)/'`libknot/rrset-dump.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libknot/$(DEPDIR)/libknot_la-rrset-dump.Tpo libknot/$(DEPDIR)/libknot_la-rrset-dump.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libknot/rrset-dump.c' object='libknot/libknot_la-rrset-dump.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot/libknot_la-rrset-dump.lo `test -f 'libknot/rrset-dump.c' || echo '$(srcdir)/'`libknot/rrset-dump.c
+
+libknot/libknot_la-rrset.lo: libknot/rrset.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot/libknot_la-rrset.lo -MD -MP -MF libknot/$(DEPDIR)/libknot_la-rrset.Tpo -c -o libknot/libknot_la-rrset.lo `test -f 'libknot/rrset.c' || echo '$(srcdir)/'`libknot/rrset.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libknot/$(DEPDIR)/libknot_la-rrset.Tpo libknot/$(DEPDIR)/libknot_la-rrset.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libknot/rrset.c' object='libknot/libknot_la-rrset.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot/libknot_la-rrset.lo `test -f 'libknot/rrset.c' || echo '$(srcdir)/'`libknot/rrset.c
+
+libknot/rrtype/libknot_la-naptr.lo: libknot/rrtype/naptr.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot/rrtype/libknot_la-naptr.lo -MD -MP -MF libknot/rrtype/$(DEPDIR)/libknot_la-naptr.Tpo -c -o libknot/rrtype/libknot_la-naptr.lo `test -f 'libknot/rrtype/naptr.c' || echo '$(srcdir)/'`libknot/rrtype/naptr.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libknot/rrtype/$(DEPDIR)/libknot_la-naptr.Tpo libknot/rrtype/$(DEPDIR)/libknot_la-naptr.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libknot/rrtype/naptr.c' object='libknot/rrtype/libknot_la-naptr.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot/rrtype/libknot_la-naptr.lo `test -f 'libknot/rrtype/naptr.c' || echo '$(srcdir)/'`libknot/rrtype/naptr.c
+
+libknot/rrtype/libknot_la-opt.lo: libknot/rrtype/opt.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot/rrtype/libknot_la-opt.lo -MD -MP -MF libknot/rrtype/$(DEPDIR)/libknot_la-opt.Tpo -c -o libknot/rrtype/libknot_la-opt.lo `test -f 'libknot/rrtype/opt.c' || echo '$(srcdir)/'`libknot/rrtype/opt.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libknot/rrtype/$(DEPDIR)/libknot_la-opt.Tpo libknot/rrtype/$(DEPDIR)/libknot_la-opt.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libknot/rrtype/opt.c' object='libknot/rrtype/libknot_la-opt.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot/rrtype/libknot_la-opt.lo `test -f 'libknot/rrtype/opt.c' || echo '$(srcdir)/'`libknot/rrtype/opt.c
+
+libknot/rrtype/libknot_la-tsig.lo: libknot/rrtype/tsig.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot/rrtype/libknot_la-tsig.lo -MD -MP -MF libknot/rrtype/$(DEPDIR)/libknot_la-tsig.Tpo -c -o libknot/rrtype/libknot_la-tsig.lo `test -f 'libknot/rrtype/tsig.c' || echo '$(srcdir)/'`libknot/rrtype/tsig.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libknot/rrtype/$(DEPDIR)/libknot_la-tsig.Tpo libknot/rrtype/$(DEPDIR)/libknot_la-tsig.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libknot/rrtype/tsig.c' object='libknot/rrtype/libknot_la-tsig.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot/rrtype/libknot_la-tsig.lo `test -f 'libknot/rrtype/tsig.c' || echo '$(srcdir)/'`libknot/rrtype/tsig.c
+
+libknot/libknot_la-tsig-op.lo: libknot/tsig-op.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot/libknot_la-tsig-op.lo -MD -MP -MF libknot/$(DEPDIR)/libknot_la-tsig-op.Tpo -c -o libknot/libknot_la-tsig-op.lo `test -f 'libknot/tsig-op.c' || echo '$(srcdir)/'`libknot/tsig-op.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libknot/$(DEPDIR)/libknot_la-tsig-op.Tpo libknot/$(DEPDIR)/libknot_la-tsig-op.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libknot/tsig-op.c' object='libknot/libknot_la-tsig-op.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot/libknot_la-tsig-op.lo `test -f 'libknot/tsig-op.c' || echo '$(srcdir)/'`libknot/tsig-op.c
+
+libknot/libknot_la-tsig.lo: libknot/tsig.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot/libknot_la-tsig.lo -MD -MP -MF libknot/$(DEPDIR)/libknot_la-tsig.Tpo -c -o libknot/libknot_la-tsig.lo `test -f 'libknot/tsig.c' || echo '$(srcdir)/'`libknot/tsig.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libknot/$(DEPDIR)/libknot_la-tsig.Tpo libknot/$(DEPDIR)/libknot_la-tsig.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libknot/tsig.c' object='libknot/libknot_la-tsig.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot/libknot_la-tsig.lo `test -f 'libknot/tsig.c' || echo '$(srcdir)/'`libknot/tsig.c
+
+libknot/yparser/libknot_la-yparser.lo: libknot/yparser/yparser.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot/yparser/libknot_la-yparser.lo -MD -MP -MF libknot/yparser/$(DEPDIR)/libknot_la-yparser.Tpo -c -o libknot/yparser/libknot_la-yparser.lo `test -f 'libknot/yparser/yparser.c' || echo '$(srcdir)/'`libknot/yparser/yparser.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libknot/yparser/$(DEPDIR)/libknot_la-yparser.Tpo libknot/yparser/$(DEPDIR)/libknot_la-yparser.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libknot/yparser/yparser.c' object='libknot/yparser/libknot_la-yparser.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot/yparser/libknot_la-yparser.lo `test -f 'libknot/yparser/yparser.c' || echo '$(srcdir)/'`libknot/yparser/yparser.c
+
+libknot/yparser/libknot_la-ypbody.lo: libknot/yparser/ypbody.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot/yparser/libknot_la-ypbody.lo -MD -MP -MF libknot/yparser/$(DEPDIR)/libknot_la-ypbody.Tpo -c -o libknot/yparser/libknot_la-ypbody.lo `test -f 'libknot/yparser/ypbody.c' || echo '$(srcdir)/'`libknot/yparser/ypbody.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libknot/yparser/$(DEPDIR)/libknot_la-ypbody.Tpo libknot/yparser/$(DEPDIR)/libknot_la-ypbody.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libknot/yparser/ypbody.c' object='libknot/yparser/libknot_la-ypbody.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot/yparser/libknot_la-ypbody.lo `test -f 'libknot/yparser/ypbody.c' || echo '$(srcdir)/'`libknot/yparser/ypbody.c
+
+libknot/yparser/libknot_la-ypformat.lo: libknot/yparser/ypformat.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot/yparser/libknot_la-ypformat.lo -MD -MP -MF libknot/yparser/$(DEPDIR)/libknot_la-ypformat.Tpo -c -o libknot/yparser/libknot_la-ypformat.lo `test -f 'libknot/yparser/ypformat.c' || echo '$(srcdir)/'`libknot/yparser/ypformat.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libknot/yparser/$(DEPDIR)/libknot_la-ypformat.Tpo libknot/yparser/$(DEPDIR)/libknot_la-ypformat.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libknot/yparser/ypformat.c' object='libknot/yparser/libknot_la-ypformat.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot/yparser/libknot_la-ypformat.lo `test -f 'libknot/yparser/ypformat.c' || echo '$(srcdir)/'`libknot/yparser/ypformat.c
+
+libknot/yparser/libknot_la-ypschema.lo: libknot/yparser/ypschema.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot/yparser/libknot_la-ypschema.lo -MD -MP -MF libknot/yparser/$(DEPDIR)/libknot_la-ypschema.Tpo -c -o libknot/yparser/libknot_la-ypschema.lo `test -f 'libknot/yparser/ypschema.c' || echo '$(srcdir)/'`libknot/yparser/ypschema.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libknot/yparser/$(DEPDIR)/libknot_la-ypschema.Tpo libknot/yparser/$(DEPDIR)/libknot_la-ypschema.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libknot/yparser/ypschema.c' object='libknot/yparser/libknot_la-ypschema.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot/yparser/libknot_la-ypschema.lo `test -f 'libknot/yparser/ypschema.c' || echo '$(srcdir)/'`libknot/yparser/ypschema.c
+
+libknot/yparser/libknot_la-yptrafo.lo: libknot/yparser/yptrafo.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot/yparser/libknot_la-yptrafo.lo -MD -MP -MF libknot/yparser/$(DEPDIR)/libknot_la-yptrafo.Tpo -c -o libknot/yparser/libknot_la-yptrafo.lo `test -f 'libknot/yparser/yptrafo.c' || echo '$(srcdir)/'`libknot/yparser/yptrafo.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libknot/yparser/$(DEPDIR)/libknot_la-yptrafo.Tpo libknot/yparser/$(DEPDIR)/libknot_la-yptrafo.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libknot/yparser/yptrafo.c' object='libknot/yparser/libknot_la-yptrafo.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot/yparser/libknot_la-yptrafo.lo `test -f 'libknot/yparser/yptrafo.c' || echo '$(srcdir)/'`libknot/yparser/yptrafo.c
+
+knot/conf/libknotd_la-base.lo: knot/conf/base.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/conf/libknotd_la-base.lo -MD -MP -MF knot/conf/$(DEPDIR)/libknotd_la-base.Tpo -c -o knot/conf/libknotd_la-base.lo `test -f 'knot/conf/base.c' || echo '$(srcdir)/'`knot/conf/base.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/conf/$(DEPDIR)/libknotd_la-base.Tpo knot/conf/$(DEPDIR)/libknotd_la-base.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/conf/base.c' object='knot/conf/libknotd_la-base.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/conf/libknotd_la-base.lo `test -f 'knot/conf/base.c' || echo '$(srcdir)/'`knot/conf/base.c
+
+knot/conf/libknotd_la-conf.lo: knot/conf/conf.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/conf/libknotd_la-conf.lo -MD -MP -MF knot/conf/$(DEPDIR)/libknotd_la-conf.Tpo -c -o knot/conf/libknotd_la-conf.lo `test -f 'knot/conf/conf.c' || echo '$(srcdir)/'`knot/conf/conf.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/conf/$(DEPDIR)/libknotd_la-conf.Tpo knot/conf/$(DEPDIR)/libknotd_la-conf.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/conf/conf.c' object='knot/conf/libknotd_la-conf.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/conf/libknotd_la-conf.lo `test -f 'knot/conf/conf.c' || echo '$(srcdir)/'`knot/conf/conf.c
+
+knot/conf/libknotd_la-confdb.lo: knot/conf/confdb.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/conf/libknotd_la-confdb.lo -MD -MP -MF knot/conf/$(DEPDIR)/libknotd_la-confdb.Tpo -c -o knot/conf/libknotd_la-confdb.lo `test -f 'knot/conf/confdb.c' || echo '$(srcdir)/'`knot/conf/confdb.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/conf/$(DEPDIR)/libknotd_la-confdb.Tpo knot/conf/$(DEPDIR)/libknotd_la-confdb.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/conf/confdb.c' object='knot/conf/libknotd_la-confdb.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/conf/libknotd_la-confdb.lo `test -f 'knot/conf/confdb.c' || echo '$(srcdir)/'`knot/conf/confdb.c
+
+knot/conf/libknotd_la-confio.lo: knot/conf/confio.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/conf/libknotd_la-confio.lo -MD -MP -MF knot/conf/$(DEPDIR)/libknotd_la-confio.Tpo -c -o knot/conf/libknotd_la-confio.lo `test -f 'knot/conf/confio.c' || echo '$(srcdir)/'`knot/conf/confio.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/conf/$(DEPDIR)/libknotd_la-confio.Tpo knot/conf/$(DEPDIR)/libknotd_la-confio.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/conf/confio.c' object='knot/conf/libknotd_la-confio.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/conf/libknotd_la-confio.lo `test -f 'knot/conf/confio.c' || echo '$(srcdir)/'`knot/conf/confio.c
+
+knot/conf/libknotd_la-migration.lo: knot/conf/migration.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/conf/libknotd_la-migration.lo -MD -MP -MF knot/conf/$(DEPDIR)/libknotd_la-migration.Tpo -c -o knot/conf/libknotd_la-migration.lo `test -f 'knot/conf/migration.c' || echo '$(srcdir)/'`knot/conf/migration.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/conf/$(DEPDIR)/libknotd_la-migration.Tpo knot/conf/$(DEPDIR)/libknotd_la-migration.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/conf/migration.c' object='knot/conf/libknotd_la-migration.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/conf/libknotd_la-migration.lo `test -f 'knot/conf/migration.c' || echo '$(srcdir)/'`knot/conf/migration.c
+
+knot/conf/libknotd_la-module.lo: knot/conf/module.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/conf/libknotd_la-module.lo -MD -MP -MF knot/conf/$(DEPDIR)/libknotd_la-module.Tpo -c -o knot/conf/libknotd_la-module.lo `test -f 'knot/conf/module.c' || echo '$(srcdir)/'`knot/conf/module.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/conf/$(DEPDIR)/libknotd_la-module.Tpo knot/conf/$(DEPDIR)/libknotd_la-module.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/conf/module.c' object='knot/conf/libknotd_la-module.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/conf/libknotd_la-module.lo `test -f 'knot/conf/module.c' || echo '$(srcdir)/'`knot/conf/module.c
+
+knot/conf/libknotd_la-schema.lo: knot/conf/schema.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/conf/libknotd_la-schema.lo -MD -MP -MF knot/conf/$(DEPDIR)/libknotd_la-schema.Tpo -c -o knot/conf/libknotd_la-schema.lo `test -f 'knot/conf/schema.c' || echo '$(srcdir)/'`knot/conf/schema.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/conf/$(DEPDIR)/libknotd_la-schema.Tpo knot/conf/$(DEPDIR)/libknotd_la-schema.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/conf/schema.c' object='knot/conf/libknotd_la-schema.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/conf/libknotd_la-schema.lo `test -f 'knot/conf/schema.c' || echo '$(srcdir)/'`knot/conf/schema.c
+
+knot/conf/libknotd_la-tools.lo: knot/conf/tools.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/conf/libknotd_la-tools.lo -MD -MP -MF knot/conf/$(DEPDIR)/libknotd_la-tools.Tpo -c -o knot/conf/libknotd_la-tools.lo `test -f 'knot/conf/tools.c' || echo '$(srcdir)/'`knot/conf/tools.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/conf/$(DEPDIR)/libknotd_la-tools.Tpo knot/conf/$(DEPDIR)/libknotd_la-tools.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/conf/tools.c' object='knot/conf/libknotd_la-tools.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/conf/libknotd_la-tools.lo `test -f 'knot/conf/tools.c' || echo '$(srcdir)/'`knot/conf/tools.c
+
+knot/ctl/libknotd_la-commands.lo: knot/ctl/commands.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/ctl/libknotd_la-commands.lo -MD -MP -MF knot/ctl/$(DEPDIR)/libknotd_la-commands.Tpo -c -o knot/ctl/libknotd_la-commands.lo `test -f 'knot/ctl/commands.c' || echo '$(srcdir)/'`knot/ctl/commands.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/ctl/$(DEPDIR)/libknotd_la-commands.Tpo knot/ctl/$(DEPDIR)/libknotd_la-commands.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/ctl/commands.c' object='knot/ctl/libknotd_la-commands.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/ctl/libknotd_la-commands.lo `test -f 'knot/ctl/commands.c' || echo '$(srcdir)/'`knot/ctl/commands.c
+
+knot/ctl/libknotd_la-process.lo: knot/ctl/process.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/ctl/libknotd_la-process.lo -MD -MP -MF knot/ctl/$(DEPDIR)/libknotd_la-process.Tpo -c -o knot/ctl/libknotd_la-process.lo `test -f 'knot/ctl/process.c' || echo '$(srcdir)/'`knot/ctl/process.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/ctl/$(DEPDIR)/libknotd_la-process.Tpo knot/ctl/$(DEPDIR)/libknotd_la-process.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/ctl/process.c' object='knot/ctl/libknotd_la-process.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/ctl/libknotd_la-process.lo `test -f 'knot/ctl/process.c' || echo '$(srcdir)/'`knot/ctl/process.c
+
+knot/dnssec/libknotd_la-context.lo: knot/dnssec/context.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/dnssec/libknotd_la-context.lo -MD -MP -MF knot/dnssec/$(DEPDIR)/libknotd_la-context.Tpo -c -o knot/dnssec/libknotd_la-context.lo `test -f 'knot/dnssec/context.c' || echo '$(srcdir)/'`knot/dnssec/context.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/dnssec/$(DEPDIR)/libknotd_la-context.Tpo knot/dnssec/$(DEPDIR)/libknotd_la-context.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/dnssec/context.c' object='knot/dnssec/libknotd_la-context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/dnssec/libknotd_la-context.lo `test -f 'knot/dnssec/context.c' || echo '$(srcdir)/'`knot/dnssec/context.c
+
+knot/dnssec/libknotd_la-ds_query.lo: knot/dnssec/ds_query.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/dnssec/libknotd_la-ds_query.lo -MD -MP -MF knot/dnssec/$(DEPDIR)/libknotd_la-ds_query.Tpo -c -o knot/dnssec/libknotd_la-ds_query.lo `test -f 'knot/dnssec/ds_query.c' || echo '$(srcdir)/'`knot/dnssec/ds_query.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/dnssec/$(DEPDIR)/libknotd_la-ds_query.Tpo knot/dnssec/$(DEPDIR)/libknotd_la-ds_query.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/dnssec/ds_query.c' object='knot/dnssec/libknotd_la-ds_query.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/dnssec/libknotd_la-ds_query.lo `test -f 'knot/dnssec/ds_query.c' || echo '$(srcdir)/'`knot/dnssec/ds_query.c
+
+knot/dnssec/kasp/libknotd_la-kasp_db.lo: knot/dnssec/kasp/kasp_db.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/dnssec/kasp/libknotd_la-kasp_db.lo -MD -MP -MF knot/dnssec/kasp/$(DEPDIR)/libknotd_la-kasp_db.Tpo -c -o knot/dnssec/kasp/libknotd_la-kasp_db.lo `test -f 'knot/dnssec/kasp/kasp_db.c' || echo '$(srcdir)/'`knot/dnssec/kasp/kasp_db.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/dnssec/kasp/$(DEPDIR)/libknotd_la-kasp_db.Tpo knot/dnssec/kasp/$(DEPDIR)/libknotd_la-kasp_db.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/dnssec/kasp/kasp_db.c' object='knot/dnssec/kasp/libknotd_la-kasp_db.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/dnssec/kasp/libknotd_la-kasp_db.lo `test -f 'knot/dnssec/kasp/kasp_db.c' || echo '$(srcdir)/'`knot/dnssec/kasp/kasp_db.c
+
+knot/dnssec/kasp/libknotd_la-kasp_zone.lo: knot/dnssec/kasp/kasp_zone.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/dnssec/kasp/libknotd_la-kasp_zone.lo -MD -MP -MF knot/dnssec/kasp/$(DEPDIR)/libknotd_la-kasp_zone.Tpo -c -o knot/dnssec/kasp/libknotd_la-kasp_zone.lo `test -f 'knot/dnssec/kasp/kasp_zone.c' || echo '$(srcdir)/'`knot/dnssec/kasp/kasp_zone.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/dnssec/kasp/$(DEPDIR)/libknotd_la-kasp_zone.Tpo knot/dnssec/kasp/$(DEPDIR)/libknotd_la-kasp_zone.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/dnssec/kasp/kasp_zone.c' object='knot/dnssec/kasp/libknotd_la-kasp_zone.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/dnssec/kasp/libknotd_la-kasp_zone.lo `test -f 'knot/dnssec/kasp/kasp_zone.c' || echo '$(srcdir)/'`knot/dnssec/kasp/kasp_zone.c
+
+knot/dnssec/kasp/libknotd_la-keystate.lo: knot/dnssec/kasp/keystate.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/dnssec/kasp/libknotd_la-keystate.lo -MD -MP -MF knot/dnssec/kasp/$(DEPDIR)/libknotd_la-keystate.Tpo -c -o knot/dnssec/kasp/libknotd_la-keystate.lo `test -f 'knot/dnssec/kasp/keystate.c' || echo '$(srcdir)/'`knot/dnssec/kasp/keystate.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/dnssec/kasp/$(DEPDIR)/libknotd_la-keystate.Tpo knot/dnssec/kasp/$(DEPDIR)/libknotd_la-keystate.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/dnssec/kasp/keystate.c' object='knot/dnssec/kasp/libknotd_la-keystate.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/dnssec/kasp/libknotd_la-keystate.lo `test -f 'knot/dnssec/kasp/keystate.c' || echo '$(srcdir)/'`knot/dnssec/kasp/keystate.c
+
+knot/dnssec/kasp/libknotd_la-keystore.lo: knot/dnssec/kasp/keystore.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/dnssec/kasp/libknotd_la-keystore.lo -MD -MP -MF knot/dnssec/kasp/$(DEPDIR)/libknotd_la-keystore.Tpo -c -o knot/dnssec/kasp/libknotd_la-keystore.lo `test -f 'knot/dnssec/kasp/keystore.c' || echo '$(srcdir)/'`knot/dnssec/kasp/keystore.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/dnssec/kasp/$(DEPDIR)/libknotd_la-keystore.Tpo knot/dnssec/kasp/$(DEPDIR)/libknotd_la-keystore.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/dnssec/kasp/keystore.c' object='knot/dnssec/kasp/libknotd_la-keystore.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/dnssec/kasp/libknotd_la-keystore.lo `test -f 'knot/dnssec/kasp/keystore.c' || echo '$(srcdir)/'`knot/dnssec/kasp/keystore.c
+
+knot/dnssec/libknotd_la-key-events.lo: knot/dnssec/key-events.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/dnssec/libknotd_la-key-events.lo -MD -MP -MF knot/dnssec/$(DEPDIR)/libknotd_la-key-events.Tpo -c -o knot/dnssec/libknotd_la-key-events.lo `test -f 'knot/dnssec/key-events.c' || echo '$(srcdir)/'`knot/dnssec/key-events.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/dnssec/$(DEPDIR)/libknotd_la-key-events.Tpo knot/dnssec/$(DEPDIR)/libknotd_la-key-events.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/dnssec/key-events.c' object='knot/dnssec/libknotd_la-key-events.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/dnssec/libknotd_la-key-events.lo `test -f 'knot/dnssec/key-events.c' || echo '$(srcdir)/'`knot/dnssec/key-events.c
+
+knot/dnssec/libknotd_la-nsec-chain.lo: knot/dnssec/nsec-chain.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/dnssec/libknotd_la-nsec-chain.lo -MD -MP -MF knot/dnssec/$(DEPDIR)/libknotd_la-nsec-chain.Tpo -c -o knot/dnssec/libknotd_la-nsec-chain.lo `test -f 'knot/dnssec/nsec-chain.c' || echo '$(srcdir)/'`knot/dnssec/nsec-chain.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/dnssec/$(DEPDIR)/libknotd_la-nsec-chain.Tpo knot/dnssec/$(DEPDIR)/libknotd_la-nsec-chain.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/dnssec/nsec-chain.c' object='knot/dnssec/libknotd_la-nsec-chain.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/dnssec/libknotd_la-nsec-chain.lo `test -f 'knot/dnssec/nsec-chain.c' || echo '$(srcdir)/'`knot/dnssec/nsec-chain.c
+
+knot/dnssec/libknotd_la-nsec3-chain.lo: knot/dnssec/nsec3-chain.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/dnssec/libknotd_la-nsec3-chain.lo -MD -MP -MF knot/dnssec/$(DEPDIR)/libknotd_la-nsec3-chain.Tpo -c -o knot/dnssec/libknotd_la-nsec3-chain.lo `test -f 'knot/dnssec/nsec3-chain.c' || echo '$(srcdir)/'`knot/dnssec/nsec3-chain.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/dnssec/$(DEPDIR)/libknotd_la-nsec3-chain.Tpo knot/dnssec/$(DEPDIR)/libknotd_la-nsec3-chain.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/dnssec/nsec3-chain.c' object='knot/dnssec/libknotd_la-nsec3-chain.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/dnssec/libknotd_la-nsec3-chain.lo `test -f 'knot/dnssec/nsec3-chain.c' || echo '$(srcdir)/'`knot/dnssec/nsec3-chain.c
+
+knot/dnssec/libknotd_la-policy.lo: knot/dnssec/policy.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/dnssec/libknotd_la-policy.lo -MD -MP -MF knot/dnssec/$(DEPDIR)/libknotd_la-policy.Tpo -c -o knot/dnssec/libknotd_la-policy.lo `test -f 'knot/dnssec/policy.c' || echo '$(srcdir)/'`knot/dnssec/policy.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/dnssec/$(DEPDIR)/libknotd_la-policy.Tpo knot/dnssec/$(DEPDIR)/libknotd_la-policy.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/dnssec/policy.c' object='knot/dnssec/libknotd_la-policy.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/dnssec/libknotd_la-policy.lo `test -f 'knot/dnssec/policy.c' || echo '$(srcdir)/'`knot/dnssec/policy.c
+
+knot/dnssec/libknotd_la-rrset-sign.lo: knot/dnssec/rrset-sign.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/dnssec/libknotd_la-rrset-sign.lo -MD -MP -MF knot/dnssec/$(DEPDIR)/libknotd_la-rrset-sign.Tpo -c -o knot/dnssec/libknotd_la-rrset-sign.lo `test -f 'knot/dnssec/rrset-sign.c' || echo '$(srcdir)/'`knot/dnssec/rrset-sign.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/dnssec/$(DEPDIR)/libknotd_la-rrset-sign.Tpo knot/dnssec/$(DEPDIR)/libknotd_la-rrset-sign.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/dnssec/rrset-sign.c' object='knot/dnssec/libknotd_la-rrset-sign.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/dnssec/libknotd_la-rrset-sign.lo `test -f 'knot/dnssec/rrset-sign.c' || echo '$(srcdir)/'`knot/dnssec/rrset-sign.c
+
+knot/dnssec/libknotd_la-zone-events.lo: knot/dnssec/zone-events.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/dnssec/libknotd_la-zone-events.lo -MD -MP -MF knot/dnssec/$(DEPDIR)/libknotd_la-zone-events.Tpo -c -o knot/dnssec/libknotd_la-zone-events.lo `test -f 'knot/dnssec/zone-events.c' || echo '$(srcdir)/'`knot/dnssec/zone-events.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/dnssec/$(DEPDIR)/libknotd_la-zone-events.Tpo knot/dnssec/$(DEPDIR)/libknotd_la-zone-events.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/dnssec/zone-events.c' object='knot/dnssec/libknotd_la-zone-events.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/dnssec/libknotd_la-zone-events.lo `test -f 'knot/dnssec/zone-events.c' || echo '$(srcdir)/'`knot/dnssec/zone-events.c
+
+knot/dnssec/libknotd_la-zone-keys.lo: knot/dnssec/zone-keys.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/dnssec/libknotd_la-zone-keys.lo -MD -MP -MF knot/dnssec/$(DEPDIR)/libknotd_la-zone-keys.Tpo -c -o knot/dnssec/libknotd_la-zone-keys.lo `test -f 'knot/dnssec/zone-keys.c' || echo '$(srcdir)/'`knot/dnssec/zone-keys.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/dnssec/$(DEPDIR)/libknotd_la-zone-keys.Tpo knot/dnssec/$(DEPDIR)/libknotd_la-zone-keys.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/dnssec/zone-keys.c' object='knot/dnssec/libknotd_la-zone-keys.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/dnssec/libknotd_la-zone-keys.lo `test -f 'knot/dnssec/zone-keys.c' || echo '$(srcdir)/'`knot/dnssec/zone-keys.c
+
+knot/dnssec/libknotd_la-zone-nsec.lo: knot/dnssec/zone-nsec.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/dnssec/libknotd_la-zone-nsec.lo -MD -MP -MF knot/dnssec/$(DEPDIR)/libknotd_la-zone-nsec.Tpo -c -o knot/dnssec/libknotd_la-zone-nsec.lo `test -f 'knot/dnssec/zone-nsec.c' || echo '$(srcdir)/'`knot/dnssec/zone-nsec.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/dnssec/$(DEPDIR)/libknotd_la-zone-nsec.Tpo knot/dnssec/$(DEPDIR)/libknotd_la-zone-nsec.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/dnssec/zone-nsec.c' object='knot/dnssec/libknotd_la-zone-nsec.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/dnssec/libknotd_la-zone-nsec.lo `test -f 'knot/dnssec/zone-nsec.c' || echo '$(srcdir)/'`knot/dnssec/zone-nsec.c
+
+knot/dnssec/libknotd_la-zone-sign.lo: knot/dnssec/zone-sign.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/dnssec/libknotd_la-zone-sign.lo -MD -MP -MF knot/dnssec/$(DEPDIR)/libknotd_la-zone-sign.Tpo -c -o knot/dnssec/libknotd_la-zone-sign.lo `test -f 'knot/dnssec/zone-sign.c' || echo '$(srcdir)/'`knot/dnssec/zone-sign.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/dnssec/$(DEPDIR)/libknotd_la-zone-sign.Tpo knot/dnssec/$(DEPDIR)/libknotd_la-zone-sign.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/dnssec/zone-sign.c' object='knot/dnssec/libknotd_la-zone-sign.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/dnssec/libknotd_la-zone-sign.lo `test -f 'knot/dnssec/zone-sign.c' || echo '$(srcdir)/'`knot/dnssec/zone-sign.c
+
+knot/events/libknotd_la-events.lo: knot/events/events.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/events/libknotd_la-events.lo -MD -MP -MF knot/events/$(DEPDIR)/libknotd_la-events.Tpo -c -o knot/events/libknotd_la-events.lo `test -f 'knot/events/events.c' || echo '$(srcdir)/'`knot/events/events.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/events/$(DEPDIR)/libknotd_la-events.Tpo knot/events/$(DEPDIR)/libknotd_la-events.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/events/events.c' object='knot/events/libknotd_la-events.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/events/libknotd_la-events.lo `test -f 'knot/events/events.c' || echo '$(srcdir)/'`knot/events/events.c
+
+knot/events/handlers/libknotd_la-dnssec.lo: knot/events/handlers/dnssec.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/events/handlers/libknotd_la-dnssec.lo -MD -MP -MF knot/events/handlers/$(DEPDIR)/libknotd_la-dnssec.Tpo -c -o knot/events/handlers/libknotd_la-dnssec.lo `test -f 'knot/events/handlers/dnssec.c' || echo '$(srcdir)/'`knot/events/handlers/dnssec.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/events/handlers/$(DEPDIR)/libknotd_la-dnssec.Tpo knot/events/handlers/$(DEPDIR)/libknotd_la-dnssec.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/events/handlers/dnssec.c' object='knot/events/handlers/libknotd_la-dnssec.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/events/handlers/libknotd_la-dnssec.lo `test -f 'knot/events/handlers/dnssec.c' || echo '$(srcdir)/'`knot/events/handlers/dnssec.c
+
+knot/events/handlers/libknotd_la-expire.lo: knot/events/handlers/expire.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/events/handlers/libknotd_la-expire.lo -MD -MP -MF knot/events/handlers/$(DEPDIR)/libknotd_la-expire.Tpo -c -o knot/events/handlers/libknotd_la-expire.lo `test -f 'knot/events/handlers/expire.c' || echo '$(srcdir)/'`knot/events/handlers/expire.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/events/handlers/$(DEPDIR)/libknotd_la-expire.Tpo knot/events/handlers/$(DEPDIR)/libknotd_la-expire.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/events/handlers/expire.c' object='knot/events/handlers/libknotd_la-expire.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/events/handlers/libknotd_la-expire.lo `test -f 'knot/events/handlers/expire.c' || echo '$(srcdir)/'`knot/events/handlers/expire.c
+
+knot/events/handlers/libknotd_la-flush.lo: knot/events/handlers/flush.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/events/handlers/libknotd_la-flush.lo -MD -MP -MF knot/events/handlers/$(DEPDIR)/libknotd_la-flush.Tpo -c -o knot/events/handlers/libknotd_la-flush.lo `test -f 'knot/events/handlers/flush.c' || echo '$(srcdir)/'`knot/events/handlers/flush.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/events/handlers/$(DEPDIR)/libknotd_la-flush.Tpo knot/events/handlers/$(DEPDIR)/libknotd_la-flush.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/events/handlers/flush.c' object='knot/events/handlers/libknotd_la-flush.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/events/handlers/libknotd_la-flush.lo `test -f 'knot/events/handlers/flush.c' || echo '$(srcdir)/'`knot/events/handlers/flush.c
+
+knot/events/handlers/libknotd_la-freeze_thaw.lo: knot/events/handlers/freeze_thaw.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/events/handlers/libknotd_la-freeze_thaw.lo -MD -MP -MF knot/events/handlers/$(DEPDIR)/libknotd_la-freeze_thaw.Tpo -c -o knot/events/handlers/libknotd_la-freeze_thaw.lo `test -f 'knot/events/handlers/freeze_thaw.c' || echo '$(srcdir)/'`knot/events/handlers/freeze_thaw.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/events/handlers/$(DEPDIR)/libknotd_la-freeze_thaw.Tpo knot/events/handlers/$(DEPDIR)/libknotd_la-freeze_thaw.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/events/handlers/freeze_thaw.c' object='knot/events/handlers/libknotd_la-freeze_thaw.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/events/handlers/libknotd_la-freeze_thaw.lo `test -f 'knot/events/handlers/freeze_thaw.c' || echo '$(srcdir)/'`knot/events/handlers/freeze_thaw.c
+
+knot/events/handlers/libknotd_la-load.lo: knot/events/handlers/load.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/events/handlers/libknotd_la-load.lo -MD -MP -MF knot/events/handlers/$(DEPDIR)/libknotd_la-load.Tpo -c -o knot/events/handlers/libknotd_la-load.lo `test -f 'knot/events/handlers/load.c' || echo '$(srcdir)/'`knot/events/handlers/load.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/events/handlers/$(DEPDIR)/libknotd_la-load.Tpo knot/events/handlers/$(DEPDIR)/libknotd_la-load.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/events/handlers/load.c' object='knot/events/handlers/libknotd_la-load.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/events/handlers/libknotd_la-load.lo `test -f 'knot/events/handlers/load.c' || echo '$(srcdir)/'`knot/events/handlers/load.c
+
+knot/events/handlers/libknotd_la-notify.lo: knot/events/handlers/notify.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/events/handlers/libknotd_la-notify.lo -MD -MP -MF knot/events/handlers/$(DEPDIR)/libknotd_la-notify.Tpo -c -o knot/events/handlers/libknotd_la-notify.lo `test -f 'knot/events/handlers/notify.c' || echo '$(srcdir)/'`knot/events/handlers/notify.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/events/handlers/$(DEPDIR)/libknotd_la-notify.Tpo knot/events/handlers/$(DEPDIR)/libknotd_la-notify.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/events/handlers/notify.c' object='knot/events/handlers/libknotd_la-notify.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/events/handlers/libknotd_la-notify.lo `test -f 'knot/events/handlers/notify.c' || echo '$(srcdir)/'`knot/events/handlers/notify.c
+
+knot/events/handlers/libknotd_la-nsec3resalt.lo: knot/events/handlers/nsec3resalt.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/events/handlers/libknotd_la-nsec3resalt.lo -MD -MP -MF knot/events/handlers/$(DEPDIR)/libknotd_la-nsec3resalt.Tpo -c -o knot/events/handlers/libknotd_la-nsec3resalt.lo `test -f 'knot/events/handlers/nsec3resalt.c' || echo '$(srcdir)/'`knot/events/handlers/nsec3resalt.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/events/handlers/$(DEPDIR)/libknotd_la-nsec3resalt.Tpo knot/events/handlers/$(DEPDIR)/libknotd_la-nsec3resalt.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/events/handlers/nsec3resalt.c' object='knot/events/handlers/libknotd_la-nsec3resalt.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/events/handlers/libknotd_la-nsec3resalt.lo `test -f 'knot/events/handlers/nsec3resalt.c' || echo '$(srcdir)/'`knot/events/handlers/nsec3resalt.c
+
+knot/events/handlers/libknotd_la-refresh.lo: knot/events/handlers/refresh.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/events/handlers/libknotd_la-refresh.lo -MD -MP -MF knot/events/handlers/$(DEPDIR)/libknotd_la-refresh.Tpo -c -o knot/events/handlers/libknotd_la-refresh.lo `test -f 'knot/events/handlers/refresh.c' || echo '$(srcdir)/'`knot/events/handlers/refresh.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/events/handlers/$(DEPDIR)/libknotd_la-refresh.Tpo knot/events/handlers/$(DEPDIR)/libknotd_la-refresh.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/events/handlers/refresh.c' object='knot/events/handlers/libknotd_la-refresh.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/events/handlers/libknotd_la-refresh.lo `test -f 'knot/events/handlers/refresh.c' || echo '$(srcdir)/'`knot/events/handlers/refresh.c
+
+knot/events/handlers/libknotd_la-update.lo: knot/events/handlers/update.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/events/handlers/libknotd_la-update.lo -MD -MP -MF knot/events/handlers/$(DEPDIR)/libknotd_la-update.Tpo -c -o knot/events/handlers/libknotd_la-update.lo `test -f 'knot/events/handlers/update.c' || echo '$(srcdir)/'`knot/events/handlers/update.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/events/handlers/$(DEPDIR)/libknotd_la-update.Tpo knot/events/handlers/$(DEPDIR)/libknotd_la-update.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/events/handlers/update.c' object='knot/events/handlers/libknotd_la-update.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/events/handlers/libknotd_la-update.lo `test -f 'knot/events/handlers/update.c' || echo '$(srcdir)/'`knot/events/handlers/update.c
+
+knot/events/handlers/libknotd_la-parent_ds_query.lo: knot/events/handlers/parent_ds_query.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/events/handlers/libknotd_la-parent_ds_query.lo -MD -MP -MF knot/events/handlers/$(DEPDIR)/libknotd_la-parent_ds_query.Tpo -c -o knot/events/handlers/libknotd_la-parent_ds_query.lo `test -f 'knot/events/handlers/parent_ds_query.c' || echo '$(srcdir)/'`knot/events/handlers/parent_ds_query.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/events/handlers/$(DEPDIR)/libknotd_la-parent_ds_query.Tpo knot/events/handlers/$(DEPDIR)/libknotd_la-parent_ds_query.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/events/handlers/parent_ds_query.c' object='knot/events/handlers/libknotd_la-parent_ds_query.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/events/handlers/libknotd_la-parent_ds_query.lo `test -f 'knot/events/handlers/parent_ds_query.c' || echo '$(srcdir)/'`knot/events/handlers/parent_ds_query.c
+
+knot/events/libknotd_la-replan.lo: knot/events/replan.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/events/libknotd_la-replan.lo -MD -MP -MF knot/events/$(DEPDIR)/libknotd_la-replan.Tpo -c -o knot/events/libknotd_la-replan.lo `test -f 'knot/events/replan.c' || echo '$(srcdir)/'`knot/events/replan.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/events/$(DEPDIR)/libknotd_la-replan.Tpo knot/events/$(DEPDIR)/libknotd_la-replan.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/events/replan.c' object='knot/events/libknotd_la-replan.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/events/libknotd_la-replan.lo `test -f 'knot/events/replan.c' || echo '$(srcdir)/'`knot/events/replan.c
+
+knot/nameserver/libknotd_la-axfr.lo: knot/nameserver/axfr.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/nameserver/libknotd_la-axfr.lo -MD -MP -MF knot/nameserver/$(DEPDIR)/libknotd_la-axfr.Tpo -c -o knot/nameserver/libknotd_la-axfr.lo `test -f 'knot/nameserver/axfr.c' || echo '$(srcdir)/'`knot/nameserver/axfr.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/nameserver/$(DEPDIR)/libknotd_la-axfr.Tpo knot/nameserver/$(DEPDIR)/libknotd_la-axfr.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/nameserver/axfr.c' object='knot/nameserver/libknotd_la-axfr.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/nameserver/libknotd_la-axfr.lo `test -f 'knot/nameserver/axfr.c' || echo '$(srcdir)/'`knot/nameserver/axfr.c
+
+knot/nameserver/libknotd_la-chaos.lo: knot/nameserver/chaos.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/nameserver/libknotd_la-chaos.lo -MD -MP -MF knot/nameserver/$(DEPDIR)/libknotd_la-chaos.Tpo -c -o knot/nameserver/libknotd_la-chaos.lo `test -f 'knot/nameserver/chaos.c' || echo '$(srcdir)/'`knot/nameserver/chaos.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/nameserver/$(DEPDIR)/libknotd_la-chaos.Tpo knot/nameserver/$(DEPDIR)/libknotd_la-chaos.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/nameserver/chaos.c' object='knot/nameserver/libknotd_la-chaos.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/nameserver/libknotd_la-chaos.lo `test -f 'knot/nameserver/chaos.c' || echo '$(srcdir)/'`knot/nameserver/chaos.c
+
+knot/nameserver/libknotd_la-internet.lo: knot/nameserver/internet.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/nameserver/libknotd_la-internet.lo -MD -MP -MF knot/nameserver/$(DEPDIR)/libknotd_la-internet.Tpo -c -o knot/nameserver/libknotd_la-internet.lo `test -f 'knot/nameserver/internet.c' || echo '$(srcdir)/'`knot/nameserver/internet.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/nameserver/$(DEPDIR)/libknotd_la-internet.Tpo knot/nameserver/$(DEPDIR)/libknotd_la-internet.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/nameserver/internet.c' object='knot/nameserver/libknotd_la-internet.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/nameserver/libknotd_la-internet.lo `test -f 'knot/nameserver/internet.c' || echo '$(srcdir)/'`knot/nameserver/internet.c
+
+knot/nameserver/libknotd_la-ixfr.lo: knot/nameserver/ixfr.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/nameserver/libknotd_la-ixfr.lo -MD -MP -MF knot/nameserver/$(DEPDIR)/libknotd_la-ixfr.Tpo -c -o knot/nameserver/libknotd_la-ixfr.lo `test -f 'knot/nameserver/ixfr.c' || echo '$(srcdir)/'`knot/nameserver/ixfr.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/nameserver/$(DEPDIR)/libknotd_la-ixfr.Tpo knot/nameserver/$(DEPDIR)/libknotd_la-ixfr.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/nameserver/ixfr.c' object='knot/nameserver/libknotd_la-ixfr.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/nameserver/libknotd_la-ixfr.lo `test -f 'knot/nameserver/ixfr.c' || echo '$(srcdir)/'`knot/nameserver/ixfr.c
+
+knot/nameserver/libknotd_la-notify.lo: knot/nameserver/notify.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/nameserver/libknotd_la-notify.lo -MD -MP -MF knot/nameserver/$(DEPDIR)/libknotd_la-notify.Tpo -c -o knot/nameserver/libknotd_la-notify.lo `test -f 'knot/nameserver/notify.c' || echo '$(srcdir)/'`knot/nameserver/notify.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/nameserver/$(DEPDIR)/libknotd_la-notify.Tpo knot/nameserver/$(DEPDIR)/libknotd_la-notify.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/nameserver/notify.c' object='knot/nameserver/libknotd_la-notify.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/nameserver/libknotd_la-notify.lo `test -f 'knot/nameserver/notify.c' || echo '$(srcdir)/'`knot/nameserver/notify.c
+
+knot/nameserver/libknotd_la-nsec_proofs.lo: knot/nameserver/nsec_proofs.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/nameserver/libknotd_la-nsec_proofs.lo -MD -MP -MF knot/nameserver/$(DEPDIR)/libknotd_la-nsec_proofs.Tpo -c -o knot/nameserver/libknotd_la-nsec_proofs.lo `test -f 'knot/nameserver/nsec_proofs.c' || echo '$(srcdir)/'`knot/nameserver/nsec_proofs.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/nameserver/$(DEPDIR)/libknotd_la-nsec_proofs.Tpo knot/nameserver/$(DEPDIR)/libknotd_la-nsec_proofs.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/nameserver/nsec_proofs.c' object='knot/nameserver/libknotd_la-nsec_proofs.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/nameserver/libknotd_la-nsec_proofs.lo `test -f 'knot/nameserver/nsec_proofs.c' || echo '$(srcdir)/'`knot/nameserver/nsec_proofs.c
+
+knot/nameserver/libknotd_la-process_query.lo: knot/nameserver/process_query.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/nameserver/libknotd_la-process_query.lo -MD -MP -MF knot/nameserver/$(DEPDIR)/libknotd_la-process_query.Tpo -c -o knot/nameserver/libknotd_la-process_query.lo `test -f 'knot/nameserver/process_query.c' || echo '$(srcdir)/'`knot/nameserver/process_query.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/nameserver/$(DEPDIR)/libknotd_la-process_query.Tpo knot/nameserver/$(DEPDIR)/libknotd_la-process_query.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/nameserver/process_query.c' object='knot/nameserver/libknotd_la-process_query.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/nameserver/libknotd_la-process_query.lo `test -f 'knot/nameserver/process_query.c' || echo '$(srcdir)/'`knot/nameserver/process_query.c
+
+knot/nameserver/libknotd_la-query_module.lo: knot/nameserver/query_module.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/nameserver/libknotd_la-query_module.lo -MD -MP -MF knot/nameserver/$(DEPDIR)/libknotd_la-query_module.Tpo -c -o knot/nameserver/libknotd_la-query_module.lo `test -f 'knot/nameserver/query_module.c' || echo '$(srcdir)/'`knot/nameserver/query_module.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/nameserver/$(DEPDIR)/libknotd_la-query_module.Tpo knot/nameserver/$(DEPDIR)/libknotd_la-query_module.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/nameserver/query_module.c' object='knot/nameserver/libknotd_la-query_module.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/nameserver/libknotd_la-query_module.lo `test -f 'knot/nameserver/query_module.c' || echo '$(srcdir)/'`knot/nameserver/query_module.c
+
+knot/nameserver/libknotd_la-tsig_ctx.lo: knot/nameserver/tsig_ctx.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/nameserver/libknotd_la-tsig_ctx.lo -MD -MP -MF knot/nameserver/$(DEPDIR)/libknotd_la-tsig_ctx.Tpo -c -o knot/nameserver/libknotd_la-tsig_ctx.lo `test -f 'knot/nameserver/tsig_ctx.c' || echo '$(srcdir)/'`knot/nameserver/tsig_ctx.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/nameserver/$(DEPDIR)/libknotd_la-tsig_ctx.Tpo knot/nameserver/$(DEPDIR)/libknotd_la-tsig_ctx.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/nameserver/tsig_ctx.c' object='knot/nameserver/libknotd_la-tsig_ctx.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/nameserver/libknotd_la-tsig_ctx.lo `test -f 'knot/nameserver/tsig_ctx.c' || echo '$(srcdir)/'`knot/nameserver/tsig_ctx.c
+
+knot/nameserver/libknotd_la-update.lo: knot/nameserver/update.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/nameserver/libknotd_la-update.lo -MD -MP -MF knot/nameserver/$(DEPDIR)/libknotd_la-update.Tpo -c -o knot/nameserver/libknotd_la-update.lo `test -f 'knot/nameserver/update.c' || echo '$(srcdir)/'`knot/nameserver/update.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/nameserver/$(DEPDIR)/libknotd_la-update.Tpo knot/nameserver/$(DEPDIR)/libknotd_la-update.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/nameserver/update.c' object='knot/nameserver/libknotd_la-update.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/nameserver/libknotd_la-update.lo `test -f 'knot/nameserver/update.c' || echo '$(srcdir)/'`knot/nameserver/update.c
+
+knot/nameserver/libknotd_la-xfr.lo: knot/nameserver/xfr.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/nameserver/libknotd_la-xfr.lo -MD -MP -MF knot/nameserver/$(DEPDIR)/libknotd_la-xfr.Tpo -c -o knot/nameserver/libknotd_la-xfr.lo `test -f 'knot/nameserver/xfr.c' || echo '$(srcdir)/'`knot/nameserver/xfr.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/nameserver/$(DEPDIR)/libknotd_la-xfr.Tpo knot/nameserver/$(DEPDIR)/libknotd_la-xfr.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/nameserver/xfr.c' object='knot/nameserver/libknotd_la-xfr.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/nameserver/libknotd_la-xfr.lo `test -f 'knot/nameserver/xfr.c' || echo '$(srcdir)/'`knot/nameserver/xfr.c
+
+knot/query/libknotd_la-capture.lo: knot/query/capture.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/query/libknotd_la-capture.lo -MD -MP -MF knot/query/$(DEPDIR)/libknotd_la-capture.Tpo -c -o knot/query/libknotd_la-capture.lo `test -f 'knot/query/capture.c' || echo '$(srcdir)/'`knot/query/capture.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/query/$(DEPDIR)/libknotd_la-capture.Tpo knot/query/$(DEPDIR)/libknotd_la-capture.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/query/capture.c' object='knot/query/libknotd_la-capture.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/query/libknotd_la-capture.lo `test -f 'knot/query/capture.c' || echo '$(srcdir)/'`knot/query/capture.c
+
+knot/query/libknotd_la-query.lo: knot/query/query.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/query/libknotd_la-query.lo -MD -MP -MF knot/query/$(DEPDIR)/libknotd_la-query.Tpo -c -o knot/query/libknotd_la-query.lo `test -f 'knot/query/query.c' || echo '$(srcdir)/'`knot/query/query.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/query/$(DEPDIR)/libknotd_la-query.Tpo knot/query/$(DEPDIR)/libknotd_la-query.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/query/query.c' object='knot/query/libknotd_la-query.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/query/libknotd_la-query.lo `test -f 'knot/query/query.c' || echo '$(srcdir)/'`knot/query/query.c
+
+knot/query/libknotd_la-requestor.lo: knot/query/requestor.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/query/libknotd_la-requestor.lo -MD -MP -MF knot/query/$(DEPDIR)/libknotd_la-requestor.Tpo -c -o knot/query/libknotd_la-requestor.lo `test -f 'knot/query/requestor.c' || echo '$(srcdir)/'`knot/query/requestor.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/query/$(DEPDIR)/libknotd_la-requestor.Tpo knot/query/$(DEPDIR)/libknotd_la-requestor.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/query/requestor.c' object='knot/query/libknotd_la-requestor.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/query/libknotd_la-requestor.lo `test -f 'knot/query/requestor.c' || echo '$(srcdir)/'`knot/query/requestor.c
+
+knot/common/libknotd_la-evsched.lo: knot/common/evsched.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/common/libknotd_la-evsched.lo -MD -MP -MF knot/common/$(DEPDIR)/libknotd_la-evsched.Tpo -c -o knot/common/libknotd_la-evsched.lo `test -f 'knot/common/evsched.c' || echo '$(srcdir)/'`knot/common/evsched.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/common/$(DEPDIR)/libknotd_la-evsched.Tpo knot/common/$(DEPDIR)/libknotd_la-evsched.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/common/evsched.c' object='knot/common/libknotd_la-evsched.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/common/libknotd_la-evsched.lo `test -f 'knot/common/evsched.c' || echo '$(srcdir)/'`knot/common/evsched.c
+
+knot/common/libknotd_la-fdset.lo: knot/common/fdset.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/common/libknotd_la-fdset.lo -MD -MP -MF knot/common/$(DEPDIR)/libknotd_la-fdset.Tpo -c -o knot/common/libknotd_la-fdset.lo `test -f 'knot/common/fdset.c' || echo '$(srcdir)/'`knot/common/fdset.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/common/$(DEPDIR)/libknotd_la-fdset.Tpo knot/common/$(DEPDIR)/libknotd_la-fdset.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/common/fdset.c' object='knot/common/libknotd_la-fdset.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/common/libknotd_la-fdset.lo `test -f 'knot/common/fdset.c' || echo '$(srcdir)/'`knot/common/fdset.c
+
+knot/common/libknotd_la-log.lo: knot/common/log.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/common/libknotd_la-log.lo -MD -MP -MF knot/common/$(DEPDIR)/libknotd_la-log.Tpo -c -o knot/common/libknotd_la-log.lo `test -f 'knot/common/log.c' || echo '$(srcdir)/'`knot/common/log.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/common/$(DEPDIR)/libknotd_la-log.Tpo knot/common/$(DEPDIR)/libknotd_la-log.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/common/log.c' object='knot/common/libknotd_la-log.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/common/libknotd_la-log.lo `test -f 'knot/common/log.c' || echo '$(srcdir)/'`knot/common/log.c
+
+knot/common/libknotd_la-process.lo: knot/common/process.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/common/libknotd_la-process.lo -MD -MP -MF knot/common/$(DEPDIR)/libknotd_la-process.Tpo -c -o knot/common/libknotd_la-process.lo `test -f 'knot/common/process.c' || echo '$(srcdir)/'`knot/common/process.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/common/$(DEPDIR)/libknotd_la-process.Tpo knot/common/$(DEPDIR)/libknotd_la-process.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/common/process.c' object='knot/common/libknotd_la-process.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/common/libknotd_la-process.lo `test -f 'knot/common/process.c' || echo '$(srcdir)/'`knot/common/process.c
+
+knot/common/libknotd_la-ref.lo: knot/common/ref.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/common/libknotd_la-ref.lo -MD -MP -MF knot/common/$(DEPDIR)/libknotd_la-ref.Tpo -c -o knot/common/libknotd_la-ref.lo `test -f 'knot/common/ref.c' || echo '$(srcdir)/'`knot/common/ref.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/common/$(DEPDIR)/libknotd_la-ref.Tpo knot/common/$(DEPDIR)/libknotd_la-ref.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/common/ref.c' object='knot/common/libknotd_la-ref.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/common/libknotd_la-ref.lo `test -f 'knot/common/ref.c' || echo '$(srcdir)/'`knot/common/ref.c
+
+knot/common/libknotd_la-stats.lo: knot/common/stats.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/common/libknotd_la-stats.lo -MD -MP -MF knot/common/$(DEPDIR)/libknotd_la-stats.Tpo -c -o knot/common/libknotd_la-stats.lo `test -f 'knot/common/stats.c' || echo '$(srcdir)/'`knot/common/stats.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/common/$(DEPDIR)/libknotd_la-stats.Tpo knot/common/$(DEPDIR)/libknotd_la-stats.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/common/stats.c' object='knot/common/libknotd_la-stats.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/common/libknotd_la-stats.lo `test -f 'knot/common/stats.c' || echo '$(srcdir)/'`knot/common/stats.c
+
+knot/server/libknotd_la-dthreads.lo: knot/server/dthreads.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/server/libknotd_la-dthreads.lo -MD -MP -MF knot/server/$(DEPDIR)/libknotd_la-dthreads.Tpo -c -o knot/server/libknotd_la-dthreads.lo `test -f 'knot/server/dthreads.c' || echo '$(srcdir)/'`knot/server/dthreads.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/server/$(DEPDIR)/libknotd_la-dthreads.Tpo knot/server/$(DEPDIR)/libknotd_la-dthreads.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/server/dthreads.c' object='knot/server/libknotd_la-dthreads.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/server/libknotd_la-dthreads.lo `test -f 'knot/server/dthreads.c' || echo '$(srcdir)/'`knot/server/dthreads.c
+
+knot/journal/libknotd_la-chgset_ctx.lo: knot/journal/chgset_ctx.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/journal/libknotd_la-chgset_ctx.lo -MD -MP -MF knot/journal/$(DEPDIR)/libknotd_la-chgset_ctx.Tpo -c -o knot/journal/libknotd_la-chgset_ctx.lo `test -f 'knot/journal/chgset_ctx.c' || echo '$(srcdir)/'`knot/journal/chgset_ctx.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/journal/$(DEPDIR)/libknotd_la-chgset_ctx.Tpo knot/journal/$(DEPDIR)/libknotd_la-chgset_ctx.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/journal/chgset_ctx.c' object='knot/journal/libknotd_la-chgset_ctx.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/journal/libknotd_la-chgset_ctx.lo `test -f 'knot/journal/chgset_ctx.c' || echo '$(srcdir)/'`knot/journal/chgset_ctx.c
+
+knot/journal/libknotd_la-journal.lo: knot/journal/journal.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/journal/libknotd_la-journal.lo -MD -MP -MF knot/journal/$(DEPDIR)/libknotd_la-journal.Tpo -c -o knot/journal/libknotd_la-journal.lo `test -f 'knot/journal/journal.c' || echo '$(srcdir)/'`knot/journal/journal.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/journal/$(DEPDIR)/libknotd_la-journal.Tpo knot/journal/$(DEPDIR)/libknotd_la-journal.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/journal/journal.c' object='knot/journal/libknotd_la-journal.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/journal/libknotd_la-journal.lo `test -f 'knot/journal/journal.c' || echo '$(srcdir)/'`knot/journal/journal.c
+
+knot/journal/libknotd_la-serialization.lo: knot/journal/serialization.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/journal/libknotd_la-serialization.lo -MD -MP -MF knot/journal/$(DEPDIR)/libknotd_la-serialization.Tpo -c -o knot/journal/libknotd_la-serialization.lo `test -f 'knot/journal/serialization.c' || echo '$(srcdir)/'`knot/journal/serialization.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/journal/$(DEPDIR)/libknotd_la-serialization.Tpo knot/journal/$(DEPDIR)/libknotd_la-serialization.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/journal/serialization.c' object='knot/journal/libknotd_la-serialization.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/journal/libknotd_la-serialization.lo `test -f 'knot/journal/serialization.c' || echo '$(srcdir)/'`knot/journal/serialization.c
+
+knot/server/libknotd_la-server.lo: knot/server/server.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/server/libknotd_la-server.lo -MD -MP -MF knot/server/$(DEPDIR)/libknotd_la-server.Tpo -c -o knot/server/libknotd_la-server.lo `test -f 'knot/server/server.c' || echo '$(srcdir)/'`knot/server/server.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/server/$(DEPDIR)/libknotd_la-server.Tpo knot/server/$(DEPDIR)/libknotd_la-server.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/server/server.c' object='knot/server/libknotd_la-server.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/server/libknotd_la-server.lo `test -f 'knot/server/server.c' || echo '$(srcdir)/'`knot/server/server.c
+
+knot/server/libknotd_la-tcp-handler.lo: knot/server/tcp-handler.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/server/libknotd_la-tcp-handler.lo -MD -MP -MF knot/server/$(DEPDIR)/libknotd_la-tcp-handler.Tpo -c -o knot/server/libknotd_la-tcp-handler.lo `test -f 'knot/server/tcp-handler.c' || echo '$(srcdir)/'`knot/server/tcp-handler.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/server/$(DEPDIR)/libknotd_la-tcp-handler.Tpo knot/server/$(DEPDIR)/libknotd_la-tcp-handler.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/server/tcp-handler.c' object='knot/server/libknotd_la-tcp-handler.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/server/libknotd_la-tcp-handler.lo `test -f 'knot/server/tcp-handler.c' || echo '$(srcdir)/'`knot/server/tcp-handler.c
+
+knot/server/libknotd_la-udp-handler.lo: knot/server/udp-handler.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/server/libknotd_la-udp-handler.lo -MD -MP -MF knot/server/$(DEPDIR)/libknotd_la-udp-handler.Tpo -c -o knot/server/libknotd_la-udp-handler.lo `test -f 'knot/server/udp-handler.c' || echo '$(srcdir)/'`knot/server/udp-handler.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/server/$(DEPDIR)/libknotd_la-udp-handler.Tpo knot/server/$(DEPDIR)/libknotd_la-udp-handler.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/server/udp-handler.c' object='knot/server/libknotd_la-udp-handler.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/server/libknotd_la-udp-handler.lo `test -f 'knot/server/udp-handler.c' || echo '$(srcdir)/'`knot/server/udp-handler.c
+
+knot/updates/libknotd_la-acl.lo: knot/updates/acl.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/updates/libknotd_la-acl.lo -MD -MP -MF knot/updates/$(DEPDIR)/libknotd_la-acl.Tpo -c -o knot/updates/libknotd_la-acl.lo `test -f 'knot/updates/acl.c' || echo '$(srcdir)/'`knot/updates/acl.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/updates/$(DEPDIR)/libknotd_la-acl.Tpo knot/updates/$(DEPDIR)/libknotd_la-acl.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/updates/acl.c' object='knot/updates/libknotd_la-acl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/updates/libknotd_la-acl.lo `test -f 'knot/updates/acl.c' || echo '$(srcdir)/'`knot/updates/acl.c
+
+knot/updates/libknotd_la-apply.lo: knot/updates/apply.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/updates/libknotd_la-apply.lo -MD -MP -MF knot/updates/$(DEPDIR)/libknotd_la-apply.Tpo -c -o knot/updates/libknotd_la-apply.lo `test -f 'knot/updates/apply.c' || echo '$(srcdir)/'`knot/updates/apply.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/updates/$(DEPDIR)/libknotd_la-apply.Tpo knot/updates/$(DEPDIR)/libknotd_la-apply.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/updates/apply.c' object='knot/updates/libknotd_la-apply.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/updates/libknotd_la-apply.lo `test -f 'knot/updates/apply.c' || echo '$(srcdir)/'`knot/updates/apply.c
+
+knot/updates/libknotd_la-changesets.lo: knot/updates/changesets.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/updates/libknotd_la-changesets.lo -MD -MP -MF knot/updates/$(DEPDIR)/libknotd_la-changesets.Tpo -c -o knot/updates/libknotd_la-changesets.lo `test -f 'knot/updates/changesets.c' || echo '$(srcdir)/'`knot/updates/changesets.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/updates/$(DEPDIR)/libknotd_la-changesets.Tpo knot/updates/$(DEPDIR)/libknotd_la-changesets.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/updates/changesets.c' object='knot/updates/libknotd_la-changesets.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/updates/libknotd_la-changesets.lo `test -f 'knot/updates/changesets.c' || echo '$(srcdir)/'`knot/updates/changesets.c
+
+knot/updates/libknotd_la-ddns.lo: knot/updates/ddns.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/updates/libknotd_la-ddns.lo -MD -MP -MF knot/updates/$(DEPDIR)/libknotd_la-ddns.Tpo -c -o knot/updates/libknotd_la-ddns.lo `test -f 'knot/updates/ddns.c' || echo '$(srcdir)/'`knot/updates/ddns.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/updates/$(DEPDIR)/libknotd_la-ddns.Tpo knot/updates/$(DEPDIR)/libknotd_la-ddns.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/updates/ddns.c' object='knot/updates/libknotd_la-ddns.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/updates/libknotd_la-ddns.lo `test -f 'knot/updates/ddns.c' || echo '$(srcdir)/'`knot/updates/ddns.c
+
+knot/updates/libknotd_la-zone-update.lo: knot/updates/zone-update.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/updates/libknotd_la-zone-update.lo -MD -MP -MF knot/updates/$(DEPDIR)/libknotd_la-zone-update.Tpo -c -o knot/updates/libknotd_la-zone-update.lo `test -f 'knot/updates/zone-update.c' || echo '$(srcdir)/'`knot/updates/zone-update.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/updates/$(DEPDIR)/libknotd_la-zone-update.Tpo knot/updates/$(DEPDIR)/libknotd_la-zone-update.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/updates/zone-update.c' object='knot/updates/libknotd_la-zone-update.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/updates/libknotd_la-zone-update.lo `test -f 'knot/updates/zone-update.c' || echo '$(srcdir)/'`knot/updates/zone-update.c
+
+knot/worker/libknotd_la-pool.lo: knot/worker/pool.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/worker/libknotd_la-pool.lo -MD -MP -MF knot/worker/$(DEPDIR)/libknotd_la-pool.Tpo -c -o knot/worker/libknotd_la-pool.lo `test -f 'knot/worker/pool.c' || echo '$(srcdir)/'`knot/worker/pool.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/worker/$(DEPDIR)/libknotd_la-pool.Tpo knot/worker/$(DEPDIR)/libknotd_la-pool.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/worker/pool.c' object='knot/worker/libknotd_la-pool.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/worker/libknotd_la-pool.lo `test -f 'knot/worker/pool.c' || echo '$(srcdir)/'`knot/worker/pool.c
+
+knot/worker/libknotd_la-queue.lo: knot/worker/queue.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/worker/libknotd_la-queue.lo -MD -MP -MF knot/worker/$(DEPDIR)/libknotd_la-queue.Tpo -c -o knot/worker/libknotd_la-queue.lo `test -f 'knot/worker/queue.c' || echo '$(srcdir)/'`knot/worker/queue.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/worker/$(DEPDIR)/libknotd_la-queue.Tpo knot/worker/$(DEPDIR)/libknotd_la-queue.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/worker/queue.c' object='knot/worker/libknotd_la-queue.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/worker/libknotd_la-queue.lo `test -f 'knot/worker/queue.c' || echo '$(srcdir)/'`knot/worker/queue.c
+
+knot/zone/libknotd_la-contents.lo: knot/zone/contents.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/zone/libknotd_la-contents.lo -MD -MP -MF knot/zone/$(DEPDIR)/libknotd_la-contents.Tpo -c -o knot/zone/libknotd_la-contents.lo `test -f 'knot/zone/contents.c' || echo '$(srcdir)/'`knot/zone/contents.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/zone/$(DEPDIR)/libknotd_la-contents.Tpo knot/zone/$(DEPDIR)/libknotd_la-contents.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/zone/contents.c' object='knot/zone/libknotd_la-contents.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/zone/libknotd_la-contents.lo `test -f 'knot/zone/contents.c' || echo '$(srcdir)/'`knot/zone/contents.c
+
+knot/zone/libknotd_la-node.lo: knot/zone/node.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/zone/libknotd_la-node.lo -MD -MP -MF knot/zone/$(DEPDIR)/libknotd_la-node.Tpo -c -o knot/zone/libknotd_la-node.lo `test -f 'knot/zone/node.c' || echo '$(srcdir)/'`knot/zone/node.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/zone/$(DEPDIR)/libknotd_la-node.Tpo knot/zone/$(DEPDIR)/libknotd_la-node.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/zone/node.c' object='knot/zone/libknotd_la-node.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/zone/libknotd_la-node.lo `test -f 'knot/zone/node.c' || echo '$(srcdir)/'`knot/zone/node.c
+
+knot/zone/libknotd_la-semantic-check.lo: knot/zone/semantic-check.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/zone/libknotd_la-semantic-check.lo -MD -MP -MF knot/zone/$(DEPDIR)/libknotd_la-semantic-check.Tpo -c -o knot/zone/libknotd_la-semantic-check.lo `test -f 'knot/zone/semantic-check.c' || echo '$(srcdir)/'`knot/zone/semantic-check.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/zone/$(DEPDIR)/libknotd_la-semantic-check.Tpo knot/zone/$(DEPDIR)/libknotd_la-semantic-check.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/zone/semantic-check.c' object='knot/zone/libknotd_la-semantic-check.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/zone/libknotd_la-semantic-check.lo `test -f 'knot/zone/semantic-check.c' || echo '$(srcdir)/'`knot/zone/semantic-check.c
+
+knot/zone/libknotd_la-serial.lo: knot/zone/serial.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/zone/libknotd_la-serial.lo -MD -MP -MF knot/zone/$(DEPDIR)/libknotd_la-serial.Tpo -c -o knot/zone/libknotd_la-serial.lo `test -f 'knot/zone/serial.c' || echo '$(srcdir)/'`knot/zone/serial.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/zone/$(DEPDIR)/libknotd_la-serial.Tpo knot/zone/$(DEPDIR)/libknotd_la-serial.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/zone/serial.c' object='knot/zone/libknotd_la-serial.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/zone/libknotd_la-serial.lo `test -f 'knot/zone/serial.c' || echo '$(srcdir)/'`knot/zone/serial.c
+
+knot/zone/libknotd_la-timers.lo: knot/zone/timers.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/zone/libknotd_la-timers.lo -MD -MP -MF knot/zone/$(DEPDIR)/libknotd_la-timers.Tpo -c -o knot/zone/libknotd_la-timers.lo `test -f 'knot/zone/timers.c' || echo '$(srcdir)/'`knot/zone/timers.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/zone/$(DEPDIR)/libknotd_la-timers.Tpo knot/zone/$(DEPDIR)/libknotd_la-timers.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/zone/timers.c' object='knot/zone/libknotd_la-timers.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/zone/libknotd_la-timers.lo `test -f 'knot/zone/timers.c' || echo '$(srcdir)/'`knot/zone/timers.c
+
+knot/zone/libknotd_la-zone-diff.lo: knot/zone/zone-diff.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/zone/libknotd_la-zone-diff.lo -MD -MP -MF knot/zone/$(DEPDIR)/libknotd_la-zone-diff.Tpo -c -o knot/zone/libknotd_la-zone-diff.lo `test -f 'knot/zone/zone-diff.c' || echo '$(srcdir)/'`knot/zone/zone-diff.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/zone/$(DEPDIR)/libknotd_la-zone-diff.Tpo knot/zone/$(DEPDIR)/libknotd_la-zone-diff.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/zone/zone-diff.c' object='knot/zone/libknotd_la-zone-diff.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/zone/libknotd_la-zone-diff.lo `test -f 'knot/zone/zone-diff.c' || echo '$(srcdir)/'`knot/zone/zone-diff.c
+
+knot/zone/libknotd_la-zone-dump.lo: knot/zone/zone-dump.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/zone/libknotd_la-zone-dump.lo -MD -MP -MF knot/zone/$(DEPDIR)/libknotd_la-zone-dump.Tpo -c -o knot/zone/libknotd_la-zone-dump.lo `test -f 'knot/zone/zone-dump.c' || echo '$(srcdir)/'`knot/zone/zone-dump.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/zone/$(DEPDIR)/libknotd_la-zone-dump.Tpo knot/zone/$(DEPDIR)/libknotd_la-zone-dump.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/zone/zone-dump.c' object='knot/zone/libknotd_la-zone-dump.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/zone/libknotd_la-zone-dump.lo `test -f 'knot/zone/zone-dump.c' || echo '$(srcdir)/'`knot/zone/zone-dump.c
+
+knot/zone/libknotd_la-zone-load.lo: knot/zone/zone-load.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/zone/libknotd_la-zone-load.lo -MD -MP -MF knot/zone/$(DEPDIR)/libknotd_la-zone-load.Tpo -c -o knot/zone/libknotd_la-zone-load.lo `test -f 'knot/zone/zone-load.c' || echo '$(srcdir)/'`knot/zone/zone-load.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/zone/$(DEPDIR)/libknotd_la-zone-load.Tpo knot/zone/$(DEPDIR)/libknotd_la-zone-load.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/zone/zone-load.c' object='knot/zone/libknotd_la-zone-load.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/zone/libknotd_la-zone-load.lo `test -f 'knot/zone/zone-load.c' || echo '$(srcdir)/'`knot/zone/zone-load.c
+
+knot/zone/libknotd_la-zone-tree.lo: knot/zone/zone-tree.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/zone/libknotd_la-zone-tree.lo -MD -MP -MF knot/zone/$(DEPDIR)/libknotd_la-zone-tree.Tpo -c -o knot/zone/libknotd_la-zone-tree.lo `test -f 'knot/zone/zone-tree.c' || echo '$(srcdir)/'`knot/zone/zone-tree.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/zone/$(DEPDIR)/libknotd_la-zone-tree.Tpo knot/zone/$(DEPDIR)/libknotd_la-zone-tree.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/zone/zone-tree.c' object='knot/zone/libknotd_la-zone-tree.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/zone/libknotd_la-zone-tree.lo `test -f 'knot/zone/zone-tree.c' || echo '$(srcdir)/'`knot/zone/zone-tree.c
+
+knot/zone/libknotd_la-zone.lo: knot/zone/zone.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/zone/libknotd_la-zone.lo -MD -MP -MF knot/zone/$(DEPDIR)/libknotd_la-zone.Tpo -c -o knot/zone/libknotd_la-zone.lo `test -f 'knot/zone/zone.c' || echo '$(srcdir)/'`knot/zone/zone.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/zone/$(DEPDIR)/libknotd_la-zone.Tpo knot/zone/$(DEPDIR)/libknotd_la-zone.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/zone/zone.c' object='knot/zone/libknotd_la-zone.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/zone/libknotd_la-zone.lo `test -f 'knot/zone/zone.c' || echo '$(srcdir)/'`knot/zone/zone.c
+
+knot/zone/libknotd_la-zonedb-load.lo: knot/zone/zonedb-load.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/zone/libknotd_la-zonedb-load.lo -MD -MP -MF knot/zone/$(DEPDIR)/libknotd_la-zonedb-load.Tpo -c -o knot/zone/libknotd_la-zonedb-load.lo `test -f 'knot/zone/zonedb-load.c' || echo '$(srcdir)/'`knot/zone/zonedb-load.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/zone/$(DEPDIR)/libknotd_la-zonedb-load.Tpo knot/zone/$(DEPDIR)/libknotd_la-zonedb-load.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/zone/zonedb-load.c' object='knot/zone/libknotd_la-zonedb-load.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/zone/libknotd_la-zonedb-load.lo `test -f 'knot/zone/zonedb-load.c' || echo '$(srcdir)/'`knot/zone/zonedb-load.c
+
+knot/zone/libknotd_la-zonedb.lo: knot/zone/zonedb.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/zone/libknotd_la-zonedb.lo -MD -MP -MF knot/zone/$(DEPDIR)/libknotd_la-zonedb.Tpo -c -o knot/zone/libknotd_la-zonedb.lo `test -f 'knot/zone/zonedb.c' || echo '$(srcdir)/'`knot/zone/zonedb.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/zone/$(DEPDIR)/libknotd_la-zonedb.Tpo knot/zone/$(DEPDIR)/libknotd_la-zonedb.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/zone/zonedb.c' object='knot/zone/libknotd_la-zonedb.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/zone/libknotd_la-zonedb.lo `test -f 'knot/zone/zonedb.c' || echo '$(srcdir)/'`knot/zone/zonedb.c
+
+knot/zone/libknotd_la-zonefile.lo: knot/zone/zonefile.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/zone/libknotd_la-zonefile.lo -MD -MP -MF knot/zone/$(DEPDIR)/libknotd_la-zonefile.Tpo -c -o knot/zone/libknotd_la-zonefile.lo `test -f 'knot/zone/zonefile.c' || echo '$(srcdir)/'`knot/zone/zonefile.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/zone/$(DEPDIR)/libknotd_la-zonefile.Tpo knot/zone/$(DEPDIR)/libknotd_la-zonefile.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/zone/zonefile.c' object='knot/zone/libknotd_la-zonefile.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/zone/libknotd_la-zonefile.lo `test -f 'knot/zone/zonefile.c' || echo '$(srcdir)/'`knot/zone/zonefile.c
+
+knot/modules/cookies/libknotd_la-cookies.lo: knot/modules/cookies/cookies.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/cookies/libknotd_la-cookies.lo -MD -MP -MF knot/modules/cookies/$(DEPDIR)/libknotd_la-cookies.Tpo -c -o knot/modules/cookies/libknotd_la-cookies.lo `test -f 'knot/modules/cookies/cookies.c' || echo '$(srcdir)/'`knot/modules/cookies/cookies.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/cookies/$(DEPDIR)/libknotd_la-cookies.Tpo knot/modules/cookies/$(DEPDIR)/libknotd_la-cookies.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/cookies/cookies.c' object='knot/modules/cookies/libknotd_la-cookies.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/cookies/libknotd_la-cookies.lo `test -f 'knot/modules/cookies/cookies.c' || echo '$(srcdir)/'`knot/modules/cookies/cookies.c
+
+knot/modules/dnsproxy/libknotd_la-dnsproxy.lo: knot/modules/dnsproxy/dnsproxy.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/dnsproxy/libknotd_la-dnsproxy.lo -MD -MP -MF knot/modules/dnsproxy/$(DEPDIR)/libknotd_la-dnsproxy.Tpo -c -o knot/modules/dnsproxy/libknotd_la-dnsproxy.lo `test -f 'knot/modules/dnsproxy/dnsproxy.c' || echo '$(srcdir)/'`knot/modules/dnsproxy/dnsproxy.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/dnsproxy/$(DEPDIR)/libknotd_la-dnsproxy.Tpo knot/modules/dnsproxy/$(DEPDIR)/libknotd_la-dnsproxy.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/dnsproxy/dnsproxy.c' object='knot/modules/dnsproxy/libknotd_la-dnsproxy.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/dnsproxy/libknotd_la-dnsproxy.lo `test -f 'knot/modules/dnsproxy/dnsproxy.c' || echo '$(srcdir)/'`knot/modules/dnsproxy/dnsproxy.c
+
+knot/modules/dnstap/libknotd_la-dnstap.lo: knot/modules/dnstap/dnstap.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/dnstap/libknotd_la-dnstap.lo -MD -MP -MF knot/modules/dnstap/$(DEPDIR)/libknotd_la-dnstap.Tpo -c -o knot/modules/dnstap/libknotd_la-dnstap.lo `test -f 'knot/modules/dnstap/dnstap.c' || echo '$(srcdir)/'`knot/modules/dnstap/dnstap.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/dnstap/$(DEPDIR)/libknotd_la-dnstap.Tpo knot/modules/dnstap/$(DEPDIR)/libknotd_la-dnstap.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/dnstap/dnstap.c' object='knot/modules/dnstap/libknotd_la-dnstap.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/dnstap/libknotd_la-dnstap.lo `test -f 'knot/modules/dnstap/dnstap.c' || echo '$(srcdir)/'`knot/modules/dnstap/dnstap.c
+
+knot/modules/geoip/libknotd_la-geoip.lo: knot/modules/geoip/geoip.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/geoip/libknotd_la-geoip.lo -MD -MP -MF knot/modules/geoip/$(DEPDIR)/libknotd_la-geoip.Tpo -c -o knot/modules/geoip/libknotd_la-geoip.lo `test -f 'knot/modules/geoip/geoip.c' || echo '$(srcdir)/'`knot/modules/geoip/geoip.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/geoip/$(DEPDIR)/libknotd_la-geoip.Tpo knot/modules/geoip/$(DEPDIR)/libknotd_la-geoip.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/geoip/geoip.c' object='knot/modules/geoip/libknotd_la-geoip.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/geoip/libknotd_la-geoip.lo `test -f 'knot/modules/geoip/geoip.c' || echo '$(srcdir)/'`knot/modules/geoip/geoip.c
+
+knot/modules/geoip/libknotd_la-geodb.lo: knot/modules/geoip/geodb.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/geoip/libknotd_la-geodb.lo -MD -MP -MF knot/modules/geoip/$(DEPDIR)/libknotd_la-geodb.Tpo -c -o knot/modules/geoip/libknotd_la-geodb.lo `test -f 'knot/modules/geoip/geodb.c' || echo '$(srcdir)/'`knot/modules/geoip/geodb.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/geoip/$(DEPDIR)/libknotd_la-geodb.Tpo knot/modules/geoip/$(DEPDIR)/libknotd_la-geodb.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/geoip/geodb.c' object='knot/modules/geoip/libknotd_la-geodb.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/geoip/libknotd_la-geodb.lo `test -f 'knot/modules/geoip/geodb.c' || echo '$(srcdir)/'`knot/modules/geoip/geodb.c
+
+knot/modules/noudp/libknotd_la-noudp.lo: knot/modules/noudp/noudp.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/noudp/libknotd_la-noudp.lo -MD -MP -MF knot/modules/noudp/$(DEPDIR)/libknotd_la-noudp.Tpo -c -o knot/modules/noudp/libknotd_la-noudp.lo `test -f 'knot/modules/noudp/noudp.c' || echo '$(srcdir)/'`knot/modules/noudp/noudp.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/noudp/$(DEPDIR)/libknotd_la-noudp.Tpo knot/modules/noudp/$(DEPDIR)/libknotd_la-noudp.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/noudp/noudp.c' object='knot/modules/noudp/libknotd_la-noudp.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/noudp/libknotd_la-noudp.lo `test -f 'knot/modules/noudp/noudp.c' || echo '$(srcdir)/'`knot/modules/noudp/noudp.c
+
+knot/modules/onlinesign/libknotd_la-onlinesign.lo: knot/modules/onlinesign/onlinesign.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/onlinesign/libknotd_la-onlinesign.lo -MD -MP -MF knot/modules/onlinesign/$(DEPDIR)/libknotd_la-onlinesign.Tpo -c -o knot/modules/onlinesign/libknotd_la-onlinesign.lo `test -f 'knot/modules/onlinesign/onlinesign.c' || echo '$(srcdir)/'`knot/modules/onlinesign/onlinesign.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/onlinesign/$(DEPDIR)/libknotd_la-onlinesign.Tpo knot/modules/onlinesign/$(DEPDIR)/libknotd_la-onlinesign.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/onlinesign/onlinesign.c' object='knot/modules/onlinesign/libknotd_la-onlinesign.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/onlinesign/libknotd_la-onlinesign.lo `test -f 'knot/modules/onlinesign/onlinesign.c' || echo '$(srcdir)/'`knot/modules/onlinesign/onlinesign.c
+
+knot/modules/onlinesign/libknotd_la-nsec_next.lo: knot/modules/onlinesign/nsec_next.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/onlinesign/libknotd_la-nsec_next.lo -MD -MP -MF knot/modules/onlinesign/$(DEPDIR)/libknotd_la-nsec_next.Tpo -c -o knot/modules/onlinesign/libknotd_la-nsec_next.lo `test -f 'knot/modules/onlinesign/nsec_next.c' || echo '$(srcdir)/'`knot/modules/onlinesign/nsec_next.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/onlinesign/$(DEPDIR)/libknotd_la-nsec_next.Tpo knot/modules/onlinesign/$(DEPDIR)/libknotd_la-nsec_next.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/onlinesign/nsec_next.c' object='knot/modules/onlinesign/libknotd_la-nsec_next.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/onlinesign/libknotd_la-nsec_next.lo `test -f 'knot/modules/onlinesign/nsec_next.c' || echo '$(srcdir)/'`knot/modules/onlinesign/nsec_next.c
+
+knot/modules/queryacl/libknotd_la-queryacl.lo: knot/modules/queryacl/queryacl.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/queryacl/libknotd_la-queryacl.lo -MD -MP -MF knot/modules/queryacl/$(DEPDIR)/libknotd_la-queryacl.Tpo -c -o knot/modules/queryacl/libknotd_la-queryacl.lo `test -f 'knot/modules/queryacl/queryacl.c' || echo '$(srcdir)/'`knot/modules/queryacl/queryacl.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/queryacl/$(DEPDIR)/libknotd_la-queryacl.Tpo knot/modules/queryacl/$(DEPDIR)/libknotd_la-queryacl.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/queryacl/queryacl.c' object='knot/modules/queryacl/libknotd_la-queryacl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/queryacl/libknotd_la-queryacl.lo `test -f 'knot/modules/queryacl/queryacl.c' || echo '$(srcdir)/'`knot/modules/queryacl/queryacl.c
+
+knot/modules/rrl/libknotd_la-rrl.lo: knot/modules/rrl/rrl.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/rrl/libknotd_la-rrl.lo -MD -MP -MF knot/modules/rrl/$(DEPDIR)/libknotd_la-rrl.Tpo -c -o knot/modules/rrl/libknotd_la-rrl.lo `test -f 'knot/modules/rrl/rrl.c' || echo '$(srcdir)/'`knot/modules/rrl/rrl.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/rrl/$(DEPDIR)/libknotd_la-rrl.Tpo knot/modules/rrl/$(DEPDIR)/libknotd_la-rrl.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/rrl/rrl.c' object='knot/modules/rrl/libknotd_la-rrl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/rrl/libknotd_la-rrl.lo `test -f 'knot/modules/rrl/rrl.c' || echo '$(srcdir)/'`knot/modules/rrl/rrl.c
+
+knot/modules/rrl/libknotd_la-functions.lo: knot/modules/rrl/functions.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/rrl/libknotd_la-functions.lo -MD -MP -MF knot/modules/rrl/$(DEPDIR)/libknotd_la-functions.Tpo -c -o knot/modules/rrl/libknotd_la-functions.lo `test -f 'knot/modules/rrl/functions.c' || echo '$(srcdir)/'`knot/modules/rrl/functions.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/rrl/$(DEPDIR)/libknotd_la-functions.Tpo knot/modules/rrl/$(DEPDIR)/libknotd_la-functions.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/rrl/functions.c' object='knot/modules/rrl/libknotd_la-functions.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/rrl/libknotd_la-functions.lo `test -f 'knot/modules/rrl/functions.c' || echo '$(srcdir)/'`knot/modules/rrl/functions.c
+
+knot/modules/stats/libknotd_la-stats.lo: knot/modules/stats/stats.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/stats/libknotd_la-stats.lo -MD -MP -MF knot/modules/stats/$(DEPDIR)/libknotd_la-stats.Tpo -c -o knot/modules/stats/libknotd_la-stats.lo `test -f 'knot/modules/stats/stats.c' || echo '$(srcdir)/'`knot/modules/stats/stats.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/stats/$(DEPDIR)/libknotd_la-stats.Tpo knot/modules/stats/$(DEPDIR)/libknotd_la-stats.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/stats/stats.c' object='knot/modules/stats/libknotd_la-stats.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/stats/libknotd_la-stats.lo `test -f 'knot/modules/stats/stats.c' || echo '$(srcdir)/'`knot/modules/stats/stats.c
+
+knot/modules/synthrecord/libknotd_la-synthrecord.lo: knot/modules/synthrecord/synthrecord.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/synthrecord/libknotd_la-synthrecord.lo -MD -MP -MF knot/modules/synthrecord/$(DEPDIR)/libknotd_la-synthrecord.Tpo -c -o knot/modules/synthrecord/libknotd_la-synthrecord.lo `test -f 'knot/modules/synthrecord/synthrecord.c' || echo '$(srcdir)/'`knot/modules/synthrecord/synthrecord.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/synthrecord/$(DEPDIR)/libknotd_la-synthrecord.Tpo knot/modules/synthrecord/$(DEPDIR)/libknotd_la-synthrecord.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/synthrecord/synthrecord.c' object='knot/modules/synthrecord/libknotd_la-synthrecord.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/synthrecord/libknotd_la-synthrecord.lo `test -f 'knot/modules/synthrecord/synthrecord.c' || echo '$(srcdir)/'`knot/modules/synthrecord/synthrecord.c
+
+knot/modules/whoami/libknotd_la-whoami.lo: knot/modules/whoami/whoami.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/whoami/libknotd_la-whoami.lo -MD -MP -MF knot/modules/whoami/$(DEPDIR)/libknotd_la-whoami.Tpo -c -o knot/modules/whoami/libknotd_la-whoami.lo `test -f 'knot/modules/whoami/whoami.c' || echo '$(srcdir)/'`knot/modules/whoami/whoami.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/whoami/$(DEPDIR)/libknotd_la-whoami.Tpo knot/modules/whoami/$(DEPDIR)/libknotd_la-whoami.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/whoami/whoami.c' object='knot/modules/whoami/libknotd_la-whoami.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/whoami/libknotd_la-whoami.lo `test -f 'knot/modules/whoami/whoami.c' || echo '$(srcdir)/'`knot/modules/whoami/whoami.c
+
+utils/common/libknotus_la-cert.lo: utils/common/cert.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotus_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/common/libknotus_la-cert.lo -MD -MP -MF utils/common/$(DEPDIR)/libknotus_la-cert.Tpo -c -o utils/common/libknotus_la-cert.lo `test -f 'utils/common/cert.c' || echo '$(srcdir)/'`utils/common/cert.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/common/$(DEPDIR)/libknotus_la-cert.Tpo utils/common/$(DEPDIR)/libknotus_la-cert.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/common/cert.c' object='utils/common/libknotus_la-cert.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotus_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/common/libknotus_la-cert.lo `test -f 'utils/common/cert.c' || echo '$(srcdir)/'`utils/common/cert.c
+
+utils/common/libknotus_la-exec.lo: utils/common/exec.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotus_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/common/libknotus_la-exec.lo -MD -MP -MF utils/common/$(DEPDIR)/libknotus_la-exec.Tpo -c -o utils/common/libknotus_la-exec.lo `test -f 'utils/common/exec.c' || echo '$(srcdir)/'`utils/common/exec.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/common/$(DEPDIR)/libknotus_la-exec.Tpo utils/common/$(DEPDIR)/libknotus_la-exec.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/common/exec.c' object='utils/common/libknotus_la-exec.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotus_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/common/libknotus_la-exec.lo `test -f 'utils/common/exec.c' || echo '$(srcdir)/'`utils/common/exec.c
+
+utils/common/libknotus_la-hex.lo: utils/common/hex.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotus_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/common/libknotus_la-hex.lo -MD -MP -MF utils/common/$(DEPDIR)/libknotus_la-hex.Tpo -c -o utils/common/libknotus_la-hex.lo `test -f 'utils/common/hex.c' || echo '$(srcdir)/'`utils/common/hex.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/common/$(DEPDIR)/libknotus_la-hex.Tpo utils/common/$(DEPDIR)/libknotus_la-hex.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/common/hex.c' object='utils/common/libknotus_la-hex.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotus_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/common/libknotus_la-hex.lo `test -f 'utils/common/hex.c' || echo '$(srcdir)/'`utils/common/hex.c
+
+utils/common/libknotus_la-lookup.lo: utils/common/lookup.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotus_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/common/libknotus_la-lookup.lo -MD -MP -MF utils/common/$(DEPDIR)/libknotus_la-lookup.Tpo -c -o utils/common/libknotus_la-lookup.lo `test -f 'utils/common/lookup.c' || echo '$(srcdir)/'`utils/common/lookup.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/common/$(DEPDIR)/libknotus_la-lookup.Tpo utils/common/$(DEPDIR)/libknotus_la-lookup.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/common/lookup.c' object='utils/common/libknotus_la-lookup.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotus_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/common/libknotus_la-lookup.lo `test -f 'utils/common/lookup.c' || echo '$(srcdir)/'`utils/common/lookup.c
+
+utils/common/libknotus_la-msg.lo: utils/common/msg.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotus_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/common/libknotus_la-msg.lo -MD -MP -MF utils/common/$(DEPDIR)/libknotus_la-msg.Tpo -c -o utils/common/libknotus_la-msg.lo `test -f 'utils/common/msg.c' || echo '$(srcdir)/'`utils/common/msg.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/common/$(DEPDIR)/libknotus_la-msg.Tpo utils/common/$(DEPDIR)/libknotus_la-msg.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/common/msg.c' object='utils/common/libknotus_la-msg.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotus_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/common/libknotus_la-msg.lo `test -f 'utils/common/msg.c' || echo '$(srcdir)/'`utils/common/msg.c
+
+utils/common/libknotus_la-netio.lo: utils/common/netio.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotus_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/common/libknotus_la-netio.lo -MD -MP -MF utils/common/$(DEPDIR)/libknotus_la-netio.Tpo -c -o utils/common/libknotus_la-netio.lo `test -f 'utils/common/netio.c' || echo '$(srcdir)/'`utils/common/netio.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/common/$(DEPDIR)/libknotus_la-netio.Tpo utils/common/$(DEPDIR)/libknotus_la-netio.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/common/netio.c' object='utils/common/libknotus_la-netio.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotus_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/common/libknotus_la-netio.lo `test -f 'utils/common/netio.c' || echo '$(srcdir)/'`utils/common/netio.c
+
+utils/common/libknotus_la-params.lo: utils/common/params.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotus_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/common/libknotus_la-params.lo -MD -MP -MF utils/common/$(DEPDIR)/libknotus_la-params.Tpo -c -o utils/common/libknotus_la-params.lo `test -f 'utils/common/params.c' || echo '$(srcdir)/'`utils/common/params.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/common/$(DEPDIR)/libknotus_la-params.Tpo utils/common/$(DEPDIR)/libknotus_la-params.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/common/params.c' object='utils/common/libknotus_la-params.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotus_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/common/libknotus_la-params.lo `test -f 'utils/common/params.c' || echo '$(srcdir)/'`utils/common/params.c
+
+utils/common/libknotus_la-resolv.lo: utils/common/resolv.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotus_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/common/libknotus_la-resolv.lo -MD -MP -MF utils/common/$(DEPDIR)/libknotus_la-resolv.Tpo -c -o utils/common/libknotus_la-resolv.lo `test -f 'utils/common/resolv.c' || echo '$(srcdir)/'`utils/common/resolv.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/common/$(DEPDIR)/libknotus_la-resolv.Tpo utils/common/$(DEPDIR)/libknotus_la-resolv.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/common/resolv.c' object='utils/common/libknotus_la-resolv.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotus_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/common/libknotus_la-resolv.lo `test -f 'utils/common/resolv.c' || echo '$(srcdir)/'`utils/common/resolv.c
+
+utils/common/libknotus_la-sign.lo: utils/common/sign.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotus_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/common/libknotus_la-sign.lo -MD -MP -MF utils/common/$(DEPDIR)/libknotus_la-sign.Tpo -c -o utils/common/libknotus_la-sign.lo `test -f 'utils/common/sign.c' || echo '$(srcdir)/'`utils/common/sign.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/common/$(DEPDIR)/libknotus_la-sign.Tpo utils/common/$(DEPDIR)/libknotus_la-sign.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/common/sign.c' object='utils/common/libknotus_la-sign.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotus_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/common/libknotus_la-sign.lo `test -f 'utils/common/sign.c' || echo '$(srcdir)/'`utils/common/sign.c
+
+utils/common/libknotus_la-tls.lo: utils/common/tls.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotus_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/common/libknotus_la-tls.lo -MD -MP -MF utils/common/$(DEPDIR)/libknotus_la-tls.Tpo -c -o utils/common/libknotus_la-tls.lo `test -f 'utils/common/tls.c' || echo '$(srcdir)/'`utils/common/tls.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/common/$(DEPDIR)/libknotus_la-tls.Tpo utils/common/$(DEPDIR)/libknotus_la-tls.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/common/tls.c' object='utils/common/libknotus_la-tls.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotus_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/common/libknotus_la-tls.lo `test -f 'utils/common/tls.c' || echo '$(srcdir)/'`utils/common/tls.c
+
+utils/common/libknotus_la-token.lo: utils/common/token.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotus_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/common/libknotus_la-token.lo -MD -MP -MF utils/common/$(DEPDIR)/libknotus_la-token.Tpo -c -o utils/common/libknotus_la-token.lo `test -f 'utils/common/token.c' || echo '$(srcdir)/'`utils/common/token.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/common/$(DEPDIR)/libknotus_la-token.Tpo utils/common/$(DEPDIR)/libknotus_la-token.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/common/token.c' object='utils/common/libknotus_la-token.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotus_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/common/libknotus_la-token.lo `test -f 'utils/common/token.c' || echo '$(srcdir)/'`utils/common/token.c
+
+libdnssec/shared/libshared_la-bignum.lo: libdnssec/shared/bignum.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libshared_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/shared/libshared_la-bignum.lo -MD -MP -MF libdnssec/shared/$(DEPDIR)/libshared_la-bignum.Tpo -c -o libdnssec/shared/libshared_la-bignum.lo `test -f 'libdnssec/shared/bignum.c' || echo '$(srcdir)/'`libdnssec/shared/bignum.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/shared/$(DEPDIR)/libshared_la-bignum.Tpo libdnssec/shared/$(DEPDIR)/libshared_la-bignum.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/shared/bignum.c' object='libdnssec/shared/libshared_la-bignum.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libshared_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/shared/libshared_la-bignum.lo `test -f 'libdnssec/shared/bignum.c' || echo '$(srcdir)/'`libdnssec/shared/bignum.c
+
+libdnssec/shared/libshared_la-dname.lo: libdnssec/shared/dname.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libshared_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/shared/libshared_la-dname.lo -MD -MP -MF libdnssec/shared/$(DEPDIR)/libshared_la-dname.Tpo -c -o libdnssec/shared/libshared_la-dname.lo `test -f 'libdnssec/shared/dname.c' || echo '$(srcdir)/'`libdnssec/shared/dname.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/shared/$(DEPDIR)/libshared_la-dname.Tpo libdnssec/shared/$(DEPDIR)/libshared_la-dname.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/shared/dname.c' object='libdnssec/shared/libshared_la-dname.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libshared_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/shared/libshared_la-dname.lo `test -f 'libdnssec/shared/dname.c' || echo '$(srcdir)/'`libdnssec/shared/dname.c
+
+libdnssec/shared/libshared_la-fs.lo: libdnssec/shared/fs.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libshared_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/shared/libshared_la-fs.lo -MD -MP -MF libdnssec/shared/$(DEPDIR)/libshared_la-fs.Tpo -c -o libdnssec/shared/libshared_la-fs.lo `test -f 'libdnssec/shared/fs.c' || echo '$(srcdir)/'`libdnssec/shared/fs.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/shared/$(DEPDIR)/libshared_la-fs.Tpo libdnssec/shared/$(DEPDIR)/libshared_la-fs.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/shared/fs.c' object='libdnssec/shared/libshared_la-fs.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libshared_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/shared/libshared_la-fs.lo `test -f 'libdnssec/shared/fs.c' || echo '$(srcdir)/'`libdnssec/shared/fs.c
+
+libdnssec/shared/libshared_la-hex.lo: libdnssec/shared/hex.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libshared_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/shared/libshared_la-hex.lo -MD -MP -MF libdnssec/shared/$(DEPDIR)/libshared_la-hex.Tpo -c -o libdnssec/shared/libshared_la-hex.lo `test -f 'libdnssec/shared/hex.c' || echo '$(srcdir)/'`libdnssec/shared/hex.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/shared/$(DEPDIR)/libshared_la-hex.Tpo libdnssec/shared/$(DEPDIR)/libshared_la-hex.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/shared/hex.c' object='libdnssec/shared/libshared_la-hex.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libshared_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/shared/libshared_la-hex.lo `test -f 'libdnssec/shared/hex.c' || echo '$(srcdir)/'`libdnssec/shared/hex.c
+
+libdnssec/shared/libshared_la-keyid_gnutls.lo: libdnssec/shared/keyid_gnutls.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libshared_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/shared/libshared_la-keyid_gnutls.lo -MD -MP -MF libdnssec/shared/$(DEPDIR)/libshared_la-keyid_gnutls.Tpo -c -o libdnssec/shared/libshared_la-keyid_gnutls.lo `test -f 'libdnssec/shared/keyid_gnutls.c' || echo '$(srcdir)/'`libdnssec/shared/keyid_gnutls.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/shared/$(DEPDIR)/libshared_la-keyid_gnutls.Tpo libdnssec/shared/$(DEPDIR)/libshared_la-keyid_gnutls.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/shared/keyid_gnutls.c' object='libdnssec/shared/libshared_la-keyid_gnutls.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libshared_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/shared/libshared_la-keyid_gnutls.lo `test -f 'libdnssec/shared/keyid_gnutls.c' || echo '$(srcdir)/'`libdnssec/shared/keyid_gnutls.c
+
+libdnssec/shared/libshared_la-pem.lo: libdnssec/shared/pem.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libshared_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdnssec/shared/libshared_la-pem.lo -MD -MP -MF libdnssec/shared/$(DEPDIR)/libshared_la-pem.Tpo -c -o libdnssec/shared/libshared_la-pem.lo `test -f 'libdnssec/shared/pem.c' || echo '$(srcdir)/'`libdnssec/shared/pem.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libdnssec/shared/$(DEPDIR)/libshared_la-pem.Tpo libdnssec/shared/$(DEPDIR)/libshared_la-pem.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libdnssec/shared/pem.c' object='libdnssec/shared/libshared_la-pem.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libshared_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdnssec/shared/libshared_la-pem.lo `test -f 'libdnssec/shared/pem.c' || echo '$(srcdir)/'`libdnssec/shared/pem.c
+
+libzscanner/libzscanner_la-error.lo: libzscanner/error.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libzscanner_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libzscanner/libzscanner_la-error.lo -MD -MP -MF libzscanner/$(DEPDIR)/libzscanner_la-error.Tpo -c -o libzscanner/libzscanner_la-error.lo `test -f 'libzscanner/error.c' || echo '$(srcdir)/'`libzscanner/error.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libzscanner/$(DEPDIR)/libzscanner_la-error.Tpo libzscanner/$(DEPDIR)/libzscanner_la-error.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libzscanner/error.c' object='libzscanner/libzscanner_la-error.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libzscanner_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libzscanner/libzscanner_la-error.lo `test -f 'libzscanner/error.c' || echo '$(srcdir)/'`libzscanner/error.c
+
+libzscanner/libzscanner_la-functions.lo: libzscanner/functions.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libzscanner_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libzscanner/libzscanner_la-functions.lo -MD -MP -MF libzscanner/$(DEPDIR)/libzscanner_la-functions.Tpo -c -o libzscanner/libzscanner_la-functions.lo `test -f 'libzscanner/functions.c' || echo '$(srcdir)/'`libzscanner/functions.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libzscanner/$(DEPDIR)/libzscanner_la-functions.Tpo libzscanner/$(DEPDIR)/libzscanner_la-functions.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libzscanner/functions.c' object='libzscanner/libzscanner_la-functions.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libzscanner_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libzscanner/libzscanner_la-functions.lo `test -f 'libzscanner/functions.c' || echo '$(srcdir)/'`libzscanner/functions.c
+
+libzscanner/libzscanner_la-scanner.lo: libzscanner/scanner.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libzscanner_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libzscanner/libzscanner_la-scanner.lo -MD -MP -MF libzscanner/$(DEPDIR)/libzscanner_la-scanner.Tpo -c -o libzscanner/libzscanner_la-scanner.lo `test -f 'libzscanner/scanner.c' || echo '$(srcdir)/'`libzscanner/scanner.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libzscanner/$(DEPDIR)/libzscanner_la-scanner.Tpo libzscanner/$(DEPDIR)/libzscanner_la-scanner.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libzscanner/scanner.c' object='libzscanner/libzscanner_la-scanner.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libzscanner_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libzscanner/libzscanner_la-scanner.lo `test -f 'libzscanner/scanner.c' || echo '$(srcdir)/'`libzscanner/scanner.c
+
+utils/kdig/kdig-kdig_exec.o: utils/kdig/kdig_exec.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kdig_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/kdig/kdig-kdig_exec.o -MD -MP -MF utils/kdig/$(DEPDIR)/kdig-kdig_exec.Tpo -c -o utils/kdig/kdig-kdig_exec.o `test -f 'utils/kdig/kdig_exec.c' || echo '$(srcdir)/'`utils/kdig/kdig_exec.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/kdig/$(DEPDIR)/kdig-kdig_exec.Tpo utils/kdig/$(DEPDIR)/kdig-kdig_exec.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/kdig/kdig_exec.c' object='utils/kdig/kdig-kdig_exec.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kdig_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/kdig/kdig-kdig_exec.o `test -f 'utils/kdig/kdig_exec.c' || echo '$(srcdir)/'`utils/kdig/kdig_exec.c
+
+utils/kdig/kdig-kdig_exec.obj: utils/kdig/kdig_exec.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kdig_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/kdig/kdig-kdig_exec.obj -MD -MP -MF utils/kdig/$(DEPDIR)/kdig-kdig_exec.Tpo -c -o utils/kdig/kdig-kdig_exec.obj `if test -f 'utils/kdig/kdig_exec.c'; then $(CYGPATH_W) 'utils/kdig/kdig_exec.c'; else $(CYGPATH_W) '$(srcdir)/utils/kdig/kdig_exec.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/kdig/$(DEPDIR)/kdig-kdig_exec.Tpo utils/kdig/$(DEPDIR)/kdig-kdig_exec.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/kdig/kdig_exec.c' object='utils/kdig/kdig-kdig_exec.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kdig_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/kdig/kdig-kdig_exec.obj `if test -f 'utils/kdig/kdig_exec.c'; then $(CYGPATH_W) 'utils/kdig/kdig_exec.c'; else $(CYGPATH_W) '$(srcdir)/utils/kdig/kdig_exec.c'; fi`
+
+utils/kdig/kdig-kdig_main.o: utils/kdig/kdig_main.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kdig_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/kdig/kdig-kdig_main.o -MD -MP -MF utils/kdig/$(DEPDIR)/kdig-kdig_main.Tpo -c -o utils/kdig/kdig-kdig_main.o `test -f 'utils/kdig/kdig_main.c' || echo '$(srcdir)/'`utils/kdig/kdig_main.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/kdig/$(DEPDIR)/kdig-kdig_main.Tpo utils/kdig/$(DEPDIR)/kdig-kdig_main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/kdig/kdig_main.c' object='utils/kdig/kdig-kdig_main.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kdig_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/kdig/kdig-kdig_main.o `test -f 'utils/kdig/kdig_main.c' || echo '$(srcdir)/'`utils/kdig/kdig_main.c
+
+utils/kdig/kdig-kdig_main.obj: utils/kdig/kdig_main.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kdig_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/kdig/kdig-kdig_main.obj -MD -MP -MF utils/kdig/$(DEPDIR)/kdig-kdig_main.Tpo -c -o utils/kdig/kdig-kdig_main.obj `if test -f 'utils/kdig/kdig_main.c'; then $(CYGPATH_W) 'utils/kdig/kdig_main.c'; else $(CYGPATH_W) '$(srcdir)/utils/kdig/kdig_main.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/kdig/$(DEPDIR)/kdig-kdig_main.Tpo utils/kdig/$(DEPDIR)/kdig-kdig_main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/kdig/kdig_main.c' object='utils/kdig/kdig-kdig_main.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kdig_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/kdig/kdig-kdig_main.obj `if test -f 'utils/kdig/kdig_main.c'; then $(CYGPATH_W) 'utils/kdig/kdig_main.c'; else $(CYGPATH_W) '$(srcdir)/utils/kdig/kdig_main.c'; fi`
+
+utils/kdig/kdig-kdig_params.o: utils/kdig/kdig_params.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kdig_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/kdig/kdig-kdig_params.o -MD -MP -MF utils/kdig/$(DEPDIR)/kdig-kdig_params.Tpo -c -o utils/kdig/kdig-kdig_params.o `test -f 'utils/kdig/kdig_params.c' || echo '$(srcdir)/'`utils/kdig/kdig_params.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/kdig/$(DEPDIR)/kdig-kdig_params.Tpo utils/kdig/$(DEPDIR)/kdig-kdig_params.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/kdig/kdig_params.c' object='utils/kdig/kdig-kdig_params.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kdig_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/kdig/kdig-kdig_params.o `test -f 'utils/kdig/kdig_params.c' || echo '$(srcdir)/'`utils/kdig/kdig_params.c
+
+utils/kdig/kdig-kdig_params.obj: utils/kdig/kdig_params.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kdig_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/kdig/kdig-kdig_params.obj -MD -MP -MF utils/kdig/$(DEPDIR)/kdig-kdig_params.Tpo -c -o utils/kdig/kdig-kdig_params.obj `if test -f 'utils/kdig/kdig_params.c'; then $(CYGPATH_W) 'utils/kdig/kdig_params.c'; else $(CYGPATH_W) '$(srcdir)/utils/kdig/kdig_params.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/kdig/$(DEPDIR)/kdig-kdig_params.Tpo utils/kdig/$(DEPDIR)/kdig-kdig_params.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/kdig/kdig_params.c' object='utils/kdig/kdig-kdig_params.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kdig_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/kdig/kdig-kdig_params.obj `if test -f 'utils/kdig/kdig_params.c'; then $(CYGPATH_W) 'utils/kdig/kdig_params.c'; else $(CYGPATH_W) '$(srcdir)/utils/kdig/kdig_params.c'; fi`
+
+utils/keymgr/keymgr-bind_privkey.o: utils/keymgr/bind_privkey.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(keymgr_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/keymgr/keymgr-bind_privkey.o -MD -MP -MF utils/keymgr/$(DEPDIR)/keymgr-bind_privkey.Tpo -c -o utils/keymgr/keymgr-bind_privkey.o `test -f 'utils/keymgr/bind_privkey.c' || echo '$(srcdir)/'`utils/keymgr/bind_privkey.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/keymgr/$(DEPDIR)/keymgr-bind_privkey.Tpo utils/keymgr/$(DEPDIR)/keymgr-bind_privkey.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/keymgr/bind_privkey.c' object='utils/keymgr/keymgr-bind_privkey.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(keymgr_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/keymgr/keymgr-bind_privkey.o `test -f 'utils/keymgr/bind_privkey.c' || echo '$(srcdir)/'`utils/keymgr/bind_privkey.c
+
+utils/keymgr/keymgr-bind_privkey.obj: utils/keymgr/bind_privkey.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(keymgr_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/keymgr/keymgr-bind_privkey.obj -MD -MP -MF utils/keymgr/$(DEPDIR)/keymgr-bind_privkey.Tpo -c -o utils/keymgr/keymgr-bind_privkey.obj `if test -f 'utils/keymgr/bind_privkey.c'; then $(CYGPATH_W) 'utils/keymgr/bind_privkey.c'; else $(CYGPATH_W) '$(srcdir)/utils/keymgr/bind_privkey.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/keymgr/$(DEPDIR)/keymgr-bind_privkey.Tpo utils/keymgr/$(DEPDIR)/keymgr-bind_privkey.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/keymgr/bind_privkey.c' object='utils/keymgr/keymgr-bind_privkey.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(keymgr_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/keymgr/keymgr-bind_privkey.obj `if test -f 'utils/keymgr/bind_privkey.c'; then $(CYGPATH_W) 'utils/keymgr/bind_privkey.c'; else $(CYGPATH_W) '$(srcdir)/utils/keymgr/bind_privkey.c'; fi`
+
+utils/keymgr/keymgr-functions.o: utils/keymgr/functions.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(keymgr_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/keymgr/keymgr-functions.o -MD -MP -MF utils/keymgr/$(DEPDIR)/keymgr-functions.Tpo -c -o utils/keymgr/keymgr-functions.o `test -f 'utils/keymgr/functions.c' || echo '$(srcdir)/'`utils/keymgr/functions.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/keymgr/$(DEPDIR)/keymgr-functions.Tpo utils/keymgr/$(DEPDIR)/keymgr-functions.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/keymgr/functions.c' object='utils/keymgr/keymgr-functions.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(keymgr_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/keymgr/keymgr-functions.o `test -f 'utils/keymgr/functions.c' || echo '$(srcdir)/'`utils/keymgr/functions.c
+
+utils/keymgr/keymgr-functions.obj: utils/keymgr/functions.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(keymgr_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/keymgr/keymgr-functions.obj -MD -MP -MF utils/keymgr/$(DEPDIR)/keymgr-functions.Tpo -c -o utils/keymgr/keymgr-functions.obj `if test -f 'utils/keymgr/functions.c'; then $(CYGPATH_W) 'utils/keymgr/functions.c'; else $(CYGPATH_W) '$(srcdir)/utils/keymgr/functions.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/keymgr/$(DEPDIR)/keymgr-functions.Tpo utils/keymgr/$(DEPDIR)/keymgr-functions.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/keymgr/functions.c' object='utils/keymgr/keymgr-functions.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(keymgr_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/keymgr/keymgr-functions.obj `if test -f 'utils/keymgr/functions.c'; then $(CYGPATH_W) 'utils/keymgr/functions.c'; else $(CYGPATH_W) '$(srcdir)/utils/keymgr/functions.c'; fi`
+
+utils/keymgr/keymgr-main.o: utils/keymgr/main.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(keymgr_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/keymgr/keymgr-main.o -MD -MP -MF utils/keymgr/$(DEPDIR)/keymgr-main.Tpo -c -o utils/keymgr/keymgr-main.o `test -f 'utils/keymgr/main.c' || echo '$(srcdir)/'`utils/keymgr/main.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/keymgr/$(DEPDIR)/keymgr-main.Tpo utils/keymgr/$(DEPDIR)/keymgr-main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/keymgr/main.c' object='utils/keymgr/keymgr-main.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(keymgr_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/keymgr/keymgr-main.o `test -f 'utils/keymgr/main.c' || echo '$(srcdir)/'`utils/keymgr/main.c
+
+utils/keymgr/keymgr-main.obj: utils/keymgr/main.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(keymgr_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/keymgr/keymgr-main.obj -MD -MP -MF utils/keymgr/$(DEPDIR)/keymgr-main.Tpo -c -o utils/keymgr/keymgr-main.obj `if test -f 'utils/keymgr/main.c'; then $(CYGPATH_W) 'utils/keymgr/main.c'; else $(CYGPATH_W) '$(srcdir)/utils/keymgr/main.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/keymgr/$(DEPDIR)/keymgr-main.Tpo utils/keymgr/$(DEPDIR)/keymgr-main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/keymgr/main.c' object='utils/keymgr/keymgr-main.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(keymgr_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/keymgr/keymgr-main.obj `if test -f 'utils/keymgr/main.c'; then $(CYGPATH_W) 'utils/keymgr/main.c'; else $(CYGPATH_W) '$(srcdir)/utils/keymgr/main.c'; fi`
+
+utils/kdig/khost-kdig_exec.o: utils/kdig/kdig_exec.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(khost_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/kdig/khost-kdig_exec.o -MD -MP -MF utils/kdig/$(DEPDIR)/khost-kdig_exec.Tpo -c -o utils/kdig/khost-kdig_exec.o `test -f 'utils/kdig/kdig_exec.c' || echo '$(srcdir)/'`utils/kdig/kdig_exec.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/kdig/$(DEPDIR)/khost-kdig_exec.Tpo utils/kdig/$(DEPDIR)/khost-kdig_exec.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/kdig/kdig_exec.c' object='utils/kdig/khost-kdig_exec.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(khost_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/kdig/khost-kdig_exec.o `test -f 'utils/kdig/kdig_exec.c' || echo '$(srcdir)/'`utils/kdig/kdig_exec.c
+
+utils/kdig/khost-kdig_exec.obj: utils/kdig/kdig_exec.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(khost_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/kdig/khost-kdig_exec.obj -MD -MP -MF utils/kdig/$(DEPDIR)/khost-kdig_exec.Tpo -c -o utils/kdig/khost-kdig_exec.obj `if test -f 'utils/kdig/kdig_exec.c'; then $(CYGPATH_W) 'utils/kdig/kdig_exec.c'; else $(CYGPATH_W) '$(srcdir)/utils/kdig/kdig_exec.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/kdig/$(DEPDIR)/khost-kdig_exec.Tpo utils/kdig/$(DEPDIR)/khost-kdig_exec.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/kdig/kdig_exec.c' object='utils/kdig/khost-kdig_exec.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(khost_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/kdig/khost-kdig_exec.obj `if test -f 'utils/kdig/kdig_exec.c'; then $(CYGPATH_W) 'utils/kdig/kdig_exec.c'; else $(CYGPATH_W) '$(srcdir)/utils/kdig/kdig_exec.c'; fi`
+
+utils/kdig/khost-kdig_params.o: utils/kdig/kdig_params.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(khost_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/kdig/khost-kdig_params.o -MD -MP -MF utils/kdig/$(DEPDIR)/khost-kdig_params.Tpo -c -o utils/kdig/khost-kdig_params.o `test -f 'utils/kdig/kdig_params.c' || echo '$(srcdir)/'`utils/kdig/kdig_params.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/kdig/$(DEPDIR)/khost-kdig_params.Tpo utils/kdig/$(DEPDIR)/khost-kdig_params.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/kdig/kdig_params.c' object='utils/kdig/khost-kdig_params.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(khost_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/kdig/khost-kdig_params.o `test -f 'utils/kdig/kdig_params.c' || echo '$(srcdir)/'`utils/kdig/kdig_params.c
+
+utils/kdig/khost-kdig_params.obj: utils/kdig/kdig_params.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(khost_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/kdig/khost-kdig_params.obj -MD -MP -MF utils/kdig/$(DEPDIR)/khost-kdig_params.Tpo -c -o utils/kdig/khost-kdig_params.obj `if test -f 'utils/kdig/kdig_params.c'; then $(CYGPATH_W) 'utils/kdig/kdig_params.c'; else $(CYGPATH_W) '$(srcdir)/utils/kdig/kdig_params.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/kdig/$(DEPDIR)/khost-kdig_params.Tpo utils/kdig/$(DEPDIR)/khost-kdig_params.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/kdig/kdig_params.c' object='utils/kdig/khost-kdig_params.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(khost_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/kdig/khost-kdig_params.obj `if test -f 'utils/kdig/kdig_params.c'; then $(CYGPATH_W) 'utils/kdig/kdig_params.c'; else $(CYGPATH_W) '$(srcdir)/utils/kdig/kdig_params.c'; fi`
+
+utils/khost/khost-khost_main.o: utils/khost/khost_main.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(khost_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/khost/khost-khost_main.o -MD -MP -MF utils/khost/$(DEPDIR)/khost-khost_main.Tpo -c -o utils/khost/khost-khost_main.o `test -f 'utils/khost/khost_main.c' || echo '$(srcdir)/'`utils/khost/khost_main.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/khost/$(DEPDIR)/khost-khost_main.Tpo utils/khost/$(DEPDIR)/khost-khost_main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/khost/khost_main.c' object='utils/khost/khost-khost_main.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(khost_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/khost/khost-khost_main.o `test -f 'utils/khost/khost_main.c' || echo '$(srcdir)/'`utils/khost/khost_main.c
+
+utils/khost/khost-khost_main.obj: utils/khost/khost_main.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(khost_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/khost/khost-khost_main.obj -MD -MP -MF utils/khost/$(DEPDIR)/khost-khost_main.Tpo -c -o utils/khost/khost-khost_main.obj `if test -f 'utils/khost/khost_main.c'; then $(CYGPATH_W) 'utils/khost/khost_main.c'; else $(CYGPATH_W) '$(srcdir)/utils/khost/khost_main.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/khost/$(DEPDIR)/khost-khost_main.Tpo utils/khost/$(DEPDIR)/khost-khost_main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/khost/khost_main.c' object='utils/khost/khost-khost_main.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(khost_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/khost/khost-khost_main.obj `if test -f 'utils/khost/khost_main.c'; then $(CYGPATH_W) 'utils/khost/khost_main.c'; else $(CYGPATH_W) '$(srcdir)/utils/khost/khost_main.c'; fi`
+
+utils/khost/khost-khost_params.o: utils/khost/khost_params.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(khost_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/khost/khost-khost_params.o -MD -MP -MF utils/khost/$(DEPDIR)/khost-khost_params.Tpo -c -o utils/khost/khost-khost_params.o `test -f 'utils/khost/khost_params.c' || echo '$(srcdir)/'`utils/khost/khost_params.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/khost/$(DEPDIR)/khost-khost_params.Tpo utils/khost/$(DEPDIR)/khost-khost_params.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/khost/khost_params.c' object='utils/khost/khost-khost_params.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(khost_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/khost/khost-khost_params.o `test -f 'utils/khost/khost_params.c' || echo '$(srcdir)/'`utils/khost/khost_params.c
+
+utils/khost/khost-khost_params.obj: utils/khost/khost_params.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(khost_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/khost/khost-khost_params.obj -MD -MP -MF utils/khost/$(DEPDIR)/khost-khost_params.Tpo -c -o utils/khost/khost-khost_params.obj `if test -f 'utils/khost/khost_params.c'; then $(CYGPATH_W) 'utils/khost/khost_params.c'; else $(CYGPATH_W) '$(srcdir)/utils/khost/khost_params.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/khost/$(DEPDIR)/khost-khost_params.Tpo utils/khost/$(DEPDIR)/khost-khost_params.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/khost/khost_params.c' object='utils/khost/khost-khost_params.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(khost_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/khost/khost-khost_params.obj `if test -f 'utils/khost/khost_params.c'; then $(CYGPATH_W) 'utils/khost/khost_params.c'; else $(CYGPATH_W) '$(srcdir)/utils/khost/khost_params.c'; fi`
+
+utils/kjournalprint/kjournalprint-main.o: utils/kjournalprint/main.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kjournalprint_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/kjournalprint/kjournalprint-main.o -MD -MP -MF utils/kjournalprint/$(DEPDIR)/kjournalprint-main.Tpo -c -o utils/kjournalprint/kjournalprint-main.o `test -f 'utils/kjournalprint/main.c' || echo '$(srcdir)/'`utils/kjournalprint/main.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/kjournalprint/$(DEPDIR)/kjournalprint-main.Tpo utils/kjournalprint/$(DEPDIR)/kjournalprint-main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/kjournalprint/main.c' object='utils/kjournalprint/kjournalprint-main.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kjournalprint_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/kjournalprint/kjournalprint-main.o `test -f 'utils/kjournalprint/main.c' || echo '$(srcdir)/'`utils/kjournalprint/main.c
+
+utils/kjournalprint/kjournalprint-main.obj: utils/kjournalprint/main.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kjournalprint_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/kjournalprint/kjournalprint-main.obj -MD -MP -MF utils/kjournalprint/$(DEPDIR)/kjournalprint-main.Tpo -c -o utils/kjournalprint/kjournalprint-main.obj `if test -f 'utils/kjournalprint/main.c'; then $(CYGPATH_W) 'utils/kjournalprint/main.c'; else $(CYGPATH_W) '$(srcdir)/utils/kjournalprint/main.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/kjournalprint/$(DEPDIR)/kjournalprint-main.Tpo utils/kjournalprint/$(DEPDIR)/kjournalprint-main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/kjournalprint/main.c' object='utils/kjournalprint/kjournalprint-main.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kjournalprint_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/kjournalprint/kjournalprint-main.obj `if test -f 'utils/kjournalprint/main.c'; then $(CYGPATH_W) 'utils/kjournalprint/main.c'; else $(CYGPATH_W) '$(srcdir)/utils/kjournalprint/main.c'; fi`
+
+utils/knotc/knotc-commands.o: utils/knotc/commands.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knotc_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/knotc/knotc-commands.o -MD -MP -MF utils/knotc/$(DEPDIR)/knotc-commands.Tpo -c -o utils/knotc/knotc-commands.o `test -f 'utils/knotc/commands.c' || echo '$(srcdir)/'`utils/knotc/commands.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/knotc/$(DEPDIR)/knotc-commands.Tpo utils/knotc/$(DEPDIR)/knotc-commands.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/knotc/commands.c' object='utils/knotc/knotc-commands.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knotc_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/knotc/knotc-commands.o `test -f 'utils/knotc/commands.c' || echo '$(srcdir)/'`utils/knotc/commands.c
+
+utils/knotc/knotc-commands.obj: utils/knotc/commands.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knotc_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/knotc/knotc-commands.obj -MD -MP -MF utils/knotc/$(DEPDIR)/knotc-commands.Tpo -c -o utils/knotc/knotc-commands.obj `if test -f 'utils/knotc/commands.c'; then $(CYGPATH_W) 'utils/knotc/commands.c'; else $(CYGPATH_W) '$(srcdir)/utils/knotc/commands.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/knotc/$(DEPDIR)/knotc-commands.Tpo utils/knotc/$(DEPDIR)/knotc-commands.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/knotc/commands.c' object='utils/knotc/knotc-commands.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knotc_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/knotc/knotc-commands.obj `if test -f 'utils/knotc/commands.c'; then $(CYGPATH_W) 'utils/knotc/commands.c'; else $(CYGPATH_W) '$(srcdir)/utils/knotc/commands.c'; fi`
+
+utils/knotc/knotc-estimator.o: utils/knotc/estimator.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knotc_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/knotc/knotc-estimator.o -MD -MP -MF utils/knotc/$(DEPDIR)/knotc-estimator.Tpo -c -o utils/knotc/knotc-estimator.o `test -f 'utils/knotc/estimator.c' || echo '$(srcdir)/'`utils/knotc/estimator.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/knotc/$(DEPDIR)/knotc-estimator.Tpo utils/knotc/$(DEPDIR)/knotc-estimator.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/knotc/estimator.c' object='utils/knotc/knotc-estimator.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knotc_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/knotc/knotc-estimator.o `test -f 'utils/knotc/estimator.c' || echo '$(srcdir)/'`utils/knotc/estimator.c
+
+utils/knotc/knotc-estimator.obj: utils/knotc/estimator.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knotc_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/knotc/knotc-estimator.obj -MD -MP -MF utils/knotc/$(DEPDIR)/knotc-estimator.Tpo -c -o utils/knotc/knotc-estimator.obj `if test -f 'utils/knotc/estimator.c'; then $(CYGPATH_W) 'utils/knotc/estimator.c'; else $(CYGPATH_W) '$(srcdir)/utils/knotc/estimator.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/knotc/$(DEPDIR)/knotc-estimator.Tpo utils/knotc/$(DEPDIR)/knotc-estimator.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/knotc/estimator.c' object='utils/knotc/knotc-estimator.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knotc_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/knotc/knotc-estimator.obj `if test -f 'utils/knotc/estimator.c'; then $(CYGPATH_W) 'utils/knotc/estimator.c'; else $(CYGPATH_W) '$(srcdir)/utils/knotc/estimator.c'; fi`
+
+utils/knotc/knotc-interactive.o: utils/knotc/interactive.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knotc_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/knotc/knotc-interactive.o -MD -MP -MF utils/knotc/$(DEPDIR)/knotc-interactive.Tpo -c -o utils/knotc/knotc-interactive.o `test -f 'utils/knotc/interactive.c' || echo '$(srcdir)/'`utils/knotc/interactive.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/knotc/$(DEPDIR)/knotc-interactive.Tpo utils/knotc/$(DEPDIR)/knotc-interactive.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/knotc/interactive.c' object='utils/knotc/knotc-interactive.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knotc_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/knotc/knotc-interactive.o `test -f 'utils/knotc/interactive.c' || echo '$(srcdir)/'`utils/knotc/interactive.c
+
+utils/knotc/knotc-interactive.obj: utils/knotc/interactive.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knotc_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/knotc/knotc-interactive.obj -MD -MP -MF utils/knotc/$(DEPDIR)/knotc-interactive.Tpo -c -o utils/knotc/knotc-interactive.obj `if test -f 'utils/knotc/interactive.c'; then $(CYGPATH_W) 'utils/knotc/interactive.c'; else $(CYGPATH_W) '$(srcdir)/utils/knotc/interactive.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/knotc/$(DEPDIR)/knotc-interactive.Tpo utils/knotc/$(DEPDIR)/knotc-interactive.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/knotc/interactive.c' object='utils/knotc/knotc-interactive.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knotc_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/knotc/knotc-interactive.obj `if test -f 'utils/knotc/interactive.c'; then $(CYGPATH_W) 'utils/knotc/interactive.c'; else $(CYGPATH_W) '$(srcdir)/utils/knotc/interactive.c'; fi`
+
+utils/knotc/knotc-process.o: utils/knotc/process.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knotc_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/knotc/knotc-process.o -MD -MP -MF utils/knotc/$(DEPDIR)/knotc-process.Tpo -c -o utils/knotc/knotc-process.o `test -f 'utils/knotc/process.c' || echo '$(srcdir)/'`utils/knotc/process.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/knotc/$(DEPDIR)/knotc-process.Tpo utils/knotc/$(DEPDIR)/knotc-process.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/knotc/process.c' object='utils/knotc/knotc-process.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knotc_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/knotc/knotc-process.o `test -f 'utils/knotc/process.c' || echo '$(srcdir)/'`utils/knotc/process.c
+
+utils/knotc/knotc-process.obj: utils/knotc/process.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knotc_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/knotc/knotc-process.obj -MD -MP -MF utils/knotc/$(DEPDIR)/knotc-process.Tpo -c -o utils/knotc/knotc-process.obj `if test -f 'utils/knotc/process.c'; then $(CYGPATH_W) 'utils/knotc/process.c'; else $(CYGPATH_W) '$(srcdir)/utils/knotc/process.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/knotc/$(DEPDIR)/knotc-process.Tpo utils/knotc/$(DEPDIR)/knotc-process.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/knotc/process.c' object='utils/knotc/knotc-process.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knotc_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/knotc/knotc-process.obj `if test -f 'utils/knotc/process.c'; then $(CYGPATH_W) 'utils/knotc/process.c'; else $(CYGPATH_W) '$(srcdir)/utils/knotc/process.c'; fi`
+
+utils/knotc/knotc-main.o: utils/knotc/main.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knotc_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/knotc/knotc-main.o -MD -MP -MF utils/knotc/$(DEPDIR)/knotc-main.Tpo -c -o utils/knotc/knotc-main.o `test -f 'utils/knotc/main.c' || echo '$(srcdir)/'`utils/knotc/main.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/knotc/$(DEPDIR)/knotc-main.Tpo utils/knotc/$(DEPDIR)/knotc-main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/knotc/main.c' object='utils/knotc/knotc-main.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knotc_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/knotc/knotc-main.o `test -f 'utils/knotc/main.c' || echo '$(srcdir)/'`utils/knotc/main.c
+
+utils/knotc/knotc-main.obj: utils/knotc/main.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knotc_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/knotc/knotc-main.obj -MD -MP -MF utils/knotc/$(DEPDIR)/knotc-main.Tpo -c -o utils/knotc/knotc-main.obj `if test -f 'utils/knotc/main.c'; then $(CYGPATH_W) 'utils/knotc/main.c'; else $(CYGPATH_W) '$(srcdir)/utils/knotc/main.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/knotc/$(DEPDIR)/knotc-main.Tpo utils/knotc/$(DEPDIR)/knotc-main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/knotc/main.c' object='utils/knotc/knotc-main.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knotc_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/knotc/knotc-main.obj `if test -f 'utils/knotc/main.c'; then $(CYGPATH_W) 'utils/knotc/main.c'; else $(CYGPATH_W) '$(srcdir)/utils/knotc/main.c'; fi`
+
+utils/knotd/knotd-main.o: utils/knotd/main.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knotd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/knotd/knotd-main.o -MD -MP -MF utils/knotd/$(DEPDIR)/knotd-main.Tpo -c -o utils/knotd/knotd-main.o `test -f 'utils/knotd/main.c' || echo '$(srcdir)/'`utils/knotd/main.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/knotd/$(DEPDIR)/knotd-main.Tpo utils/knotd/$(DEPDIR)/knotd-main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/knotd/main.c' object='utils/knotd/knotd-main.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knotd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/knotd/knotd-main.o `test -f 'utils/knotd/main.c' || echo '$(srcdir)/'`utils/knotd/main.c
+
+utils/knotd/knotd-main.obj: utils/knotd/main.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knotd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/knotd/knotd-main.obj -MD -MP -MF utils/knotd/$(DEPDIR)/knotd-main.Tpo -c -o utils/knotd/knotd-main.obj `if test -f 'utils/knotd/main.c'; then $(CYGPATH_W) 'utils/knotd/main.c'; else $(CYGPATH_W) '$(srcdir)/utils/knotd/main.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/knotd/$(DEPDIR)/knotd-main.Tpo utils/knotd/$(DEPDIR)/knotd-main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/knotd/main.c' object='utils/knotd/knotd-main.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knotd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/knotd/knotd-main.obj `if test -f 'utils/knotd/main.c'; then $(CYGPATH_W) 'utils/knotd/main.c'; else $(CYGPATH_W) '$(srcdir)/utils/knotd/main.c'; fi`
+
+utils/knsec3hash/knsec3hash-knsec3hash.o: utils/knsec3hash/knsec3hash.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knsec3hash_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/knsec3hash/knsec3hash-knsec3hash.o -MD -MP -MF utils/knsec3hash/$(DEPDIR)/knsec3hash-knsec3hash.Tpo -c -o utils/knsec3hash/knsec3hash-knsec3hash.o `test -f 'utils/knsec3hash/knsec3hash.c' || echo '$(srcdir)/'`utils/knsec3hash/knsec3hash.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/knsec3hash/$(DEPDIR)/knsec3hash-knsec3hash.Tpo utils/knsec3hash/$(DEPDIR)/knsec3hash-knsec3hash.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/knsec3hash/knsec3hash.c' object='utils/knsec3hash/knsec3hash-knsec3hash.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knsec3hash_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/knsec3hash/knsec3hash-knsec3hash.o `test -f 'utils/knsec3hash/knsec3hash.c' || echo '$(srcdir)/'`utils/knsec3hash/knsec3hash.c
+
+utils/knsec3hash/knsec3hash-knsec3hash.obj: utils/knsec3hash/knsec3hash.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knsec3hash_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/knsec3hash/knsec3hash-knsec3hash.obj -MD -MP -MF utils/knsec3hash/$(DEPDIR)/knsec3hash-knsec3hash.Tpo -c -o utils/knsec3hash/knsec3hash-knsec3hash.obj `if test -f 'utils/knsec3hash/knsec3hash.c'; then $(CYGPATH_W) 'utils/knsec3hash/knsec3hash.c'; else $(CYGPATH_W) '$(srcdir)/utils/knsec3hash/knsec3hash.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/knsec3hash/$(DEPDIR)/knsec3hash-knsec3hash.Tpo utils/knsec3hash/$(DEPDIR)/knsec3hash-knsec3hash.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/knsec3hash/knsec3hash.c' object='utils/knsec3hash/knsec3hash-knsec3hash.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knsec3hash_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/knsec3hash/knsec3hash-knsec3hash.obj `if test -f 'utils/knsec3hash/knsec3hash.c'; then $(CYGPATH_W) 'utils/knsec3hash/knsec3hash.c'; else $(CYGPATH_W) '$(srcdir)/utils/knsec3hash/knsec3hash.c'; fi`
+
+utils/knsupdate/knsupdate-knsupdate_exec.o: utils/knsupdate/knsupdate_exec.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knsupdate_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/knsupdate/knsupdate-knsupdate_exec.o -MD -MP -MF utils/knsupdate/$(DEPDIR)/knsupdate-knsupdate_exec.Tpo -c -o utils/knsupdate/knsupdate-knsupdate_exec.o `test -f 'utils/knsupdate/knsupdate_exec.c' || echo '$(srcdir)/'`utils/knsupdate/knsupdate_exec.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/knsupdate/$(DEPDIR)/knsupdate-knsupdate_exec.Tpo utils/knsupdate/$(DEPDIR)/knsupdate-knsupdate_exec.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/knsupdate/knsupdate_exec.c' object='utils/knsupdate/knsupdate-knsupdate_exec.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knsupdate_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/knsupdate/knsupdate-knsupdate_exec.o `test -f 'utils/knsupdate/knsupdate_exec.c' || echo '$(srcdir)/'`utils/knsupdate/knsupdate_exec.c
+
+utils/knsupdate/knsupdate-knsupdate_exec.obj: utils/knsupdate/knsupdate_exec.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knsupdate_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/knsupdate/knsupdate-knsupdate_exec.obj -MD -MP -MF utils/knsupdate/$(DEPDIR)/knsupdate-knsupdate_exec.Tpo -c -o utils/knsupdate/knsupdate-knsupdate_exec.obj `if test -f 'utils/knsupdate/knsupdate_exec.c'; then $(CYGPATH_W) 'utils/knsupdate/knsupdate_exec.c'; else $(CYGPATH_W) '$(srcdir)/utils/knsupdate/knsupdate_exec.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/knsupdate/$(DEPDIR)/knsupdate-knsupdate_exec.Tpo utils/knsupdate/$(DEPDIR)/knsupdate-knsupdate_exec.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/knsupdate/knsupdate_exec.c' object='utils/knsupdate/knsupdate-knsupdate_exec.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knsupdate_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/knsupdate/knsupdate-knsupdate_exec.obj `if test -f 'utils/knsupdate/knsupdate_exec.c'; then $(CYGPATH_W) 'utils/knsupdate/knsupdate_exec.c'; else $(CYGPATH_W) '$(srcdir)/utils/knsupdate/knsupdate_exec.c'; fi`
+
+utils/knsupdate/knsupdate-knsupdate_main.o: utils/knsupdate/knsupdate_main.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knsupdate_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/knsupdate/knsupdate-knsupdate_main.o -MD -MP -MF utils/knsupdate/$(DEPDIR)/knsupdate-knsupdate_main.Tpo -c -o utils/knsupdate/knsupdate-knsupdate_main.o `test -f 'utils/knsupdate/knsupdate_main.c' || echo '$(srcdir)/'`utils/knsupdate/knsupdate_main.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/knsupdate/$(DEPDIR)/knsupdate-knsupdate_main.Tpo utils/knsupdate/$(DEPDIR)/knsupdate-knsupdate_main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/knsupdate/knsupdate_main.c' object='utils/knsupdate/knsupdate-knsupdate_main.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knsupdate_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/knsupdate/knsupdate-knsupdate_main.o `test -f 'utils/knsupdate/knsupdate_main.c' || echo '$(srcdir)/'`utils/knsupdate/knsupdate_main.c
+
+utils/knsupdate/knsupdate-knsupdate_main.obj: utils/knsupdate/knsupdate_main.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knsupdate_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/knsupdate/knsupdate-knsupdate_main.obj -MD -MP -MF utils/knsupdate/$(DEPDIR)/knsupdate-knsupdate_main.Tpo -c -o utils/knsupdate/knsupdate-knsupdate_main.obj `if test -f 'utils/knsupdate/knsupdate_main.c'; then $(CYGPATH_W) 'utils/knsupdate/knsupdate_main.c'; else $(CYGPATH_W) '$(srcdir)/utils/knsupdate/knsupdate_main.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/knsupdate/$(DEPDIR)/knsupdate-knsupdate_main.Tpo utils/knsupdate/$(DEPDIR)/knsupdate-knsupdate_main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/knsupdate/knsupdate_main.c' object='utils/knsupdate/knsupdate-knsupdate_main.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knsupdate_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/knsupdate/knsupdate-knsupdate_main.obj `if test -f 'utils/knsupdate/knsupdate_main.c'; then $(CYGPATH_W) 'utils/knsupdate/knsupdate_main.c'; else $(CYGPATH_W) '$(srcdir)/utils/knsupdate/knsupdate_main.c'; fi`
+
+utils/knsupdate/knsupdate-knsupdate_params.o: utils/knsupdate/knsupdate_params.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knsupdate_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/knsupdate/knsupdate-knsupdate_params.o -MD -MP -MF utils/knsupdate/$(DEPDIR)/knsupdate-knsupdate_params.Tpo -c -o utils/knsupdate/knsupdate-knsupdate_params.o `test -f 'utils/knsupdate/knsupdate_params.c' || echo '$(srcdir)/'`utils/knsupdate/knsupdate_params.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/knsupdate/$(DEPDIR)/knsupdate-knsupdate_params.Tpo utils/knsupdate/$(DEPDIR)/knsupdate-knsupdate_params.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/knsupdate/knsupdate_params.c' object='utils/knsupdate/knsupdate-knsupdate_params.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knsupdate_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/knsupdate/knsupdate-knsupdate_params.o `test -f 'utils/knsupdate/knsupdate_params.c' || echo '$(srcdir)/'`utils/knsupdate/knsupdate_params.c
+
+utils/knsupdate/knsupdate-knsupdate_params.obj: utils/knsupdate/knsupdate_params.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knsupdate_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/knsupdate/knsupdate-knsupdate_params.obj -MD -MP -MF utils/knsupdate/$(DEPDIR)/knsupdate-knsupdate_params.Tpo -c -o utils/knsupdate/knsupdate-knsupdate_params.obj `if test -f 'utils/knsupdate/knsupdate_params.c'; then $(CYGPATH_W) 'utils/knsupdate/knsupdate_params.c'; else $(CYGPATH_W) '$(srcdir)/utils/knsupdate/knsupdate_params.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/knsupdate/$(DEPDIR)/knsupdate-knsupdate_params.Tpo utils/knsupdate/$(DEPDIR)/knsupdate-knsupdate_params.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/knsupdate/knsupdate_params.c' object='utils/knsupdate/knsupdate-knsupdate_params.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knsupdate_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/knsupdate/knsupdate-knsupdate_params.obj `if test -f 'utils/knsupdate/knsupdate_params.c'; then $(CYGPATH_W) 'utils/knsupdate/knsupdate_params.c'; else $(CYGPATH_W) '$(srcdir)/utils/knsupdate/knsupdate_params.c'; fi`
+
+utils/kzonecheck/kzonecheck-main.o: utils/kzonecheck/main.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kzonecheck_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/kzonecheck/kzonecheck-main.o -MD -MP -MF utils/kzonecheck/$(DEPDIR)/kzonecheck-main.Tpo -c -o utils/kzonecheck/kzonecheck-main.o `test -f 'utils/kzonecheck/main.c' || echo '$(srcdir)/'`utils/kzonecheck/main.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/kzonecheck/$(DEPDIR)/kzonecheck-main.Tpo utils/kzonecheck/$(DEPDIR)/kzonecheck-main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/kzonecheck/main.c' object='utils/kzonecheck/kzonecheck-main.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kzonecheck_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/kzonecheck/kzonecheck-main.o `test -f 'utils/kzonecheck/main.c' || echo '$(srcdir)/'`utils/kzonecheck/main.c
+
+utils/kzonecheck/kzonecheck-main.obj: utils/kzonecheck/main.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kzonecheck_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/kzonecheck/kzonecheck-main.obj -MD -MP -MF utils/kzonecheck/$(DEPDIR)/kzonecheck-main.Tpo -c -o utils/kzonecheck/kzonecheck-main.obj `if test -f 'utils/kzonecheck/main.c'; then $(CYGPATH_W) 'utils/kzonecheck/main.c'; else $(CYGPATH_W) '$(srcdir)/utils/kzonecheck/main.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/kzonecheck/$(DEPDIR)/kzonecheck-main.Tpo utils/kzonecheck/$(DEPDIR)/kzonecheck-main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/kzonecheck/main.c' object='utils/kzonecheck/kzonecheck-main.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kzonecheck_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/kzonecheck/kzonecheck-main.obj `if test -f 'utils/kzonecheck/main.c'; then $(CYGPATH_W) 'utils/kzonecheck/main.c'; else $(CYGPATH_W) '$(srcdir)/utils/kzonecheck/main.c'; fi`
+
+utils/kzonecheck/kzonecheck-zone_check.o: utils/kzonecheck/zone_check.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kzonecheck_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/kzonecheck/kzonecheck-zone_check.o -MD -MP -MF utils/kzonecheck/$(DEPDIR)/kzonecheck-zone_check.Tpo -c -o utils/kzonecheck/kzonecheck-zone_check.o `test -f 'utils/kzonecheck/zone_check.c' || echo '$(srcdir)/'`utils/kzonecheck/zone_check.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/kzonecheck/$(DEPDIR)/kzonecheck-zone_check.Tpo utils/kzonecheck/$(DEPDIR)/kzonecheck-zone_check.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/kzonecheck/zone_check.c' object='utils/kzonecheck/kzonecheck-zone_check.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kzonecheck_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/kzonecheck/kzonecheck-zone_check.o `test -f 'utils/kzonecheck/zone_check.c' || echo '$(srcdir)/'`utils/kzonecheck/zone_check.c
+
+utils/kzonecheck/kzonecheck-zone_check.obj: utils/kzonecheck/zone_check.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kzonecheck_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/kzonecheck/kzonecheck-zone_check.obj -MD -MP -MF utils/kzonecheck/$(DEPDIR)/kzonecheck-zone_check.Tpo -c -o utils/kzonecheck/kzonecheck-zone_check.obj `if test -f 'utils/kzonecheck/zone_check.c'; then $(CYGPATH_W) 'utils/kzonecheck/zone_check.c'; else $(CYGPATH_W) '$(srcdir)/utils/kzonecheck/zone_check.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/kzonecheck/$(DEPDIR)/kzonecheck-zone_check.Tpo utils/kzonecheck/$(DEPDIR)/kzonecheck-zone_check.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/kzonecheck/zone_check.c' object='utils/kzonecheck/kzonecheck-zone_check.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kzonecheck_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/kzonecheck/kzonecheck-zone_check.obj `if test -f 'utils/kzonecheck/zone_check.c'; then $(CYGPATH_W) 'utils/kzonecheck/zone_check.c'; else $(CYGPATH_W) '$(srcdir)/utils/kzonecheck/zone_check.c'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+ -rm -rf contrib/.libs contrib/_libs
+ -rm -rf contrib/dnstap/.libs contrib/dnstap/_libs
+ -rm -rf contrib/lmdb/.libs contrib/lmdb/_libs
+ -rm -rf contrib/openbsd/.libs contrib/openbsd/_libs
+ -rm -rf contrib/qp-trie/.libs contrib/qp-trie/_libs
+ -rm -rf contrib/ucw/.libs contrib/ucw/_libs
+ -rm -rf knot/common/.libs knot/common/_libs
+ -rm -rf knot/conf/.libs knot/conf/_libs
+ -rm -rf knot/ctl/.libs knot/ctl/_libs
+ -rm -rf knot/dnssec/.libs knot/dnssec/_libs
+ -rm -rf knot/dnssec/kasp/.libs knot/dnssec/kasp/_libs
+ -rm -rf knot/events/.libs knot/events/_libs
+ -rm -rf knot/events/handlers/.libs knot/events/handlers/_libs
+ -rm -rf knot/journal/.libs knot/journal/_libs
+ -rm -rf knot/modules/.libs knot/modules/_libs
+ -rm -rf knot/modules/cookies/.libs knot/modules/cookies/_libs
+ -rm -rf knot/modules/dnsproxy/.libs knot/modules/dnsproxy/_libs
+ -rm -rf knot/modules/dnstap/.libs knot/modules/dnstap/_libs
+ -rm -rf knot/modules/geoip/.libs knot/modules/geoip/_libs
+ -rm -rf knot/modules/noudp/.libs knot/modules/noudp/_libs
+ -rm -rf knot/modules/onlinesign/.libs knot/modules/onlinesign/_libs
+ -rm -rf knot/modules/queryacl/.libs knot/modules/queryacl/_libs
+ -rm -rf knot/modules/rrl/.libs knot/modules/rrl/_libs
+ -rm -rf knot/modules/stats/.libs knot/modules/stats/_libs
+ -rm -rf knot/modules/synthrecord/.libs knot/modules/synthrecord/_libs
+ -rm -rf knot/modules/whoami/.libs knot/modules/whoami/_libs
+ -rm -rf knot/nameserver/.libs knot/nameserver/_libs
+ -rm -rf knot/query/.libs knot/query/_libs
+ -rm -rf knot/server/.libs knot/server/_libs
+ -rm -rf knot/updates/.libs knot/updates/_libs
+ -rm -rf knot/worker/.libs knot/worker/_libs
+ -rm -rf knot/zone/.libs knot/zone/_libs
+ -rm -rf libdnssec/.libs libdnssec/_libs
+ -rm -rf libdnssec/contrib/.libs libdnssec/contrib/_libs
+ -rm -rf libdnssec/key/.libs libdnssec/key/_libs
+ -rm -rf libdnssec/keystore/.libs libdnssec/keystore/_libs
+ -rm -rf libdnssec/list/.libs libdnssec/list/_libs
+ -rm -rf libdnssec/nsec/.libs libdnssec/nsec/_libs
+ -rm -rf libdnssec/p11/.libs libdnssec/p11/_libs
+ -rm -rf libdnssec/shared/.libs libdnssec/shared/_libs
+ -rm -rf libdnssec/sign/.libs libdnssec/sign/_libs
+ -rm -rf libknot/.libs libknot/_libs
+ -rm -rf libknot/control/.libs libknot/control/_libs
+ -rm -rf libknot/db/.libs libknot/db/_libs
+ -rm -rf libknot/packet/.libs libknot/packet/_libs
+ -rm -rf libknot/rrtype/.libs libknot/rrtype/_libs
+ -rm -rf libknot/yparser/.libs libknot/yparser/_libs
+ -rm -rf libzscanner/.libs libzscanner/_libs
+ -rm -rf utils/common/.libs utils/common/_libs
+install-pkgconfigDATA: $(pkgconfig_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \
+ done
+
+uninstall-pkgconfigDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir)
+install-include_libdnssecHEADERS: $(include_libdnssec_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(include_libdnssec_HEADERS)'; test -n "$(include_libdnssecdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(include_libdnssecdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(include_libdnssecdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(include_libdnssecdir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(include_libdnssecdir)" || exit $$?; \
+ done
+
+uninstall-include_libdnssecHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(include_libdnssec_HEADERS)'; test -n "$(include_libdnssecdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(include_libdnssecdir)'; $(am__uninstall_files_from_dir)
+install-include_libknotdHEADERS: $(include_libknotd_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(include_libknotd_HEADERS)'; test -n "$(include_libknotddir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(include_libknotddir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(include_libknotddir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(include_libknotddir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(include_libknotddir)" || exit $$?; \
+ done
+
+uninstall-include_libknotdHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(include_libknotd_HEADERS)'; test -n "$(include_libknotddir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(include_libknotddir)'; $(am__uninstall_files_from_dir)
+install-include_libzscannerHEADERS: $(include_libzscanner_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(include_libzscanner_HEADERS)'; test -n "$(include_libzscannerdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(include_libzscannerdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(include_libzscannerdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(include_libzscannerdir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(include_libzscannerdir)" || exit $$?; \
+ done
+
+uninstall-include_libzscannerHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(include_libzscanner_HEADERS)'; test -n "$(include_libzscannerdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(include_libzscannerdir)'; $(am__uninstall_files_from_dir)
+install-nobase_include_libknotHEADERS: $(nobase_include_libknot_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(nobase_include_libknot_HEADERS)'; test -n "$(include_libknotdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(include_libknotdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(include_libknotdir)" || exit 1; \
+ fi; \
+ $(am__nobase_list) | while read dir files; do \
+ xfiles=; for file in $$files; do \
+ if test -f "$$file"; then xfiles="$$xfiles $$file"; \
+ else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \
+ test -z "$$xfiles" || { \
+ test "x$$dir" = x. || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(include_libknotdir)/$$dir'"; \
+ $(MKDIR_P) "$(DESTDIR)$(include_libknotdir)/$$dir"; }; \
+ echo " $(INSTALL_HEADER) $$xfiles '$(DESTDIR)$(include_libknotdir)/$$dir'"; \
+ $(INSTALL_HEADER) $$xfiles "$(DESTDIR)$(include_libknotdir)/$$dir" || exit $$?; }; \
+ done
+
+uninstall-nobase_include_libknotHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(nobase_include_libknot_HEADERS)'; test -n "$(include_libknotdir)" || list=; \
+ $(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \
+ dir='$(DESTDIR)$(include_libknotdir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS) \
+ config.h
+install-binPROGRAMS: install-libLTLIBRARIES
+
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkglibdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(include_libdnssecdir)" "$(DESTDIR)$(include_libknotddir)" "$(DESTDIR)$(include_libzscannerdir)" "$(DESTDIR)$(include_libknotdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+ -rm -f contrib/$(DEPDIR)/$(am__dirstamp)
+ -rm -f contrib/$(am__dirstamp)
+ -rm -f contrib/dnstap/$(DEPDIR)/$(am__dirstamp)
+ -rm -f contrib/dnstap/$(am__dirstamp)
+ -rm -f contrib/lmdb/$(DEPDIR)/$(am__dirstamp)
+ -rm -f contrib/lmdb/$(am__dirstamp)
+ -rm -f contrib/openbsd/$(DEPDIR)/$(am__dirstamp)
+ -rm -f contrib/openbsd/$(am__dirstamp)
+ -rm -f contrib/qp-trie/$(DEPDIR)/$(am__dirstamp)
+ -rm -f contrib/qp-trie/$(am__dirstamp)
+ -rm -f contrib/ucw/$(DEPDIR)/$(am__dirstamp)
+ -rm -f contrib/ucw/$(am__dirstamp)
+ -rm -f knot/common/$(DEPDIR)/$(am__dirstamp)
+ -rm -f knot/common/$(am__dirstamp)
+ -rm -f knot/conf/$(DEPDIR)/$(am__dirstamp)
+ -rm -f knot/conf/$(am__dirstamp)
+ -rm -f knot/ctl/$(DEPDIR)/$(am__dirstamp)
+ -rm -f knot/ctl/$(am__dirstamp)
+ -rm -f knot/dnssec/$(DEPDIR)/$(am__dirstamp)
+ -rm -f knot/dnssec/$(am__dirstamp)
+ -rm -f knot/dnssec/kasp/$(DEPDIR)/$(am__dirstamp)
+ -rm -f knot/dnssec/kasp/$(am__dirstamp)
+ -rm -f knot/events/$(DEPDIR)/$(am__dirstamp)
+ -rm -f knot/events/$(am__dirstamp)
+ -rm -f knot/events/handlers/$(DEPDIR)/$(am__dirstamp)
+ -rm -f knot/events/handlers/$(am__dirstamp)
+ -rm -f knot/journal/$(DEPDIR)/$(am__dirstamp)
+ -rm -f knot/journal/$(am__dirstamp)
+ -rm -f knot/modules/$(am__dirstamp)
+ -rm -f knot/modules/cookies/$(DEPDIR)/$(am__dirstamp)
+ -rm -f knot/modules/cookies/$(am__dirstamp)
+ -rm -f knot/modules/dnsproxy/$(DEPDIR)/$(am__dirstamp)
+ -rm -f knot/modules/dnsproxy/$(am__dirstamp)
+ -rm -f knot/modules/dnstap/$(DEPDIR)/$(am__dirstamp)
+ -rm -f knot/modules/dnstap/$(am__dirstamp)
+ -rm -f knot/modules/geoip/$(DEPDIR)/$(am__dirstamp)
+ -rm -f knot/modules/geoip/$(am__dirstamp)
+ -rm -f knot/modules/noudp/$(DEPDIR)/$(am__dirstamp)
+ -rm -f knot/modules/noudp/$(am__dirstamp)
+ -rm -f knot/modules/onlinesign/$(DEPDIR)/$(am__dirstamp)
+ -rm -f knot/modules/onlinesign/$(am__dirstamp)
+ -rm -f knot/modules/queryacl/$(DEPDIR)/$(am__dirstamp)
+ -rm -f knot/modules/queryacl/$(am__dirstamp)
+ -rm -f knot/modules/rrl/$(DEPDIR)/$(am__dirstamp)
+ -rm -f knot/modules/rrl/$(am__dirstamp)
+ -rm -f knot/modules/stats/$(DEPDIR)/$(am__dirstamp)
+ -rm -f knot/modules/stats/$(am__dirstamp)
+ -rm -f knot/modules/synthrecord/$(DEPDIR)/$(am__dirstamp)
+ -rm -f knot/modules/synthrecord/$(am__dirstamp)
+ -rm -f knot/modules/whoami/$(DEPDIR)/$(am__dirstamp)
+ -rm -f knot/modules/whoami/$(am__dirstamp)
+ -rm -f knot/nameserver/$(DEPDIR)/$(am__dirstamp)
+ -rm -f knot/nameserver/$(am__dirstamp)
+ -rm -f knot/query/$(DEPDIR)/$(am__dirstamp)
+ -rm -f knot/query/$(am__dirstamp)
+ -rm -f knot/server/$(DEPDIR)/$(am__dirstamp)
+ -rm -f knot/server/$(am__dirstamp)
+ -rm -f knot/updates/$(DEPDIR)/$(am__dirstamp)
+ -rm -f knot/updates/$(am__dirstamp)
+ -rm -f knot/worker/$(DEPDIR)/$(am__dirstamp)
+ -rm -f knot/worker/$(am__dirstamp)
+ -rm -f knot/zone/$(DEPDIR)/$(am__dirstamp)
+ -rm -f knot/zone/$(am__dirstamp)
+ -rm -f libdnssec/$(DEPDIR)/$(am__dirstamp)
+ -rm -f libdnssec/$(am__dirstamp)
+ -rm -f libdnssec/contrib/$(DEPDIR)/$(am__dirstamp)
+ -rm -f libdnssec/contrib/$(am__dirstamp)
+ -rm -f libdnssec/key/$(DEPDIR)/$(am__dirstamp)
+ -rm -f libdnssec/key/$(am__dirstamp)
+ -rm -f libdnssec/keystore/$(DEPDIR)/$(am__dirstamp)
+ -rm -f libdnssec/keystore/$(am__dirstamp)
+ -rm -f libdnssec/list/$(DEPDIR)/$(am__dirstamp)
+ -rm -f libdnssec/list/$(am__dirstamp)
+ -rm -f libdnssec/nsec/$(DEPDIR)/$(am__dirstamp)
+ -rm -f libdnssec/nsec/$(am__dirstamp)
+ -rm -f libdnssec/p11/$(DEPDIR)/$(am__dirstamp)
+ -rm -f libdnssec/p11/$(am__dirstamp)
+ -rm -f libdnssec/shared/$(DEPDIR)/$(am__dirstamp)
+ -rm -f libdnssec/shared/$(am__dirstamp)
+ -rm -f libdnssec/sign/$(DEPDIR)/$(am__dirstamp)
+ -rm -f libdnssec/sign/$(am__dirstamp)
+ -rm -f libknot/$(DEPDIR)/$(am__dirstamp)
+ -rm -f libknot/$(am__dirstamp)
+ -rm -f libknot/control/$(DEPDIR)/$(am__dirstamp)
+ -rm -f libknot/control/$(am__dirstamp)
+ -rm -f libknot/db/$(DEPDIR)/$(am__dirstamp)
+ -rm -f libknot/db/$(am__dirstamp)
+ -rm -f libknot/packet/$(DEPDIR)/$(am__dirstamp)
+ -rm -f libknot/packet/$(am__dirstamp)
+ -rm -f libknot/rrtype/$(DEPDIR)/$(am__dirstamp)
+ -rm -f libknot/rrtype/$(am__dirstamp)
+ -rm -f libknot/yparser/$(DEPDIR)/$(am__dirstamp)
+ -rm -f libknot/yparser/$(am__dirstamp)
+ -rm -f libzscanner/$(DEPDIR)/$(am__dirstamp)
+ -rm -f libzscanner/$(am__dirstamp)
+ -rm -f utils/common/$(DEPDIR)/$(am__dirstamp)
+ -rm -f utils/common/$(am__dirstamp)
+ -rm -f utils/kdig/$(DEPDIR)/$(am__dirstamp)
+ -rm -f utils/kdig/$(am__dirstamp)
+ -rm -f utils/keymgr/$(DEPDIR)/$(am__dirstamp)
+ -rm -f utils/keymgr/$(am__dirstamp)
+ -rm -f utils/khost/$(DEPDIR)/$(am__dirstamp)
+ -rm -f utils/khost/$(am__dirstamp)
+ -rm -f utils/kjournalprint/$(DEPDIR)/$(am__dirstamp)
+ -rm -f utils/kjournalprint/$(am__dirstamp)
+ -rm -f utils/knotc/$(DEPDIR)/$(am__dirstamp)
+ -rm -f utils/knotc/$(am__dirstamp)
+ -rm -f utils/knotd/$(DEPDIR)/$(am__dirstamp)
+ -rm -f utils/knotd/$(am__dirstamp)
+ -rm -f utils/knsec3hash/$(DEPDIR)/$(am__dirstamp)
+ -rm -f utils/knsec3hash/$(am__dirstamp)
+ -rm -f utils/knsupdate/$(DEPDIR)/$(am__dirstamp)
+ -rm -f utils/knsupdate/$(am__dirstamp)
+ -rm -f utils/kzonecheck/$(DEPDIR)/$(am__dirstamp)
+ -rm -f utils/kzonecheck/$(am__dirstamp)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+@HAVE_DAEMON_FALSE@install-data-hook:
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \
+ clean-libtool clean-noinstLTLIBRARIES clean-pkglibLTLIBRARIES \
+ clean-sbinPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf contrib/$(DEPDIR) contrib/dnstap/$(DEPDIR) contrib/lmdb/$(DEPDIR) contrib/openbsd/$(DEPDIR) contrib/qp-trie/$(DEPDIR) contrib/ucw/$(DEPDIR) knot/common/$(DEPDIR) knot/conf/$(DEPDIR) knot/ctl/$(DEPDIR) knot/dnssec/$(DEPDIR) knot/dnssec/kasp/$(DEPDIR) knot/events/$(DEPDIR) knot/events/handlers/$(DEPDIR) knot/journal/$(DEPDIR) knot/modules/cookies/$(DEPDIR) knot/modules/dnsproxy/$(DEPDIR) knot/modules/dnstap/$(DEPDIR) knot/modules/geoip/$(DEPDIR) knot/modules/noudp/$(DEPDIR) knot/modules/onlinesign/$(DEPDIR) knot/modules/queryacl/$(DEPDIR) knot/modules/rrl/$(DEPDIR) knot/modules/stats/$(DEPDIR) knot/modules/synthrecord/$(DEPDIR) knot/modules/whoami/$(DEPDIR) knot/nameserver/$(DEPDIR) knot/query/$(DEPDIR) knot/server/$(DEPDIR) knot/updates/$(DEPDIR) knot/worker/$(DEPDIR) knot/zone/$(DEPDIR) libdnssec/$(DEPDIR) libdnssec/contrib/$(DEPDIR) libdnssec/key/$(DEPDIR) libdnssec/keystore/$(DEPDIR) libdnssec/list/$(DEPDIR) libdnssec/nsec/$(DEPDIR) libdnssec/p11/$(DEPDIR) libdnssec/shared/$(DEPDIR) libdnssec/sign/$(DEPDIR) libknot/$(DEPDIR) libknot/control/$(DEPDIR) libknot/db/$(DEPDIR) libknot/packet/$(DEPDIR) libknot/rrtype/$(DEPDIR) libknot/yparser/$(DEPDIR) libzscanner/$(DEPDIR) utils/common/$(DEPDIR) utils/kdig/$(DEPDIR) utils/keymgr/$(DEPDIR) utils/khost/$(DEPDIR) utils/kjournalprint/$(DEPDIR) utils/knotc/$(DEPDIR) utils/knotd/$(DEPDIR) utils/knsec3hash/$(DEPDIR) utils/knsupdate/$(DEPDIR) utils/kzonecheck/$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-hdr distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-include_libdnssecHEADERS \
+ install-include_libknotdHEADERS \
+ install-include_libzscannerHEADERS \
+ install-nobase_include_libknotHEADERS install-pkgconfigDATA
+ @$(NORMAL_INSTALL)
+ $(MAKE) $(AM_MAKEFLAGS) install-data-hook
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS install-libLTLIBRARIES \
+ install-pkglibLTLIBRARIES install-sbinPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am: installcheck-binPROGRAMS installcheck-sbinPROGRAMS
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf contrib/$(DEPDIR) contrib/dnstap/$(DEPDIR) contrib/lmdb/$(DEPDIR) contrib/openbsd/$(DEPDIR) contrib/qp-trie/$(DEPDIR) contrib/ucw/$(DEPDIR) knot/common/$(DEPDIR) knot/conf/$(DEPDIR) knot/ctl/$(DEPDIR) knot/dnssec/$(DEPDIR) knot/dnssec/kasp/$(DEPDIR) knot/events/$(DEPDIR) knot/events/handlers/$(DEPDIR) knot/journal/$(DEPDIR) knot/modules/cookies/$(DEPDIR) knot/modules/dnsproxy/$(DEPDIR) knot/modules/dnstap/$(DEPDIR) knot/modules/geoip/$(DEPDIR) knot/modules/noudp/$(DEPDIR) knot/modules/onlinesign/$(DEPDIR) knot/modules/queryacl/$(DEPDIR) knot/modules/rrl/$(DEPDIR) knot/modules/stats/$(DEPDIR) knot/modules/synthrecord/$(DEPDIR) knot/modules/whoami/$(DEPDIR) knot/nameserver/$(DEPDIR) knot/query/$(DEPDIR) knot/server/$(DEPDIR) knot/updates/$(DEPDIR) knot/worker/$(DEPDIR) knot/zone/$(DEPDIR) libdnssec/$(DEPDIR) libdnssec/contrib/$(DEPDIR) libdnssec/key/$(DEPDIR) libdnssec/keystore/$(DEPDIR) libdnssec/list/$(DEPDIR) libdnssec/nsec/$(DEPDIR) libdnssec/p11/$(DEPDIR) libdnssec/shared/$(DEPDIR) libdnssec/sign/$(DEPDIR) libknot/$(DEPDIR) libknot/control/$(DEPDIR) libknot/db/$(DEPDIR) libknot/packet/$(DEPDIR) libknot/rrtype/$(DEPDIR) libknot/yparser/$(DEPDIR) libzscanner/$(DEPDIR) utils/common/$(DEPDIR) utils/kdig/$(DEPDIR) utils/keymgr/$(DEPDIR) utils/khost/$(DEPDIR) utils/kjournalprint/$(DEPDIR) utils/knotc/$(DEPDIR) utils/knotd/$(DEPDIR) utils/knsec3hash/$(DEPDIR) utils/knsupdate/$(DEPDIR) utils/kzonecheck/$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-include_libdnssecHEADERS \
+ uninstall-include_libknotdHEADERS \
+ uninstall-include_libzscannerHEADERS uninstall-libLTLIBRARIES \
+ uninstall-nobase_include_libknotHEADERS \
+ uninstall-pkgconfigDATA uninstall-pkglibLTLIBRARIES \
+ uninstall-sbinPROGRAMS
+
+.MAKE: all check install install-am install-data-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \
+ clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \
+ clean-libtool clean-noinstLTLIBRARIES clean-pkglibLTLIBRARIES \
+ clean-sbinPROGRAMS cscopelist-am ctags ctags-am distclean \
+ distclean-compile distclean-generic distclean-hdr \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-binPROGRAMS \
+ install-data install-data-am install-data-hook install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-include_libdnssecHEADERS \
+ install-include_libknotdHEADERS \
+ install-include_libzscannerHEADERS install-info \
+ install-info-am install-libLTLIBRARIES install-man \
+ install-nobase_include_libknotHEADERS install-pdf \
+ install-pdf-am install-pkgconfigDATA install-pkglibLTLIBRARIES \
+ install-ps install-ps-am install-sbinPROGRAMS install-strip \
+ installcheck installcheck-am installcheck-binPROGRAMS \
+ installcheck-sbinPROGRAMS installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am uninstall-binPROGRAMS \
+ uninstall-include_libdnssecHEADERS \
+ uninstall-include_libknotdHEADERS \
+ uninstall-include_libzscannerHEADERS uninstall-libLTLIBRARIES \
+ uninstall-nobase_include_libknotHEADERS \
+ uninstall-pkgconfigDATA uninstall-pkglibLTLIBRARIES \
+ uninstall-sbinPROGRAMS
+
+.PRECIOUS: Makefile
+
+
+@HAVE_LIBDNSTAP_TRUE@.proto.pb-c.c:
+@HAVE_LIBDNSTAP_TRUE@ $(AM_V_GEN)@PROTOC_C@ --c_out=. -I$(srcdir) $<
+
+@HAVE_LIBDNSTAP_TRUE@.proto.pb-c.h:
+@HAVE_LIBDNSTAP_TRUE@ $(AM_V_GEN)@PROTOC_C@ --c_out=. -I$(srcdir) $<
+
+@FAST_PARSER_TRUE@libzscanner/scanner.c: libzscanner/scanner.c.g2
+@FAST_PARSER_TRUE@ @cp $(srcdir)/$@.g2 $@
+@FAST_PARSER_TRUE@ @echo "NOTE: Compilation of scanner.c can take several minutes!"
+@FAST_PARSER_FALSE@libzscanner/scanner.c: libzscanner/scanner.c.t0
+@FAST_PARSER_FALSE@ @cp $(srcdir)/$@.t0 $@
+
+# Create storage and run-time directories
+@HAVE_DAEMON_TRUE@install-data-hook:
+@HAVE_DAEMON_TRUE@ $(INSTALL) -d $(DESTDIR)/@config_dir@
+@HAVE_DAEMON_TRUE@ $(INSTALL) -d $(DESTDIR)/@run_dir@
+@HAVE_DAEMON_TRUE@ $(INSTALL) -d $(DESTDIR)/@storage_dir@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/config.h.in b/src/config.h.in
new file mode 100644
index 0000000..f0c8b56
--- /dev/null
+++ b/src/config.h.in
@@ -0,0 +1,208 @@
+/* src/config.h.in. Generated from configure.ac by autoheader. */
+
+/* Passed CFLAGS from environment */
+#undef CONFIGURE_CFLAGS
+
+/* Params passed to configure */
+#undef CONFIGURE_PARAMS
+
+/* Configure summary */
+#undef CONFIGURE_SUMMARY
+
+/* Configuration DB mapsize. */
+#undef CONF_MAPSIZE
+
+/* POSIX capabilities available */
+#undef ENABLE_CAP_NG
+
+/* PKCS #11 support available */
+#undef ENABLE_PKCS11
+
+/* Use recvmmsg(). */
+#undef ENABLE_RECVMMSG
+
+/* Use SO_REUSEPORT. */
+#undef ENABLE_REUSEPORT
+
+/* Use systemd integration. */
+#undef ENABLE_SYSTEMD
+
+/* Define to 1 if you have the `accept4' function. */
+#undef HAVE_ACCEPT4
+
+/* Define to 1 if you have the <arpa/nameser.h> header file. */
+#undef HAVE_ARPA_NAMESER_H
+
+/* Define to 1 if you have '__atomic' functions. */
+#undef HAVE_ATOMIC
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#undef HAVE_CLOCK_GETTIME
+
+/* Define if FreeBSD-like cpuset_t exists. */
+#undef HAVE_CPUSET_BSD
+
+/* Define if Linux-like cpu_set_t exists. */
+#undef HAVE_CPUSET_LINUX
+
+/* Define if cpuset_t and cpuset(3) exists. */
+#undef HAVE_CPUSET_NETBSD
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* GnuTLS ED25519 support available */
+#undef HAVE_ED25519
+
+/* Define to 1 if you have the `fgetln' function. */
+#undef HAVE_FGETLN
+
+/* Define to 1 if you have the `getline' function. */
+#undef HAVE_GETLINE
+
+/* Define to 1 if you have the `initgroups' function. */
+#undef HAVE_INITGROUPS
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <lmdb.h> header file. */
+#undef HAVE_LMDB_H
+
+/* Define to 1 if you have the `malloc_trim' function. */
+#undef HAVE_MALLOC_TRIM
+
+/* Define to 1 to enable MaxMind DB. */
+#undef HAVE_MAXMINDDB
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define to 1 if you have the <pthread_np.h> header file. */
+#undef HAVE_PTHREAD_NP_H
+
+/* Define to 1 if you have the `pthread_setaffinity_np' function. */
+#undef HAVE_PTHREAD_SETAFFINITY_NP
+
+/* Define to 1 if you have the <resolv.h> header file. */
+#undef HAVE_RESOLV_H
+
+/* Define to 1 if you have the `setgroups' function. */
+#undef HAVE_SETGROUPS
+
+/* gnutls_privkey_sign_data2 available */
+#undef HAVE_SIGN_DATA2
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strlcat' function. */
+#undef HAVE_STRLCAT
+
+/* Define to 1 if you have the `strlcpy' function. */
+#undef HAVE_STRLCPY
+
+/* Define to 1 if you have the `sysctlbyname' function. */
+#undef HAVE_SYSCTLBYNAME
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#undef HAVE_SYS_UIO_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 or 0, depending whether the compiler supports simple visibility
+ declarations. */
+#undef HAVE_VISIBILITY
+
+/* Define to 1 to enable IDN support */
+#undef LIBIDN
+
+/* Define to proper libidn header */
+#undef LIBIDN_HEADER
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#undef LT_OBJDIR
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to 1 to enable dnstap support for kdig */
+#undef USE_DNSTAP
+
+/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to 1 if on MINIX. */
+#undef _MINIX
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+ this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#undef _POSIX_SOURCE
diff --git a/src/contrib/Makefile.inc b/src/contrib/Makefile.inc
new file mode 100644
index 0000000..a6b6576
--- /dev/null
+++ b/src/contrib/Makefile.inc
@@ -0,0 +1,103 @@
+noinst_LTLIBRARIES += libcontrib.la
+
+libcontrib_la_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAG_VISIBILITY)
+libcontrib_la_LDFLAGS = $(AM_LDFLAGS) $(LDFLAG_EXCLUDE_LIBS)
+if !HAVE_LMDB
+libcontrib_la_LDFLAGS += $(pthread_LIBS)
+endif !HAVE_LMDB
+
+EXTRA_DIST += \
+ contrib/licenses/0BSD \
+ contrib/licenses/BSD-3-Clause \
+ contrib/licenses/LGPL-2.0 \
+ contrib/licenses/OLDAP-2.8 \
+ contrib/lmdb/LICENSE \
+ contrib/openbsd/LICENSE \
+ contrib/ucw/LICENSE \
+ contrib/dnstap/dnstap.proto
+
+libcontrib_la_SOURCES = \
+ contrib/asan.h \
+ contrib/base32hex.c \
+ contrib/base32hex.h \
+ contrib/base64.c \
+ contrib/base64.h \
+ contrib/ctype.h \
+ contrib/dynarray.h \
+ contrib/files.c \
+ contrib/files.h \
+ contrib/getline.c \
+ contrib/getline.h \
+ contrib/macros.h \
+ contrib/mempattern.c \
+ contrib/mempattern.h \
+ contrib/net.c \
+ contrib/net.h \
+ contrib/qp-trie/trie.c \
+ contrib/qp-trie/trie.h \
+ contrib/sockaddr.c \
+ contrib/sockaddr.h \
+ contrib/string.c \
+ contrib/string.h \
+ contrib/strtonum.h \
+ contrib/time.c \
+ contrib/time.h \
+ contrib/tolower.h \
+ contrib/trim.h \
+ contrib/wire_ctx.h \
+ contrib/openbsd/siphash.c \
+ contrib/openbsd/siphash.h \
+ contrib/openbsd/strlcat.c \
+ contrib/openbsd/strlcat.h \
+ contrib/openbsd/strlcpy.c \
+ contrib/openbsd/strlcpy.h \
+ contrib/ucw/array-sort.h \
+ contrib/ucw/binsearch.h \
+ contrib/ucw/heap.c \
+ contrib/ucw/heap.h \
+ contrib/ucw/lists.c \
+ contrib/ucw/lists.h \
+ contrib/ucw/mempool.c \
+ contrib/ucw/mempool.h
+
+if !HAVE_LMDB
+libcontrib_la_SOURCES += \
+ contrib/lmdb/lmdb.h \
+ contrib/lmdb/mdb.c \
+ contrib/lmdb/midl.c \
+ contrib/lmdb/midl.h
+endif !HAVE_LMDB
+
+if HAVE_LIBDNSTAP
+noinst_LTLIBRARIES += libdnstap.la
+
+libdnstap_la_CPPFLAGS = $(AM_CPPFLAGS) $(DNSTAP_CFLAGS)
+libdnstap_la_LDFLAGS = $(AM_LDFLAGS) $(DNSTAP_LIBS)
+
+SUFFIXES = .proto .pb-c.c .pb-c.h
+
+.proto.pb-c.c:
+ $(AM_V_GEN)@PROTOC_C@ --c_out=. -I$(srcdir) $<
+
+.proto.pb-c.h:
+ $(AM_V_GEN)@PROTOC_C@ --c_out=. -I$(srcdir) $<
+
+libdnstap_la_SOURCES = \
+ contrib/dnstap/convert.c \
+ contrib/dnstap/convert.h \
+ contrib/dnstap/dnstap.c \
+ contrib/dnstap/dnstap.h \
+ contrib/dnstap/message.c \
+ contrib/dnstap/message.h \
+ contrib/dnstap/reader.c \
+ contrib/dnstap/reader.h \
+ contrib/dnstap/writer.c \
+ contrib/dnstap/writer.h
+
+nodist_libdnstap_la_SOURCES = \
+ contrib/dnstap/dnstap.pb-c.c \
+ contrib/dnstap/dnstap.pb-c.h
+
+BUILT_SOURCES += $(nodist_libdnstap_la_SOURCES)
+CLEANFILES += $(nodist_libdnstap_la_SOURCES)
+endif HAVE_LIBDNSTAP
diff --git a/src/contrib/asan.h b/src/contrib/asan.h
new file mode 100644
index 0000000..112f81e
--- /dev/null
+++ b/src/contrib/asan.h
@@ -0,0 +1,37 @@
+/* Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+/*
+ * see sanitizer/asan_interface.h in compiler-rt (LLVM)
+ */
+#ifndef __has_feature
+ #define __has_feature(feature) 0
+#endif
+#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
+ void __asan_poison_memory_region(void const volatile *addr, size_t size);
+ void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
+ #define ASAN_POISON_MEMORY_REGION(addr, size) \
+ __asan_poison_memory_region((addr), (size))
+ #define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
+ __asan_unpoison_memory_region((addr), (size))
+#else
+ #define ASAN_POISON_MEMORY_REGION(addr, size) \
+ ((void)(addr), (void)(size))
+ #define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
+ ((void)(addr), (void)(size))
+#endif
diff --git a/src/contrib/base32hex.c b/src/contrib/base32hex.c
new file mode 100644
index 0000000..56fb427
--- /dev/null
+++ b/src/contrib/base32hex.c
@@ -0,0 +1,353 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "contrib/base32hex.h"
+#include "libknot/errcode.h"
+
+#include <stdlib.h>
+#include <stdint.h>
+
+/*! \brief Maximal length of binary input to Base32hex encoding. */
+#define MAX_BIN_DATA_LEN ((INT32_MAX / 8) * 5)
+
+/*! \brief Base32hex padding character. */
+static const uint8_t base32hex_pad = '=';
+/*! \brief Base32hex alphabet. */
+static const uint8_t base32hex_enc[] = "0123456789abcdefghijklmnopqrstuv";
+
+/*! \brief Indicates bad Base32hex character. */
+#define KO 255
+/*! \brief Indicates Base32hex padding character. */
+#define PD 32
+
+/*! \brief Transformation and validation table for decoding Base32hex. */
+static const uint8_t base32hex_dec[256] = {
+ [ 0] = KO, [ 43] = KO, ['V'] = 31, [129] = KO, [172] = KO, [215] = KO,
+ [ 1] = KO, [ 44] = KO, ['W'] = KO, [130] = KO, [173] = KO, [216] = KO,
+ [ 2] = KO, [ 45] = KO, ['X'] = KO, [131] = KO, [174] = KO, [217] = KO,
+ [ 3] = KO, [ 46] = KO, ['Y'] = KO, [132] = KO, [175] = KO, [218] = KO,
+ [ 4] = KO, [ 47] = KO, ['Z'] = KO, [133] = KO, [176] = KO, [219] = KO,
+ [ 5] = KO, ['0'] = 0, [ 91] = KO, [134] = KO, [177] = KO, [220] = KO,
+ [ 6] = KO, ['1'] = 1, [ 92] = KO, [135] = KO, [178] = KO, [221] = KO,
+ [ 7] = KO, ['2'] = 2, [ 93] = KO, [136] = KO, [179] = KO, [222] = KO,
+ [ 8] = KO, ['3'] = 3, [ 94] = KO, [137] = KO, [180] = KO, [223] = KO,
+ [ 9] = KO, ['4'] = 4, [ 95] = KO, [138] = KO, [181] = KO, [224] = KO,
+ [ 10] = KO, ['5'] = 5, [ 96] = KO, [139] = KO, [182] = KO, [225] = KO,
+ [ 11] = KO, ['6'] = 6, ['a'] = 10, [140] = KO, [183] = KO, [226] = KO,
+ [ 12] = KO, ['7'] = 7, ['b'] = 11, [141] = KO, [184] = KO, [227] = KO,
+ [ 13] = KO, ['8'] = 8, ['c'] = 12, [142] = KO, [185] = KO, [228] = KO,
+ [ 14] = KO, ['9'] = 9, ['d'] = 13, [143] = KO, [186] = KO, [229] = KO,
+ [ 15] = KO, [ 58] = KO, ['e'] = 14, [144] = KO, [187] = KO, [230] = KO,
+ [ 16] = KO, [ 59] = KO, ['f'] = 15, [145] = KO, [188] = KO, [231] = KO,
+ [ 17] = KO, [ 60] = KO, ['g'] = 16, [146] = KO, [189] = KO, [232] = KO,
+ [ 18] = KO, ['='] = PD, ['h'] = 17, [147] = KO, [190] = KO, [233] = KO,
+ [ 19] = KO, [ 62] = KO, ['i'] = 18, [148] = KO, [191] = KO, [234] = KO,
+ [ 20] = KO, [ 63] = KO, ['j'] = 19, [149] = KO, [192] = KO, [235] = KO,
+ [ 21] = KO, [ 64] = KO, ['k'] = 20, [150] = KO, [193] = KO, [236] = KO,
+ [ 22] = KO, ['A'] = 10, ['l'] = 21, [151] = KO, [194] = KO, [237] = KO,
+ [ 23] = KO, ['B'] = 11, ['m'] = 22, [152] = KO, [195] = KO, [238] = KO,
+ [ 24] = KO, ['C'] = 12, ['n'] = 23, [153] = KO, [196] = KO, [239] = KO,
+ [ 25] = KO, ['D'] = 13, ['o'] = 24, [154] = KO, [197] = KO, [240] = KO,
+ [ 26] = KO, ['E'] = 14, ['p'] = 25, [155] = KO, [198] = KO, [241] = KO,
+ [ 27] = KO, ['F'] = 15, ['q'] = 26, [156] = KO, [199] = KO, [242] = KO,
+ [ 28] = KO, ['G'] = 16, ['r'] = 27, [157] = KO, [200] = KO, [243] = KO,
+ [ 29] = KO, ['H'] = 17, ['s'] = 28, [158] = KO, [201] = KO, [244] = KO,
+ [ 30] = KO, ['I'] = 18, ['t'] = 29, [159] = KO, [202] = KO, [245] = KO,
+ [ 31] = KO, ['J'] = 19, ['u'] = 30, [160] = KO, [203] = KO, [246] = KO,
+ [ 32] = KO, ['K'] = 20, ['v'] = 31, [161] = KO, [204] = KO, [247] = KO,
+ [ 33] = KO, ['L'] = 21, ['w'] = KO, [162] = KO, [205] = KO, [248] = KO,
+ [ 34] = KO, ['M'] = 22, ['x'] = KO, [163] = KO, [206] = KO, [249] = KO,
+ [ 35] = KO, ['N'] = 23, ['y'] = KO, [164] = KO, [207] = KO, [250] = KO,
+ [ 36] = KO, ['O'] = 24, ['z'] = KO, [165] = KO, [208] = KO, [251] = KO,
+ [ 37] = KO, ['P'] = 25, [123] = KO, [166] = KO, [209] = KO, [252] = KO,
+ [ 38] = KO, ['Q'] = 26, [124] = KO, [167] = KO, [210] = KO, [253] = KO,
+ [ 39] = KO, ['R'] = 27, [125] = KO, [168] = KO, [211] = KO, [254] = KO,
+ [ 40] = KO, ['S'] = 28, [126] = KO, [169] = KO, [212] = KO, [255] = KO,
+ [ 41] = KO, ['T'] = 29, [127] = KO, [170] = KO, [213] = KO,
+ [ 42] = KO, ['U'] = 30, [128] = KO, [171] = KO, [214] = KO,
+};
+
+int32_t base32hex_encode(const uint8_t *in,
+ const uint32_t in_len,
+ uint8_t *out,
+ const uint32_t out_len)
+{
+ // Checking inputs.
+ if (in == NULL || out == NULL) {
+ return KNOT_EINVAL;
+ }
+ if (in_len > MAX_BIN_DATA_LEN || out_len < ((in_len + 4) / 5) * 8) {
+ return KNOT_ERANGE;
+ }
+
+ uint8_t rest_len = in_len % 5;
+ const uint8_t *stop = in + in_len - rest_len;
+ uint8_t *text = out;
+
+ // Encoding loop takes 5 bytes and creates 8 characters.
+ while (in < stop) {
+ text[0] = base32hex_enc[in[0] >> 3];
+ text[1] = base32hex_enc[(in[0] & 0x07) << 2 | in[1] >> 6];
+ text[2] = base32hex_enc[(in[1] & 0x3E) >> 1];
+ text[3] = base32hex_enc[(in[1] & 0x01) << 4 | in[2] >> 4];
+ text[4] = base32hex_enc[(in[2] & 0x0F) << 1 | in[3] >> 7];
+ text[5] = base32hex_enc[(in[3] & 0x7C) >> 2];
+ text[6] = base32hex_enc[(in[3] & 0x03) << 3 | in[4] >> 5];
+ text[7] = base32hex_enc[in[4] & 0x1F];
+ text += 8;
+ in += 5;
+ }
+
+ // Processing of padding, if any.
+ switch (rest_len) {
+ case 4:
+ text[0] = base32hex_enc[in[0] >> 3];
+ text[1] = base32hex_enc[(in[0] & 0x07) << 2 | in[1] >> 6];
+ text[2] = base32hex_enc[(in[1] & 0x3E) >> 1];
+ text[3] = base32hex_enc[(in[1] & 0x01) << 4 | in[2] >> 4];
+ text[4] = base32hex_enc[(in[2] & 0x0F) << 1 | in[3] >> 7];
+ text[5] = base32hex_enc[(in[3] & 0x7C) >> 2];
+ text[6] = base32hex_enc[(in[3] & 0x03) << 3];
+ text[7] = base32hex_pad;
+ text += 8;
+ break;
+ case 3:
+ text[0] = base32hex_enc[in[0] >> 3];
+ text[1] = base32hex_enc[(in[0] & 0x07) << 2 | in[1] >> 6];
+ text[2] = base32hex_enc[(in[1] & 0x3E) >> 1];
+ text[3] = base32hex_enc[(in[1] & 0x01) << 4 | in[2] >> 4];
+ text[4] = base32hex_enc[(in[2] & 0x0F) << 1];
+ text[5] = base32hex_pad;
+ text[6] = base32hex_pad;
+ text[7] = base32hex_pad;
+ text += 8;
+ break;
+ case 2:
+ text[0] = base32hex_enc[in[0] >> 3];
+ text[1] = base32hex_enc[(in[0] & 0x07) << 2 | in[1] >> 6];
+ text[2] = base32hex_enc[(in[1] & 0x3E) >> 1];
+ text[3] = base32hex_enc[(in[1] & 0x01) << 4];
+ text[4] = base32hex_pad;
+ text[5] = base32hex_pad;
+ text[6] = base32hex_pad;
+ text[7] = base32hex_pad;
+ text += 8;
+ break;
+ case 1:
+ text[0] = base32hex_enc[in[0] >> 3];
+ text[1] = base32hex_enc[(in[0] & 0x07) << 2];
+ text[2] = base32hex_pad;
+ text[3] = base32hex_pad;
+ text[4] = base32hex_pad;
+ text[5] = base32hex_pad;
+ text[6] = base32hex_pad;
+ text[7] = base32hex_pad;
+ text += 8;
+ break;
+ }
+
+ return (text - out);
+}
+
+int32_t base32hex_encode_alloc(const uint8_t *in,
+ const uint32_t in_len,
+ uint8_t **out)
+{
+ // Checking inputs.
+ if (out == NULL) {
+ return KNOT_EINVAL;
+ }
+ if (in_len > MAX_BIN_DATA_LEN) {
+ return KNOT_ERANGE;
+ }
+
+ // Compute output buffer length.
+ uint32_t out_len = ((in_len + 4) / 5) * 8;
+
+ // Allocate output buffer.
+ *out = malloc(out_len);
+ if (*out == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ // Encode data.
+ int32_t ret = base32hex_encode(in, in_len, *out, out_len);
+ if (ret < 0) {
+ free(*out);
+ *out = NULL;
+ }
+
+ return ret;
+}
+
+int32_t base32hex_decode(const uint8_t *in,
+ const uint32_t in_len,
+ uint8_t *out,
+ const uint32_t out_len)
+{
+ // Checking inputs.
+ if (in == NULL || out == NULL) {
+ return KNOT_EINVAL;
+ }
+ if (in_len > INT32_MAX || out_len < ((in_len + 7) / 8) * 5) {
+ return KNOT_ERANGE;
+ }
+ if ((in_len % 8) != 0) {
+ return KNOT_BASE32HEX_ESIZE;
+ }
+
+ const uint8_t *stop = in + in_len;
+ uint8_t *bin = out;
+ uint8_t pad_len = 0;
+ uint8_t c1, c2, c3, c4, c5, c6, c7, c8;
+
+ // Decoding loop takes 8 characters and creates 5 bytes.
+ while (in < stop) {
+ // Filling and transforming 8 Base32hex chars.
+ c1 = base32hex_dec[in[0]];
+ c2 = base32hex_dec[in[1]];
+ c3 = base32hex_dec[in[2]];
+ c4 = base32hex_dec[in[3]];
+ c5 = base32hex_dec[in[4]];
+ c6 = base32hex_dec[in[5]];
+ c7 = base32hex_dec[in[6]];
+ c8 = base32hex_dec[in[7]];
+
+ // Check 8. char if is bad or padding.
+ if (c8 >= PD) {
+ if (c8 == PD && pad_len == 0) {
+ pad_len = 1;
+ } else {
+ return KNOT_BASE32HEX_ECHAR;
+ }
+ }
+
+ // Check 7. char if is bad or padding (if so, 6. must be too).
+ if (c7 >= PD) {
+ if (c7 == PD && c6 == PD && pad_len == 1) {
+ pad_len = 3;
+ } else {
+ return KNOT_BASE32HEX_ECHAR;
+ }
+ }
+
+ // Check 6. char if is bad or padding.
+ if (c6 >= PD) {
+ if (!(c6 == PD && pad_len == 3)) {
+ return KNOT_BASE32HEX_ECHAR;
+ }
+ }
+
+ // Check 5. char if is bad or padding.
+ if (c5 >= PD) {
+ if (c5 == PD && pad_len == 3) {
+ pad_len = 4;
+ } else {
+ return KNOT_BASE32HEX_ECHAR;
+ }
+ }
+
+ // Check 4. char if is bad or padding (if so, 3. must be too).
+ if (c4 >= PD) {
+ if (c4 == PD && c3 == PD && pad_len == 4) {
+ pad_len = 6;
+ } else {
+ return KNOT_BASE32HEX_ECHAR;
+ }
+ }
+
+ // Check 3. char if is bad or padding.
+ if (c3 >= PD) {
+ if (!(c3 == PD && pad_len == 6)) {
+ return KNOT_BASE32HEX_ECHAR;
+ }
+ }
+
+ // 1. and 2. chars must not be padding.
+ if (c2 >= PD || c1 >= PD) {
+ return KNOT_BASE32HEX_ECHAR;
+ }
+
+ // Computing of output data based on padding length.
+ switch (pad_len) {
+ case 0:
+ bin[4] = (c7 << 5) + c8;
+ // FALLTHROUGH
+ case 1:
+ bin[3] = (c5 << 7) + (c6 << 2) + (c7 >> 3);
+ // FALLTHROUGH
+ case 3:
+ bin[2] = (c4 << 4) + (c5 >> 1);
+ // FALLTHROUGH
+ case 4:
+ bin[1] = (c2 << 6) + (c3 << 1) + (c4 >> 4);
+ // FALLTHROUGH
+ case 6:
+ bin[0] = (c1 << 3) + (c2 >> 2);
+ }
+
+ // Update output end.
+ switch (pad_len) {
+ case 0:
+ bin += 5;
+ break;
+ case 1:
+ bin += 4;
+ break;
+ case 3:
+ bin += 3;
+ break;
+ case 4:
+ bin += 2;
+ break;
+ case 6:
+ bin += 1;
+ break;
+ }
+
+ in += 8;
+ }
+
+ return (bin - out);
+}
+
+int32_t base32hex_decode_alloc(const uint8_t *in,
+ const uint32_t in_len,
+ uint8_t **out)
+{
+ // Checking inputs.
+ if (out == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ // Compute output buffer length.
+ uint32_t out_len = ((in_len + 7) / 8) * 5;
+
+ // Allocate output buffer.
+ *out = malloc(out_len);
+ if (*out == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ // Decode data.
+ int32_t ret = base32hex_decode(in, in_len, *out, out_len);
+ if (ret < 0) {
+ free(*out);
+ *out = NULL;
+ }
+
+ return ret;
+}
diff --git a/src/contrib/base32hex.h b/src/contrib/base32hex.h
new file mode 100644
index 0000000..027acd8
--- /dev/null
+++ b/src/contrib/base32hex.h
@@ -0,0 +1,103 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \brief Base32hex implementation (RFC 4648).
+ *
+ * \note Input Base32hex string can contain a-v characters. These characters
+ * are considered as A-V equivalent. Lower-case variant is used for encoding!
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+/*!
+ * \brief Encodes binary data using Base32hex.
+ *
+ * \note Output data buffer contains Base32hex text string which isn't
+ * terminated with '\0'!
+ *
+ * \param in Input binary data.
+ * \param in_len Length of input data.
+ * \param out Output data buffer.
+ * \param out_len Size of output buffer.
+ *
+ * \retval >=0 length of output string.
+ * \retval KNOT_E* if error.
+ */
+int32_t base32hex_encode(const uint8_t *in,
+ const uint32_t in_len,
+ uint8_t *out,
+ const uint32_t out_len);
+
+/*!
+ * \brief Encodes binary data using Base32hex and output stores to own buffer.
+ *
+ * \note Output data buffer contains Base32hex text string which isn't
+ * terminated with '\0'!
+ *
+ * \note Output buffer should be deallocated after use.
+ *
+ * \param in Input binary data.
+ * \param in_len Length of input data.
+ * \param out Output data buffer.
+ *
+ * \retval >=0 length of output string.
+ * \retval KNOT_E* if error.
+ */
+int32_t base32hex_encode_alloc(const uint8_t *in,
+ const uint32_t in_len,
+ uint8_t **out);
+
+/*!
+ * \brief Decodes text data using Base32hex.
+ *
+ * \note Input data needn't be terminated with '\0'.
+ *
+ * \note Input data must be continuous Base32hex string!
+ *
+ * \param in Input text data.
+ * \param in_len Length of input string.
+ * \param out Output data buffer.
+ * \param out_len Size of output buffer.
+ *
+ * \retval >=0 length of output data.
+ * \retval KNOT_E* if error.
+ */
+int32_t base32hex_decode(const uint8_t *in,
+ const uint32_t in_len,
+ uint8_t *out,
+ const uint32_t out_len);
+
+/*!
+ * \brief Decodes text data using Base32hex and output stores to own buffer.
+ *
+ * \note Input data needn't be terminated with '\0'.
+ *
+ * \note Input data must be continuous Base32hex string!
+ *
+ * \note Output buffer should be deallocated after use.
+ *
+ * \param in Input text data.
+ * \param in_len Length of input string.
+ * \param out Output data buffer.
+ *
+ * \retval >=0 length of output data.
+ * \retval KNOT_E* if error.
+ */
+int32_t base32hex_decode_alloc(const uint8_t *in,
+ const uint32_t in_len,
+ uint8_t **out);
diff --git a/src/contrib/base64.c b/src/contrib/base64.c
new file mode 100644
index 0000000..a0d83a4
--- /dev/null
+++ b/src/contrib/base64.c
@@ -0,0 +1,272 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "contrib/base64.h"
+#include "libknot/errcode.h"
+
+#include <stdlib.h>
+#include <stdint.h>
+
+/*! \brief Maximal length of binary input to Base64 encoding. */
+#define MAX_BIN_DATA_LEN ((INT32_MAX / 4) * 3)
+
+/*! \brief Base64 padding character. */
+static const uint8_t base64_pad = '=';
+/*! \brief Base64 alphabet. */
+static const uint8_t base64_enc[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/*! \brief Indicates bad Base64 character. */
+#define KO 255
+/*! \brief Indicates Base64 padding character. */
+#define PD 64
+
+/*! \brief Transformation and validation table for decoding Base64. */
+static const uint8_t base64_dec[256] = {
+ [ 0] = KO, ['+'] = 62, ['V'] = 21, [129] = KO, [172] = KO, [215] = KO,
+ [ 1] = KO, [ 44] = KO, ['W'] = 22, [130] = KO, [173] = KO, [216] = KO,
+ [ 2] = KO, [ 45] = KO, ['X'] = 23, [131] = KO, [174] = KO, [217] = KO,
+ [ 3] = KO, [ 46] = KO, ['Y'] = 24, [132] = KO, [175] = KO, [218] = KO,
+ [ 4] = KO, ['/'] = 63, ['Z'] = 25, [133] = KO, [176] = KO, [219] = KO,
+ [ 5] = KO, ['0'] = 52, [ 91] = KO, [134] = KO, [177] = KO, [220] = KO,
+ [ 6] = KO, ['1'] = 53, [ 92] = KO, [135] = KO, [178] = KO, [221] = KO,
+ [ 7] = KO, ['2'] = 54, [ 93] = KO, [136] = KO, [179] = KO, [222] = KO,
+ [ 8] = KO, ['3'] = 55, [ 94] = KO, [137] = KO, [180] = KO, [223] = KO,
+ [ 9] = KO, ['4'] = 56, [ 95] = KO, [138] = KO, [181] = KO, [224] = KO,
+ [ 10] = KO, ['5'] = 57, [ 96] = KO, [139] = KO, [182] = KO, [225] = KO,
+ [ 11] = KO, ['6'] = 58, ['a'] = 26, [140] = KO, [183] = KO, [226] = KO,
+ [ 12] = KO, ['7'] = 59, ['b'] = 27, [141] = KO, [184] = KO, [227] = KO,
+ [ 13] = KO, ['8'] = 60, ['c'] = 28, [142] = KO, [185] = KO, [228] = KO,
+ [ 14] = KO, ['9'] = 61, ['d'] = 29, [143] = KO, [186] = KO, [229] = KO,
+ [ 15] = KO, [ 58] = KO, ['e'] = 30, [144] = KO, [187] = KO, [230] = KO,
+ [ 16] = KO, [ 59] = KO, ['f'] = 31, [145] = KO, [188] = KO, [231] = KO,
+ [ 17] = KO, [ 60] = KO, ['g'] = 32, [146] = KO, [189] = KO, [232] = KO,
+ [ 18] = KO, ['='] = PD, ['h'] = 33, [147] = KO, [190] = KO, [233] = KO,
+ [ 19] = KO, [ 62] = KO, ['i'] = 34, [148] = KO, [191] = KO, [234] = KO,
+ [ 20] = KO, [ 63] = KO, ['j'] = 35, [149] = KO, [192] = KO, [235] = KO,
+ [ 21] = KO, [ 64] = KO, ['k'] = 36, [150] = KO, [193] = KO, [236] = KO,
+ [ 22] = KO, ['A'] = 0, ['l'] = 37, [151] = KO, [194] = KO, [237] = KO,
+ [ 23] = KO, ['B'] = 1, ['m'] = 38, [152] = KO, [195] = KO, [238] = KO,
+ [ 24] = KO, ['C'] = 2, ['n'] = 39, [153] = KO, [196] = KO, [239] = KO,
+ [ 25] = KO, ['D'] = 3, ['o'] = 40, [154] = KO, [197] = KO, [240] = KO,
+ [ 26] = KO, ['E'] = 4, ['p'] = 41, [155] = KO, [198] = KO, [241] = KO,
+ [ 27] = KO, ['F'] = 5, ['q'] = 42, [156] = KO, [199] = KO, [242] = KO,
+ [ 28] = KO, ['G'] = 6, ['r'] = 43, [157] = KO, [200] = KO, [243] = KO,
+ [ 29] = KO, ['H'] = 7, ['s'] = 44, [158] = KO, [201] = KO, [244] = KO,
+ [ 30] = KO, ['I'] = 8, ['t'] = 45, [159] = KO, [202] = KO, [245] = KO,
+ [ 31] = KO, ['J'] = 9, ['u'] = 46, [160] = KO, [203] = KO, [246] = KO,
+ [ 32] = KO, ['K'] = 10, ['v'] = 47, [161] = KO, [204] = KO, [247] = KO,
+ [ 33] = KO, ['L'] = 11, ['w'] = 48, [162] = KO, [205] = KO, [248] = KO,
+ [ 34] = KO, ['M'] = 12, ['x'] = 49, [163] = KO, [206] = KO, [249] = KO,
+ [ 35] = KO, ['N'] = 13, ['y'] = 50, [164] = KO, [207] = KO, [250] = KO,
+ [ 36] = KO, ['O'] = 14, ['z'] = 51, [165] = KO, [208] = KO, [251] = KO,
+ [ 37] = KO, ['P'] = 15, [123] = KO, [166] = KO, [209] = KO, [252] = KO,
+ [ 38] = KO, ['Q'] = 16, [124] = KO, [167] = KO, [210] = KO, [253] = KO,
+ [ 39] = KO, ['R'] = 17, [125] = KO, [168] = KO, [211] = KO, [254] = KO,
+ [ 40] = KO, ['S'] = 18, [126] = KO, [169] = KO, [212] = KO, [255] = KO,
+ [ 41] = KO, ['T'] = 19, [127] = KO, [170] = KO, [213] = KO,
+ [ 42] = KO, ['U'] = 20, [128] = KO, [171] = KO, [214] = KO,
+};
+
+int32_t base64_encode(const uint8_t *in,
+ const uint32_t in_len,
+ uint8_t *out,
+ const uint32_t out_len)
+{
+ // Checking inputs.
+ if (in == NULL || out == NULL) {
+ return KNOT_EINVAL;
+ }
+ if (in_len > MAX_BIN_DATA_LEN || out_len < ((in_len + 2) / 3) * 4) {
+ return KNOT_ERANGE;
+ }
+
+ uint8_t rest_len = in_len % 3;
+ const uint8_t *stop = in + in_len - rest_len;
+ uint8_t *text = out;
+
+ // Encoding loop takes 3 bytes and creates 4 characters.
+ while (in < stop) {
+ text[0] = base64_enc[in[0] >> 2];
+ text[1] = base64_enc[(in[0] & 0x03) << 4 | in[1] >> 4];
+ text[2] = base64_enc[(in[1] & 0x0F) << 2 | in[2] >> 6];
+ text[3] = base64_enc[in[2] & 0x3F];
+ text += 4;
+ in += 3;
+ }
+
+ // Processing of padding, if any.
+ switch (rest_len) {
+ case 2:
+ text[0] = base64_enc[in[0] >> 2];
+ text[1] = base64_enc[(in[0] & 0x03) << 4 | in[1] >> 4];
+ text[2] = base64_enc[(in[1] & 0x0F) << 2];
+ text[3] = base64_pad;
+ text += 4;
+ break;
+ case 1:
+ text[0] = base64_enc[in[0] >> 2];
+ text[1] = base64_enc[(in[0] & 0x03) << 4];
+ text[2] = base64_pad;
+ text[3] = base64_pad;
+ text += 4;
+ break;
+ }
+
+ return (text - out);
+}
+
+int32_t base64_encode_alloc(const uint8_t *in,
+ const uint32_t in_len,
+ uint8_t **out)
+{
+ // Checking inputs.
+ if (out == NULL) {
+ return KNOT_EINVAL;
+ }
+ if (in_len > MAX_BIN_DATA_LEN) {
+ return KNOT_ERANGE;
+ }
+
+ // Compute output buffer length.
+ uint32_t out_len = ((in_len + 2) / 3) * 4;
+
+ // Allocate output buffer.
+ *out = malloc(out_len);
+ if (*out == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ // Encode data.
+ int32_t ret = base64_encode(in, in_len, *out, out_len);
+ if (ret < 0) {
+ free(*out);
+ *out = NULL;
+ }
+
+ return ret;
+}
+
+int32_t base64_decode(const uint8_t *in,
+ const uint32_t in_len,
+ uint8_t *out,
+ const uint32_t out_len)
+{
+ // Checking inputs.
+ if (in == NULL || out == NULL) {
+ return KNOT_EINVAL;
+ }
+ if (in_len > INT32_MAX || out_len < ((in_len + 3) / 4) * 3) {
+ return KNOT_ERANGE;
+ }
+ if ((in_len % 4) != 0) {
+ return KNOT_BASE64_ESIZE;
+ }
+
+ const uint8_t *stop = in + in_len;
+ uint8_t *bin = out;
+ uint8_t pad_len = 0;
+ uint8_t c1, c2, c3, c4;
+
+ // Decoding loop takes 4 characters and creates 3 bytes.
+ while (in < stop) {
+ // Filling and transforming 4 Base64 chars.
+ c1 = base64_dec[in[0]];
+ c2 = base64_dec[in[1]];
+ c3 = base64_dec[in[2]];
+ c4 = base64_dec[in[3]];
+
+ // Check 4. char if is bad or padding.
+ if (c4 >= PD) {
+ if (c4 == PD && pad_len == 0) {
+ pad_len = 1;
+ } else {
+ return KNOT_BASE64_ECHAR;
+ }
+ }
+
+ // Check 3. char if is bad or padding.
+ if (c3 >= PD) {
+ if (c3 == PD && pad_len == 1) {
+ pad_len = 2;
+ } else {
+ return KNOT_BASE64_ECHAR;
+ }
+ }
+
+ // Check 1. and 2. chars if are not padding.
+ if (c2 >= PD || c1 >= PD) {
+ return KNOT_BASE64_ECHAR;
+ }
+
+ // Computing of output data based on padding length.
+ switch (pad_len) {
+ case 0:
+ bin[2] = (c3 << 6) + c4;
+ // FALLTHROUGH
+ case 1:
+ bin[1] = (c2 << 4) + (c3 >> 2);
+ // FALLTHROUGH
+ case 2:
+ bin[0] = (c1 << 2) + (c2 >> 4);
+ }
+
+ // Update output end.
+ switch (pad_len) {
+ case 0:
+ bin += 3;
+ break;
+ case 1:
+ bin += 2;
+ break;
+ case 2:
+ bin += 1;
+ break;
+ }
+
+ in += 4;
+ }
+
+ return (bin - out);
+}
+
+int32_t base64_decode_alloc(const uint8_t *in,
+ const uint32_t in_len,
+ uint8_t **out)
+{
+ // Checking inputs.
+ if (out == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ // Compute output buffer length.
+ uint32_t out_len = ((in_len + 3) / 4) * 3;
+
+ // Allocate output buffer.
+ *out = malloc(out_len);
+ if (*out == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ // Decode data.
+ int32_t ret = base64_decode(in, in_len, *out, out_len);
+ if (ret < 0) {
+ free(*out);
+ *out = NULL;
+ }
+
+ return ret;
+}
diff --git a/src/contrib/base64.h b/src/contrib/base64.h
new file mode 100644
index 0000000..611574e
--- /dev/null
+++ b/src/contrib/base64.h
@@ -0,0 +1,102 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \brief Base64 implementation (RFC 4648).
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+/*!
+ * \brief Encodes binary data using Base64.
+ *
+ * \note Output data buffer contains Base64 text string which isn't
+ * terminated with '\0'!
+ *
+ * \param in Input binary data.
+ * \param in_len Length of input data.
+ * \param out Output data buffer.
+ * \param out_len Size of output buffer.
+ *
+ * \retval >=0 length of output string.
+ * \retval KNOT_E* if error.
+ */
+int32_t base64_encode(const uint8_t *in,
+ const uint32_t in_len,
+ uint8_t *out,
+ const uint32_t out_len);
+
+/*!
+ * \brief Encodes binary data using Base64 and output stores to own buffer.
+ *
+ * \note Output data buffer contains Base64 text string which isn't
+ * terminated with '\0'!
+ *
+ * \note Output buffer should be deallocated after use.
+ *
+ * \param in Input binary data.
+ * \param in_len Length of input data.
+ * \param out Output data buffer.
+ *
+ * \retval >=0 length of output string.
+ * \retval KNOT_E* if error.
+ */
+int32_t base64_encode_alloc(const uint8_t *in,
+ const uint32_t in_len,
+ uint8_t **out);
+
+/*!
+ * \brief Decodes text data using Base64.
+ *
+ * \note Input data needn't be terminated with '\0'.
+ *
+ * \note Input data must be continuous Base64 string!
+ *
+ * \param in Input text data.
+ * \param in_len Length of input string.
+ * \param out Output data buffer.
+ * \param out_len Size of output buffer.
+ *
+ * \retval >=0 length of output data.
+ * \retval KNOT_E* if error.
+ */
+int32_t base64_decode(const uint8_t *in,
+ const uint32_t in_len,
+ uint8_t *out,
+ const uint32_t out_len);
+
+/*!
+ * \brief Decodes text data using Base64 and output stores to own buffer.
+ *
+ * \note Input data needn't be terminated with '\0'.
+ *
+ * \note Input data must be continuous Base64 string!
+ *
+ * \note Output buffer should be deallocated after use.
+ *
+ * \param in Input text data.
+ * \param in_len Length of input string.
+ * \param out Output data buffer.
+ *
+ * \retval >=0 length of output data.
+ * \retval KNOT_E* if error.
+ */
+int32_t base64_decode_alloc(const uint8_t *in,
+ const uint32_t in_len,
+ uint8_t **out);
+
+/*! @} */
diff --git a/src/contrib/ctype.h b/src/contrib/ctype.h
new file mode 100644
index 0000000..93b85db
--- /dev/null
+++ b/src/contrib/ctype.h
@@ -0,0 +1,192 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \brief Locale-independent ctype functions.
+ */
+
+#pragma once
+
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+enum {
+ CT_DIGIT = 1 << 0,
+ CT_UPPER = 1 << 1,
+ CT_LOWER = 1 << 2,
+ CT_XDIGT = 1 << 3,
+ CT_PUNCT = 1 << 4,
+ CT_PRINT = 1 << 5,
+ CT_SPACE = 1 << 6,
+};
+
+static const uint8_t char_mask[256] = {
+ // 0 - 8
+ ['\t'] = CT_SPACE,
+ ['\n'] = CT_SPACE,
+ ['\v'] = CT_SPACE,
+ ['\f'] = CT_SPACE,
+ ['\r'] = CT_SPACE,
+ // 14 - 31
+ [' '] = CT_PRINT | CT_SPACE,
+
+ ['!'] = CT_PRINT | CT_PUNCT,
+ ['"'] = CT_PRINT | CT_PUNCT,
+ ['#'] = CT_PRINT | CT_PUNCT,
+ ['$'] = CT_PRINT | CT_PUNCT,
+ ['%'] = CT_PRINT | CT_PUNCT,
+ ['&'] = CT_PRINT | CT_PUNCT,
+ ['\''] = CT_PRINT | CT_PUNCT,
+ ['('] = CT_PRINT | CT_PUNCT,
+ [')'] = CT_PRINT | CT_PUNCT,
+ ['*'] = CT_PRINT | CT_PUNCT,
+ ['+'] = CT_PRINT | CT_PUNCT,
+ [','] = CT_PRINT | CT_PUNCT,
+ ['-'] = CT_PRINT | CT_PUNCT,
+ ['.'] = CT_PRINT | CT_PUNCT,
+ ['/'] = CT_PRINT | CT_PUNCT,
+
+ ['0'] = CT_PRINT | CT_DIGIT | CT_XDIGT,
+ ['1'] = CT_PRINT | CT_DIGIT | CT_XDIGT,
+ ['2'] = CT_PRINT | CT_DIGIT | CT_XDIGT,
+ ['3'] = CT_PRINT | CT_DIGIT | CT_XDIGT,
+ ['4'] = CT_PRINT | CT_DIGIT | CT_XDIGT,
+ ['5'] = CT_PRINT | CT_DIGIT | CT_XDIGT,
+ ['6'] = CT_PRINT | CT_DIGIT | CT_XDIGT,
+ ['7'] = CT_PRINT | CT_DIGIT | CT_XDIGT,
+ ['8'] = CT_PRINT | CT_DIGIT | CT_XDIGT,
+ ['9'] = CT_PRINT | CT_DIGIT | CT_XDIGT,
+
+ [':'] = CT_PRINT | CT_PUNCT,
+ [';'] = CT_PRINT | CT_PUNCT,
+ ['<'] = CT_PRINT | CT_PUNCT,
+ ['='] = CT_PRINT | CT_PUNCT,
+ ['>'] = CT_PRINT | CT_PUNCT,
+ ['?'] = CT_PRINT | CT_PUNCT,
+ ['@'] = CT_PRINT | CT_PUNCT,
+
+ ['A'] = CT_PRINT | CT_UPPER | CT_XDIGT,
+ ['B'] = CT_PRINT | CT_UPPER | CT_XDIGT,
+ ['C'] = CT_PRINT | CT_UPPER | CT_XDIGT,
+ ['D'] = CT_PRINT | CT_UPPER | CT_XDIGT,
+ ['E'] = CT_PRINT | CT_UPPER | CT_XDIGT,
+ ['F'] = CT_PRINT | CT_UPPER | CT_XDIGT,
+ ['G'] = CT_PRINT | CT_UPPER,
+ ['H'] = CT_PRINT | CT_UPPER,
+ ['I'] = CT_PRINT | CT_UPPER,
+ ['J'] = CT_PRINT | CT_UPPER,
+ ['K'] = CT_PRINT | CT_UPPER,
+ ['L'] = CT_PRINT | CT_UPPER,
+ ['M'] = CT_PRINT | CT_UPPER,
+ ['N'] = CT_PRINT | CT_UPPER,
+ ['O'] = CT_PRINT | CT_UPPER,
+ ['P'] = CT_PRINT | CT_UPPER,
+ ['Q'] = CT_PRINT | CT_UPPER,
+ ['R'] = CT_PRINT | CT_UPPER,
+ ['S'] = CT_PRINT | CT_UPPER,
+ ['T'] = CT_PRINT | CT_UPPER,
+ ['U'] = CT_PRINT | CT_UPPER,
+ ['V'] = CT_PRINT | CT_UPPER,
+ ['W'] = CT_PRINT | CT_UPPER,
+ ['X'] = CT_PRINT | CT_UPPER,
+ ['Y'] = CT_PRINT | CT_UPPER,
+ ['Z'] = CT_PRINT | CT_UPPER,
+
+ ['['] = CT_PRINT | CT_PUNCT,
+ ['\\'] = CT_PRINT | CT_PUNCT,
+ [']'] = CT_PRINT | CT_PUNCT,
+ ['^'] = CT_PRINT | CT_PUNCT,
+ ['_'] = CT_PRINT | CT_PUNCT,
+ ['`'] = CT_PRINT | CT_PUNCT,
+
+ ['a'] = CT_PRINT | CT_LOWER | CT_XDIGT,
+ ['b'] = CT_PRINT | CT_LOWER | CT_XDIGT,
+ ['c'] = CT_PRINT | CT_LOWER | CT_XDIGT,
+ ['d'] = CT_PRINT | CT_LOWER | CT_XDIGT,
+ ['e'] = CT_PRINT | CT_LOWER | CT_XDIGT,
+ ['f'] = CT_PRINT | CT_LOWER | CT_XDIGT,
+ ['g'] = CT_PRINT | CT_LOWER,
+ ['h'] = CT_PRINT | CT_LOWER,
+ ['i'] = CT_PRINT | CT_LOWER,
+ ['j'] = CT_PRINT | CT_LOWER,
+ ['k'] = CT_PRINT | CT_LOWER,
+ ['l'] = CT_PRINT | CT_LOWER,
+ ['m'] = CT_PRINT | CT_LOWER,
+ ['n'] = CT_PRINT | CT_LOWER,
+ ['o'] = CT_PRINT | CT_LOWER,
+ ['p'] = CT_PRINT | CT_LOWER,
+ ['q'] = CT_PRINT | CT_LOWER,
+ ['r'] = CT_PRINT | CT_LOWER,
+ ['s'] = CT_PRINT | CT_LOWER,
+ ['t'] = CT_PRINT | CT_LOWER,
+ ['u'] = CT_PRINT | CT_LOWER,
+ ['v'] = CT_PRINT | CT_LOWER,
+ ['w'] = CT_PRINT | CT_LOWER,
+ ['x'] = CT_PRINT | CT_LOWER,
+ ['y'] = CT_PRINT | CT_LOWER,
+ ['z'] = CT_PRINT | CT_LOWER,
+
+ ['{'] = CT_PRINT | CT_PUNCT,
+ ['|'] = CT_PRINT | CT_PUNCT,
+ ['}'] = CT_PRINT | CT_PUNCT,
+ ['~'] = CT_PRINT | CT_PUNCT,
+ // 127 - 255
+};
+
+static inline bool is_alnum(uint8_t c)
+{
+ return char_mask[c] & (CT_DIGIT | CT_UPPER | CT_LOWER);
+}
+
+static inline bool is_alpha(uint8_t c)
+{
+ return char_mask[c] & (CT_UPPER | CT_LOWER);
+}
+
+static inline bool is_digit(uint8_t c)
+{
+ return char_mask[c] & CT_DIGIT;
+}
+
+static inline bool is_xdigit(uint8_t c)
+{
+ return char_mask[c] & CT_XDIGT;
+}
+
+static inline bool is_lower(uint8_t c)
+{
+ return char_mask[c] & CT_LOWER;
+}
+
+static inline bool is_upper(uint8_t c)
+{
+ return char_mask[c] & CT_UPPER;
+}
+
+static inline bool is_print(uint8_t c)
+{
+ return char_mask[c] & CT_PRINT;
+}
+
+static inline bool is_punct(uint8_t c)
+{
+ return char_mask[c] & CT_PUNCT;
+}
+
+static inline bool is_space(uint8_t c)
+{
+ return char_mask[c] & CT_SPACE;
+}
diff --git a/src/contrib/dnstap/convert.c b/src/contrib/dnstap/convert.c
new file mode 100644
index 0000000..f59bacd
--- /dev/null
+++ b/src/contrib/dnstap/convert.c
@@ -0,0 +1,142 @@
+/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+
+#include "contrib/dnstap/convert.h"
+#include "contrib/dnstap/dnstap.pb-c.h"
+
+/*!
+ * \brief Translation between real and Dnstap value.
+ */
+typedef struct mapping {
+ int real;
+ int dnstap;
+} mapping_t;
+
+/*!
+ * \brief Mapping for network family.
+ */
+static const mapping_t SOCKET_FAMILY_MAPPING[] = {
+ { AF_INET, DNSTAP__SOCKET_FAMILY__INET },
+ { AF_INET6, DNSTAP__SOCKET_FAMILY__INET6 },
+ { 0 }
+};
+
+/*!
+ * \brief Mapping from network protocol.
+ */
+static const mapping_t SOCKET_PROTOCOL_MAPPING[] = {
+ { IPPROTO_UDP, DNSTAP__SOCKET_PROTOCOL__UDP },
+ { IPPROTO_TCP, DNSTAP__SOCKET_PROTOCOL__TCP },
+ { 0 }
+};
+
+/*!
+ * \brief Get Dnstap value for a given real value.
+ */
+static int encode(const mapping_t *mapping, int real)
+{
+ for (const mapping_t *m = mapping; m->real != 0; m += 1) {
+ if (m->real == real) {
+ return m->dnstap;
+ }
+ }
+
+ return 0;
+}
+
+/*!
+ * \brief Get real value for a given Dnstap value.
+ */
+static int decode(const mapping_t *mapping, int dnstap)
+{
+ for (const mapping_t *m = mapping; m->real != 0; m += 1) {
+ if (m->dnstap == dnstap) {
+ return m->real;
+ }
+ }
+
+ return 0;
+}
+
+/* -- public API ----------------------------------------------------------- */
+
+Dnstap__SocketFamily dt_family_encode(int family)
+{
+ return encode(SOCKET_FAMILY_MAPPING, family);
+}
+
+int dt_family_decode(Dnstap__SocketFamily dnstap_family)
+{
+ return decode(SOCKET_FAMILY_MAPPING, dnstap_family);
+}
+
+Dnstap__SocketProtocol dt_protocol_encode(int protocol)
+{
+ return encode(SOCKET_PROTOCOL_MAPPING, protocol);
+}
+
+int dt_protocol_decode(Dnstap__SocketProtocol dnstap_protocol)
+{
+ return decode(SOCKET_PROTOCOL_MAPPING, dnstap_protocol);
+}
+
+bool dt_message_type_is_query(Dnstap__Message__Type type)
+{
+ switch (type) {
+ case DNSTAP__MESSAGE__TYPE__AUTH_QUERY:
+ case DNSTAP__MESSAGE__TYPE__CLIENT_QUERY:
+ case DNSTAP__MESSAGE__TYPE__FORWARDER_QUERY:
+ case DNSTAP__MESSAGE__TYPE__RESOLVER_QUERY:
+ case DNSTAP__MESSAGE__TYPE__STUB_QUERY:
+ case DNSTAP__MESSAGE__TYPE__TOOL_QUERY:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool dt_message_type_is_response(Dnstap__Message__Type type)
+{
+ switch (type) {
+ case DNSTAP__MESSAGE__TYPE__AUTH_RESPONSE:
+ case DNSTAP__MESSAGE__TYPE__CLIENT_RESPONSE:
+ case DNSTAP__MESSAGE__TYPE__FORWARDER_RESPONSE:
+ case DNSTAP__MESSAGE__TYPE__RESOLVER_RESPONSE:
+ case DNSTAP__MESSAGE__TYPE__STUB_RESPONSE:
+ case DNSTAP__MESSAGE__TYPE__TOOL_RESPONSE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool dt_message_role_is_initiator(Dnstap__Message__Type type)
+{
+ switch (type) {
+ case DNSTAP__MESSAGE__TYPE__AUTH_QUERY:
+ case DNSTAP__MESSAGE__TYPE__AUTH_RESPONSE:
+ case DNSTAP__MESSAGE__TYPE__CLIENT_QUERY:
+ case DNSTAP__MESSAGE__TYPE__CLIENT_RESPONSE:
+ return false;
+ default:
+ return true;
+ }
+}
diff --git a/src/contrib/dnstap/convert.h b/src/contrib/dnstap/convert.h
new file mode 100644
index 0000000..bf00ffb
--- /dev/null
+++ b/src/contrib/dnstap/convert.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \brief Dnstap identifiers conversions.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+
+#include "contrib/dnstap/dnstap.pb-c.h"
+
+/*!
+ * \brief Get Dnstap socket family from the real one.
+ */
+Dnstap__SocketFamily dt_family_encode(int family);
+
+/*!
+ * \brief Get real socket family from the Dnstap one.
+ */
+int dt_family_decode(Dnstap__SocketFamily dnstap_family);
+
+/*!
+ * \brief Get Dnstap protocol from a real one.
+ */
+Dnstap__SocketProtocol dt_protocol_encode(int protocol);
+
+/*!
+ * \brief Get real protocol from the Dnstap one.
+ */
+int dt_protocol_decode(Dnstap__SocketProtocol dnstap_protocol);
+
+/*!
+ * Check if a message type is any type of a query.
+ */
+bool dt_message_type_is_query(Dnstap__Message__Type type);
+
+/*!
+ * Check if a message type is any type of a response.
+ */
+bool dt_message_type_is_response(Dnstap__Message__Type type);
+
+/*!
+ * Check if a message role is any type of an initiator.
+ */
+bool dt_message_role_is_initiator(Dnstap__Message__Type type);
diff --git a/src/contrib/dnstap/dnstap.c b/src/contrib/dnstap/dnstap.c
new file mode 100644
index 0000000..9e24eac
--- /dev/null
+++ b/src/contrib/dnstap/dnstap.c
@@ -0,0 +1,40 @@
+/* Copyright (C) 2014 Farsight Security, Inc. <software@farsightsecurity.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "contrib/dnstap/dnstap.pb-c.h"
+
+#define DNSTAP_INITIAL_BUF_SIZE 256
+
+uint8_t* dt_pack(const Dnstap__Dnstap *d, uint8_t **buf, size_t *sz)
+{
+ ProtobufCBufferSimple sbuf = { { NULL } };
+
+ sbuf.base.append = protobuf_c_buffer_simple_append;
+ sbuf.len = 0;
+ sbuf.alloced = DNSTAP_INITIAL_BUF_SIZE;
+ sbuf.data = malloc(sbuf.alloced);
+ if (sbuf.data == NULL) {
+ return NULL;
+ }
+ sbuf.must_free_data = 1;
+
+ *sz = dnstap__dnstap__pack_to_buffer(d, (ProtobufCBuffer *) &sbuf);
+ *buf = sbuf.data;
+ return *buf;
+}
diff --git a/src/contrib/dnstap/dnstap.h b/src/contrib/dnstap/dnstap.h
new file mode 100644
index 0000000..41e5f65
--- /dev/null
+++ b/src/contrib/dnstap/dnstap.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 2014 Farsight Security, Inc. <software@farsightsecurity.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \author Robert Edmonds <edmonds@fsi.io>
+ *
+ * \brief Public interface for dnstap.
+ */
+
+#pragma once
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "contrib/dnstap/dnstap.pb-c.h"
+
+/*! \brief Frame Streams "Content Type" value for dnstap. */
+#define DNSTAP_CONTENT_TYPE "protobuf:dnstap.Dnstap"
+
+/*!
+ * \brief Serializes a filled out dnstap protobuf struct. Dynamically allocates
+ * storage for the serialized frame.
+ *
+ * \note This function returns a copy of its parameter return value 'buf' to
+ * make error checking slightly easier.
+ *
+ * \param d dnstap protobuf struct.
+ * \param[out] buf Serialized frame.
+ * \param[out] sz Size in bytes of the serialized frame.
+ *
+ * \return Serialized frame.
+ * \retval NULL if error.
+ */
+uint8_t* dt_pack(const Dnstap__Dnstap *d, uint8_t **buf, size_t *sz);
diff --git a/src/contrib/dnstap/dnstap.proto b/src/contrib/dnstap/dnstap.proto
new file mode 100644
index 0000000..ea5c77a
--- /dev/null
+++ b/src/contrib/dnstap/dnstap.proto
@@ -0,0 +1,270 @@
+// dnstap: flexible, structured event replication format for DNS software
+//
+// This file contains the protobuf schemas for the "dnstap" structured event
+// replication format for DNS software.
+
+// Written in 2013-2014 by Farsight Security, Inc.
+//
+// To the extent possible under law, the author(s) have dedicated all
+// copyright and related and neighboring rights to this file to the public
+// domain worldwide. This file is distributed without any warranty.
+//
+// You should have received a copy of the CC0 Public Domain Dedication along
+// with this file. If not, see:
+//
+// <http://creativecommons.org/publicdomain/zero/1.0/>.
+
+syntax = "proto2";
+
+package dnstap;
+
+// "Dnstap": this is the top-level dnstap type, which is a "union" type that
+// contains other kinds of dnstap payloads, although currently only one type
+// of dnstap payload is defined.
+// See: https://developers.google.com/protocol-buffers/docs/techniques#union
+message Dnstap {
+ // DNS server identity.
+ // If enabled, this is the identity string of the DNS server which generated
+ // this message. Typically this would be the same string as returned by an
+ // "NSID" (RFC 5001) query.
+ optional bytes identity = 1;
+
+ // DNS server version.
+ // If enabled, this is the version string of the DNS server which generated
+ // this message. Typically this would be the same string as returned by a
+ // "version.bind" query.
+ optional bytes version = 2;
+
+ // Extra data for this payload.
+ // This field can be used for adding an arbitrary byte-string annotation to
+ // the payload. No encoding or interpretation is applied or enforced.
+ optional bytes extra = 3;
+
+ // Identifies which field below is filled in.
+ enum Type {
+ MESSAGE = 1;
+ }
+ required Type type = 15;
+
+ // One of the following will be filled in.
+ optional Message message = 14;
+}
+
+// SocketFamily: the network protocol family of a socket. This specifies how
+// to interpret "network address" fields.
+enum SocketFamily {
+ INET = 1; // IPv4 (RFC 791)
+ INET6 = 2; // IPv6 (RFC 2460)
+}
+
+// SocketProtocol: the transport protocol of a socket. This specifies how to
+// interpret "transport port" fields.
+enum SocketProtocol {
+ UDP = 1; // User Datagram Protocol (RFC 768)
+ TCP = 2; // Transmission Control Protocol (RFC 793)
+}
+
+// Message: a wire-format (RFC 1035 section 4) DNS message and associated
+// metadata. Applications generating "Message" payloads should follow
+// certain requirements based on the MessageType, see below.
+message Message {
+
+ // There are eight types of "Message" defined that correspond to the
+ // four arrows in the following diagram, slightly modified from RFC 1035
+ // section 2:
+
+ // +---------+ +----------+ +--------+
+ // | | query | | query | |
+ // | Stub |-SQ--------CQ->| Recursive|-RQ----AQ->| Auth. |
+ // | Resolver| | Server | | Name |
+ // | |<-SR--------CR-| |<-RR----AR-| Server |
+ // +---------+ response | | response | |
+ // +----------+ +--------+
+
+ // Each arrow has two Type values each, one for each "end" of each arrow,
+ // because these are considered to be distinct events. Each end of each
+ // arrow on the diagram above has been marked with a two-letter Type
+ // mnemonic. Clockwise from upper left, these mnemonic values are:
+ //
+ // SQ: STUB_QUERY
+ // CQ: CLIENT_QUERY
+ // RQ: RESOLVER_QUERY
+ // AQ: AUTH_QUERY
+ // AR: AUTH_RESPONSE
+ // RR: RESOLVER_RESPONSE
+ // CR: CLIENT_RESPONSE
+ // SR: STUB_RESPONSE
+
+ // Two additional types of "Message" have been defined for the
+ // "forwarding" case where an upstream DNS server is responsible for
+ // further recursion. These are not shown on the diagram above, but have
+ // the following mnemonic values:
+
+ // FQ: FORWARDER_QUERY
+ // FR: FORWARDER_RESPONSE
+
+ // The "Message" Type values are defined below.
+
+ enum Type {
+ // AUTH_QUERY is a DNS query message received from a resolver by an
+ // authoritative name server, from the perspective of the authoritative
+ // name server.
+ AUTH_QUERY = 1;
+
+ // AUTH_RESPONSE is a DNS response message sent from an authoritative
+ // name server to a resolver, from the perspective of the authoritative
+ // name server.
+ AUTH_RESPONSE = 2;
+
+ // RESOLVER_QUERY is a DNS query message sent from a resolver to an
+ // authoritative name server, from the perspective of the resolver.
+ // Resolvers typically clear the RD (recursion desired) bit when
+ // sending queries.
+ RESOLVER_QUERY = 3;
+
+ // RESOLVER_RESPONSE is a DNS response message received from an
+ // authoritative name server by a resolver, from the perspective of
+ // the resolver.
+ RESOLVER_RESPONSE = 4;
+
+ // CLIENT_QUERY is a DNS query message sent from a client to a DNS
+ // server which is expected to perform further recursion, from the
+ // perspective of the DNS server. The client may be a stub resolver or
+ // forwarder or some other type of software which typically sets the RD
+ // (recursion desired) bit when querying the DNS server. The DNS server
+ // may be a simple forwarding proxy or it may be a full recursive
+ // resolver.
+ CLIENT_QUERY = 5;
+
+ // CLIENT_RESPONSE is a DNS response message sent from a DNS server to
+ // a client, from the perspective of the DNS server. The DNS server
+ // typically sets the RA (recursion available) bit when responding.
+ CLIENT_RESPONSE = 6;
+
+ // FORWARDER_QUERY is a DNS query message sent from a downstream DNS
+ // server to an upstream DNS server which is expected to perform
+ // further recursion, from the perspective of the downstream DNS
+ // server.
+ FORWARDER_QUERY = 7;
+
+ // FORWARDER_RESPONSE is a DNS response message sent from an upstream
+ // DNS server performing recursion to a downstream DNS server, from the
+ // perspective of the downstream DNS server.
+ FORWARDER_RESPONSE = 8;
+
+ // STUB_QUERY is a DNS query message sent from a stub resolver to a DNS
+ // server, from the perspective of the stub resolver.
+ STUB_QUERY = 9;
+
+ // STUB_RESPONSE is a DNS response message sent from a DNS server to a
+ // stub resolver, from the perspective of the stub resolver.
+ STUB_RESPONSE = 10;
+
+ // TOOL_QUERY is a DNS query message sent from a DNS software tool to a
+ // DNS server, from the perspective of the tool.
+ TOOL_QUERY = 11;
+
+ // TOOL_RESPONSE is a DNS response message received by a DNS software
+ // tool from a DNS server, from the perspective of the tool.
+ TOOL_RESPONSE = 12;
+ }
+
+ // One of the Type values described above.
+ required Type type = 1;
+
+ // One of the SocketFamily values described above.
+ optional SocketFamily socket_family = 2;
+
+ // One of the SocketProtocol values described above.
+ optional SocketProtocol socket_protocol = 3;
+
+ // The network address of the message initiator.
+ // For SocketFamily INET, this field is 4 octets (IPv4 address).
+ // For SocketFamily INET6, this field is 16 octets (IPv6 address).
+ optional bytes query_address = 4;
+
+ // The network address of the message responder.
+ // For SocketFamily INET, this field is 4 octets (IPv4 address).
+ // For SocketFamily INET6, this field is 16 octets (IPv6 address).
+ optional bytes response_address = 5;
+
+ // The transport port of the message initiator.
+ // This is a 16-bit UDP or TCP port number, depending on SocketProtocol.
+ optional uint32 query_port = 6;
+
+ // The transport port of the message responder.
+ // This is a 16-bit UDP or TCP port number, depending on SocketProtocol.
+ optional uint32 response_port = 7;
+
+ // The time at which the DNS query message was sent or received, depending
+ // on whether this is an AUTH_QUERY, RESOLVER_QUERY, or CLIENT_QUERY.
+ // This is the number of seconds since the UNIX epoch.
+ optional uint64 query_time_sec = 8;
+
+ // The time at which the DNS query message was sent or received.
+ // This is the seconds fraction, expressed as a count of nanoseconds.
+ optional fixed32 query_time_nsec = 9;
+
+ // The initiator's original wire-format DNS query message, verbatim.
+ optional bytes query_message = 10;
+
+ // The "zone" or "bailiwick" pertaining to the DNS query message.
+ // This is a wire-format DNS domain name.
+ optional bytes query_zone = 11;
+
+ // The time at which the DNS response message was sent or received,
+ // depending on whether this is an AUTH_RESPONSE, RESOLVER_RESPONSE, or
+ // CLIENT_RESPONSE.
+ // This is the number of seconds since the UNIX epoch.
+ optional uint64 response_time_sec = 12;
+
+ // The time at which the DNS response message was sent or received.
+ // This is the seconds fraction, expressed as a count of nanoseconds.
+ optional fixed32 response_time_nsec = 13;
+
+ // The responder's original wire-format DNS response message, verbatim.
+ optional bytes response_message = 14;
+}
+
+// All fields except for 'type' in the Message schema are optional.
+// It is recommended that at least the following fields be filled in for
+// particular types of Messages.
+
+// AUTH_QUERY:
+// socket_family, socket_protocol
+// query_address, query_port
+// query_message
+// query_time_sec, query_time_nsec
+
+// AUTH_RESPONSE:
+// socket_family, socket_protocol
+// query_address, query_port
+// query_time_sec, query_time_nsec
+// response_message
+// response_time_sec, response_time_nsec
+
+// RESOLVER_QUERY:
+// socket_family, socket_protocol
+// query_message
+// query_time_sec, query_time_nsec
+// query_zone
+// response_address, response_port
+
+// RESOLVER_RESPONSE:
+// socket_family, socket_protocol
+// query_time_sec, query_time_nsec
+// query_zone
+// response_address, response_port
+// response_message
+// response_time_sec, response_time_nsec
+
+// CLIENT_QUERY:
+// socket_family, socket_protocol
+// query_message
+// query_time_sec, query_time_nsec
+
+// CLIENT_RESPONSE:
+// socket_family, socket_protocol
+// query_time_sec, query_time_nsec
+// response_message
+// response_time_sec, response_time_nsec
diff --git a/src/contrib/dnstap/message.c b/src/contrib/dnstap/message.c
new file mode 100644
index 0000000..0b41e9d
--- /dev/null
+++ b/src/contrib/dnstap/message.c
@@ -0,0 +1,130 @@
+/* Copyright (C) 2017 Farsight Security, Inc. <software@farsightsecurity.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libknot/errcode.h"
+
+#include "contrib/dnstap/convert.h"
+#include "contrib/dnstap/message.h"
+
+static void set_address(const struct sockaddr *sockaddr,
+ ProtobufCBinaryData *addr,
+ protobuf_c_boolean *has_addr,
+ uint32_t *port,
+ protobuf_c_boolean *has_port)
+{
+ if (sockaddr == NULL) {
+ *has_addr = 0;
+ *has_port = 0;
+ return;
+ }
+
+ *has_addr = 1;
+ *has_port = 1;
+
+ if (sockaddr->sa_family == AF_INET) {
+ const struct sockaddr_in *sai;
+ sai = (const struct sockaddr_in *)sockaddr;
+ addr->len = sizeof(sai->sin_addr);
+ addr->data = (uint8_t *)&sai->sin_addr.s_addr;
+ *port = ntohs(sai->sin_port);
+ } else if (sockaddr->sa_family == AF_INET6) {
+ const struct sockaddr_in6 *sai6;
+ sai6 = (const struct sockaddr_in6 *)sockaddr;
+ addr->len = sizeof(sai6->sin6_addr);
+ addr->data = (uint8_t *)&sai6->sin6_addr.s6_addr;
+ *port = ntohs(sai6->sin6_port);
+ }
+}
+
+static int get_family(const struct sockaddr *query_sa,
+ const struct sockaddr *response_sa)
+{
+ const struct sockaddr *source = query_sa ? query_sa : response_sa;
+ if (source == NULL) {
+ return 0;
+ }
+
+ return dt_family_encode(source->sa_family);
+}
+
+int dt_message_fill(Dnstap__Message *m,
+ const Dnstap__Message__Type type,
+ const struct sockaddr *query_sa,
+ const struct sockaddr *response_sa,
+ const int protocol,
+ const void *wire,
+ const size_t len_wire,
+ const struct timespec *mtime)
+{
+ if (m == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ memset(m, 0, sizeof(*m));
+
+ m->base.descriptor = &dnstap__message__descriptor;
+
+ // Message.type
+ m->type = type;
+
+ // Message.socket_family
+ m->socket_family = get_family(query_sa, response_sa);
+ m->has_socket_family = m->socket_family != 0;
+
+ // Message.socket_protocol
+ m->socket_protocol = dt_protocol_encode(protocol);
+ m->has_socket_protocol = m->socket_protocol != 0;
+
+ // Message addresses
+ set_address(query_sa, &m->query_address, &m->has_query_address,
+ &m->query_port, &m->has_query_port);
+ set_address(response_sa, &m->response_address, &m->has_response_address,
+ &m->response_port, &m->has_response_port);
+
+ if (dt_message_type_is_query(type)) {
+ // Message.query_message
+ m->query_message.len = len_wire;
+ m->query_message.data = (uint8_t *)wire;
+ m->has_query_message = 1;
+ // Message.query_time_sec, Message.query_time_nsec
+ if (mtime != NULL) {
+ m->query_time_sec = mtime->tv_sec;
+ m->query_time_nsec = mtime->tv_nsec;
+ m->has_query_time_sec = 1;
+ m->has_query_time_nsec = 1;
+ }
+ } else if (dt_message_type_is_response(type)) {
+ // Message.response_message
+ m->response_message.len = len_wire;
+ m->response_message.data = (uint8_t *)wire;
+ m->has_response_message = 1;
+ // Message.response_time_sec, Message.response_time_nsec
+ if (mtime != NULL) {
+ m->response_time_sec = mtime->tv_sec;
+ m->response_time_nsec = mtime->tv_nsec;
+ m->has_response_time_sec = 1;
+ m->has_response_time_nsec = 1;
+ }
+ }
+
+ return KNOT_EOK;
+}
diff --git a/src/contrib/dnstap/message.h b/src/contrib/dnstap/message.h
new file mode 100644
index 0000000..11a967d
--- /dev/null
+++ b/src/contrib/dnstap/message.h
@@ -0,0 +1,62 @@
+/* Copyright (C) 2017 Farsight Security, Inc. <software@farsightsecurity.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \author Robert Edmonds <edmonds@fsi.io>
+ *
+ * \brief Dnstap message interface.
+ */
+
+#pragma once
+
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <stddef.h>
+
+#include "contrib/dnstap/dnstap.pb-c.h"
+
+/*!
+ * \brief Fill a Dnstap__Message structure with the given parameters.
+ *
+ * \param[out] m
+ * Dnstap__Message structure to fill. Will be zeroed first.
+ * \param type
+ * One of the DNSTAP__MESSAGE__TYPE__* values.
+ * \param query_sa
+ * sockaddr_in or sockaddr_in6 to use when filling the 'socket_family',
+ * 'query_address', 'query_port' fields.
+ * \param response_sa
+ * sockaddr_in or sockaddr_in6 to use when filling the 'socket_family',
+ * 'response_address', 'response_port' fields.
+ * \param protocol
+ * \c IPPROTO_UDP or \c IPPROTO_TCP.
+ * \param wire
+ * Wire-format query message or response message (depending on 'type').
+ * \param len_wire
+ * Length in bytes of 'wire'.
+ * \param mtime
+ * Message time. May be NULL.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EINVAL
+ */
+int dt_message_fill(Dnstap__Message *m,
+ const Dnstap__Message__Type type,
+ const struct sockaddr *query_sa,
+ const struct sockaddr *response_sa,
+ const int protocol,
+ const void *wire,
+ const size_t len_wire,
+ const struct timespec *mtime);
diff --git a/src/contrib/dnstap/reader.c b/src/contrib/dnstap/reader.c
new file mode 100644
index 0000000..593c6ec
--- /dev/null
+++ b/src/contrib/dnstap/reader.c
@@ -0,0 +1,105 @@
+/* Copyright (C) 2014 Farsight Security, Inc. <software@farsightsecurity.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libknot/errcode.h"
+
+#include "contrib/macros.h"
+#include "contrib/dnstap/dnstap.h"
+#include "contrib/dnstap/reader.h"
+
+dt_reader_t* dt_reader_create(const char *file_path)
+{
+ struct fstrm_file_options *fopt = NULL;
+ struct fstrm_reader_options *ropt = NULL;
+ dt_reader_t *reader = NULL;
+ fstrm_res res;
+
+ reader = calloc(1, sizeof(dt_reader_t));
+ if (reader == NULL) {
+ goto fail;
+ }
+
+ // Open reader.
+ fopt = fstrm_file_options_init();
+ fstrm_file_options_set_file_path(fopt, file_path);
+ ropt = fstrm_reader_options_init();
+ fstrm_reader_options_add_content_type(ropt,
+ (const uint8_t *) DNSTAP_CONTENT_TYPE,
+ strlen(DNSTAP_CONTENT_TYPE));
+ reader->fr = fstrm_file_reader_init(fopt, ropt);
+ fstrm_file_options_destroy(&fopt);
+ fstrm_reader_options_destroy(&ropt);
+ if (reader->fr == NULL) {
+ goto fail;
+ }
+ res = fstrm_reader_open(reader->fr);
+ if (res != fstrm_res_success) {
+ goto fail;
+ }
+
+ return reader;
+fail:
+ dt_reader_free(reader);
+ return NULL;
+}
+
+void dt_reader_free(dt_reader_t *reader)
+{
+ if (reader == NULL) {
+ return;
+ }
+
+ fstrm_reader_destroy(&reader->fr);
+ free(reader);
+}
+
+int dt_reader_read(dt_reader_t *reader, Dnstap__Dnstap **d)
+{
+ fstrm_res res;
+ const uint8_t *data = NULL;
+ size_t len = 0;
+
+ res = fstrm_reader_read(reader->fr, &data, &len);
+ if (res == fstrm_res_success) {
+ *d = dnstap__dnstap__unpack(NULL, len, data);
+ if (*d == NULL) {
+ return KNOT_ENOMEM;
+ }
+ } else if (res == fstrm_res_failure) {
+ return KNOT_ERROR;
+ } else if (res == fstrm_res_stop) {
+ return KNOT_EOF;
+ }
+
+ return KNOT_EOK;
+}
+
+void dt_reader_free_frame(dt_reader_t *reader, Dnstap__Dnstap **frame_ptr)
+{
+ if (!*frame_ptr) {
+ return;
+ }
+
+ UNUSED(reader);
+
+ dnstap__dnstap__free_unpacked(*frame_ptr, NULL);
+ *frame_ptr = NULL;
+}
diff --git a/src/contrib/dnstap/reader.h b/src/contrib/dnstap/reader.h
new file mode 100644
index 0000000..c8cda26
--- /dev/null
+++ b/src/contrib/dnstap/reader.h
@@ -0,0 +1,72 @@
+/* Copyright (C) 2017 Farsight Security, Inc. <software@farsightsecurity.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \brief Dnstap file reader.
+ */
+
+#pragma once
+
+#include <fstrm.h>
+#include <protobuf-c/protobuf-c.h>
+
+#include "contrib/dnstap/dnstap.pb-c.h"
+
+/*! \brief Structure for dnstap file reader. */
+typedef struct {
+ /*!< Input reader. */
+ struct fstrm_reader *fr;
+} dt_reader_t;
+
+/*!
+ * \brief Creates dnstap file reader structure.
+ *
+ * \param file_path Name of file to read input from.
+ *
+ * \retval reader if success.
+ * \retval NULL if error.
+ */
+dt_reader_t* dt_reader_create(const char *file_path);
+
+/*!
+ * \brief Close dnstap file reader.
+ *
+ * \param reader dnstap file reader structure.
+ */
+void dt_reader_free(dt_reader_t *reader);
+
+/*!
+ * \brief Read a dnstap protobuf from a dnstap file reader.
+ *
+ * Caller must deallocate the returned protobuf with the
+ * dnstap__dnstap__free_unpacked() function.
+ *
+ * \param[in] reader dnstap file reader structure.
+ * \param[out] d Unpacked dnstap protobuf.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_ERROR
+ * \retval KNOT_EOF
+ * \retval KNOT_ENOMEM
+ */
+int dt_reader_read(dt_reader_t *reader, Dnstap__Dnstap **d);
+
+/*!
+ * \brief free the frame allocated by dt_read_data.
+ *
+ * \param reader Dnstap reader context.
+ * \param d The frame to be freed.
+ */
+void dt_reader_free_frame(dt_reader_t *reader, Dnstap__Dnstap **d);
diff --git a/src/contrib/dnstap/writer.c b/src/contrib/dnstap/writer.c
new file mode 100644
index 0000000..08f4519
--- /dev/null
+++ b/src/contrib/dnstap/writer.c
@@ -0,0 +1,120 @@
+/* Copyright (C) 2014 Farsight Security, Inc. <software@farsightsecurity.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libknot/errcode.h"
+
+#include "contrib/dnstap/dnstap.h"
+#include "contrib/dnstap/writer.h"
+
+dt_writer_t* dt_writer_create(const char *file_path, const char *version)
+{
+ struct fstrm_file_options *fopt = NULL;
+ struct fstrm_writer_options *wopt = NULL;
+ dt_writer_t *writer = NULL;
+ fstrm_res res;
+
+ writer = calloc(1, sizeof(dt_writer_t));
+ if (writer == NULL) {
+ goto fail;
+ }
+
+ // Set "version".
+ if (version != NULL) {
+ writer->len_version = strlen(version);
+ writer->version = strdup(version);
+ if (!writer->version) {
+ goto fail;
+ }
+ }
+
+ // Open writer.
+ fopt = fstrm_file_options_init();
+ fstrm_file_options_set_file_path(fopt, file_path);
+ wopt = fstrm_writer_options_init();
+ fstrm_writer_options_add_content_type(wopt,
+ (const uint8_t *) DNSTAP_CONTENT_TYPE,
+ strlen(DNSTAP_CONTENT_TYPE));
+ writer->fw = fstrm_file_writer_init(fopt, wopt);
+ fstrm_file_options_destroy(&fopt);
+ fstrm_writer_options_destroy(&wopt);
+ if (writer->fw == NULL) {
+ goto fail;
+ }
+
+ res = fstrm_writer_open(writer->fw);
+ if (res != fstrm_res_success) {
+ goto fail;
+ }
+
+ return writer;
+fail:
+ dt_writer_free(writer);
+ return NULL;
+}
+
+void dt_writer_free(dt_writer_t *writer)
+{
+ if (writer == NULL) {
+ return;
+ }
+
+ fstrm_writer_destroy(&writer->fw);
+ free(writer->version);
+ free(writer);
+}
+
+int dt_writer_write(dt_writer_t *writer, const ProtobufCMessage *msg)
+{
+ Dnstap__Dnstap dnstap = DNSTAP__DNSTAP__INIT;
+ size_t len;
+ uint8_t *data;
+
+ if (writer->fw == NULL) {
+ return KNOT_EOK;
+ }
+
+ // Only handle dnstap/Message.
+ assert(msg->descriptor == &dnstap__message__descriptor);
+
+ // Fill out 'dnstap'.
+ if (writer->version) {
+ dnstap.version.data = writer->version;
+ dnstap.version.len = writer->len_version;
+ dnstap.has_version = 1;
+ }
+ dnstap.type = DNSTAP__DNSTAP__TYPE__MESSAGE;
+ dnstap.message = (Dnstap__Message *)msg;
+
+ // Serialize the dnstap frame.
+ if (!dt_pack(&dnstap, &data, &len)) {
+ return KNOT_ENOMEM;
+ }
+
+ // Write the dnstap frame to the output stream.
+ if (fstrm_writer_write(writer->fw, data, len) != fstrm_res_success) {
+ return KNOT_ERROR;
+ }
+
+ // Cleanup.
+ free(data);
+
+ return KNOT_EOK;
+}
diff --git a/src/contrib/dnstap/writer.h b/src/contrib/dnstap/writer.h
new file mode 100644
index 0000000..4fe7326
--- /dev/null
+++ b/src/contrib/dnstap/writer.h
@@ -0,0 +1,70 @@
+/* Copyright (C) 2014 Farsight Security, Inc. <software@farsightsecurity.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \author Robert Edmonds <edmonds@fsi.io>
+ *
+ * \brief Dnstap file writer.
+ */
+
+#pragma once
+
+#include <fstrm.h>
+#include <protobuf-c/protobuf-c.h>
+
+/*! \brief Structure for dnstap file writer. */
+typedef struct {
+ /*!< Output writer. */
+ struct fstrm_writer *fw;
+
+ /*!< dnstap "version" field. */
+ void *version;
+
+ /*!< length of dnstap "version" field. */
+ size_t len_version;
+} dt_writer_t;
+
+/*!
+ * \brief Creates dnstap file writer structure.
+ *
+ * \param file_path Name of file to write output to.
+ * \param version Version string of software. May be NULL.
+ *
+ * \retval writer if success.
+ * \retval NULL if error.
+ */
+dt_writer_t* dt_writer_create(const char *file_path, const char *version);
+
+/*!
+ * \brief Finish writing dnstap file writer and free resources.
+ *
+ * \param writer dnstap file writer structure.
+ */
+void dt_writer_free(dt_writer_t *writer);
+
+/*!
+ * \brief Write a protobuf to the dnstap file writer.
+ *
+ * Supported protobuf types for the 'msg' parameter:
+ * \c Dnstap__Message
+ *
+ * \param writer dnstap file writer structure.
+ * \param msg dnstap protobuf. Must be a supported type.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EINVAL
+ * \retval KNOT_ENOMEM
+ */
+int dt_writer_write(dt_writer_t *writer, const ProtobufCMessage *msg);
diff --git a/src/contrib/dynarray.h b/src/contrib/dynarray.h
new file mode 100644
index 0000000..79eab31
--- /dev/null
+++ b/src/contrib/dynarray.h
@@ -0,0 +1,123 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \brief Simple write-once allocation-optimal dynamic array.
+ *
+ * Include it into your .c file
+ *
+ * prefix - identifier prefix, e.g. ptr -> struct ptr_dynarray, ptr_dynarray_add(), ...
+ * ntype - data type to be stored. Let it be a number, pointer or small struct
+ * initial_capacity - how many data items will be allocated on stac and copied with assignment
+ *
+ * prefix_dynarray_add() - add a data item
+ * prefix_dynarray_fix() - call EVERYTIME the array is copied from some already invalid stack
+ * prefix_dynarray_free() - call EVERYTIME you dismiss all copies of the array
+ *
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+
+#pragma once
+
+#define DYNARRAY_VISIBILITY_STATIC static
+#define DYNARRAY_VISIBILITY_PUBLIC
+#define DYNARRAY_VISIBILITY_LIBRARY __public__
+
+#define dynarray_declare(prefix, ntype, visibility, initial_capacity) \
+ typedef struct prefix ## _dynarray { \
+ ssize_t capacity; \
+ ssize_t size; \
+ ntype *(*arr)(struct prefix ## _dynarray *dynarray); \
+ ntype init[initial_capacity]; \
+ ntype *_arr; \
+ } prefix ## _dynarray_t; \
+ \
+ visibility ntype *prefix ## _dynarray_arr(prefix ## _dynarray_t *dynarray); \
+ visibility void prefix ## _dynarray_add(prefix ## _dynarray_t *dynarray, \
+ ntype const *to_add); \
+ visibility void prefix ## _dynarray_free(prefix ## _dynarray_t *dynarray);
+
+#define dynarray_foreach(prefix, ntype, ptr, array) \
+ for (ntype *ptr = prefix ## _dynarray_arr(&(array)); \
+ ptr < prefix ## _dynarray_arr(&(array)) + (array).size; ptr++)
+
+#define dynarray_define(prefix, ntype, visibility) \
+ \
+ static void prefix ## _dynarray_free__(struct prefix ## _dynarray *dynarray) \
+ { \
+ if (dynarray->capacity > sizeof(dynarray->init) / sizeof(*dynarray->init)) { \
+ free(dynarray->_arr); \
+ } \
+ } \
+ \
+ __attribute__((unused)) \
+ visibility ntype *prefix ## _dynarray_arr(struct prefix ## _dynarray *dynarray) \
+ { \
+ assert(dynarray->size <= dynarray->capacity); \
+ return (dynarray->capacity <= sizeof(dynarray->init) / sizeof(*dynarray->init) ? \
+ dynarray->init : dynarray->_arr); \
+ } \
+ \
+ static ntype *prefix ## _dynarray_arr_init__(struct prefix ## _dynarray *dynarray) \
+ { \
+ assert(dynarray->capacity == sizeof(dynarray->init) / sizeof(*dynarray->init)); \
+ return dynarray->init; \
+ } \
+ \
+ static ntype *prefix ## _dynarray_arr_arr__(struct prefix ## _dynarray *dynarray) \
+ { \
+ assert(dynarray->capacity > sizeof(dynarray->init) / sizeof(*dynarray->init)); \
+ return dynarray->_arr; \
+ } \
+ \
+ __attribute__((unused)) \
+ visibility void prefix ## _dynarray_add(struct prefix ## _dynarray *dynarray, \
+ ntype const *to_add) \
+ { \
+ if (dynarray->capacity < 0) { \
+ return; \
+ } \
+ if (dynarray->capacity == 0) { \
+ dynarray->capacity = sizeof(dynarray->init) / sizeof(*dynarray->init); \
+ dynarray->arr = prefix ## _dynarray_arr_init__; \
+ } \
+ if (dynarray->size >= dynarray->capacity) { \
+ ssize_t new_capacity = dynarray->capacity * 2 + 1; \
+ ntype *new_arr = calloc(new_capacity, sizeof(ntype)); \
+ if (new_arr == NULL) { \
+ prefix ## _dynarray_free__(dynarray); \
+ dynarray->capacity = dynarray->size = -1; \
+ return; \
+ } \
+ if (dynarray->capacity > 0) { \
+ memcpy(new_arr, prefix ## _dynarray_arr(dynarray), \
+ dynarray->capacity * sizeof(ntype)); \
+ } \
+ prefix ## _dynarray_free__(dynarray); \
+ dynarray->_arr = new_arr; \
+ dynarray->capacity = new_capacity; \
+ dynarray->arr = prefix ## _dynarray_arr_arr__; \
+ } \
+ prefix ## _dynarray_arr(dynarray)[dynarray->size++] = *to_add; \
+ } \
+ \
+ __attribute__((unused)) \
+ visibility void prefix ## _dynarray_free(struct prefix ## _dynarray *dynarray) \
+ { \
+ prefix ## _dynarray_free__(dynarray); \
+ memset(dynarray, 0, sizeof(*dynarray)); \
+ }
diff --git a/src/contrib/files.c b/src/contrib/files.c
new file mode 100644
index 0000000..3181386
--- /dev/null
+++ b/src/contrib/files.c
@@ -0,0 +1,134 @@
+/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <ftw.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "contrib/files.h"
+#include "contrib/string.h"
+#include "libknot/errcode.h"
+
+static int remove_file(const char *path, const struct stat *stat, int type, struct FTW *ftw)
+{
+ (void)stat;
+ (void)ftw;
+ if (type == FTW_DP) {
+ return rmdir(path);
+ } else {
+ return unlink(path);
+ }
+}
+
+bool remove_path(const char *path)
+{
+ return (0 == nftw(path, remove_file, 1, FTW_DEPTH | FTW_PHYS));
+}
+
+int make_dir(const char *path, mode_t mode, bool ignore_existing)
+{
+ if (mkdir(path, mode) == 0) {
+ return KNOT_EOK;
+ }
+
+ if (!ignore_existing || errno != EEXIST) {
+ return knot_map_errno();
+ }
+
+ assert(errno == EEXIST);
+
+ struct stat st = { 0 };
+ if (stat(path, &st) != 0) {
+ return knot_map_errno();
+ }
+
+ if (!S_ISDIR(st.st_mode)) {
+ return knot_map_errno_code(ENOTDIR);
+ }
+
+ return KNOT_EOK;
+}
+
+int make_path(const char *path, mode_t mode)
+{
+ if (path == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ char *dir = strdup(path);
+ if (dir == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ for (char *p = strchr(dir + 1, '/'); p != NULL; p = strchr(p + 1, '/')) {
+ *p = '\0';
+ if (mkdir(dir, mode) == -1 && errno != EEXIST) {
+ free(dir);
+ return knot_map_errno();
+ }
+ *p = '/';
+ }
+
+ free(dir);
+
+ return KNOT_EOK;
+}
+
+int open_tmp_file(const char *path, char **tmp_name, FILE **file, mode_t mode)
+{
+ int ret;
+
+ *tmp_name = sprintf_alloc("%s.XXXXXX", path);
+ if (*tmp_name == NULL) {
+ ret = KNOT_ENOMEM;
+ goto open_tmp_failed;
+ }
+
+ int fd = mkstemp(*tmp_name);
+ if (fd < 0) {
+ ret = knot_map_errno();
+ goto open_tmp_failed;
+ }
+
+ if (fchmod(fd, mode) != 0) {
+ ret = knot_map_errno();
+ close(fd);
+ unlink(*tmp_name);
+ goto open_tmp_failed;
+ }
+
+ *file = fdopen(fd, "w");
+ if (*file == NULL) {
+ ret = knot_map_errno();
+ close(fd);
+ unlink(*tmp_name);
+ goto open_tmp_failed;
+ }
+
+ return KNOT_EOK;
+open_tmp_failed:
+ free(*tmp_name);
+ *tmp_name = NULL;
+ *file = NULL;
+
+ assert(ret != KNOT_EOK);
+ return ret;
+}
diff --git a/src/contrib/files.h b/src/contrib/files.h
new file mode 100644
index 0000000..c4c681f
--- /dev/null
+++ b/src/contrib/files.h
@@ -0,0 +1,43 @@
+/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+/*!
+ * \brief Delete file or directory (recursive).
+ *
+ * \return true on success, false when one or more files failed to be removed.
+ */
+bool remove_path(const char *path);
+
+/*!
+ * Equivalent to mkdir(2), can succeed if the directory already exists.
+ */
+int make_dir(const char *path, mode_t mode, bool ignore_existing);
+
+/*!
+ * Makes a directory part of the path with all parent directories if not exist.
+ */
+int make_path(const char *path, mode_t mode);
+
+/*!
+ * Creates and opens for writing a temporary file based on given path.
+ */
+int open_tmp_file(const char *path, char **tmp_name, FILE **file, mode_t mode);
diff --git a/src/contrib/getline.c b/src/contrib/getline.c
new file mode 100644
index 0000000..074c511
--- /dev/null
+++ b/src/contrib/getline.c
@@ -0,0 +1,60 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+// FreeBSD POSIX2008 getline
+#ifndef _WITH_GETLINE
+#define _WITH_GETLINE
+#endif
+
+#include "contrib/getline.h"
+
+#include <stdio.h> // getline or fgetln
+#include <stdlib.h> // free
+#include <string.h> // memcpy
+
+ssize_t knot_getline(char **lineptr, size_t *n, FILE *stream)
+{
+#ifdef HAVE_GETLINE
+ return getline(lineptr, n, stream);
+#else
+#ifdef HAVE_FGETLN
+ size_t length = 0;
+ char *buffer = fgetln(stream, &length);
+ if (buffer == NULL) {
+ return -1;
+ }
+
+ /* NOTE: Function fgetln doesn't return terminated string!
+ * Output buffer from the fgetln can't be freed.
+ */
+
+ // If the output buffer is not specified or is small, extend it.
+ if (*lineptr == NULL || *n <= length) {
+ char *tmp = realloc(*lineptr, length + 1);
+ if (tmp == NULL) {
+ return -1;
+ }
+ *lineptr = tmp;
+ *n = length + 1;
+ }
+
+ memcpy(*lineptr, buffer, length);
+ (*lineptr)[length] = '\0';
+
+ return length;
+#endif
+#endif
+}
diff --git a/src/contrib/getline.h b/src/contrib/getline.h
new file mode 100644
index 0000000..11c7fe3
--- /dev/null
+++ b/src/contrib/getline.h
@@ -0,0 +1,38 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \brief Multiplatform getline wrapper.
+ */
+
+#pragma once
+
+#include <stdio.h>
+#include <sys/types.h>
+
+/*!
+ * \brief Reads a line from a stream.
+ *
+ * This function has the same semantics as POSIX.1-2008 getline().
+ * If necessary, the output buffer will be allocated/reallocated.
+ *
+ * \param lineptr Output buffer.
+ * \param n Output buffer size.
+ * \param stream Input stream.
+ *
+ * \retval Number of characters read, including new line delimiter,
+ * not including terminating. -1 on error or EOF.
+ */
+ssize_t knot_getline(char **lineptr, size_t *n, FILE *stream);
diff --git a/src/contrib/licenses/0BSD b/src/contrib/licenses/0BSD
new file mode 100644
index 0000000..56c5528
--- /dev/null
+++ b/src/contrib/licenses/0BSD
@@ -0,0 +1,12 @@
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
diff --git a/src/contrib/licenses/BSD-3-Clause b/src/contrib/licenses/BSD-3-Clause
new file mode 100644
index 0000000..8041f21
--- /dev/null
+++ b/src/contrib/licenses/BSD-3-Clause
@@ -0,0 +1,21 @@
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+3. Neither the name of the copyright holder nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/src/contrib/licenses/LGPL-2.0 b/src/contrib/licenses/LGPL-2.0
new file mode 100644
index 0000000..d159169
--- /dev/null
+++ b/src/contrib/licenses/LGPL-2.0
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/src/contrib/licenses/OLDAP-2.8 b/src/contrib/licenses/OLDAP-2.8
new file mode 100644
index 0000000..05ad757
--- /dev/null
+++ b/src/contrib/licenses/OLDAP-2.8
@@ -0,0 +1,47 @@
+The OpenLDAP Public License
+ Version 2.8, 17 August 2003
+
+Redistribution and use of this software and associated documentation
+("Software"), with or without modification, are permitted provided
+that the following conditions are met:
+
+1. Redistributions in source form must retain copyright statements
+ and notices,
+
+2. Redistributions in binary form must reproduce applicable copyright
+ statements and notices, this list of conditions, and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution, and
+
+3. Redistributions must contain a verbatim copy of this document.
+
+The OpenLDAP Foundation may revise this license from time to time.
+Each revision is distinguished by a version number. You may use
+this Software under terms of this license revision or under the
+terms of any subsequent revision of the license.
+
+THIS SOFTWARE IS PROVIDED BY THE OPENLDAP FOUNDATION AND ITS
+CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+SHALL THE OPENLDAP FOUNDATION, ITS CONTRIBUTORS, OR THE AUTHOR(S)
+OR OWNER(S) OF THE SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+The names of the authors and copyright holders must not be used in
+advertising or otherwise to promote the sale, use or other dealing
+in this Software without specific, written prior permission. Title
+to copyright in this Software shall at all times remain with copyright
+holders.
+
+OpenLDAP is a registered trademark of the OpenLDAP Foundation.
+
+Copyright 1999-2003 The OpenLDAP Foundation, Redwood City,
+California, USA. All Rights Reserved. Permission to copy and
+distribute verbatim copies of this document is granted.
diff --git a/src/contrib/lmdb/LICENSE b/src/contrib/lmdb/LICENSE
new file mode 100644
index 0000000..66210f0
--- /dev/null
+++ b/src/contrib/lmdb/LICENSE
@@ -0,0 +1 @@
+../licenses/OLDAP-2.8 \ No newline at end of file
diff --git a/src/contrib/lmdb/lmdb.h b/src/contrib/lmdb/lmdb.h
new file mode 100644
index 0000000..32a278e
--- /dev/null
+++ b/src/contrib/lmdb/lmdb.h
@@ -0,0 +1,1604 @@
+/** @file lmdb.h
+ * @brief Lightning memory-mapped database library
+ *
+ * @mainpage Lightning Memory-Mapped Database Manager (LMDB)
+ *
+ * @section intro_sec Introduction
+ * LMDB is a Btree-based database management library modeled loosely on the
+ * BerkeleyDB API, but much simplified. The entire database is exposed
+ * in a memory map, and all data fetches return data directly
+ * from the mapped memory, so no malloc's or memcpy's occur during
+ * data fetches. As such, the library is extremely simple because it
+ * requires no page caching layer of its own, and it is extremely high
+ * performance and memory-efficient. It is also fully transactional with
+ * full ACID semantics, and when the memory map is read-only, the
+ * database integrity cannot be corrupted by stray pointer writes from
+ * application code.
+ *
+ * The library is fully thread-aware and supports concurrent read/write
+ * access from multiple processes and threads. Data pages use a copy-on-
+ * write strategy so no active data pages are ever overwritten, which
+ * also provides resistance to corruption and eliminates the need of any
+ * special recovery procedures after a system crash. Writes are fully
+ * serialized; only one write transaction may be active at a time, which
+ * guarantees that writers can never deadlock. The database structure is
+ * multi-versioned so readers run with no locks; writers cannot block
+ * readers, and readers don't block writers.
+ *
+ * Unlike other well-known database mechanisms which use either write-ahead
+ * transaction logs or append-only data writes, LMDB requires no maintenance
+ * during operation. Both write-ahead loggers and append-only databases
+ * require periodic checkpointing and/or compaction of their log or database
+ * files otherwise they grow without bound. LMDB tracks free pages within
+ * the database and re-uses them for new write operations, so the database
+ * size does not grow without bound in normal use.
+ *
+ * The memory map can be used as a read-only or read-write map. It is
+ * read-only by default as this provides total immunity to corruption.
+ * Using read-write mode offers much higher write performance, but adds
+ * the possibility for stray application writes thru pointers to silently
+ * corrupt the database. Of course if your application code is known to
+ * be bug-free (...) then this is not an issue.
+ *
+ * If this is your first time using a transactional embedded key/value
+ * store, you may find the \ref starting page to be helpful.
+ *
+ * @section caveats_sec Caveats
+ * Troubleshooting the lock file, plus semaphores on BSD systems:
+ *
+ * - A broken lockfile can cause sync issues.
+ * Stale reader transactions left behind by an aborted program
+ * cause further writes to grow the database quickly, and
+ * stale locks can block further operation.
+ *
+ * Fix: Check for stale readers periodically, using the
+ * #mdb_reader_check function or the \ref mdb_stat_1 "mdb_stat" tool.
+ * Stale writers will be cleared automatically on some systems:
+ * - Windows - automatic
+ * - Linux, systems using POSIX mutexes with Robust option - automatic
+ * - not on BSD, systems using POSIX semaphores.
+ * Otherwise just make all programs using the database close it;
+ * the lockfile is always reset on first open of the environment.
+ *
+ * - On BSD systems or others configured with MDB_USE_POSIX_SEM,
+ * startup can fail due to semaphores owned by another userid.
+ *
+ * Fix: Open and close the database as the user which owns the
+ * semaphores (likely last user) or as root, while no other
+ * process is using the database.
+ *
+ * Restrictions/caveats (in addition to those listed for some functions):
+ *
+ * - Only the database owner should normally use the database on
+ * BSD systems or when otherwise configured with MDB_USE_POSIX_SEM.
+ * Multiple users can cause startup to fail later, as noted above.
+ *
+ * - There is normally no pure read-only mode, since readers need write
+ * access to locks and lock file. Exceptions: On read-only filesystems
+ * or with the #MDB_NOLOCK flag described under #mdb_env_open().
+ *
+ * - An LMDB configuration will often reserve considerable \b unused
+ * memory address space and maybe file size for future growth.
+ * This does not use actual memory or disk space, but users may need
+ * to understand the difference so they won't be scared off.
+ *
+ * - By default, in versions before 0.9.10, unused portions of the data
+ * file might receive garbage data from memory freed by other code.
+ * (This does not happen when using the #MDB_WRITEMAP flag.) As of
+ * 0.9.10 the default behavior is to initialize such memory before
+ * writing to the data file. Since there may be a slight performance
+ * cost due to this initialization, applications may disable it using
+ * the #MDB_NOMEMINIT flag. Applications handling sensitive data
+ * which must not be written should not use this flag. This flag is
+ * irrelevant when using #MDB_WRITEMAP.
+ *
+ * - A thread can only use one transaction at a time, plus any child
+ * transactions. Each transaction belongs to one thread. See below.
+ * The #MDB_NOTLS flag changes this for read-only transactions.
+ *
+ * - Use an MDB_env* in the process which opened it, not after fork().
+ *
+ * - Do not have open an LMDB database twice in the same process at
+ * the same time. Not even from a plain open() call - close()ing it
+ * breaks fcntl() advisory locking. (It is OK to reopen it after
+ * fork() - exec*(), since the lockfile has FD_CLOEXEC set.)
+ *
+ * - Avoid long-lived transactions. Read transactions prevent
+ * reuse of pages freed by newer write transactions, thus the
+ * database can grow quickly. Write transactions prevent
+ * other write transactions, since writes are serialized.
+ *
+ * - Avoid suspending a process with active transactions. These
+ * would then be "long-lived" as above. Also read transactions
+ * suspended when writers commit could sometimes see wrong data.
+ *
+ * ...when several processes can use a database concurrently:
+ *
+ * - Avoid aborting a process with an active transaction.
+ * The transaction becomes "long-lived" as above until a check
+ * for stale readers is performed or the lockfile is reset,
+ * since the process may not remove it from the lockfile.
+ *
+ * This does not apply to write transactions if the system clears
+ * stale writers, see above.
+ *
+ * - If you do that anyway, do a periodic check for stale readers. Or
+ * close the environment once in a while, so the lockfile can get reset.
+ *
+ * - Do not use LMDB databases on remote filesystems, even between
+ * processes on the same host. This breaks flock() on some OSes,
+ * possibly memory map sync, and certainly sync between programs
+ * on different hosts.
+ *
+ * - Opening a database can fail if another process is opening or
+ * closing it at exactly the same time.
+ *
+ * @author Howard Chu, Symas Corporation.
+ *
+ * @copyright Copyright 2011-2018 Howard Chu, Symas Corp. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ *
+ * @par Derived From:
+ * This code is derived from btree.c written by Martin Hedenfalk.
+ *
+ * Copyright (c) 2009, 2010 Martin Hedenfalk <martin@bzero.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef _LMDB_H_
+#define _LMDB_H_
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Unix permissions for creating files, or dummy definition for Windows */
+#ifdef _MSC_VER
+typedef int mdb_mode_t;
+#else
+typedef mode_t mdb_mode_t;
+#endif
+
+/** An abstraction for a file handle.
+ * On POSIX systems file handles are small integers. On Windows
+ * they're opaque pointers.
+ */
+#ifdef _WIN32
+typedef void *mdb_filehandle_t;
+#else
+typedef int mdb_filehandle_t;
+#endif
+
+/** @defgroup mdb LMDB API
+ * @{
+ * @brief OpenLDAP Lightning Memory-Mapped Database Manager
+ */
+/** @defgroup Version Version Macros
+ * @{
+ */
+/** Library major version */
+#define MDB_VERSION_MAJOR 0
+/** Library minor version */
+#define MDB_VERSION_MINOR 9
+/** Library patch version */
+#define MDB_VERSION_PATCH 22
+
+/** Combine args a,b,c into a single integer for easy version comparisons */
+#define MDB_VERINT(a,b,c) (((a) << 24) | ((b) << 16) | (c))
+
+/** The full library version as a single integer */
+#define MDB_VERSION_FULL \
+ MDB_VERINT(MDB_VERSION_MAJOR,MDB_VERSION_MINOR,MDB_VERSION_PATCH)
+
+/** The release date of this library version */
+#define MDB_VERSION_DATE "March 21, 2018"
+
+/** A stringifier for the version info */
+#define MDB_VERSTR(a,b,c,d) "LMDB " #a "." #b "." #c ": (" d ")"
+
+/** A helper for the stringifier macro */
+#define MDB_VERFOO(a,b,c,d) MDB_VERSTR(a,b,c,d)
+
+/** The full library version as a C string */
+#define MDB_VERSION_STRING \
+ MDB_VERFOO(MDB_VERSION_MAJOR,MDB_VERSION_MINOR,MDB_VERSION_PATCH,MDB_VERSION_DATE)
+/** @} */
+
+/** @brief Opaque structure for a database environment.
+ *
+ * A DB environment supports multiple databases, all residing in the same
+ * shared-memory map.
+ */
+typedef struct MDB_env MDB_env;
+
+/** @brief Opaque structure for a transaction handle.
+ *
+ * All database operations require a transaction handle. Transactions may be
+ * read-only or read-write.
+ */
+typedef struct MDB_txn MDB_txn;
+
+/** @brief A handle for an individual database in the DB environment. */
+typedef unsigned int MDB_dbi;
+
+/** @brief Opaque structure for navigating through a database */
+typedef struct MDB_cursor MDB_cursor;
+
+/** @brief Generic structure used for passing keys and data in and out
+ * of the database.
+ *
+ * Values returned from the database are valid only until a subsequent
+ * update operation, or the end of the transaction. Do not modify or
+ * free them, they commonly point into the database itself.
+ *
+ * Key sizes must be between 1 and #mdb_env_get_maxkeysize() inclusive.
+ * The same applies to data sizes in databases with the #MDB_DUPSORT flag.
+ * Other data items can in theory be from 0 to 0xffffffff bytes long.
+ */
+typedef struct MDB_val {
+ size_t mv_size; /**< size of the data item */
+ void *mv_data; /**< address of the data item */
+} MDB_val;
+
+/** @brief A callback function used to compare two keys in a database */
+typedef int (MDB_cmp_func)(const MDB_val *a, const MDB_val *b);
+
+/** @brief A callback function used to relocate a position-dependent data item
+ * in a fixed-address database.
+ *
+ * The \b newptr gives the item's desired address in
+ * the memory map, and \b oldptr gives its previous address. The item's actual
+ * data resides at the address in \b item. This callback is expected to walk
+ * through the fields of the record in \b item and modify any
+ * values based at the \b oldptr address to be relative to the \b newptr address.
+ * @param[in,out] item The item that is to be relocated.
+ * @param[in] oldptr The previous address.
+ * @param[in] newptr The new address to relocate to.
+ * @param[in] relctx An application-provided context, set by #mdb_set_relctx().
+ * @todo This feature is currently unimplemented.
+ */
+typedef void (MDB_rel_func)(MDB_val *item, void *oldptr, void *newptr, void *relctx);
+
+/** @defgroup mdb_env Environment Flags
+ * @{
+ */
+ /** mmap at a fixed address (experimental) */
+#define MDB_FIXEDMAP 0x01
+ /** no environment directory */
+#define MDB_NOSUBDIR 0x4000
+ /** don't fsync after commit */
+#define MDB_NOSYNC 0x10000
+ /** read only */
+#define MDB_RDONLY 0x20000
+ /** don't fsync metapage after commit */
+#define MDB_NOMETASYNC 0x40000
+ /** use writable mmap */
+#define MDB_WRITEMAP 0x80000
+ /** use asynchronous msync when #MDB_WRITEMAP is used */
+#define MDB_MAPASYNC 0x100000
+ /** tie reader locktable slots to #MDB_txn objects instead of to threads */
+#define MDB_NOTLS 0x200000
+ /** don't do any locking, caller must manage their own locks */
+#define MDB_NOLOCK 0x400000
+ /** don't do readahead (no effect on Windows) */
+#define MDB_NORDAHEAD 0x800000
+ /** don't initialize malloc'd memory before writing to datafile */
+#define MDB_NOMEMINIT 0x1000000
+/** @} */
+
+/** @defgroup mdb_dbi_open Database Flags
+ * @{
+ */
+ /** use reverse string keys */
+#define MDB_REVERSEKEY 0x02
+ /** use sorted duplicates */
+#define MDB_DUPSORT 0x04
+ /** numeric keys in native byte order: either unsigned int or size_t.
+ * The keys must all be of the same size. */
+#define MDB_INTEGERKEY 0x08
+ /** with #MDB_DUPSORT, sorted dup items have fixed size */
+#define MDB_DUPFIXED 0x10
+ /** with #MDB_DUPSORT, dups are #MDB_INTEGERKEY-style integers */
+#define MDB_INTEGERDUP 0x20
+ /** with #MDB_DUPSORT, use reverse string dups */
+#define MDB_REVERSEDUP 0x40
+ /** create DB if not already existing */
+#define MDB_CREATE 0x40000
+/** @} */
+
+/** @defgroup mdb_put Write Flags
+ * @{
+ */
+/** For put: Don't write if the key already exists. */
+#define MDB_NOOVERWRITE 0x10
+/** Only for #MDB_DUPSORT<br>
+ * For put: don't write if the key and data pair already exist.<br>
+ * For mdb_cursor_del: remove all duplicate data items.
+ */
+#define MDB_NODUPDATA 0x20
+/** For mdb_cursor_put: overwrite the current key/data pair */
+#define MDB_CURRENT 0x40
+/** For put: Just reserve space for data, don't copy it. Return a
+ * pointer to the reserved space.
+ */
+#define MDB_RESERVE 0x10000
+/** Data is being appended, don't split full pages. */
+#define MDB_APPEND 0x20000
+/** Duplicate data is being appended, don't split full pages. */
+#define MDB_APPENDDUP 0x40000
+/** Store multiple data items in one call. Only for #MDB_DUPFIXED. */
+#define MDB_MULTIPLE 0x80000
+/* @} */
+
+/** @defgroup mdb_copy Copy Flags
+ * @{
+ */
+/** Compacting copy: Omit free space from copy, and renumber all
+ * pages sequentially.
+ */
+#define MDB_CP_COMPACT 0x01
+/* @} */
+
+/** @brief Cursor Get operations.
+ *
+ * This is the set of all operations for retrieving data
+ * using a cursor.
+ */
+typedef enum MDB_cursor_op {
+ MDB_FIRST, /**< Position at first key/data item */
+ MDB_FIRST_DUP, /**< Position at first data item of current key.
+ Only for #MDB_DUPSORT */
+ MDB_GET_BOTH, /**< Position at key/data pair. Only for #MDB_DUPSORT */
+ MDB_GET_BOTH_RANGE, /**< position at key, nearest data. Only for #MDB_DUPSORT */
+ MDB_GET_CURRENT, /**< Return key/data at current cursor position */
+ MDB_GET_MULTIPLE, /**< Return key and up to a page of duplicate data items
+ from current cursor position. Move cursor to prepare
+ for #MDB_NEXT_MULTIPLE. Only for #MDB_DUPFIXED */
+ MDB_LAST, /**< Position at last key/data item */
+ MDB_LAST_DUP, /**< Position at last data item of current key.
+ Only for #MDB_DUPSORT */
+ MDB_NEXT, /**< Position at next data item */
+ MDB_NEXT_DUP, /**< Position at next data item of current key.
+ Only for #MDB_DUPSORT */
+ MDB_NEXT_MULTIPLE, /**< Return key and up to a page of duplicate data items
+ from next cursor position. Move cursor to prepare
+ for #MDB_NEXT_MULTIPLE. Only for #MDB_DUPFIXED */
+ MDB_NEXT_NODUP, /**< Position at first data item of next key */
+ MDB_PREV, /**< Position at previous data item */
+ MDB_PREV_DUP, /**< Position at previous data item of current key.
+ Only for #MDB_DUPSORT */
+ MDB_PREV_NODUP, /**< Position at last data item of previous key */
+ MDB_SET, /**< Position at specified key */
+ MDB_SET_KEY, /**< Position at specified key, return key + data */
+ MDB_SET_RANGE, /**< Position at first key greater than or equal to specified key. */
+ MDB_PREV_MULTIPLE /**< Position at previous page and return key and up to
+ a page of duplicate data items. Only for #MDB_DUPFIXED */
+} MDB_cursor_op;
+
+/** @defgroup errors Return Codes
+ *
+ * BerkeleyDB uses -30800 to -30999, we'll go under them
+ * @{
+ */
+ /** Successful result */
+#define MDB_SUCCESS 0
+ /** key/data pair already exists */
+#define MDB_KEYEXIST (-30799)
+ /** key/data pair not found (EOF) */
+#define MDB_NOTFOUND (-30798)
+ /** Requested page not found - this usually indicates corruption */
+#define MDB_PAGE_NOTFOUND (-30797)
+ /** Located page was wrong type */
+#define MDB_CORRUPTED (-30796)
+ /** Update of meta page failed or environment had fatal error */
+#define MDB_PANIC (-30795)
+ /** Environment version mismatch */
+#define MDB_VERSION_MISMATCH (-30794)
+ /** File is not a valid LMDB file */
+#define MDB_INVALID (-30793)
+ /** Environment mapsize reached */
+#define MDB_MAP_FULL (-30792)
+ /** Environment maxdbs reached */
+#define MDB_DBS_FULL (-30791)
+ /** Environment maxreaders reached */
+#define MDB_READERS_FULL (-30790)
+ /** Too many TLS keys in use - Windows only */
+#define MDB_TLS_FULL (-30789)
+ /** Txn has too many dirty pages */
+#define MDB_TXN_FULL (-30788)
+ /** Cursor stack too deep - internal error */
+#define MDB_CURSOR_FULL (-30787)
+ /** Page has not enough space - internal error */
+#define MDB_PAGE_FULL (-30786)
+ /** Database contents grew beyond environment mapsize */
+#define MDB_MAP_RESIZED (-30785)
+ /** Operation and DB incompatible, or DB type changed. This can mean:
+ * <ul>
+ * <li>The operation expects an #MDB_DUPSORT / #MDB_DUPFIXED database.
+ * <li>Opening a named DB when the unnamed DB has #MDB_DUPSORT / #MDB_INTEGERKEY.
+ * <li>Accessing a data record as a database, or vice versa.
+ * <li>The database was dropped and recreated with different flags.
+ * </ul>
+ */
+#define MDB_INCOMPATIBLE (-30784)
+ /** Invalid reuse of reader locktable slot */
+#define MDB_BAD_RSLOT (-30783)
+ /** Transaction must abort, has a child, or is invalid */
+#define MDB_BAD_TXN (-30782)
+ /** Unsupported size of key/DB name/data, or wrong DUPFIXED size */
+#define MDB_BAD_VALSIZE (-30781)
+ /** The specified DBI was changed unexpectedly */
+#define MDB_BAD_DBI (-30780)
+ /** The last defined error code */
+#define MDB_LAST_ERRCODE MDB_BAD_DBI
+/** @} */
+
+/** @brief Statistics for a database in the environment */
+typedef struct MDB_stat {
+ unsigned int ms_psize; /**< Size of a database page.
+ This is currently the same for all databases. */
+ unsigned int ms_depth; /**< Depth (height) of the B-tree */
+ size_t ms_branch_pages; /**< Number of internal (non-leaf) pages */
+ size_t ms_leaf_pages; /**< Number of leaf pages */
+ size_t ms_overflow_pages; /**< Number of overflow pages */
+ size_t ms_entries; /**< Number of data items */
+} MDB_stat;
+
+/** @brief Information about the environment */
+typedef struct MDB_envinfo {
+ void *me_mapaddr; /**< Address of map, if fixed */
+ size_t me_mapsize; /**< Size of the data memory map */
+ size_t me_last_pgno; /**< ID of the last used page */
+ size_t me_last_txnid; /**< ID of the last committed transaction */
+ unsigned int me_maxreaders; /**< max reader slots in the environment */
+ unsigned int me_numreaders; /**< max reader slots used in the environment */
+} MDB_envinfo;
+
+ /** @brief Return the LMDB library version information.
+ *
+ * @param[out] major if non-NULL, the library major version number is copied here
+ * @param[out] minor if non-NULL, the library minor version number is copied here
+ * @param[out] patch if non-NULL, the library patch version number is copied here
+ * @retval "version string" The library version as a string
+ */
+char *mdb_version(int *major, int *minor, int *patch);
+
+ /** @brief Return a string describing a given error code.
+ *
+ * This function is a superset of the ANSI C X3.159-1989 (ANSI C) strerror(3)
+ * function. If the error code is greater than or equal to 0, then the string
+ * returned by the system function strerror(3) is returned. If the error code
+ * is less than 0, an error string corresponding to the LMDB library error is
+ * returned. See @ref errors for a list of LMDB-specific error codes.
+ * @param[in] err The error code
+ * @retval "error message" The description of the error
+ */
+char *mdb_strerror(int err);
+
+ /** @brief Create an LMDB environment handle.
+ *
+ * This function allocates memory for a #MDB_env structure. To release
+ * the allocated memory and discard the handle, call #mdb_env_close().
+ * Before the handle may be used, it must be opened using #mdb_env_open().
+ * Various other options may also need to be set before opening the handle,
+ * e.g. #mdb_env_set_mapsize(), #mdb_env_set_maxreaders(), #mdb_env_set_maxdbs(),
+ * depending on usage requirements.
+ * @param[out] env The address where the new handle will be stored
+ * @return A non-zero error value on failure and 0 on success.
+ */
+int mdb_env_create(MDB_env **env);
+
+ /** @brief Open an environment handle.
+ *
+ * If this function fails, #mdb_env_close() must be called to discard the #MDB_env handle.
+ * @param[in] env An environment handle returned by #mdb_env_create()
+ * @param[in] path The directory in which the database files reside. This
+ * directory must already exist and be writable.
+ * @param[in] flags Special options for this environment. This parameter
+ * must be set to 0 or by bitwise OR'ing together one or more of the
+ * values described here.
+ * Flags set by mdb_env_set_flags() are also used.
+ * <ul>
+ * <li>#MDB_FIXEDMAP
+ * use a fixed address for the mmap region. This flag must be specified
+ * when creating the environment, and is stored persistently in the environment.
+ * If successful, the memory map will always reside at the same virtual address
+ * and pointers used to reference data items in the database will be constant
+ * across multiple invocations. This option may not always work, depending on
+ * how the operating system has allocated memory to shared libraries and other uses.
+ * The feature is highly experimental.
+ * <li>#MDB_NOSUBDIR
+ * By default, LMDB creates its environment in a directory whose
+ * pathname is given in \b path, and creates its data and lock files
+ * under that directory. With this option, \b path is used as-is for
+ * the database main data file. The database lock file is the \b path
+ * with "-lock" appended.
+ * <li>#MDB_RDONLY
+ * Open the environment in read-only mode. No write operations will be
+ * allowed. LMDB will still modify the lock file - except on read-only
+ * filesystems, where LMDB does not use locks.
+ * <li>#MDB_WRITEMAP
+ * Use a writeable memory map unless MDB_RDONLY is set. This uses
+ * fewer mallocs but loses protection from application bugs
+ * like wild pointer writes and other bad updates into the database.
+ * This may be slightly faster for DBs that fit entirely in RAM, but
+ * is slower for DBs larger than RAM.
+ * Incompatible with nested transactions.
+ * Do not mix processes with and without MDB_WRITEMAP on the same
+ * environment. This can defeat durability (#mdb_env_sync etc).
+ * <li>#MDB_NOMETASYNC
+ * Flush system buffers to disk only once per transaction, omit the
+ * metadata flush. Defer that until the system flushes files to disk,
+ * or next non-MDB_RDONLY commit or #mdb_env_sync(). This optimization
+ * maintains database integrity, but a system crash may undo the last
+ * committed transaction. I.e. it preserves the ACI (atomicity,
+ * consistency, isolation) but not D (durability) database property.
+ * This flag may be changed at any time using #mdb_env_set_flags().
+ * <li>#MDB_NOSYNC
+ * Don't flush system buffers to disk when committing a transaction.
+ * This optimization means a system crash can corrupt the database or
+ * lose the last transactions if buffers are not yet flushed to disk.
+ * The risk is governed by how often the system flushes dirty buffers
+ * to disk and how often #mdb_env_sync() is called. However, if the
+ * filesystem preserves write order and the #MDB_WRITEMAP flag is not
+ * used, transactions exhibit ACI (atomicity, consistency, isolation)
+ * properties and only lose D (durability). I.e. database integrity
+ * is maintained, but a system crash may undo the final transactions.
+ * Note that (#MDB_NOSYNC | #MDB_WRITEMAP) leaves the system with no
+ * hint for when to write transactions to disk, unless #mdb_env_sync()
+ * is called. (#MDB_MAPASYNC | #MDB_WRITEMAP) may be preferable.
+ * This flag may be changed at any time using #mdb_env_set_flags().
+ * <li>#MDB_MAPASYNC
+ * When using #MDB_WRITEMAP, use asynchronous flushes to disk.
+ * As with #MDB_NOSYNC, a system crash can then corrupt the
+ * database or lose the last transactions. Calling #mdb_env_sync()
+ * ensures on-disk database integrity until next commit.
+ * This flag may be changed at any time using #mdb_env_set_flags().
+ * <li>#MDB_NOTLS
+ * Don't use Thread-Local Storage. Tie reader locktable slots to
+ * #MDB_txn objects instead of to threads. I.e. #mdb_txn_reset() keeps
+ * the slot reseved for the #MDB_txn object. A thread may use parallel
+ * read-only transactions. A read-only transaction may span threads if
+ * the user synchronizes its use. Applications that multiplex many
+ * user threads over individual OS threads need this option. Such an
+ * application must also serialize the write transactions in an OS
+ * thread, since LMDB's write locking is unaware of the user threads.
+ * <li>#MDB_NOLOCK
+ * Don't do any locking. If concurrent access is anticipated, the
+ * caller must manage all concurrency itself. For proper operation
+ * the caller must enforce single-writer semantics, and must ensure
+ * that no readers are using old transactions while a writer is
+ * active. The simplest approach is to use an exclusive lock so that
+ * no readers may be active at all when a writer begins.
+ * <li>#MDB_NORDAHEAD
+ * Turn off readahead. Most operating systems perform readahead on
+ * read requests by default. This option turns it off if the OS
+ * supports it. Turning it off may help random read performance
+ * when the DB is larger than RAM and system RAM is full.
+ * The option is not implemented on Windows.
+ * <li>#MDB_NOMEMINIT
+ * Don't initialize malloc'd memory before writing to unused spaces
+ * in the data file. By default, memory for pages written to the data
+ * file is obtained using malloc. While these pages may be reused in
+ * subsequent transactions, freshly malloc'd pages will be initialized
+ * to zeroes before use. This avoids persisting leftover data from other
+ * code (that used the heap and subsequently freed the memory) into the
+ * data file. Note that many other system libraries may allocate
+ * and free memory from the heap for arbitrary uses. E.g., stdio may
+ * use the heap for file I/O buffers. This initialization step has a
+ * modest performance cost so some applications may want to disable
+ * it using this flag. This option can be a problem for applications
+ * which handle sensitive data like passwords, and it makes memory
+ * checkers like Valgrind noisy. This flag is not needed with #MDB_WRITEMAP,
+ * which writes directly to the mmap instead of using malloc for pages. The
+ * initialization is also skipped if #MDB_RESERVE is used; the
+ * caller is expected to overwrite all of the memory that was
+ * reserved in that case.
+ * This flag may be changed at any time using #mdb_env_set_flags().
+ * </ul>
+ * @param[in] mode The UNIX permissions to set on created files and semaphores.
+ * This parameter is ignored on Windows.
+ * @return A non-zero error value on failure and 0 on success. Some possible
+ * errors are:
+ * <ul>
+ * <li>#MDB_VERSION_MISMATCH - the version of the LMDB library doesn't match the
+ * version that created the database environment.
+ * <li>#MDB_INVALID - the environment file headers are corrupted.
+ * <li>ENOENT - the directory specified by the path parameter doesn't exist.
+ * <li>EACCES - the user didn't have permission to access the environment files.
+ * <li>EAGAIN - the environment was locked by another process.
+ * </ul>
+ */
+int mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode);
+
+ /** @brief Copy an LMDB environment to the specified path.
+ *
+ * This function may be used to make a backup of an existing environment.
+ * No lockfile is created, since it gets recreated at need.
+ * @note This call can trigger significant file size growth if run in
+ * parallel with write transactions, because it employs a read-only
+ * transaction. See long-lived transactions under @ref caveats_sec.
+ * @param[in] env An environment handle returned by #mdb_env_create(). It
+ * must have already been opened successfully.
+ * @param[in] path The directory in which the copy will reside. This
+ * directory must already exist and be writable but must otherwise be
+ * empty.
+ * @return A non-zero error value on failure and 0 on success.
+ */
+int mdb_env_copy(MDB_env *env, const char *path);
+
+ /** @brief Copy an LMDB environment to the specified file descriptor.
+ *
+ * This function may be used to make a backup of an existing environment.
+ * No lockfile is created, since it gets recreated at need.
+ * @note This call can trigger significant file size growth if run in
+ * parallel with write transactions, because it employs a read-only
+ * transaction. See long-lived transactions under @ref caveats_sec.
+ * @param[in] env An environment handle returned by #mdb_env_create(). It
+ * must have already been opened successfully.
+ * @param[in] fd The filedescriptor to write the copy to. It must
+ * have already been opened for Write access.
+ * @return A non-zero error value on failure and 0 on success.
+ */
+int mdb_env_copyfd(MDB_env *env, mdb_filehandle_t fd);
+
+ /** @brief Copy an LMDB environment to the specified path, with options.
+ *
+ * This function may be used to make a backup of an existing environment.
+ * No lockfile is created, since it gets recreated at need.
+ * @note This call can trigger significant file size growth if run in
+ * parallel with write transactions, because it employs a read-only
+ * transaction. See long-lived transactions under @ref caveats_sec.
+ * @param[in] env An environment handle returned by #mdb_env_create(). It
+ * must have already been opened successfully.
+ * @param[in] path The directory in which the copy will reside. This
+ * directory must already exist and be writable but must otherwise be
+ * empty.
+ * @param[in] flags Special options for this operation. This parameter
+ * must be set to 0 or by bitwise OR'ing together one or more of the
+ * values described here.
+ * <ul>
+ * <li>#MDB_CP_COMPACT - Perform compaction while copying: omit free
+ * pages and sequentially renumber all pages in output. This option
+ * consumes more CPU and runs more slowly than the default.
+ * Currently it fails if the environment has suffered a page leak.
+ * </ul>
+ * @return A non-zero error value on failure and 0 on success.
+ */
+int mdb_env_copy2(MDB_env *env, const char *path, unsigned int flags);
+
+ /** @brief Copy an LMDB environment to the specified file descriptor,
+ * with options.
+ *
+ * This function may be used to make a backup of an existing environment.
+ * No lockfile is created, since it gets recreated at need. See
+ * #mdb_env_copy2() for further details.
+ * @note This call can trigger significant file size growth if run in
+ * parallel with write transactions, because it employs a read-only
+ * transaction. See long-lived transactions under @ref caveats_sec.
+ * @param[in] env An environment handle returned by #mdb_env_create(). It
+ * must have already been opened successfully.
+ * @param[in] fd The filedescriptor to write the copy to. It must
+ * have already been opened for Write access.
+ * @param[in] flags Special options for this operation.
+ * See #mdb_env_copy2() for options.
+ * @return A non-zero error value on failure and 0 on success.
+ */
+int mdb_env_copyfd2(MDB_env *env, mdb_filehandle_t fd, unsigned int flags);
+
+ /** @brief Return statistics about the LMDB environment.
+ *
+ * @param[in] env An environment handle returned by #mdb_env_create()
+ * @param[out] stat The address of an #MDB_stat structure
+ * where the statistics will be copied
+ */
+int mdb_env_stat(MDB_env *env, MDB_stat *stat);
+
+ /** @brief Return information about the LMDB environment.
+ *
+ * @param[in] env An environment handle returned by #mdb_env_create()
+ * @param[out] stat The address of an #MDB_envinfo structure
+ * where the information will be copied
+ */
+int mdb_env_info(MDB_env *env, MDB_envinfo *stat);
+
+ /** @brief Flush the data buffers to disk.
+ *
+ * Data is always written to disk when #mdb_txn_commit() is called,
+ * but the operating system may keep it buffered. LMDB always flushes
+ * the OS buffers upon commit as well, unless the environment was
+ * opened with #MDB_NOSYNC or in part #MDB_NOMETASYNC. This call is
+ * not valid if the environment was opened with #MDB_RDONLY.
+ * @param[in] env An environment handle returned by #mdb_env_create()
+ * @param[in] force If non-zero, force a synchronous flush. Otherwise
+ * if the environment has the #MDB_NOSYNC flag set the flushes
+ * will be omitted, and with #MDB_MAPASYNC they will be asynchronous.
+ * @return A non-zero error value on failure and 0 on success. Some possible
+ * errors are:
+ * <ul>
+ * <li>EACCES - the environment is read-only.
+ * <li>EINVAL - an invalid parameter was specified.
+ * <li>EIO - an error occurred during synchronization.
+ * </ul>
+ */
+int mdb_env_sync(MDB_env *env, int force);
+
+ /** @brief Close the environment and release the memory map.
+ *
+ * Only a single thread may call this function. All transactions, databases,
+ * and cursors must already be closed before calling this function. Attempts to
+ * use any such handles after calling this function will cause a SIGSEGV.
+ * The environment handle will be freed and must not be used again after this call.
+ * @param[in] env An environment handle returned by #mdb_env_create()
+ */
+void mdb_env_close(MDB_env *env);
+
+ /** @brief Set environment flags.
+ *
+ * This may be used to set some flags in addition to those from
+ * #mdb_env_open(), or to unset these flags. If several threads
+ * change the flags at the same time, the result is undefined.
+ * @param[in] env An environment handle returned by #mdb_env_create()
+ * @param[in] flags The flags to change, bitwise OR'ed together
+ * @param[in] onoff A non-zero value sets the flags, zero clears them.
+ * @return A non-zero error value on failure and 0 on success. Some possible
+ * errors are:
+ * <ul>
+ * <li>EINVAL - an invalid parameter was specified.
+ * </ul>
+ */
+int mdb_env_set_flags(MDB_env *env, unsigned int flags, int onoff);
+
+ /** @brief Get environment flags.
+ *
+ * @param[in] env An environment handle returned by #mdb_env_create()
+ * @param[out] flags The address of an integer to store the flags
+ * @return A non-zero error value on failure and 0 on success. Some possible
+ * errors are:
+ * <ul>
+ * <li>EINVAL - an invalid parameter was specified.
+ * </ul>
+ */
+int mdb_env_get_flags(MDB_env *env, unsigned int *flags);
+
+ /** @brief Return the path that was used in #mdb_env_open().
+ *
+ * @param[in] env An environment handle returned by #mdb_env_create()
+ * @param[out] path Address of a string pointer to contain the path. This
+ * is the actual string in the environment, not a copy. It should not be
+ * altered in any way.
+ * @return A non-zero error value on failure and 0 on success. Some possible
+ * errors are:
+ * <ul>
+ * <li>EINVAL - an invalid parameter was specified.
+ * </ul>
+ */
+int mdb_env_get_path(MDB_env *env, const char **path);
+
+ /** @brief Return the filedescriptor for the given environment.
+ *
+ * This function may be called after fork(), so the descriptor can be
+ * closed before exec*(). Other LMDB file descriptors have FD_CLOEXEC.
+ * (Until LMDB 0.9.18, only the lockfile had that.)
+ *
+ * @param[in] env An environment handle returned by #mdb_env_create()
+ * @param[out] fd Address of a mdb_filehandle_t to contain the descriptor.
+ * @return A non-zero error value on failure and 0 on success. Some possible
+ * errors are:
+ * <ul>
+ * <li>EINVAL - an invalid parameter was specified.
+ * </ul>
+ */
+int mdb_env_get_fd(MDB_env *env, mdb_filehandle_t *fd);
+
+ /** @brief Set the size of the memory map to use for this environment.
+ *
+ * The size should be a multiple of the OS page size. The default is
+ * 10485760 bytes. The size of the memory map is also the maximum size
+ * of the database. The value should be chosen as large as possible,
+ * to accommodate future growth of the database.
+ * This function should be called after #mdb_env_create() and before #mdb_env_open().
+ * It may be called at later times if no transactions are active in
+ * this process. Note that the library does not check for this condition,
+ * the caller must ensure it explicitly.
+ *
+ * The new size takes effect immediately for the current process but
+ * will not be persisted to any others until a write transaction has been
+ * committed by the current process. Also, only mapsize increases are
+ * persisted into the environment.
+ *
+ * If the mapsize is increased by another process, and data has grown
+ * beyond the range of the current mapsize, #mdb_txn_begin() will
+ * return #MDB_MAP_RESIZED. This function may be called with a size
+ * of zero to adopt the new size.
+ *
+ * Any attempt to set a size smaller than the space already consumed
+ * by the environment will be silently changed to the current size of the used space.
+ * @param[in] env An environment handle returned by #mdb_env_create()
+ * @param[in] size The size in bytes
+ * @return A non-zero error value on failure and 0 on success. Some possible
+ * errors are:
+ * <ul>
+ * <li>EINVAL - an invalid parameter was specified, or the environment has
+ * an active write transaction.
+ * </ul>
+ */
+int mdb_env_set_mapsize(MDB_env *env, size_t size);
+
+ /** @brief Set the maximum number of threads/reader slots for the environment.
+ *
+ * This defines the number of slots in the lock table that is used to track readers in the
+ * the environment. The default is 126.
+ * Starting a read-only transaction normally ties a lock table slot to the
+ * current thread until the environment closes or the thread exits. If
+ * MDB_NOTLS is in use, #mdb_txn_begin() instead ties the slot to the
+ * MDB_txn object until it or the #MDB_env object is destroyed.
+ * This function may only be called after #mdb_env_create() and before #mdb_env_open().
+ * @param[in] env An environment handle returned by #mdb_env_create()
+ * @param[in] readers The maximum number of reader lock table slots
+ * @return A non-zero error value on failure and 0 on success. Some possible
+ * errors are:
+ * <ul>
+ * <li>EINVAL - an invalid parameter was specified, or the environment is already open.
+ * </ul>
+ */
+int mdb_env_set_maxreaders(MDB_env *env, unsigned int readers);
+
+ /** @brief Get the maximum number of threads/reader slots for the environment.
+ *
+ * @param[in] env An environment handle returned by #mdb_env_create()
+ * @param[out] readers Address of an integer to store the number of readers
+ * @return A non-zero error value on failure and 0 on success. Some possible
+ * errors are:
+ * <ul>
+ * <li>EINVAL - an invalid parameter was specified.
+ * </ul>
+ */
+int mdb_env_get_maxreaders(MDB_env *env, unsigned int *readers);
+
+ /** @brief Set the maximum number of named databases for the environment.
+ *
+ * This function is only needed if multiple databases will be used in the
+ * environment. Simpler applications that use the environment as a single
+ * unnamed database can ignore this option.
+ * This function may only be called after #mdb_env_create() and before #mdb_env_open().
+ *
+ * Currently a moderate number of slots are cheap but a huge number gets
+ * expensive: 7-120 words per transaction, and every #mdb_dbi_open()
+ * does a linear search of the opened slots.
+ * @param[in] env An environment handle returned by #mdb_env_create()
+ * @param[in] dbs The maximum number of databases
+ * @return A non-zero error value on failure and 0 on success. Some possible
+ * errors are:
+ * <ul>
+ * <li>EINVAL - an invalid parameter was specified, or the environment is already open.
+ * </ul>
+ */
+int mdb_env_set_maxdbs(MDB_env *env, MDB_dbi dbs);
+
+ /** @brief Get the maximum size of keys and #MDB_DUPSORT data we can write.
+ *
+ * Depends on the compile-time constant #MDB_MAXKEYSIZE. Default 511.
+ * See @ref MDB_val.
+ * @param[in] env An environment handle returned by #mdb_env_create()
+ * @return The maximum size of a key we can write
+ */
+int mdb_env_get_maxkeysize(MDB_env *env);
+
+ /** @brief Set application information associated with the #MDB_env.
+ *
+ * @param[in] env An environment handle returned by #mdb_env_create()
+ * @param[in] ctx An arbitrary pointer for whatever the application needs.
+ * @return A non-zero error value on failure and 0 on success.
+ */
+int mdb_env_set_userctx(MDB_env *env, void *ctx);
+
+ /** @brief Get the application information associated with the #MDB_env.
+ *
+ * @param[in] env An environment handle returned by #mdb_env_create()
+ * @return The pointer set by #mdb_env_set_userctx().
+ */
+void *mdb_env_get_userctx(MDB_env *env);
+
+ /** @brief A callback function for most LMDB assert() failures,
+ * called before printing the message and aborting.
+ *
+ * @param[in] env An environment handle returned by #mdb_env_create().
+ * @param[in] msg The assertion message, not including newline.
+ */
+typedef void MDB_assert_func(MDB_env *env, const char *msg);
+
+ /** Set or reset the assert() callback of the environment.
+ * Disabled if liblmdb is buillt with NDEBUG.
+ * @note This hack should become obsolete as lmdb's error handling matures.
+ * @param[in] env An environment handle returned by #mdb_env_create().
+ * @param[in] func An #MDB_assert_func function, or 0.
+ * @return A non-zero error value on failure and 0 on success.
+ */
+int mdb_env_set_assert(MDB_env *env, MDB_assert_func *func);
+
+ /** @brief Create a transaction for use with the environment.
+ *
+ * The transaction handle may be discarded using #mdb_txn_abort() or #mdb_txn_commit().
+ * @note A transaction and its cursors must only be used by a single
+ * thread, and a thread may only have a single transaction at a time.
+ * If #MDB_NOTLS is in use, this does not apply to read-only transactions.
+ * @note Cursors may not span transactions.
+ * @param[in] env An environment handle returned by #mdb_env_create()
+ * @param[in] parent If this parameter is non-NULL, the new transaction
+ * will be a nested transaction, with the transaction indicated by \b parent
+ * as its parent. Transactions may be nested to any level. A parent
+ * transaction and its cursors may not issue any other operations than
+ * mdb_txn_commit and mdb_txn_abort while it has active child transactions.
+ * @param[in] flags Special options for this transaction. This parameter
+ * must be set to 0 or by bitwise OR'ing together one or more of the
+ * values described here.
+ * <ul>
+ * <li>#MDB_RDONLY
+ * This transaction will not perform any write operations.
+ * </ul>
+ * @param[out] txn Address where the new #MDB_txn handle will be stored
+ * @return A non-zero error value on failure and 0 on success. Some possible
+ * errors are:
+ * <ul>
+ * <li>#MDB_PANIC - a fatal error occurred earlier and the environment
+ * must be shut down.
+ * <li>#MDB_MAP_RESIZED - another process wrote data beyond this MDB_env's
+ * mapsize and this environment's map must be resized as well.
+ * See #mdb_env_set_mapsize().
+ * <li>#MDB_READERS_FULL - a read-only transaction was requested and
+ * the reader lock table is full. See #mdb_env_set_maxreaders().
+ * <li>ENOMEM - out of memory.
+ * </ul>
+ */
+int mdb_txn_begin(MDB_env *env, MDB_txn *parent, unsigned int flags, MDB_txn **txn);
+
+ /** @brief Returns the transaction's #MDB_env
+ *
+ * @param[in] txn A transaction handle returned by #mdb_txn_begin()
+ */
+MDB_env *mdb_txn_env(MDB_txn *txn);
+
+ /** @brief Return the transaction's ID.
+ *
+ * This returns the identifier associated with this transaction. For a
+ * read-only transaction, this corresponds to the snapshot being read;
+ * concurrent readers will frequently have the same transaction ID.
+ *
+ * @param[in] txn A transaction handle returned by #mdb_txn_begin()
+ * @return A transaction ID, valid if input is an active transaction.
+ */
+size_t mdb_txn_id(MDB_txn *txn);
+
+ /** @brief Commit all the operations of a transaction into the database.
+ *
+ * The transaction handle is freed. It and its cursors must not be used
+ * again after this call, except with #mdb_cursor_renew().
+ * @note Earlier documentation incorrectly said all cursors would be freed.
+ * Only write-transactions free cursors.
+ * @param[in] txn A transaction handle returned by #mdb_txn_begin()
+ * @return A non-zero error value on failure and 0 on success. Some possible
+ * errors are:
+ * <ul>
+ * <li>EINVAL - an invalid parameter was specified.
+ * <li>ENOSPC - no more disk space.
+ * <li>EIO - a low-level I/O error occurred while writing.
+ * <li>ENOMEM - out of memory.
+ * </ul>
+ */
+int mdb_txn_commit(MDB_txn *txn);
+
+ /** @brief Abandon all the operations of the transaction instead of saving them.
+ *
+ * The transaction handle is freed. It and its cursors must not be used
+ * again after this call, except with #mdb_cursor_renew().
+ * @note Earlier documentation incorrectly said all cursors would be freed.
+ * Only write-transactions free cursors.
+ * @param[in] txn A transaction handle returned by #mdb_txn_begin()
+ */
+void mdb_txn_abort(MDB_txn *txn);
+
+ /** @brief Reset a read-only transaction.
+ *
+ * Abort the transaction like #mdb_txn_abort(), but keep the transaction
+ * handle. #mdb_txn_renew() may reuse the handle. This saves allocation
+ * overhead if the process will start a new read-only transaction soon,
+ * and also locking overhead if #MDB_NOTLS is in use. The reader table
+ * lock is released, but the table slot stays tied to its thread or
+ * #MDB_txn. Use mdb_txn_abort() to discard a reset handle, and to free
+ * its lock table slot if MDB_NOTLS is in use.
+ * Cursors opened within the transaction must not be used
+ * again after this call, except with #mdb_cursor_renew().
+ * Reader locks generally don't interfere with writers, but they keep old
+ * versions of database pages allocated. Thus they prevent the old pages
+ * from being reused when writers commit new data, and so under heavy load
+ * the database size may grow much more rapidly than otherwise.
+ * @param[in] txn A transaction handle returned by #mdb_txn_begin()
+ */
+void mdb_txn_reset(MDB_txn *txn);
+
+ /** @brief Renew a read-only transaction.
+ *
+ * This acquires a new reader lock for a transaction handle that had been
+ * released by #mdb_txn_reset(). It must be called before a reset transaction
+ * may be used again.
+ * @param[in] txn A transaction handle returned by #mdb_txn_begin()
+ * @return A non-zero error value on failure and 0 on success. Some possible
+ * errors are:
+ * <ul>
+ * <li>#MDB_PANIC - a fatal error occurred earlier and the environment
+ * must be shut down.
+ * <li>EINVAL - an invalid parameter was specified.
+ * </ul>
+ */
+int mdb_txn_renew(MDB_txn *txn);
+
+/** Compat with version <= 0.9.4, avoid clash with libmdb from MDB Tools project */
+#define mdb_open(txn,name,flags,dbi) mdb_dbi_open(txn,name,flags,dbi)
+/** Compat with version <= 0.9.4, avoid clash with libmdb from MDB Tools project */
+#define mdb_close(env,dbi) mdb_dbi_close(env,dbi)
+
+ /** @brief Open a database in the environment.
+ *
+ * A database handle denotes the name and parameters of a database,
+ * independently of whether such a database exists.
+ * The database handle may be discarded by calling #mdb_dbi_close().
+ * The old database handle is returned if the database was already open.
+ * The handle may only be closed once.
+ *
+ * The database handle will be private to the current transaction until
+ * the transaction is successfully committed. If the transaction is
+ * aborted the handle will be closed automatically.
+ * After a successful commit the handle will reside in the shared
+ * environment, and may be used by other transactions.
+ *
+ * This function must not be called from multiple concurrent
+ * transactions in the same process. A transaction that uses
+ * this function must finish (either commit or abort) before
+ * any other transaction in the process may use this function.
+ *
+ * To use named databases (with name != NULL), #mdb_env_set_maxdbs()
+ * must be called before opening the environment. Database names are
+ * keys in the unnamed database, and may be read but not written.
+ *
+ * @param[in] txn A transaction handle returned by #mdb_txn_begin()
+ * @param[in] name The name of the database to open. If only a single
+ * database is needed in the environment, this value may be NULL.
+ * @param[in] flags Special options for this database. This parameter
+ * must be set to 0 or by bitwise OR'ing together one or more of the
+ * values described here.
+ * <ul>
+ * <li>#MDB_REVERSEKEY
+ * Keys are strings to be compared in reverse order, from the end
+ * of the strings to the beginning. By default, Keys are treated as strings and
+ * compared from beginning to end.
+ * <li>#MDB_DUPSORT
+ * Duplicate keys may be used in the database. (Or, from another perspective,
+ * keys may have multiple data items, stored in sorted order.) By default
+ * keys must be unique and may have only a single data item.
+ * <li>#MDB_INTEGERKEY
+ * Keys are binary integers in native byte order, either unsigned int
+ * or size_t, and will be sorted as such.
+ * The keys must all be of the same size.
+ * <li>#MDB_DUPFIXED
+ * This flag may only be used in combination with #MDB_DUPSORT. This option
+ * tells the library that the data items for this database are all the same
+ * size, which allows further optimizations in storage and retrieval. When
+ * all data items are the same size, the #MDB_GET_MULTIPLE, #MDB_NEXT_MULTIPLE
+ * and #MDB_PREV_MULTIPLE cursor operations may be used to retrieve multiple
+ * items at once.
+ * <li>#MDB_INTEGERDUP
+ * This option specifies that duplicate data items are binary integers,
+ * similar to #MDB_INTEGERKEY keys.
+ * <li>#MDB_REVERSEDUP
+ * This option specifies that duplicate data items should be compared as
+ * strings in reverse order.
+ * <li>#MDB_CREATE
+ * Create the named database if it doesn't exist. This option is not
+ * allowed in a read-only transaction or a read-only environment.
+ * </ul>
+ * @param[out] dbi Address where the new #MDB_dbi handle will be stored
+ * @return A non-zero error value on failure and 0 on success. Some possible
+ * errors are:
+ * <ul>
+ * <li>#MDB_NOTFOUND - the specified database doesn't exist in the environment
+ * and #MDB_CREATE was not specified.
+ * <li>#MDB_DBS_FULL - too many databases have been opened. See #mdb_env_set_maxdbs().
+ * </ul>
+ */
+int mdb_dbi_open(MDB_txn *txn, const char *name, unsigned int flags, MDB_dbi *dbi);
+
+ /** @brief Retrieve statistics for a database.
+ *
+ * @param[in] txn A transaction handle returned by #mdb_txn_begin()
+ * @param[in] dbi A database handle returned by #mdb_dbi_open()
+ * @param[out] stat The address of an #MDB_stat structure
+ * where the statistics will be copied
+ * @return A non-zero error value on failure and 0 on success. Some possible
+ * errors are:
+ * <ul>
+ * <li>EINVAL - an invalid parameter was specified.
+ * </ul>
+ */
+int mdb_stat(MDB_txn *txn, MDB_dbi dbi, MDB_stat *stat);
+
+ /** @brief Retrieve the DB flags for a database handle.
+ *
+ * @param[in] txn A transaction handle returned by #mdb_txn_begin()
+ * @param[in] dbi A database handle returned by #mdb_dbi_open()
+ * @param[out] flags Address where the flags will be returned.
+ * @return A non-zero error value on failure and 0 on success.
+ */
+int mdb_dbi_flags(MDB_txn *txn, MDB_dbi dbi, unsigned int *flags);
+
+ /** @brief Close a database handle. Normally unnecessary. Use with care:
+ *
+ * This call is not mutex protected. Handles should only be closed by
+ * a single thread, and only if no other threads are going to reference
+ * the database handle or one of its cursors any further. Do not close
+ * a handle if an existing transaction has modified its database.
+ * Doing so can cause misbehavior from database corruption to errors
+ * like MDB_BAD_VALSIZE (since the DB name is gone).
+ *
+ * Closing a database handle is not necessary, but lets #mdb_dbi_open()
+ * reuse the handle value. Usually it's better to set a bigger
+ * #mdb_env_set_maxdbs(), unless that value would be large.
+ *
+ * @param[in] env An environment handle returned by #mdb_env_create()
+ * @param[in] dbi A database handle returned by #mdb_dbi_open()
+ */
+void mdb_dbi_close(MDB_env *env, MDB_dbi dbi);
+
+ /** @brief Empty or delete+close a database.
+ *
+ * See #mdb_dbi_close() for restrictions about closing the DB handle.
+ * @param[in] txn A transaction handle returned by #mdb_txn_begin()
+ * @param[in] dbi A database handle returned by #mdb_dbi_open()
+ * @param[in] del 0 to empty the DB, 1 to delete it from the
+ * environment and close the DB handle.
+ * @return A non-zero error value on failure and 0 on success.
+ */
+int mdb_drop(MDB_txn *txn, MDB_dbi dbi, int del);
+
+ /** @brief Set a custom key comparison function for a database.
+ *
+ * The comparison function is called whenever it is necessary to compare a
+ * key specified by the application with a key currently stored in the database.
+ * If no comparison function is specified, and no special key flags were specified
+ * with #mdb_dbi_open(), the keys are compared lexically, with shorter keys collating
+ * before longer keys.
+ * @warning This function must be called before any data access functions are used,
+ * otherwise data corruption may occur. The same comparison function must be used by every
+ * program accessing the database, every time the database is used.
+ * @param[in] txn A transaction handle returned by #mdb_txn_begin()
+ * @param[in] dbi A database handle returned by #mdb_dbi_open()
+ * @param[in] cmp A #MDB_cmp_func function
+ * @return A non-zero error value on failure and 0 on success. Some possible
+ * errors are:
+ * <ul>
+ * <li>EINVAL - an invalid parameter was specified.
+ * </ul>
+ */
+int mdb_set_compare(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp);
+
+ /** @brief Set a custom data comparison function for a #MDB_DUPSORT database.
+ *
+ * This comparison function is called whenever it is necessary to compare a data
+ * item specified by the application with a data item currently stored in the database.
+ * This function only takes effect if the database was opened with the #MDB_DUPSORT
+ * flag.
+ * If no comparison function is specified, and no special key flags were specified
+ * with #mdb_dbi_open(), the data items are compared lexically, with shorter items collating
+ * before longer items.
+ * @warning This function must be called before any data access functions are used,
+ * otherwise data corruption may occur. The same comparison function must be used by every
+ * program accessing the database, every time the database is used.
+ * @param[in] txn A transaction handle returned by #mdb_txn_begin()
+ * @param[in] dbi A database handle returned by #mdb_dbi_open()
+ * @param[in] cmp A #MDB_cmp_func function
+ * @return A non-zero error value on failure and 0 on success. Some possible
+ * errors are:
+ * <ul>
+ * <li>EINVAL - an invalid parameter was specified.
+ * </ul>
+ */
+int mdb_set_dupsort(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp);
+
+ /** @brief Set a relocation function for a #MDB_FIXEDMAP database.
+ *
+ * @todo The relocation function is called whenever it is necessary to move the data
+ * of an item to a different position in the database (e.g. through tree
+ * balancing operations, shifts as a result of adds or deletes, etc.). It is
+ * intended to allow address/position-dependent data items to be stored in
+ * a database in an environment opened with the #MDB_FIXEDMAP option.
+ * Currently the relocation feature is unimplemented and setting
+ * this function has no effect.
+ * @param[in] txn A transaction handle returned by #mdb_txn_begin()
+ * @param[in] dbi A database handle returned by #mdb_dbi_open()
+ * @param[in] rel A #MDB_rel_func function
+ * @return A non-zero error value on failure and 0 on success. Some possible
+ * errors are:
+ * <ul>
+ * <li>EINVAL - an invalid parameter was specified.
+ * </ul>
+ */
+int mdb_set_relfunc(MDB_txn *txn, MDB_dbi dbi, MDB_rel_func *rel);
+
+ /** @brief Set a context pointer for a #MDB_FIXEDMAP database's relocation function.
+ *
+ * See #mdb_set_relfunc and #MDB_rel_func for more details.
+ * @param[in] txn A transaction handle returned by #mdb_txn_begin()
+ * @param[in] dbi A database handle returned by #mdb_dbi_open()
+ * @param[in] ctx An arbitrary pointer for whatever the application needs.
+ * It will be passed to the callback function set by #mdb_set_relfunc
+ * as its \b relctx parameter whenever the callback is invoked.
+ * @return A non-zero error value on failure and 0 on success. Some possible
+ * errors are:
+ * <ul>
+ * <li>EINVAL - an invalid parameter was specified.
+ * </ul>
+ */
+int mdb_set_relctx(MDB_txn *txn, MDB_dbi dbi, void *ctx);
+
+ /** @brief Get items from a database.
+ *
+ * This function retrieves key/data pairs from the database. The address
+ * and length of the data associated with the specified \b key are returned
+ * in the structure to which \b data refers.
+ * If the database supports duplicate keys (#MDB_DUPSORT) then the
+ * first data item for the key will be returned. Retrieval of other
+ * items requires the use of #mdb_cursor_get().
+ *
+ * @note The memory pointed to by the returned values is owned by the
+ * database. The caller need not dispose of the memory, and may not
+ * modify it in any way. For values returned in a read-only transaction
+ * any modification attempts will cause a SIGSEGV.
+ * @note Values returned from the database are valid only until a
+ * subsequent update operation, or the end of the transaction.
+ * @param[in] txn A transaction handle returned by #mdb_txn_begin()
+ * @param[in] dbi A database handle returned by #mdb_dbi_open()
+ * @param[in] key The key to search for in the database
+ * @param[out] data The data corresponding to the key
+ * @return A non-zero error value on failure and 0 on success. Some possible
+ * errors are:
+ * <ul>
+ * <li>#MDB_NOTFOUND - the key was not in the database.
+ * <li>EINVAL - an invalid parameter was specified.
+ * </ul>
+ */
+int mdb_get(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data);
+
+ /** @brief Store items into a database.
+ *
+ * This function stores key/data pairs in the database. The default behavior
+ * is to enter the new key/data pair, replacing any previously existing key
+ * if duplicates are disallowed, or adding a duplicate data item if
+ * duplicates are allowed (#MDB_DUPSORT).
+ * @param[in] txn A transaction handle returned by #mdb_txn_begin()
+ * @param[in] dbi A database handle returned by #mdb_dbi_open()
+ * @param[in] key The key to store in the database
+ * @param[in,out] data The data to store
+ * @param[in] flags Special options for this operation. This parameter
+ * must be set to 0 or by bitwise OR'ing together one or more of the
+ * values described here.
+ * <ul>
+ * <li>#MDB_NODUPDATA - enter the new key/data pair only if it does not
+ * already appear in the database. This flag may only be specified
+ * if the database was opened with #MDB_DUPSORT. The function will
+ * return #MDB_KEYEXIST if the key/data pair already appears in the
+ * database.
+ * <li>#MDB_NOOVERWRITE - enter the new key/data pair only if the key
+ * does not already appear in the database. The function will return
+ * #MDB_KEYEXIST if the key already appears in the database, even if
+ * the database supports duplicates (#MDB_DUPSORT). The \b data
+ * parameter will be set to point to the existing item.
+ * <li>#MDB_RESERVE - reserve space for data of the given size, but
+ * don't copy the given data. Instead, return a pointer to the
+ * reserved space, which the caller can fill in later - before
+ * the next update operation or the transaction ends. This saves
+ * an extra memcpy if the data is being generated later.
+ * LMDB does nothing else with this memory, the caller is expected
+ * to modify all of the space requested. This flag must not be
+ * specified if the database was opened with #MDB_DUPSORT.
+ * <li>#MDB_APPEND - append the given key/data pair to the end of the
+ * database. This option allows fast bulk loading when keys are
+ * already known to be in the correct order. Loading unsorted keys
+ * with this flag will cause a #MDB_KEYEXIST error.
+ * <li>#MDB_APPENDDUP - as above, but for sorted dup data.
+ * </ul>
+ * @return A non-zero error value on failure and 0 on success. Some possible
+ * errors are:
+ * <ul>
+ * <li>#MDB_MAP_FULL - the database is full, see #mdb_env_set_mapsize().
+ * <li>#MDB_TXN_FULL - the transaction has too many dirty pages.
+ * <li>EACCES - an attempt was made to write in a read-only transaction.
+ * <li>EINVAL - an invalid parameter was specified.
+ * </ul>
+ */
+int mdb_put(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data,
+ unsigned int flags);
+
+ /** @brief Delete items from a database.
+ *
+ * This function removes key/data pairs from the database.
+ * If the database does not support sorted duplicate data items
+ * (#MDB_DUPSORT) the data parameter is ignored.
+ * If the database supports sorted duplicates and the data parameter
+ * is NULL, all of the duplicate data items for the key will be
+ * deleted. Otherwise, if the data parameter is non-NULL
+ * only the matching data item will be deleted.
+ * This function will return #MDB_NOTFOUND if the specified key/data
+ * pair is not in the database.
+ * @param[in] txn A transaction handle returned by #mdb_txn_begin()
+ * @param[in] dbi A database handle returned by #mdb_dbi_open()
+ * @param[in] key The key to delete from the database
+ * @param[in] data The data to delete
+ * @return A non-zero error value on failure and 0 on success. Some possible
+ * errors are:
+ * <ul>
+ * <li>EACCES - an attempt was made to write in a read-only transaction.
+ * <li>EINVAL - an invalid parameter was specified.
+ * </ul>
+ */
+int mdb_del(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data);
+
+ /** @brief Create a cursor handle.
+ *
+ * A cursor is associated with a specific transaction and database.
+ * A cursor cannot be used when its database handle is closed. Nor
+ * when its transaction has ended, except with #mdb_cursor_renew().
+ * It can be discarded with #mdb_cursor_close().
+ * A cursor in a write-transaction can be closed before its transaction
+ * ends, and will otherwise be closed when its transaction ends.
+ * A cursor in a read-only transaction must be closed explicitly, before
+ * or after its transaction ends. It can be reused with
+ * #mdb_cursor_renew() before finally closing it.
+ * @note Earlier documentation said that cursors in every transaction
+ * were closed when the transaction committed or aborted.
+ * @param[in] txn A transaction handle returned by #mdb_txn_begin()
+ * @param[in] dbi A database handle returned by #mdb_dbi_open()
+ * @param[out] cursor Address where the new #MDB_cursor handle will be stored
+ * @return A non-zero error value on failure and 0 on success. Some possible
+ * errors are:
+ * <ul>
+ * <li>EINVAL - an invalid parameter was specified.
+ * </ul>
+ */
+int mdb_cursor_open(MDB_txn *txn, MDB_dbi dbi, MDB_cursor **cursor);
+
+ /** @brief Close a cursor handle.
+ *
+ * The cursor handle will be freed and must not be used again after this call.
+ * Its transaction must still be live if it is a write-transaction.
+ * @param[in] cursor A cursor handle returned by #mdb_cursor_open()
+ */
+void mdb_cursor_close(MDB_cursor *cursor);
+
+ /** @brief Renew a cursor handle.
+ *
+ * A cursor is associated with a specific transaction and database.
+ * Cursors that are only used in read-only
+ * transactions may be re-used, to avoid unnecessary malloc/free overhead.
+ * The cursor may be associated with a new read-only transaction, and
+ * referencing the same database handle as it was created with.
+ * This may be done whether the previous transaction is live or dead.
+ * @param[in] txn A transaction handle returned by #mdb_txn_begin()
+ * @param[in] cursor A cursor handle returned by #mdb_cursor_open()
+ * @return A non-zero error value on failure and 0 on success. Some possible
+ * errors are:
+ * <ul>
+ * <li>EINVAL - an invalid parameter was specified.
+ * </ul>
+ */
+int mdb_cursor_renew(MDB_txn *txn, MDB_cursor *cursor);
+
+ /** @brief Return the cursor's transaction handle.
+ *
+ * @param[in] cursor A cursor handle returned by #mdb_cursor_open()
+ */
+MDB_txn *mdb_cursor_txn(MDB_cursor *cursor);
+
+ /** @brief Return the cursor's database handle.
+ *
+ * @param[in] cursor A cursor handle returned by #mdb_cursor_open()
+ */
+MDB_dbi mdb_cursor_dbi(MDB_cursor *cursor);
+
+ /** @brief Retrieve by cursor.
+ *
+ * This function retrieves key/data pairs from the database. The address and length
+ * of the key are returned in the object to which \b key refers (except for the
+ * case of the #MDB_SET option, in which the \b key object is unchanged), and
+ * the address and length of the data are returned in the object to which \b data
+ * refers.
+ * See #mdb_get() for restrictions on using the output values.
+ * @param[in] cursor A cursor handle returned by #mdb_cursor_open()
+ * @param[in,out] key The key for a retrieved item
+ * @param[in,out] data The data of a retrieved item
+ * @param[in] op A cursor operation #MDB_cursor_op
+ * @return A non-zero error value on failure and 0 on success. Some possible
+ * errors are:
+ * <ul>
+ * <li>#MDB_NOTFOUND - no matching key found.
+ * <li>EINVAL - an invalid parameter was specified.
+ * </ul>
+ */
+int mdb_cursor_get(MDB_cursor *cursor, MDB_val *key, MDB_val *data,
+ MDB_cursor_op op);
+
+ /** @brief Store by cursor.
+ *
+ * This function stores key/data pairs into the database.
+ * The cursor is positioned at the new item, or on failure usually near it.
+ * @note Earlier documentation incorrectly said errors would leave the
+ * state of the cursor unchanged.
+ * @param[in] cursor A cursor handle returned by #mdb_cursor_open()
+ * @param[in] key The key operated on.
+ * @param[in] data The data operated on.
+ * @param[in] flags Options for this operation. This parameter
+ * must be set to 0 or one of the values described here.
+ * <ul>
+ * <li>#MDB_CURRENT - replace the item at the current cursor position.
+ * The \b key parameter must still be provided, and must match it.
+ * If using sorted duplicates (#MDB_DUPSORT) the data item must still
+ * sort into the same place. This is intended to be used when the
+ * new data is the same size as the old. Otherwise it will simply
+ * perform a delete of the old record followed by an insert.
+ * <li>#MDB_NODUPDATA - enter the new key/data pair only if it does not
+ * already appear in the database. This flag may only be specified
+ * if the database was opened with #MDB_DUPSORT. The function will
+ * return #MDB_KEYEXIST if the key/data pair already appears in the
+ * database.
+ * <li>#MDB_NOOVERWRITE - enter the new key/data pair only if the key
+ * does not already appear in the database. The function will return
+ * #MDB_KEYEXIST if the key already appears in the database, even if
+ * the database supports duplicates (#MDB_DUPSORT).
+ * <li>#MDB_RESERVE - reserve space for data of the given size, but
+ * don't copy the given data. Instead, return a pointer to the
+ * reserved space, which the caller can fill in later - before
+ * the next update operation or the transaction ends. This saves
+ * an extra memcpy if the data is being generated later. This flag
+ * must not be specified if the database was opened with #MDB_DUPSORT.
+ * <li>#MDB_APPEND - append the given key/data pair to the end of the
+ * database. No key comparisons are performed. This option allows
+ * fast bulk loading when keys are already known to be in the
+ * correct order. Loading unsorted keys with this flag will cause
+ * a #MDB_KEYEXIST error.
+ * <li>#MDB_APPENDDUP - as above, but for sorted dup data.
+ * <li>#MDB_MULTIPLE - store multiple contiguous data elements in a
+ * single request. This flag may only be specified if the database
+ * was opened with #MDB_DUPFIXED. The \b data argument must be an
+ * array of two MDB_vals. The mv_size of the first MDB_val must be
+ * the size of a single data element. The mv_data of the first MDB_val
+ * must point to the beginning of the array of contiguous data elements.
+ * The mv_size of the second MDB_val must be the count of the number
+ * of data elements to store. On return this field will be set to
+ * the count of the number of elements actually written. The mv_data
+ * of the second MDB_val is unused.
+ * </ul>
+ * @return A non-zero error value on failure and 0 on success. Some possible
+ * errors are:
+ * <ul>
+ * <li>#MDB_MAP_FULL - the database is full, see #mdb_env_set_mapsize().
+ * <li>#MDB_TXN_FULL - the transaction has too many dirty pages.
+ * <li>EACCES - an attempt was made to write in a read-only transaction.
+ * <li>EINVAL - an invalid parameter was specified.
+ * </ul>
+ */
+int mdb_cursor_put(MDB_cursor *cursor, MDB_val *key, MDB_val *data,
+ unsigned int flags);
+
+ /** @brief Delete current key/data pair
+ *
+ * This function deletes the key/data pair to which the cursor refers.
+ * @param[in] cursor A cursor handle returned by #mdb_cursor_open()
+ * @param[in] flags Options for this operation. This parameter
+ * must be set to 0 or one of the values described here.
+ * <ul>
+ * <li>#MDB_NODUPDATA - delete all of the data items for the current key.
+ * This flag may only be specified if the database was opened with #MDB_DUPSORT.
+ * </ul>
+ * @return A non-zero error value on failure and 0 on success. Some possible
+ * errors are:
+ * <ul>
+ * <li>EACCES - an attempt was made to write in a read-only transaction.
+ * <li>EINVAL - an invalid parameter was specified.
+ * </ul>
+ */
+int mdb_cursor_del(MDB_cursor *cursor, unsigned int flags);
+
+ /** @brief Return count of duplicates for current key.
+ *
+ * This call is only valid on databases that support sorted duplicate
+ * data items #MDB_DUPSORT.
+ * @param[in] cursor A cursor handle returned by #mdb_cursor_open()
+ * @param[out] countp Address where the count will be stored
+ * @return A non-zero error value on failure and 0 on success. Some possible
+ * errors are:
+ * <ul>
+ * <li>EINVAL - cursor is not initialized, or an invalid parameter was specified.
+ * </ul>
+ */
+int mdb_cursor_count(MDB_cursor *cursor, size_t *countp);
+
+ /** @brief Compare two data items according to a particular database.
+ *
+ * This returns a comparison as if the two data items were keys in the
+ * specified database.
+ * @param[in] txn A transaction handle returned by #mdb_txn_begin()
+ * @param[in] dbi A database handle returned by #mdb_dbi_open()
+ * @param[in] a The first item to compare
+ * @param[in] b The second item to compare
+ * @return < 0 if a < b, 0 if a == b, > 0 if a > b
+ */
+int mdb_cmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b);
+
+ /** @brief Compare two data items according to a particular database.
+ *
+ * This returns a comparison as if the two items were data items of
+ * the specified database. The database must have the #MDB_DUPSORT flag.
+ * @param[in] txn A transaction handle returned by #mdb_txn_begin()
+ * @param[in] dbi A database handle returned by #mdb_dbi_open()
+ * @param[in] a The first item to compare
+ * @param[in] b The second item to compare
+ * @return < 0 if a < b, 0 if a == b, > 0 if a > b
+ */
+int mdb_dcmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b);
+
+ /** @brief A callback function used to print a message from the library.
+ *
+ * @param[in] msg The string to be printed.
+ * @param[in] ctx An arbitrary context pointer for the callback.
+ * @return < 0 on failure, >= 0 on success.
+ */
+typedef int (MDB_msg_func)(const char *msg, void *ctx);
+
+ /** @brief Dump the entries in the reader lock table.
+ *
+ * @param[in] env An environment handle returned by #mdb_env_create()
+ * @param[in] func A #MDB_msg_func function
+ * @param[in] ctx Anything the message function needs
+ * @return < 0 on failure, >= 0 on success.
+ */
+int mdb_reader_list(MDB_env *env, MDB_msg_func *func, void *ctx);
+
+ /** @brief Check for stale entries in the reader lock table.
+ *
+ * @param[in] env An environment handle returned by #mdb_env_create()
+ * @param[out] dead Number of stale slots that were cleared
+ * @return 0 on success, non-zero on failure.
+ */
+int mdb_reader_check(MDB_env *env, int *dead);
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+/** @page tools LMDB Command Line Tools
+ The following describes the command line tools that are available for LMDB.
+ \li \ref mdb_copy_1
+ \li \ref mdb_dump_1
+ \li \ref mdb_load_1
+ \li \ref mdb_stat_1
+*/
+
+#endif /* _LMDB_H_ */
diff --git a/src/contrib/lmdb/mdb.c b/src/contrib/lmdb/mdb.c
new file mode 100644
index 0000000..d9e7c5e
--- /dev/null
+++ b/src/contrib/lmdb/mdb.c
@@ -0,0 +1,10266 @@
+/** @file mdb.c
+ * @brief Lightning memory-mapped database library
+ *
+ * A Btree-based database management library modeled loosely on the
+ * BerkeleyDB API, but much simplified.
+ */
+/*
+ * Copyright 2011-2018 Howard Chu, Symas Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ *
+ * This code is derived from btree.c written by Martin Hedenfalk.
+ *
+ * Copyright (c) 2009, 2010 Martin Hedenfalk <martin@bzero.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+#if defined(__WIN64__)
+#define _FILE_OFFSET_BITS 64
+#endif
+#ifdef _WIN32
+#include <malloc.h>
+#include <windows.h>
+#include <wchar.h> /* get wcscpy() */
+
+/** getpid() returns int; MinGW defines pid_t but MinGW64 typedefs it
+ * as int64 which is wrong. MSVC doesn't define it at all, so just
+ * don't use it.
+ */
+#define MDB_PID_T int
+#define MDB_THR_T DWORD
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef __GNUC__
+# include <sys/param.h>
+#else
+# define LITTLE_ENDIAN 1234
+# define BIG_ENDIAN 4321
+# define BYTE_ORDER LITTLE_ENDIAN
+# ifndef SSIZE_MAX
+# define SSIZE_MAX INT_MAX
+# endif
+#endif
+#else
+#include <sys/types.h>
+#include <sys/stat.h>
+#define MDB_PID_T pid_t
+#define MDB_THR_T pthread_t
+#include <sys/param.h>
+#include <sys/uio.h>
+#include <sys/mman.h>
+#ifdef HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#include <fcntl.h>
+#endif
+
+#if defined(__mips) && defined(__linux)
+/* MIPS has cache coherency issues, requires explicit cache control */
+#include <asm/cachectl.h>
+extern int cacheflush(char *addr, int nbytes, int cache);
+#define CACHEFLUSH(addr, bytes, cache) cacheflush(addr, bytes, cache)
+#else
+#define CACHEFLUSH(addr, bytes, cache)
+#endif
+
+#if defined(__linux) && !defined(MDB_FDATASYNC_WORKS)
+/** fdatasync is broken on ext3/ext4fs on older kernels, see
+ * description in #mdb_env_open2 comments. You can safely
+ * define MDB_FDATASYNC_WORKS if this code will only be run
+ * on kernels 3.6 and newer.
+ */
+#define BROKEN_FDATASYNC
+#endif
+
+#include <errno.h>
+#include <limits.h>
+#include <stddef.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifdef _MSC_VER
+#include <io.h>
+typedef SSIZE_T ssize_t;
+#else
+#include <unistd.h>
+#endif
+
+#if defined(__sun) || defined(ANDROID)
+/* Most platforms have posix_memalign, older may only have memalign */
+#define HAVE_MEMALIGN 1
+#include <malloc.h>
+/* On Solaris, we need the POSIX sigwait function */
+#if defined (__sun)
+# define _POSIX_PTHREAD_SEMANTICS 1
+#endif
+#endif
+
+#if !(defined(BYTE_ORDER) || defined(__BYTE_ORDER))
+#include <netinet/in.h>
+#include <resolv.h> /* defines BYTE_ORDER on HPUX and Solaris */
+#endif
+
+#if defined(__APPLE__) || defined (BSD) || defined(__FreeBSD_kernel__)
+# define MDB_USE_POSIX_SEM 1
+# define MDB_FDATASYNC fsync
+#elif defined(ANDROID)
+# define MDB_FDATASYNC fsync
+#endif
+
+#ifndef _WIN32
+#include <pthread.h>
+#include <signal.h>
+#ifdef MDB_USE_POSIX_SEM
+# define MDB_USE_HASH 1
+#include <semaphore.h>
+#else
+#define MDB_USE_POSIX_MUTEX 1
+#endif
+#endif
+
+#if defined(_WIN32) + defined(MDB_USE_POSIX_SEM) \
+ + defined(MDB_USE_POSIX_MUTEX) != 1
+# error "Ambiguous shared-lock implementation"
+#endif
+
+#ifdef USE_VALGRIND
+#include <valgrind/memcheck.h>
+#define VGMEMP_CREATE(h,r,z) VALGRIND_CREATE_MEMPOOL(h,r,z)
+#define VGMEMP_ALLOC(h,a,s) VALGRIND_MEMPOOL_ALLOC(h,a,s)
+#define VGMEMP_FREE(h,a) VALGRIND_MEMPOOL_FREE(h,a)
+#define VGMEMP_DESTROY(h) VALGRIND_DESTROY_MEMPOOL(h)
+#define VGMEMP_DEFINED(a,s) VALGRIND_MAKE_MEM_DEFINED(a,s)
+#else
+#define VGMEMP_CREATE(h,r,z)
+#define VGMEMP_ALLOC(h,a,s)
+#define VGMEMP_FREE(h,a)
+#define VGMEMP_DESTROY(h)
+#define VGMEMP_DEFINED(a,s)
+#endif
+
+#ifndef BYTE_ORDER
+# if (defined(_LITTLE_ENDIAN) || defined(_BIG_ENDIAN)) && !(defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN))
+/* Solaris just defines one or the other */
+# define LITTLE_ENDIAN 1234
+# define BIG_ENDIAN 4321
+# ifdef _LITTLE_ENDIAN
+# define BYTE_ORDER LITTLE_ENDIAN
+# else
+# define BYTE_ORDER BIG_ENDIAN
+# endif
+# else
+# define BYTE_ORDER __BYTE_ORDER
+# endif
+#endif
+
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN __LITTLE_ENDIAN
+#endif
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN __BIG_ENDIAN
+#endif
+
+#if defined(__i386) || defined(__x86_64) || defined(_M_IX86)
+#define MISALIGNED_OK 1
+#endif
+
+#include "lmdb.h"
+#include "midl.h"
+
+#if (BYTE_ORDER == LITTLE_ENDIAN) == (BYTE_ORDER == BIG_ENDIAN)
+# error "Unknown or unsupported endianness (BYTE_ORDER)"
+#elif (-6 & 5) || CHAR_BIT != 8 || UINT_MAX < 0xffffffff || ULONG_MAX % 0xFFFF
+# error "Two's complement, reasonably sized integer types, please"
+#endif
+
+#ifdef __GNUC__
+/** Put infrequently used env functions in separate section */
+# ifdef __APPLE__
+# define ESECT __attribute__ ((section("__TEXT,text_env")))
+# else
+# define ESECT __attribute__ ((section("text_env")))
+# endif
+#else
+#define ESECT
+#endif
+
+#ifdef _WIN32
+#define CALL_CONV WINAPI
+#else
+#define CALL_CONV
+#endif
+
+/** @defgroup internal LMDB Internals
+ * @{
+ */
+/** @defgroup compat Compatibility Macros
+ * A bunch of macros to minimize the amount of platform-specific ifdefs
+ * needed throughout the rest of the code. When the features this library
+ * needs are similar enough to POSIX to be hidden in a one-or-two line
+ * replacement, this macro approach is used.
+ * @{
+ */
+
+ /** Features under development */
+#ifndef MDB_DEVEL
+#define MDB_DEVEL 0
+#endif
+
+ /** Wrapper around __func__, which is a C99 feature */
+#if __STDC_VERSION__ >= 199901L
+# define mdb_func_ __func__
+#elif __GNUC__ >= 2 || _MSC_VER >= 1300
+# define mdb_func_ __FUNCTION__
+#else
+/* If a debug message says <mdb_unknown>(), update the #if statements above */
+# define mdb_func_ "<mdb_unknown>"
+#endif
+
+/* Internal error codes, not exposed outside liblmdb */
+#define MDB_NO_ROOT (MDB_LAST_ERRCODE + 10)
+#ifdef _WIN32
+#define MDB_OWNERDEAD ((int) WAIT_ABANDONED)
+#elif defined(MDB_USE_POSIX_MUTEX) && defined(EOWNERDEAD)
+#define MDB_OWNERDEAD EOWNERDEAD /**< #LOCK_MUTEX0() result if dead owner */
+#endif
+
+#ifdef __GLIBC__
+#define GLIBC_VER ((__GLIBC__ << 16 )| __GLIBC_MINOR__)
+#endif
+/** Some platforms define the EOWNERDEAD error code
+ * even though they don't support Robust Mutexes.
+ * Compile with -DMDB_USE_ROBUST=0, or use some other
+ * mechanism like -DMDB_USE_POSIX_SEM instead of
+ * -DMDB_USE_POSIX_MUTEX.
+ * (Posix semaphores are not robust.)
+ */
+#ifndef MDB_USE_ROBUST
+/* Android currently lacks Robust Mutex support. So does glibc < 2.4. */
+# if defined(MDB_USE_POSIX_MUTEX) && (defined(ANDROID) || \
+ (defined(__GLIBC__) && GLIBC_VER < 0x020004))
+# define MDB_USE_ROBUST 0
+# else
+# define MDB_USE_ROBUST 1
+# endif
+#endif /* !MDB_USE_ROBUST */
+
+#if defined(MDB_USE_POSIX_MUTEX) && (MDB_USE_ROBUST)
+/* glibc < 2.12 only provided _np API */
+# if (defined(__GLIBC__) && GLIBC_VER < 0x02000c) || \
+ (defined(PTHREAD_MUTEX_ROBUST_NP) && !defined(PTHREAD_MUTEX_ROBUST))
+# define PTHREAD_MUTEX_ROBUST PTHREAD_MUTEX_ROBUST_NP
+# define pthread_mutexattr_setrobust(attr, flag) pthread_mutexattr_setrobust_np(attr, flag)
+# define pthread_mutex_consistent(mutex) pthread_mutex_consistent_np(mutex)
+# endif
+#endif /* MDB_USE_POSIX_MUTEX && MDB_USE_ROBUST */
+
+#if defined(MDB_OWNERDEAD) && (MDB_USE_ROBUST)
+#define MDB_ROBUST_SUPPORTED 1
+#endif
+
+#ifdef _WIN32
+#define MDB_USE_HASH 1
+#define MDB_PIDLOCK 0
+#define THREAD_RET DWORD
+#define pthread_t HANDLE
+#define pthread_mutex_t HANDLE
+#define pthread_cond_t HANDLE
+typedef HANDLE mdb_mutex_t, mdb_mutexref_t;
+#define pthread_key_t DWORD
+#define pthread_self() GetCurrentThreadId()
+#define pthread_key_create(x,y) \
+ ((*(x) = TlsAlloc()) == TLS_OUT_OF_INDEXES ? ErrCode() : 0)
+#define pthread_key_delete(x) TlsFree(x)
+#define pthread_getspecific(x) TlsGetValue(x)
+#define pthread_setspecific(x,y) (TlsSetValue(x,y) ? 0 : ErrCode())
+#define pthread_mutex_unlock(x) ReleaseMutex(*x)
+#define pthread_mutex_lock(x) WaitForSingleObject(*x, INFINITE)
+#define pthread_cond_signal(x) SetEvent(*x)
+#define pthread_cond_wait(cond,mutex) do{SignalObjectAndWait(*mutex, *cond, INFINITE, FALSE); WaitForSingleObject(*mutex, INFINITE);}while(0)
+#define THREAD_CREATE(thr,start,arg) \
+ (((thr) = CreateThread(NULL, 0, start, arg, 0, NULL)) ? 0 : ErrCode())
+#define THREAD_FINISH(thr) \
+ (WaitForSingleObject(thr, INFINITE) ? ErrCode() : 0)
+#define LOCK_MUTEX0(mutex) WaitForSingleObject(mutex, INFINITE)
+#define UNLOCK_MUTEX(mutex) ReleaseMutex(mutex)
+#define mdb_mutex_consistent(mutex) 0
+#define getpid() GetCurrentProcessId()
+#define MDB_FDATASYNC(fd) (!FlushFileBuffers(fd))
+#define MDB_MSYNC(addr,len,flags) (!FlushViewOfFile(addr,len))
+#define ErrCode() GetLastError()
+#define GET_PAGESIZE(x) {SYSTEM_INFO si; GetSystemInfo(&si); (x) = si.dwPageSize;}
+#define close(fd) (CloseHandle(fd) ? 0 : -1)
+#define munmap(ptr,len) UnmapViewOfFile(ptr)
+#ifdef PROCESS_QUERY_LIMITED_INFORMATION
+#define MDB_PROCESS_QUERY_LIMITED_INFORMATION PROCESS_QUERY_LIMITED_INFORMATION
+#else
+#define MDB_PROCESS_QUERY_LIMITED_INFORMATION 0x1000
+#endif
+#define Z "I"
+#else
+#define THREAD_RET void *
+#define THREAD_CREATE(thr,start,arg) pthread_create(&thr,NULL,start,arg)
+#define THREAD_FINISH(thr) pthread_join(thr,NULL)
+#define Z "z" /**< printf format modifier for size_t */
+
+ /** For MDB_LOCK_FORMAT: True if readers take a pid lock in the lockfile */
+#define MDB_PIDLOCK 1
+
+#ifdef MDB_USE_POSIX_SEM
+
+typedef sem_t *mdb_mutex_t, *mdb_mutexref_t;
+#define LOCK_MUTEX0(mutex) mdb_sem_wait(mutex)
+#define UNLOCK_MUTEX(mutex) sem_post(mutex)
+
+static int
+mdb_sem_wait(sem_t *sem)
+{
+ int rc;
+ while ((rc = sem_wait(sem)) && (rc = errno) == EINTR) ;
+ return rc;
+}
+
+#else /* MDB_USE_POSIX_MUTEX: */
+ /** Shared mutex/semaphore as the original is stored.
+ *
+ * Not for copies. Instead it can be assigned to an #mdb_mutexref_t.
+ * When mdb_mutexref_t is a pointer and mdb_mutex_t is not, then it
+ * is array[size 1] so it can be assigned to the pointer.
+ */
+typedef pthread_mutex_t mdb_mutex_t[1];
+ /** Reference to an #mdb_mutex_t */
+typedef pthread_mutex_t *mdb_mutexref_t;
+ /** Lock the reader or writer mutex.
+ * Returns 0 or a code to give #mdb_mutex_failed(), as in #LOCK_MUTEX().
+ */
+#define LOCK_MUTEX0(mutex) pthread_mutex_lock(mutex)
+ /** Unlock the reader or writer mutex.
+ */
+#define UNLOCK_MUTEX(mutex) pthread_mutex_unlock(mutex)
+ /** Mark mutex-protected data as repaired, after death of previous owner.
+ */
+#define mdb_mutex_consistent(mutex) pthread_mutex_consistent(mutex)
+#endif /* MDB_USE_POSIX_SEM */
+
+ /** Get the error code for the last failed system function.
+ */
+#define ErrCode() errno
+
+ /** An abstraction for a file handle.
+ * On POSIX systems file handles are small integers. On Windows
+ * they're opaque pointers.
+ */
+#define HANDLE int
+
+ /** A value for an invalid file handle.
+ * Mainly used to initialize file variables and signify that they are
+ * unused.
+ */
+#define INVALID_HANDLE_VALUE (-1)
+
+ /** Get the size of a memory page for the system.
+ * This is the basic size that the platform's memory manager uses, and is
+ * fundamental to the use of memory-mapped files.
+ */
+#define GET_PAGESIZE(x) ((x) = sysconf(_SC_PAGE_SIZE))
+#endif
+
+#if defined(_WIN32) || defined(MDB_USE_POSIX_SEM)
+#define MNAME_LEN 32
+#else
+#define MNAME_LEN (sizeof(pthread_mutex_t))
+#endif
+
+/** @} */
+
+#ifdef MDB_ROBUST_SUPPORTED
+ /** Lock mutex, handle any error, set rc = result.
+ * Return 0 on success, nonzero (not rc) on error.
+ */
+#define LOCK_MUTEX(rc, env, mutex) \
+ (((rc) = LOCK_MUTEX0(mutex)) && \
+ ((rc) = mdb_mutex_failed(env, mutex, rc)))
+static int mdb_mutex_failed(MDB_env *env, mdb_mutexref_t mutex, int rc);
+#else
+#define LOCK_MUTEX(rc, env, mutex) ((rc) = LOCK_MUTEX0(mutex))
+#define mdb_mutex_failed(env, mutex, rc) (rc)
+#endif
+
+#ifndef _WIN32
+/** A flag for opening a file and requesting synchronous data writes.
+ * This is only used when writing a meta page. It's not strictly needed;
+ * we could just do a normal write and then immediately perform a flush.
+ * But if this flag is available it saves us an extra system call.
+ *
+ * @note If O_DSYNC is undefined but exists in /usr/include,
+ * preferably set some compiler flag to get the definition.
+ */
+#ifndef MDB_DSYNC
+# ifdef O_DSYNC
+# define MDB_DSYNC O_DSYNC
+# else
+# define MDB_DSYNC O_SYNC
+# endif
+#endif
+#endif
+
+/** Function for flushing the data of a file. Define this to fsync
+ * if fdatasync() is not supported.
+ */
+#ifndef MDB_FDATASYNC
+# define MDB_FDATASYNC fdatasync
+#endif
+
+#ifndef MDB_MSYNC
+# define MDB_MSYNC(addr,len,flags) msync(addr,len,flags)
+#endif
+
+#ifndef MS_SYNC
+#define MS_SYNC 1
+#endif
+
+#ifndef MS_ASYNC
+#define MS_ASYNC 0
+#endif
+
+ /** A page number in the database.
+ * Note that 64 bit page numbers are overkill, since pages themselves
+ * already represent 12-13 bits of addressable memory, and the OS will
+ * always limit applications to a maximum of 63 bits of address space.
+ *
+ * @note In the #MDB_node structure, we only store 48 bits of this value,
+ * which thus limits us to only 60 bits of addressable data.
+ */
+typedef MDB_ID pgno_t;
+
+ /** A transaction ID.
+ * See struct MDB_txn.mt_txnid for details.
+ */
+typedef MDB_ID txnid_t;
+
+/** @defgroup debug Debug Macros
+ * @{
+ */
+#ifndef MDB_DEBUG
+ /** Enable debug output. Needs variable argument macros (a C99 feature).
+ * Set this to 1 for copious tracing. Set to 2 to add dumps of all IDLs
+ * read from and written to the database (used for free space management).
+ */
+#define MDB_DEBUG 0
+#endif
+
+#if MDB_DEBUG
+static int mdb_debug;
+static txnid_t mdb_debug_start;
+
+ /** Print a debug message with printf formatting.
+ * Requires double parenthesis around 2 or more args.
+ */
+# define DPRINTF(args) ((void) ((mdb_debug) && DPRINTF0 args))
+# define DPRINTF0(fmt, ...) \
+ fprintf(stderr, "%s:%d " fmt "\n", mdb_func_, __LINE__, __VA_ARGS__)
+#else
+# define DPRINTF(args) ((void) 0)
+#endif
+ /** Print a debug string.
+ * The string is printed literally, with no format processing.
+ */
+#define DPUTS(arg) DPRINTF(("%s", arg))
+ /** Debuging output value of a cursor DBI: Negative in a sub-cursor. */
+#define DDBI(mc) \
+ (((mc)->mc_flags & C_SUB) ? -(int)(mc)->mc_dbi : (int)(mc)->mc_dbi)
+/** @} */
+
+ /** @brief The maximum size of a database page.
+ *
+ * It is 32k or 64k, since value-PAGEBASE must fit in
+ * #MDB_page.%mp_upper.
+ *
+ * LMDB will use database pages < OS pages if needed.
+ * That causes more I/O in write transactions: The OS must
+ * know (read) the whole page before writing a partial page.
+ *
+ * Note that we don't currently support Huge pages. On Linux,
+ * regular data files cannot use Huge pages, and in general
+ * Huge pages aren't actually pageable. We rely on the OS
+ * demand-pager to read our data and page it out when memory
+ * pressure from other processes is high. So until OSs have
+ * actual paging support for Huge pages, they're not viable.
+ */
+#define MAX_PAGESIZE (PAGEBASE ? 0x10000 : 0x8000)
+
+ /** The minimum number of keys required in a database page.
+ * Setting this to a larger value will place a smaller bound on the
+ * maximum size of a data item. Data items larger than this size will
+ * be pushed into overflow pages instead of being stored directly in
+ * the B-tree node. This value used to default to 4. With a page size
+ * of 4096 bytes that meant that any item larger than 1024 bytes would
+ * go into an overflow page. That also meant that on average 2-3KB of
+ * each overflow page was wasted space. The value cannot be lower than
+ * 2 because then there would no longer be a tree structure. With this
+ * value, items larger than 2KB will go into overflow pages, and on
+ * average only 1KB will be wasted.
+ */
+#define MDB_MINKEYS 2
+
+ /** A stamp that identifies a file as an LMDB file.
+ * There's nothing special about this value other than that it is easily
+ * recognizable, and it will reflect any byte order mismatches.
+ */
+#define MDB_MAGIC 0xBEEFC0DE
+
+ /** The version number for a database's datafile format. */
+#define MDB_DATA_VERSION ((MDB_DEVEL) ? 999 : 1)
+ /** The version number for a database's lockfile format. */
+#define MDB_LOCK_VERSION 1
+
+ /** @brief The max size of a key we can write, or 0 for computed max.
+ *
+ * This macro should normally be left alone or set to 0.
+ * Note that a database with big keys or dupsort data cannot be
+ * reliably modified by a liblmdb which uses a smaller max.
+ * The default is 511 for backwards compat, or 0 when #MDB_DEVEL.
+ *
+ * Other values are allowed, for backwards compat. However:
+ * A value bigger than the computed max can break if you do not
+ * know what you are doing, and liblmdb <= 0.9.10 can break when
+ * modifying a DB with keys/dupsort data bigger than its max.
+ *
+ * Data items in an #MDB_DUPSORT database are also limited to
+ * this size, since they're actually keys of a sub-DB. Keys and
+ * #MDB_DUPSORT data items must fit on a node in a regular page.
+ */
+#ifndef MDB_MAXKEYSIZE
+#define MDB_MAXKEYSIZE ((MDB_DEVEL) ? 0 : 511)
+#endif
+
+ /** The maximum size of a key we can write to the environment. */
+#if MDB_MAXKEYSIZE
+#define ENV_MAXKEY(env) (MDB_MAXKEYSIZE)
+#else
+#define ENV_MAXKEY(env) ((env)->me_maxkey)
+#endif
+
+ /** @brief The maximum size of a data item.
+ *
+ * We only store a 32 bit value for node sizes.
+ */
+#define MAXDATASIZE 0xffffffffUL
+
+#if MDB_DEBUG
+ /** Key size which fits in a #DKBUF.
+ * @ingroup debug
+ */
+#define DKBUF_MAXKEYSIZE ((MDB_MAXKEYSIZE) > 0 ? (MDB_MAXKEYSIZE) : 511)
+ /** A key buffer.
+ * @ingroup debug
+ * This is used for printing a hex dump of a key's contents.
+ */
+#define DKBUF char kbuf[DKBUF_MAXKEYSIZE*2+1]
+ /** Display a key in hex.
+ * @ingroup debug
+ * Invoke a function to display a key in hex.
+ */
+#define DKEY(x) mdb_dkey(x, kbuf)
+#else
+#define DKBUF
+#define DKEY(x) 0
+#endif
+
+ /** An invalid page number.
+ * Mainly used to denote an empty tree.
+ */
+#define P_INVALID (~(pgno_t)0)
+
+ /** Test if the flags \b f are set in a flag word \b w. */
+#define F_ISSET(w, f) (((w) & (f)) == (f))
+
+ /** Round \b n up to an even number. */
+#define EVEN(n) (((n) + 1U) & -2) /* sign-extending -2 to match n+1U */
+
+ /** Used for offsets within a single page.
+ * Since memory pages are typically 4 or 8KB in size, 12-13 bits,
+ * this is plenty.
+ */
+typedef uint16_t indx_t;
+
+ /** Default size of memory map.
+ * This is certainly too small for any actual applications. Apps should always set
+ * the size explicitly using #mdb_env_set_mapsize().
+ */
+#define DEFAULT_MAPSIZE 1048576
+
+/** @defgroup readers Reader Lock Table
+ * Readers don't acquire any locks for their data access. Instead, they
+ * simply record their transaction ID in the reader table. The reader
+ * mutex is needed just to find an empty slot in the reader table. The
+ * slot's address is saved in thread-specific data so that subsequent read
+ * transactions started by the same thread need no further locking to proceed.
+ *
+ * If #MDB_NOTLS is set, the slot address is not saved in thread-specific data.
+ *
+ * No reader table is used if the database is on a read-only filesystem, or
+ * if #MDB_NOLOCK is set.
+ *
+ * Since the database uses multi-version concurrency control, readers don't
+ * actually need any locking. This table is used to keep track of which
+ * readers are using data from which old transactions, so that we'll know
+ * when a particular old transaction is no longer in use. Old transactions
+ * that have discarded any data pages can then have those pages reclaimed
+ * for use by a later write transaction.
+ *
+ * The lock table is constructed such that reader slots are aligned with the
+ * processor's cache line size. Any slot is only ever used by one thread.
+ * This alignment guarantees that there will be no contention or cache
+ * thrashing as threads update their own slot info, and also eliminates
+ * any need for locking when accessing a slot.
+ *
+ * A writer thread will scan every slot in the table to determine the oldest
+ * outstanding reader transaction. Any freed pages older than this will be
+ * reclaimed by the writer. The writer doesn't use any locks when scanning
+ * this table. This means that there's no guarantee that the writer will
+ * see the most up-to-date reader info, but that's not required for correct
+ * operation - all we need is to know the upper bound on the oldest reader,
+ * we don't care at all about the newest reader. So the only consequence of
+ * reading stale information here is that old pages might hang around a
+ * while longer before being reclaimed. That's actually good anyway, because
+ * the longer we delay reclaiming old pages, the more likely it is that a
+ * string of contiguous pages can be found after coalescing old pages from
+ * many old transactions together.
+ * @{
+ */
+ /** Number of slots in the reader table.
+ * This value was chosen somewhat arbitrarily. 126 readers plus a
+ * couple mutexes fit exactly into 8KB on my development machine.
+ * Applications should set the table size using #mdb_env_set_maxreaders().
+ */
+#define DEFAULT_READERS 126
+
+ /** The size of a CPU cache line in bytes. We want our lock structures
+ * aligned to this size to avoid false cache line sharing in the
+ * lock table.
+ * This value works for most CPUs. For Itanium this should be 128.
+ */
+#ifndef CACHELINE
+#define CACHELINE 64
+#endif
+
+ /** The information we store in a single slot of the reader table.
+ * In addition to a transaction ID, we also record the process and
+ * thread ID that owns a slot, so that we can detect stale information,
+ * e.g. threads or processes that went away without cleaning up.
+ * @note We currently don't check for stale records. We simply re-init
+ * the table when we know that we're the only process opening the
+ * lock file.
+ */
+typedef struct MDB_rxbody {
+ /** Current Transaction ID when this transaction began, or (txnid_t)-1.
+ * Multiple readers that start at the same time will probably have the
+ * same ID here. Again, it's not important to exclude them from
+ * anything; all we need to know is which version of the DB they
+ * started from so we can avoid overwriting any data used in that
+ * particular version.
+ */
+ volatile txnid_t mrb_txnid;
+ /** The process ID of the process owning this reader txn. */
+ volatile MDB_PID_T mrb_pid;
+ /** The thread ID of the thread owning this txn. */
+ volatile MDB_THR_T mrb_tid;
+} MDB_rxbody;
+
+ /** The actual reader record, with cacheline padding. */
+typedef struct MDB_reader {
+ union {
+ MDB_rxbody mrx;
+ /** shorthand for mrb_txnid */
+#define mr_txnid mru.mrx.mrb_txnid
+#define mr_pid mru.mrx.mrb_pid
+#define mr_tid mru.mrx.mrb_tid
+ /** cache line alignment */
+ char pad[(sizeof(MDB_rxbody)+CACHELINE-1) & ~(CACHELINE-1)];
+ } mru;
+} MDB_reader;
+
+ /** The header for the reader table.
+ * The table resides in a memory-mapped file. (This is a different file
+ * than is used for the main database.)
+ *
+ * For POSIX the actual mutexes reside in the shared memory of this
+ * mapped file. On Windows, mutexes are named objects allocated by the
+ * kernel; we store the mutex names in this mapped file so that other
+ * processes can grab them. This same approach is also used on
+ * MacOSX/Darwin (using named semaphores) since MacOSX doesn't support
+ * process-shared POSIX mutexes. For these cases where a named object
+ * is used, the object name is derived from a 64 bit FNV hash of the
+ * environment pathname. As such, naming collisions are extremely
+ * unlikely. If a collision occurs, the results are unpredictable.
+ */
+typedef struct MDB_txbody {
+ /** Stamp identifying this as an LMDB file. It must be set
+ * to #MDB_MAGIC. */
+ uint32_t mtb_magic;
+ /** Format of this lock file. Must be set to #MDB_LOCK_FORMAT. */
+ uint32_t mtb_format;
+#if defined(_WIN32) || defined(MDB_USE_POSIX_SEM)
+ char mtb_rmname[MNAME_LEN];
+#else
+ /** Mutex protecting access to this table.
+ * This is the reader table lock used with LOCK_MUTEX().
+ */
+ mdb_mutex_t mtb_rmutex;
+#endif
+ /** The ID of the last transaction committed to the database.
+ * This is recorded here only for convenience; the value can always
+ * be determined by reading the main database meta pages.
+ */
+ volatile txnid_t mtb_txnid;
+ /** The number of slots that have been used in the reader table.
+ * This always records the maximum count, it is not decremented
+ * when readers release their slots.
+ */
+ volatile unsigned mtb_numreaders;
+} MDB_txbody;
+
+ /** The actual reader table definition. */
+typedef struct MDB_txninfo {
+ union {
+ MDB_txbody mtb;
+#define mti_magic mt1.mtb.mtb_magic
+#define mti_format mt1.mtb.mtb_format
+#define mti_rmutex mt1.mtb.mtb_rmutex
+#define mti_rmname mt1.mtb.mtb_rmname
+#define mti_txnid mt1.mtb.mtb_txnid
+#define mti_numreaders mt1.mtb.mtb_numreaders
+ char pad[(sizeof(MDB_txbody)+CACHELINE-1) & ~(CACHELINE-1)];
+ } mt1;
+ union {
+#if defined(_WIN32) || defined(MDB_USE_POSIX_SEM)
+ char mt2_wmname[MNAME_LEN];
+#define mti_wmname mt2.mt2_wmname
+#else
+ mdb_mutex_t mt2_wmutex;
+#define mti_wmutex mt2.mt2_wmutex
+#endif
+ char pad[(MNAME_LEN+CACHELINE-1) & ~(CACHELINE-1)];
+ } mt2;
+ MDB_reader mti_readers[1];
+} MDB_txninfo;
+
+ /** Lockfile format signature: version, features and field layout */
+#define MDB_LOCK_FORMAT \
+ ((uint32_t) \
+ ((MDB_LOCK_VERSION) \
+ /* Flags which describe functionality */ \
+ + (((MDB_PIDLOCK) != 0) << 16)))
+/** @} */
+
+/** Common header for all page types. The page type depends on #mp_flags.
+ *
+ * #P_BRANCH and #P_LEAF pages have unsorted '#MDB_node's at the end, with
+ * sorted #mp_ptrs[] entries referring to them. Exception: #P_LEAF2 pages
+ * omit mp_ptrs and pack sorted #MDB_DUPFIXED values after the page header.
+ *
+ * #P_OVERFLOW records occupy one or more contiguous pages where only the
+ * first has a page header. They hold the real data of #F_BIGDATA nodes.
+ *
+ * #P_SUBP sub-pages are small leaf "pages" with duplicate data.
+ * A node with flag #F_DUPDATA but not #F_SUBDATA contains a sub-page.
+ * (Duplicate data can also go in sub-databases, which use normal pages.)
+ *
+ * #P_META pages contain #MDB_meta, the start point of an LMDB snapshot.
+ *
+ * Each non-metapage up to #MDB_meta.%mm_last_pg is reachable exactly once
+ * in the snapshot: Either used by a database or listed in a freeDB record.
+ */
+typedef struct MDB_page {
+#define mp_pgno mp_p.p_pgno
+#define mp_next mp_p.p_next
+ union {
+ pgno_t p_pgno; /**< page number */
+ struct MDB_page *p_next; /**< for in-memory list of freed pages */
+ } mp_p;
+ uint16_t mp_pad; /**< key size if this is a LEAF2 page */
+/** @defgroup mdb_page Page Flags
+ * @ingroup internal
+ * Flags for the page headers.
+ * @{
+ */
+#define P_BRANCH 0x01 /**< branch page */
+#define P_LEAF 0x02 /**< leaf page */
+#define P_OVERFLOW 0x04 /**< overflow page */
+#define P_META 0x08 /**< meta page */
+#define P_DIRTY 0x10 /**< dirty page, also set for #P_SUBP pages */
+#define P_LEAF2 0x20 /**< for #MDB_DUPFIXED records */
+#define P_SUBP 0x40 /**< for #MDB_DUPSORT sub-pages */
+#define P_LOOSE 0x4000 /**< page was dirtied then freed, can be reused */
+#define P_KEEP 0x8000 /**< leave this page alone during spill */
+/** @} */
+ uint16_t mp_flags; /**< @ref mdb_page */
+#define mp_lower mp_pb.pb.pb_lower
+#define mp_upper mp_pb.pb.pb_upper
+#define mp_pages mp_pb.pb_pages
+ union {
+ struct {
+ indx_t pb_lower; /**< lower bound of free space */
+ indx_t pb_upper; /**< upper bound of free space */
+ } pb;
+ uint32_t pb_pages; /**< number of overflow pages */
+ } mp_pb;
+ indx_t mp_ptrs[1]; /**< dynamic size */
+} MDB_page;
+
+ /** Size of the page header, excluding dynamic data at the end */
+#define PAGEHDRSZ ((unsigned) offsetof(MDB_page, mp_ptrs))
+
+ /** Address of first usable data byte in a page, after the header */
+#define METADATA(p) ((void *)((char *)(p) + PAGEHDRSZ))
+
+ /** ITS#7713, change PAGEBASE to handle 65536 byte pages */
+#define PAGEBASE ((MDB_DEVEL) ? PAGEHDRSZ : 0)
+
+ /** Number of nodes on a page */
+#define NUMKEYS(p) (((p)->mp_lower - (PAGEHDRSZ-PAGEBASE)) >> 1)
+
+ /** The amount of space remaining in the page */
+#define SIZELEFT(p) (indx_t)((p)->mp_upper - (p)->mp_lower)
+
+ /** The percentage of space used in the page, in tenths of a percent. */
+#define PAGEFILL(env, p) (1000L * ((env)->me_psize - PAGEHDRSZ - SIZELEFT(p)) / \
+ ((env)->me_psize - PAGEHDRSZ))
+ /** The minimum page fill factor, in tenths of a percent.
+ * Pages emptier than this are candidates for merging.
+ */
+#define FILL_THRESHOLD 250
+
+ /** Test if a page is a leaf page */
+#define IS_LEAF(p) F_ISSET((p)->mp_flags, P_LEAF)
+ /** Test if a page is a LEAF2 page */
+#define IS_LEAF2(p) F_ISSET((p)->mp_flags, P_LEAF2)
+ /** Test if a page is a branch page */
+#define IS_BRANCH(p) F_ISSET((p)->mp_flags, P_BRANCH)
+ /** Test if a page is an overflow page */
+#define IS_OVERFLOW(p) F_ISSET((p)->mp_flags, P_OVERFLOW)
+ /** Test if a page is a sub page */
+#define IS_SUBP(p) F_ISSET((p)->mp_flags, P_SUBP)
+
+ /** The number of overflow pages needed to store the given size. */
+#define OVPAGES(size, psize) ((PAGEHDRSZ-1 + (size)) / (psize) + 1)
+
+ /** Link in #MDB_txn.%mt_loose_pgs list.
+ * Kept outside the page header, which is needed when reusing the page.
+ */
+#define NEXT_LOOSE_PAGE(p) (*(MDB_page **)((p) + 2))
+
+ /** Header for a single key/data pair within a page.
+ * Used in pages of type #P_BRANCH and #P_LEAF without #P_LEAF2.
+ * We guarantee 2-byte alignment for 'MDB_node's.
+ *
+ * #mn_lo and #mn_hi are used for data size on leaf nodes, and for child
+ * pgno on branch nodes. On 64 bit platforms, #mn_flags is also used
+ * for pgno. (Branch nodes have no flags). Lo and hi are in host byte
+ * order in case some accesses can be optimized to 32-bit word access.
+ *
+ * Leaf node flags describe node contents. #F_BIGDATA says the node's
+ * data part is the page number of an overflow page with actual data.
+ * #F_DUPDATA and #F_SUBDATA can be combined giving duplicate data in
+ * a sub-page/sub-database, and named databases (just #F_SUBDATA).
+ */
+typedef struct MDB_node {
+ /** part of data size or pgno
+ * @{ */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ unsigned short mn_lo, mn_hi;
+#else
+ unsigned short mn_hi, mn_lo;
+#endif
+ /** @} */
+/** @defgroup mdb_node Node Flags
+ * @ingroup internal
+ * Flags for node headers.
+ * @{
+ */
+#define F_BIGDATA 0x01 /**< data put on overflow page */
+#define F_SUBDATA 0x02 /**< data is a sub-database */
+#define F_DUPDATA 0x04 /**< data has duplicates */
+
+/** valid flags for #mdb_node_add() */
+#define NODE_ADD_FLAGS (F_DUPDATA|F_SUBDATA|MDB_RESERVE|MDB_APPEND)
+
+/** @} */
+ unsigned short mn_flags; /**< @ref mdb_node */
+ unsigned short mn_ksize; /**< key size */
+ char mn_data[1]; /**< key and data are appended here */
+} MDB_node;
+
+ /** Size of the node header, excluding dynamic data at the end */
+#define NODESIZE offsetof(MDB_node, mn_data)
+
+ /** Bit position of top word in page number, for shifting mn_flags */
+#define PGNO_TOPWORD ((pgno_t)-1 > 0xffffffffu ? 32 : 0)
+
+ /** Size of a node in a branch page with a given key.
+ * This is just the node header plus the key, there is no data.
+ */
+#define INDXSIZE(k) (NODESIZE + ((k) == NULL ? 0 : (k)->mv_size))
+
+ /** Size of a node in a leaf page with a given key and data.
+ * This is node header plus key plus data size.
+ */
+#define LEAFSIZE(k, d) (NODESIZE + (k)->mv_size + (d)->mv_size)
+
+ /** Address of node \b i in page \b p */
+#define NODEPTR(p, i) ((MDB_node *)((char *)(p) + (p)->mp_ptrs[i] + PAGEBASE))
+
+ /** Address of the key for the node */
+#define NODEKEY(node) (void *)((node)->mn_data)
+
+ /** Address of the data for a node */
+#define NODEDATA(node) (void *)((char *)(node)->mn_data + (node)->mn_ksize)
+
+ /** Get the page number pointed to by a branch node */
+#define NODEPGNO(node) \
+ ((node)->mn_lo | ((pgno_t) (node)->mn_hi << 16) | \
+ (PGNO_TOPWORD ? ((pgno_t) (node)->mn_flags << PGNO_TOPWORD) : 0))
+ /** Set the page number in a branch node */
+#define SETPGNO(node,pgno) do { \
+ (node)->mn_lo = (pgno) & 0xffff; (node)->mn_hi = (pgno) >> 16; \
+ if (PGNO_TOPWORD) (node)->mn_flags = (pgno) >> PGNO_TOPWORD; } while(0)
+
+ /** Get the size of the data in a leaf node */
+#define NODEDSZ(node) ((node)->mn_lo | ((unsigned)(node)->mn_hi << 16))
+ /** Set the size of the data for a leaf node */
+#define SETDSZ(node,size) do { \
+ (node)->mn_lo = (size) & 0xffff; (node)->mn_hi = (size) >> 16;} while(0)
+ /** The size of a key in a node */
+#define NODEKSZ(node) ((node)->mn_ksize)
+
+ /** Copy a page number from src to dst */
+#ifdef MISALIGNED_OK
+#define COPY_PGNO(dst,src) dst = src
+#else
+#if SIZE_MAX > 4294967295UL
+#define COPY_PGNO(dst,src) do { \
+ unsigned short *s, *d; \
+ s = (unsigned short *)&(src); \
+ d = (unsigned short *)&(dst); \
+ *d++ = *s++; \
+ *d++ = *s++; \
+ *d++ = *s++; \
+ *d = *s; \
+} while (0)
+#else
+#define COPY_PGNO(dst,src) do { \
+ unsigned short *s, *d; \
+ s = (unsigned short *)&(src); \
+ d = (unsigned short *)&(dst); \
+ *d++ = *s++; \
+ *d = *s; \
+} while (0)
+#endif
+#endif
+ /** The address of a key in a LEAF2 page.
+ * LEAF2 pages are used for #MDB_DUPFIXED sorted-duplicate sub-DBs.
+ * There are no node headers, keys are stored contiguously.
+ */
+#define LEAF2KEY(p, i, ks) ((char *)(p) + PAGEHDRSZ + ((i)*(ks)))
+
+ /** Set the \b node's key into \b keyptr, if requested. */
+#define MDB_GET_KEY(node, keyptr) { if ((keyptr) != NULL) { \
+ (keyptr)->mv_size = NODEKSZ(node); (keyptr)->mv_data = NODEKEY(node); } }
+
+ /** Set the \b node's key into \b key. */
+#define MDB_GET_KEY2(node, key) { key.mv_size = NODEKSZ(node); key.mv_data = NODEKEY(node); }
+
+ /** Information about a single database in the environment. */
+typedef struct MDB_db {
+ uint32_t md_pad; /**< also ksize for LEAF2 pages */
+ uint16_t md_flags; /**< @ref mdb_dbi_open */
+ uint16_t md_depth; /**< depth of this tree */
+ pgno_t md_branch_pages; /**< number of internal pages */
+ pgno_t md_leaf_pages; /**< number of leaf pages */
+ pgno_t md_overflow_pages; /**< number of overflow pages */
+ size_t md_entries; /**< number of data items */
+ pgno_t md_root; /**< the root page of this tree */
+} MDB_db;
+
+#define MDB_VALID 0x8000 /**< DB handle is valid, for me_dbflags */
+#define PERSISTENT_FLAGS (0xffff & ~(MDB_VALID))
+ /** #mdb_dbi_open() flags */
+#define VALID_FLAGS (MDB_REVERSEKEY|MDB_DUPSORT|MDB_INTEGERKEY|MDB_DUPFIXED|\
+ MDB_INTEGERDUP|MDB_REVERSEDUP|MDB_CREATE)
+
+ /** Handle for the DB used to track free pages. */
+#define FREE_DBI 0
+ /** Handle for the default DB. */
+#define MAIN_DBI 1
+ /** Number of DBs in metapage (free and main) - also hardcoded elsewhere */
+#define CORE_DBS 2
+
+ /** Number of meta pages - also hardcoded elsewhere */
+#define NUM_METAS 2
+
+ /** Meta page content.
+ * A meta page is the start point for accessing a database snapshot.
+ * Pages 0-1 are meta pages. Transaction N writes meta page #(N % 2).
+ */
+typedef struct MDB_meta {
+ /** Stamp identifying this as an LMDB file. It must be set
+ * to #MDB_MAGIC. */
+ uint32_t mm_magic;
+ /** Version number of this file. Must be set to #MDB_DATA_VERSION. */
+ uint32_t mm_version;
+ void *mm_address; /**< address for fixed mapping */
+ size_t mm_mapsize; /**< size of mmap region */
+ MDB_db mm_dbs[CORE_DBS]; /**< first is free space, 2nd is main db */
+ /** The size of pages used in this DB */
+#define mm_psize mm_dbs[FREE_DBI].md_pad
+ /** Any persistent environment flags. @ref mdb_env */
+#define mm_flags mm_dbs[FREE_DBI].md_flags
+ /** Last used page in the datafile.
+ * Actually the file may be shorter if the freeDB lists the final pages.
+ */
+ pgno_t mm_last_pg;
+ volatile txnid_t mm_txnid; /**< txnid that committed this page */
+} MDB_meta;
+
+ /** Buffer for a stack-allocated meta page.
+ * The members define size and alignment, and silence type
+ * aliasing warnings. They are not used directly; that could
+ * mean incorrectly using several union members in parallel.
+ */
+typedef union MDB_metabuf {
+ MDB_page mb_page;
+ struct {
+ char mm_pad[PAGEHDRSZ];
+ MDB_meta mm_meta;
+ } mb_metabuf;
+} MDB_metabuf;
+
+ /** Auxiliary DB info.
+ * The information here is mostly static/read-only. There is
+ * only a single copy of this record in the environment.
+ */
+typedef struct MDB_dbx {
+ MDB_val md_name; /**< name of the database */
+ MDB_cmp_func *md_cmp; /**< function for comparing keys */
+ MDB_cmp_func *md_dcmp; /**< function for comparing data items */
+ MDB_rel_func *md_rel; /**< user relocate function */
+ void *md_relctx; /**< user-provided context for md_rel */
+} MDB_dbx;
+
+ /** A database transaction.
+ * Every operation requires a transaction handle.
+ */
+struct MDB_txn {
+ MDB_txn *mt_parent; /**< parent of a nested txn */
+ /** Nested txn under this txn, set together with flag #MDB_TXN_HAS_CHILD */
+ MDB_txn *mt_child;
+ pgno_t mt_next_pgno; /**< next unallocated page */
+ /** The ID of this transaction. IDs are integers incrementing from 1.
+ * Only committed write transactions increment the ID. If a transaction
+ * aborts, the ID may be re-used by the next writer.
+ */
+ txnid_t mt_txnid;
+ MDB_env *mt_env; /**< the DB environment */
+ /** The list of pages that became unused during this transaction.
+ */
+ MDB_IDL mt_free_pgs;
+ /** The list of loose pages that became unused and may be reused
+ * in this transaction, linked through #NEXT_LOOSE_PAGE(page).
+ */
+ MDB_page *mt_loose_pgs;
+ /** Number of loose pages (#mt_loose_pgs) */
+ int mt_loose_count;
+ /** The sorted list of dirty pages we temporarily wrote to disk
+ * because the dirty list was full. page numbers in here are
+ * shifted left by 1, deleted slots have the LSB set.
+ */
+ MDB_IDL mt_spill_pgs;
+ union {
+ /** For write txns: Modified pages. Sorted when not MDB_WRITEMAP. */
+ MDB_ID2L dirty_list;
+ /** For read txns: This thread/txn's reader table slot, or NULL. */
+ MDB_reader *reader;
+ } mt_u;
+ /** Array of records for each DB known in the environment. */
+ MDB_dbx *mt_dbxs;
+ /** Array of MDB_db records for each known DB */
+ MDB_db *mt_dbs;
+ /** Array of sequence numbers for each DB handle */
+ unsigned int *mt_dbiseqs;
+/** @defgroup mt_dbflag Transaction DB Flags
+ * @ingroup internal
+ * @{
+ */
+#define DB_DIRTY 0x01 /**< DB was written in this txn */
+#define DB_STALE 0x02 /**< Named-DB record is older than txnID */
+#define DB_NEW 0x04 /**< Named-DB handle opened in this txn */
+#define DB_VALID 0x08 /**< DB handle is valid, see also #MDB_VALID */
+#define DB_USRVALID 0x10 /**< As #DB_VALID, but not set for #FREE_DBI */
+#define DB_DUPDATA 0x20 /**< DB is #MDB_DUPSORT data */
+/** @} */
+ /** In write txns, array of cursors for each DB */
+ MDB_cursor **mt_cursors;
+ /** Array of flags for each DB */
+ unsigned char *mt_dbflags;
+ /** Number of DB records in use, or 0 when the txn is finished.
+ * This number only ever increments until the txn finishes; we
+ * don't decrement it when individual DB handles are closed.
+ */
+ MDB_dbi mt_numdbs;
+
+/** @defgroup mdb_txn Transaction Flags
+ * @ingroup internal
+ * @{
+ */
+ /** #mdb_txn_begin() flags */
+#define MDB_TXN_BEGIN_FLAGS MDB_RDONLY
+#define MDB_TXN_RDONLY MDB_RDONLY /**< read-only transaction */
+ /* internal txn flags */
+#define MDB_TXN_WRITEMAP MDB_WRITEMAP /**< copy of #MDB_env flag in writers */
+#define MDB_TXN_FINISHED 0x01 /**< txn is finished or never began */
+#define MDB_TXN_ERROR 0x02 /**< txn is unusable after an error */
+#define MDB_TXN_DIRTY 0x04 /**< must write, even if dirty list is empty */
+#define MDB_TXN_SPILLS 0x08 /**< txn or a parent has spilled pages */
+#define MDB_TXN_HAS_CHILD 0x10 /**< txn has an #MDB_txn.%mt_child */
+ /** most operations on the txn are currently illegal */
+#define MDB_TXN_BLOCKED (MDB_TXN_FINISHED|MDB_TXN_ERROR|MDB_TXN_HAS_CHILD)
+/** @} */
+ unsigned int mt_flags; /**< @ref mdb_txn */
+ /** #dirty_list room: Array size - \#dirty pages visible to this txn.
+ * Includes ancestor txns' dirty pages not hidden by other txns'
+ * dirty/spilled pages. Thus commit(nested txn) has room to merge
+ * dirty_list into mt_parent after freeing hidden mt_parent pages.
+ */
+ unsigned int mt_dirty_room;
+};
+
+/** Enough space for 2^32 nodes with minimum of 2 keys per node. I.e., plenty.
+ * At 4 keys per node, enough for 2^64 nodes, so there's probably no need to
+ * raise this on a 64 bit machine.
+ */
+#define CURSOR_STACK 32
+
+struct MDB_xcursor;
+
+ /** Cursors are used for all DB operations.
+ * A cursor holds a path of (page pointer, key index) from the DB
+ * root to a position in the DB, plus other state. #MDB_DUPSORT
+ * cursors include an xcursor to the current data item. Write txns
+ * track their cursors and keep them up to date when data moves.
+ * Exception: An xcursor's pointer to a #P_SUBP page can be stale.
+ * (A node with #F_DUPDATA but no #F_SUBDATA contains a subpage).
+ */
+struct MDB_cursor {
+ /** Next cursor on this DB in this txn */
+ MDB_cursor *mc_next;
+ /** Backup of the original cursor if this cursor is a shadow */
+ MDB_cursor *mc_backup;
+ /** Context used for databases with #MDB_DUPSORT, otherwise NULL */
+ struct MDB_xcursor *mc_xcursor;
+ /** The transaction that owns this cursor */
+ MDB_txn *mc_txn;
+ /** The database handle this cursor operates on */
+ MDB_dbi mc_dbi;
+ /** The database record for this cursor */
+ MDB_db *mc_db;
+ /** The database auxiliary record for this cursor */
+ MDB_dbx *mc_dbx;
+ /** The @ref mt_dbflag for this database */
+ unsigned char *mc_dbflag;
+ unsigned short mc_snum; /**< number of pushed pages */
+ unsigned short mc_top; /**< index of top page, normally mc_snum-1 */
+/** @defgroup mdb_cursor Cursor Flags
+ * @ingroup internal
+ * Cursor state flags.
+ * @{
+ */
+#define C_INITIALIZED 0x01 /**< cursor has been initialized and is valid */
+#define C_EOF 0x02 /**< No more data */
+#define C_SUB 0x04 /**< Cursor is a sub-cursor */
+#define C_DEL 0x08 /**< last op was a cursor_del */
+#define C_UNTRACK 0x40 /**< Un-track cursor when closing */
+/** @} */
+ unsigned int mc_flags; /**< @ref mdb_cursor */
+ MDB_page *mc_pg[CURSOR_STACK]; /**< stack of pushed pages */
+ indx_t mc_ki[CURSOR_STACK]; /**< stack of page indices */
+};
+
+ /** Context for sorted-dup records.
+ * We could have gone to a fully recursive design, with arbitrarily
+ * deep nesting of sub-databases. But for now we only handle these
+ * levels - main DB, optional sub-DB, sorted-duplicate DB.
+ */
+typedef struct MDB_xcursor {
+ /** A sub-cursor for traversing the Dup DB */
+ MDB_cursor mx_cursor;
+ /** The database record for this Dup DB */
+ MDB_db mx_db;
+ /** The auxiliary DB record for this Dup DB */
+ MDB_dbx mx_dbx;
+ /** The @ref mt_dbflag for this Dup DB */
+ unsigned char mx_dbflag;
+} MDB_xcursor;
+
+ /** Check if there is an inited xcursor */
+#define XCURSOR_INITED(mc) \
+ ((mc)->mc_xcursor && ((mc)->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED))
+
+ /** Update the xcursor's sub-page pointer, if any, in \b mc. Needed
+ * when the node which contains the sub-page may have moved. Called
+ * with leaf page \b mp = mc->mc_pg[\b top].
+ */
+#define XCURSOR_REFRESH(mc, top, mp) do { \
+ MDB_page *xr_pg = (mp); \
+ MDB_node *xr_node; \
+ if (!XCURSOR_INITED(mc) || (mc)->mc_ki[top] >= NUMKEYS(xr_pg)) break; \
+ xr_node = NODEPTR(xr_pg, (mc)->mc_ki[top]); \
+ if ((xr_node->mn_flags & (F_DUPDATA|F_SUBDATA)) == F_DUPDATA) \
+ (mc)->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(xr_node); \
+} while (0)
+
+ /** State of FreeDB old pages, stored in the MDB_env */
+typedef struct MDB_pgstate {
+ pgno_t *mf_pghead; /**< Reclaimed freeDB pages, or NULL before use */
+ txnid_t mf_pglast; /**< ID of last used record, or 0 if !mf_pghead */
+} MDB_pgstate;
+
+ /** The database environment. */
+struct MDB_env {
+ HANDLE me_fd; /**< The main data file */
+ HANDLE me_lfd; /**< The lock file */
+ HANDLE me_mfd; /**< For writing and syncing the meta pages */
+ /** Failed to update the meta page. Probably an I/O error. */
+#define MDB_FATAL_ERROR 0x80000000U
+ /** Some fields are initialized. */
+#define MDB_ENV_ACTIVE 0x20000000U
+ /** me_txkey is set */
+#define MDB_ENV_TXKEY 0x10000000U
+ /** fdatasync is unreliable */
+#define MDB_FSYNCONLY 0x08000000U
+ uint32_t me_flags; /**< @ref mdb_env */
+ unsigned int me_psize; /**< DB page size, inited from me_os_psize */
+ unsigned int me_os_psize; /**< OS page size, from #GET_PAGESIZE */
+ unsigned int me_maxreaders; /**< size of the reader table */
+ /** Max #MDB_txninfo.%mti_numreaders of interest to #mdb_env_close() */
+ volatile int me_close_readers;
+ MDB_dbi me_numdbs; /**< number of DBs opened */
+ MDB_dbi me_maxdbs; /**< size of the DB table */
+ MDB_PID_T me_pid; /**< process ID of this env */
+ char *me_path; /**< path to the DB files */
+ char *me_map; /**< the memory map of the data file */
+ MDB_txninfo *me_txns; /**< the memory map of the lock file or NULL */
+ MDB_meta *me_metas[NUM_METAS]; /**< pointers to the two meta pages */
+ void *me_pbuf; /**< scratch area for DUPSORT put() */
+ MDB_txn *me_txn; /**< current write transaction */
+ MDB_txn *me_txn0; /**< prealloc'd write transaction */
+ size_t me_mapsize; /**< size of the data memory map */
+ off_t me_size; /**< current file size */
+ pgno_t me_maxpg; /**< me_mapsize / me_psize */
+ MDB_dbx *me_dbxs; /**< array of static DB info */
+ uint16_t *me_dbflags; /**< array of flags from MDB_db.md_flags */
+ unsigned int *me_dbiseqs; /**< array of dbi sequence numbers */
+ pthread_key_t me_txkey; /**< thread-key for readers */
+ txnid_t me_pgoldest; /**< ID of oldest reader last time we looked */
+ MDB_pgstate me_pgstate; /**< state of old pages from freeDB */
+# define me_pglast me_pgstate.mf_pglast
+# define me_pghead me_pgstate.mf_pghead
+ MDB_page *me_dpages; /**< list of malloc'd blocks for re-use */
+ /** IDL of pages that became unused in a write txn */
+ MDB_IDL me_free_pgs;
+ /** ID2L of pages written during a write txn. Length MDB_IDL_UM_SIZE. */
+ MDB_ID2L me_dirty_list;
+ /** Max number of freelist items that can fit in a single overflow page */
+ int me_maxfree_1pg;
+ /** Max size of a node on a page */
+ unsigned int me_nodemax;
+#if !(MDB_MAXKEYSIZE)
+ unsigned int me_maxkey; /**< max size of a key */
+#endif
+ int me_live_reader; /**< have liveness lock in reader table */
+#ifdef _WIN32
+ int me_pidquery; /**< Used in OpenProcess */
+#endif
+#ifdef MDB_USE_POSIX_MUTEX /* Posix mutexes reside in shared mem */
+# define me_rmutex me_txns->mti_rmutex /**< Shared reader lock */
+# define me_wmutex me_txns->mti_wmutex /**< Shared writer lock */
+#else
+ mdb_mutex_t me_rmutex;
+ mdb_mutex_t me_wmutex;
+#endif
+ void *me_userctx; /**< User-settable context */
+ MDB_assert_func *me_assert_func; /**< Callback for assertion failures */
+};
+
+ /** Nested transaction */
+typedef struct MDB_ntxn {
+ MDB_txn mnt_txn; /**< the transaction */
+ MDB_pgstate mnt_pgstate; /**< parent transaction's saved freestate */
+} MDB_ntxn;
+
+ /** max number of pages to commit in one writev() call */
+#define MDB_COMMIT_PAGES 64
+#if defined(IOV_MAX) && IOV_MAX < MDB_COMMIT_PAGES
+#undef MDB_COMMIT_PAGES
+#define MDB_COMMIT_PAGES IOV_MAX
+#endif
+
+ /** max bytes to write in one call */
+#define MAX_WRITE (0x40000000U >> (sizeof(ssize_t) == 4))
+
+ /** Check \b txn and \b dbi arguments to a function */
+#define TXN_DBI_EXIST(txn, dbi, validity) \
+ ((txn) && (dbi)<(txn)->mt_numdbs && ((txn)->mt_dbflags[dbi] & (validity)))
+
+ /** Check for misused \b dbi handles */
+#define TXN_DBI_CHANGED(txn, dbi) \
+ ((txn)->mt_dbiseqs[dbi] != (txn)->mt_env->me_dbiseqs[dbi])
+
+static int mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp);
+static int mdb_page_new(MDB_cursor *mc, uint32_t flags, int num, MDB_page **mp);
+static int mdb_page_touch(MDB_cursor *mc);
+
+#define MDB_END_NAMES {"committed", "empty-commit", "abort", "reset", \
+ "reset-tmp", "fail-begin", "fail-beginchild"}
+enum {
+ /* mdb_txn_end operation number, for logging */
+ MDB_END_COMMITTED, MDB_END_EMPTY_COMMIT, MDB_END_ABORT, MDB_END_RESET,
+ MDB_END_RESET_TMP, MDB_END_FAIL_BEGIN, MDB_END_FAIL_BEGINCHILD
+};
+#define MDB_END_OPMASK 0x0F /**< mask for #mdb_txn_end() operation number */
+#define MDB_END_UPDATE 0x10 /**< update env state (DBIs) */
+#define MDB_END_FREE 0x20 /**< free txn unless it is #MDB_env.%me_txn0 */
+#define MDB_END_SLOT MDB_NOTLS /**< release any reader slot if #MDB_NOTLS */
+static void mdb_txn_end(MDB_txn *txn, unsigned mode);
+
+static int mdb_page_get(MDB_cursor *mc, pgno_t pgno, MDB_page **mp, int *lvl);
+static int mdb_page_search_root(MDB_cursor *mc,
+ MDB_val *key, int modify);
+#define MDB_PS_MODIFY 1
+#define MDB_PS_ROOTONLY 2
+#define MDB_PS_FIRST 4
+#define MDB_PS_LAST 8
+static int mdb_page_search(MDB_cursor *mc,
+ MDB_val *key, int flags);
+static int mdb_page_merge(MDB_cursor *csrc, MDB_cursor *cdst);
+
+#define MDB_SPLIT_REPLACE MDB_APPENDDUP /**< newkey is not new */
+static int mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata,
+ pgno_t newpgno, unsigned int nflags);
+
+static int mdb_env_read_header(MDB_env *env, MDB_meta *meta);
+static MDB_meta *mdb_env_pick_meta(const MDB_env *env);
+static int mdb_env_write_meta(MDB_txn *txn);
+#ifdef MDB_USE_POSIX_MUTEX /* Drop unused excl arg */
+# define mdb_env_close0(env, excl) mdb_env_close1(env)
+#endif
+static void mdb_env_close0(MDB_env *env, int excl);
+
+static MDB_node *mdb_node_search(MDB_cursor *mc, MDB_val *key, int *exactp);
+static int mdb_node_add(MDB_cursor *mc, indx_t indx,
+ MDB_val *key, MDB_val *data, pgno_t pgno, unsigned int flags);
+static void mdb_node_del(MDB_cursor *mc, int ksize);
+static void mdb_node_shrink(MDB_page *mp, indx_t indx);
+static int mdb_node_move(MDB_cursor *csrc, MDB_cursor *cdst, int fromleft);
+static int mdb_node_read(MDB_cursor *mc, MDB_node *leaf, MDB_val *data);
+static size_t mdb_leaf_size(MDB_env *env, MDB_val *key, MDB_val *data);
+static size_t mdb_branch_size(MDB_env *env, MDB_val *key);
+
+static int mdb_rebalance(MDB_cursor *mc);
+static int mdb_update_key(MDB_cursor *mc, MDB_val *key);
+
+static void mdb_cursor_pop(MDB_cursor *mc);
+static int mdb_cursor_push(MDB_cursor *mc, MDB_page *mp);
+
+static int mdb_cursor_del0(MDB_cursor *mc);
+static int mdb_del0(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data, unsigned flags);
+static int mdb_cursor_sibling(MDB_cursor *mc, int move_right);
+static int mdb_cursor_next(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op);
+static int mdb_cursor_prev(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op);
+static int mdb_cursor_set(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op,
+ int *exactp);
+static int mdb_cursor_first(MDB_cursor *mc, MDB_val *key, MDB_val *data);
+static int mdb_cursor_last(MDB_cursor *mc, MDB_val *key, MDB_val *data);
+
+static void mdb_cursor_init(MDB_cursor *mc, MDB_txn *txn, MDB_dbi dbi, MDB_xcursor *mx);
+static void mdb_xcursor_init0(MDB_cursor *mc);
+static void mdb_xcursor_init1(MDB_cursor *mc, MDB_node *node);
+static void mdb_xcursor_init2(MDB_cursor *mc, MDB_xcursor *src_mx, int force);
+
+static int mdb_drop0(MDB_cursor *mc, int subs);
+static void mdb_default_cmp(MDB_txn *txn, MDB_dbi dbi);
+static int mdb_reader_check0(MDB_env *env, int rlocked, int *dead);
+
+/** @cond */
+static MDB_cmp_func mdb_cmp_memn, mdb_cmp_memnr, mdb_cmp_int, mdb_cmp_cint, mdb_cmp_long;
+/** @endcond */
+
+/** Compare two items pointing at size_t's of unknown alignment. */
+#ifdef MISALIGNED_OK
+# define mdb_cmp_clong mdb_cmp_long
+#else
+# define mdb_cmp_clong mdb_cmp_cint
+#endif
+
+#ifdef _WIN32
+static SECURITY_DESCRIPTOR mdb_null_sd;
+static SECURITY_ATTRIBUTES mdb_all_sa;
+static int mdb_sec_inited;
+
+struct MDB_name;
+static int utf8_to_utf16(const char *src, struct MDB_name *dst, int xtra);
+#endif
+
+/** Return the library version info. */
+char * ESECT
+mdb_version(int *major, int *minor, int *patch)
+{
+ if (major) *major = MDB_VERSION_MAJOR;
+ if (minor) *minor = MDB_VERSION_MINOR;
+ if (patch) *patch = MDB_VERSION_PATCH;
+ return MDB_VERSION_STRING;
+}
+
+/** Table of descriptions for LMDB @ref errors */
+static char *const mdb_errstr[] = {
+ "MDB_KEYEXIST: Key/data pair already exists",
+ "MDB_NOTFOUND: No matching key/data pair found",
+ "MDB_PAGE_NOTFOUND: Requested page not found",
+ "MDB_CORRUPTED: Located page was wrong type",
+ "MDB_PANIC: Update of meta page failed or environment had fatal error",
+ "MDB_VERSION_MISMATCH: Database environment version mismatch",
+ "MDB_INVALID: File is not an LMDB file",
+ "MDB_MAP_FULL: Environment mapsize limit reached",
+ "MDB_DBS_FULL: Environment maxdbs limit reached",
+ "MDB_READERS_FULL: Environment maxreaders limit reached",
+ "MDB_TLS_FULL: Thread-local storage keys full - too many environments open",
+ "MDB_TXN_FULL: Transaction has too many dirty pages - transaction too big",
+ "MDB_CURSOR_FULL: Internal error - cursor stack limit reached",
+ "MDB_PAGE_FULL: Internal error - page has no more space",
+ "MDB_MAP_RESIZED: Database contents grew beyond environment mapsize",
+ "MDB_INCOMPATIBLE: Operation and DB incompatible, or DB flags changed",
+ "MDB_BAD_RSLOT: Invalid reuse of reader locktable slot",
+ "MDB_BAD_TXN: Transaction must abort, has a child, or is invalid",
+ "MDB_BAD_VALSIZE: Unsupported size of key/DB name/data, or wrong DUPFIXED size",
+ "MDB_BAD_DBI: The specified DBI handle was closed/changed unexpectedly",
+};
+
+char *
+mdb_strerror(int err)
+{
+#ifdef _WIN32
+ /** HACK: pad 4KB on stack over the buf. Return system msgs in buf.
+ * This works as long as no function between the call to mdb_strerror
+ * and the actual use of the message uses more than 4K of stack.
+ */
+#define MSGSIZE 1024
+#define PADSIZE 4096
+ char buf[MSGSIZE+PADSIZE], *ptr = buf;
+#endif
+ int i;
+ if (!err)
+ return ("Successful return: 0");
+
+ if (err >= MDB_KEYEXIST && err <= MDB_LAST_ERRCODE) {
+ i = err - MDB_KEYEXIST;
+ return mdb_errstr[i];
+ }
+
+#ifdef _WIN32
+ /* These are the C-runtime error codes we use. The comment indicates
+ * their numeric value, and the Win32 error they would correspond to
+ * if the error actually came from a Win32 API. A major mess, we should
+ * have used LMDB-specific error codes for everything.
+ */
+ switch(err) {
+ case ENOENT: /* 2, FILE_NOT_FOUND */
+ case EIO: /* 5, ACCESS_DENIED */
+ case ENOMEM: /* 12, INVALID_ACCESS */
+ case EACCES: /* 13, INVALID_DATA */
+ case EBUSY: /* 16, CURRENT_DIRECTORY */
+ case EINVAL: /* 22, BAD_COMMAND */
+ case ENOSPC: /* 28, OUT_OF_PAPER */
+ return strerror(err);
+ default:
+ ;
+ }
+ buf[0] = 0;
+ FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, err, 0, ptr, MSGSIZE, (va_list *)buf+MSGSIZE);
+ return ptr;
+#else
+ return strerror(err);
+#endif
+}
+
+/** assert(3) variant in cursor context */
+#define mdb_cassert(mc, expr) mdb_assert0((mc)->mc_txn->mt_env, expr, #expr)
+/** assert(3) variant in transaction context */
+#define mdb_tassert(txn, expr) mdb_assert0((txn)->mt_env, expr, #expr)
+/** assert(3) variant in environment context */
+#define mdb_eassert(env, expr) mdb_assert0(env, expr, #expr)
+
+#ifndef NDEBUG
+# define mdb_assert0(env, expr, expr_txt) ((expr) ? (void)0 : \
+ mdb_assert_fail(env, expr_txt, mdb_func_, __FILE__, __LINE__))
+
+static void ESECT
+mdb_assert_fail(MDB_env *env, const char *expr_txt,
+ const char *func, const char *file, int line)
+{
+ char buf[400];
+ sprintf(buf, "%.100s:%d: Assertion '%.200s' failed in %.40s()",
+ file, line, expr_txt, func);
+ if (env->me_assert_func)
+ env->me_assert_func(env, buf);
+ fprintf(stderr, "%s\n", buf);
+ abort();
+}
+#else
+# define mdb_assert0(env, expr, expr_txt) ((void) 0)
+#endif /* NDEBUG */
+
+#if MDB_DEBUG
+/** Return the page number of \b mp which may be sub-page, for debug output */
+static pgno_t
+mdb_dbg_pgno(MDB_page *mp)
+{
+ pgno_t ret;
+ COPY_PGNO(ret, mp->mp_pgno);
+ return ret;
+}
+
+/** Display a key in hexadecimal and return the address of the result.
+ * @param[in] key the key to display
+ * @param[in] buf the buffer to write into. Should always be #DKBUF.
+ * @return The key in hexadecimal form.
+ */
+char *
+mdb_dkey(MDB_val *key, char *buf)
+{
+ char *ptr = buf;
+ unsigned char *c = key->mv_data;
+ unsigned int i;
+
+ if (!key)
+ return "";
+
+ if (key->mv_size > DKBUF_MAXKEYSIZE)
+ return "MDB_MAXKEYSIZE";
+ /* may want to make this a dynamic check: if the key is mostly
+ * printable characters, print it as-is instead of converting to hex.
+ */
+#if 1
+ buf[0] = '\0';
+ for (i=0; i<key->mv_size; i++)
+ ptr += sprintf(ptr, "%02x", *c++);
+#else
+ sprintf(buf, "%.*s", key->mv_size, key->mv_data);
+#endif
+ return buf;
+}
+
+static const char *
+mdb_leafnode_type(MDB_node *n)
+{
+ static char *const tp[2][2] = {{"", ": DB"}, {": sub-page", ": sub-DB"}};
+ return F_ISSET(n->mn_flags, F_BIGDATA) ? ": overflow page" :
+ tp[F_ISSET(n->mn_flags, F_DUPDATA)][F_ISSET(n->mn_flags, F_SUBDATA)];
+}
+
+/** Display all the keys in the page. */
+void
+mdb_page_list(MDB_page *mp)
+{
+ pgno_t pgno = mdb_dbg_pgno(mp);
+ const char *type, *state = (mp->mp_flags & P_DIRTY) ? ", dirty" : "";
+ MDB_node *node;
+ unsigned int i, nkeys, nsize, total = 0;
+ MDB_val key;
+ DKBUF;
+
+ switch (mp->mp_flags & (P_BRANCH|P_LEAF|P_LEAF2|P_META|P_OVERFLOW|P_SUBP)) {
+ case P_BRANCH: type = "Branch page"; break;
+ case P_LEAF: type = "Leaf page"; break;
+ case P_LEAF|P_SUBP: type = "Sub-page"; break;
+ case P_LEAF|P_LEAF2: type = "LEAF2 page"; break;
+ case P_LEAF|P_LEAF2|P_SUBP: type = "LEAF2 sub-page"; break;
+ case P_OVERFLOW:
+ fprintf(stderr, "Overflow page %"Z"u pages %u%s\n",
+ pgno, mp->mp_pages, state);
+ return;
+ case P_META:
+ fprintf(stderr, "Meta-page %"Z"u txnid %"Z"u\n",
+ pgno, ((MDB_meta *)METADATA(mp))->mm_txnid);
+ return;
+ default:
+ fprintf(stderr, "Bad page %"Z"u flags 0x%X\n", pgno, mp->mp_flags);
+ return;
+ }
+
+ nkeys = NUMKEYS(mp);
+ fprintf(stderr, "%s %"Z"u numkeys %d%s\n", type, pgno, nkeys, state);
+
+ for (i=0; i<nkeys; i++) {
+ if (IS_LEAF2(mp)) { /* LEAF2 pages have no mp_ptrs[] or node headers */
+ key.mv_size = nsize = mp->mp_pad;
+ key.mv_data = LEAF2KEY(mp, i, nsize);
+ total += nsize;
+ fprintf(stderr, "key %d: nsize %d, %s\n", i, nsize, DKEY(&key));
+ continue;
+ }
+ node = NODEPTR(mp, i);
+ key.mv_size = node->mn_ksize;
+ key.mv_data = node->mn_data;
+ nsize = NODESIZE + key.mv_size;
+ if (IS_BRANCH(mp)) {
+ fprintf(stderr, "key %d: page %"Z"u, %s\n", i, NODEPGNO(node),
+ DKEY(&key));
+ total += nsize;
+ } else {
+ if (F_ISSET(node->mn_flags, F_BIGDATA))
+ nsize += sizeof(pgno_t);
+ else
+ nsize += NODEDSZ(node);
+ total += nsize;
+ nsize += sizeof(indx_t);
+ fprintf(stderr, "key %d: nsize %d, %s%s\n",
+ i, nsize, DKEY(&key), mdb_leafnode_type(node));
+ }
+ total = EVEN(total);
+ }
+ fprintf(stderr, "Total: header %d + contents %d + unused %d\n",
+ IS_LEAF2(mp) ? PAGEHDRSZ : PAGEBASE + mp->mp_lower, total, SIZELEFT(mp));
+}
+
+void
+mdb_cursor_chk(MDB_cursor *mc)
+{
+ unsigned int i;
+ MDB_node *node;
+ MDB_page *mp;
+
+ if (!mc->mc_snum || !(mc->mc_flags & C_INITIALIZED)) return;
+ for (i=0; i<mc->mc_top; i++) {
+ mp = mc->mc_pg[i];
+ node = NODEPTR(mp, mc->mc_ki[i]);
+ if (NODEPGNO(node) != mc->mc_pg[i+1]->mp_pgno)
+ printf("oops!\n");
+ }
+ if (mc->mc_ki[i] >= NUMKEYS(mc->mc_pg[i]))
+ printf("ack!\n");
+ if (XCURSOR_INITED(mc)) {
+ node = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]);
+ if (((node->mn_flags & (F_DUPDATA|F_SUBDATA)) == F_DUPDATA) &&
+ mc->mc_xcursor->mx_cursor.mc_pg[0] != NODEDATA(node)) {
+ printf("blah!\n");
+ }
+ }
+}
+#endif
+
+#if (MDB_DEBUG) > 2
+/** Count all the pages in each DB and in the freelist
+ * and make sure it matches the actual number of pages
+ * being used.
+ * All named DBs must be open for a correct count.
+ */
+static void mdb_audit(MDB_txn *txn)
+{
+ MDB_cursor mc;
+ MDB_val key, data;
+ MDB_ID freecount, count;
+ MDB_dbi i;
+ int rc;
+
+ freecount = 0;
+ mdb_cursor_init(&mc, txn, FREE_DBI, NULL);
+ while ((rc = mdb_cursor_get(&mc, &key, &data, MDB_NEXT)) == 0)
+ freecount += *(MDB_ID *)data.mv_data;
+ mdb_tassert(txn, rc == MDB_NOTFOUND);
+
+ count = 0;
+ for (i = 0; i<txn->mt_numdbs; i++) {
+ MDB_xcursor mx;
+ if (!(txn->mt_dbflags[i] & DB_VALID))
+ continue;
+ mdb_cursor_init(&mc, txn, i, &mx);
+ if (txn->mt_dbs[i].md_root == P_INVALID)
+ continue;
+ count += txn->mt_dbs[i].md_branch_pages +
+ txn->mt_dbs[i].md_leaf_pages +
+ txn->mt_dbs[i].md_overflow_pages;
+ if (txn->mt_dbs[i].md_flags & MDB_DUPSORT) {
+ rc = mdb_page_search(&mc, NULL, MDB_PS_FIRST);
+ for (; rc == MDB_SUCCESS; rc = mdb_cursor_sibling(&mc, 1)) {
+ unsigned j;
+ MDB_page *mp;
+ mp = mc.mc_pg[mc.mc_top];
+ for (j=0; j<NUMKEYS(mp); j++) {
+ MDB_node *leaf = NODEPTR(mp, j);
+ if (leaf->mn_flags & F_SUBDATA) {
+ MDB_db db;
+ memcpy(&db, NODEDATA(leaf), sizeof(db));
+ count += db.md_branch_pages + db.md_leaf_pages +
+ db.md_overflow_pages;
+ }
+ }
+ }
+ mdb_tassert(txn, rc == MDB_NOTFOUND);
+ }
+ }
+ if (freecount + count + NUM_METAS != txn->mt_next_pgno) {
+ fprintf(stderr, "audit: %"Z"u freecount: %"Z"u count: %"Z"u total: %"Z"u next_pgno: %"Z"u\n",
+ txn->mt_txnid, freecount, count+NUM_METAS,
+ freecount+count+NUM_METAS, txn->mt_next_pgno);
+ }
+}
+#endif
+
+int
+mdb_cmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b)
+{
+ return txn->mt_dbxs[dbi].md_cmp(a, b);
+}
+
+int
+mdb_dcmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b)
+{
+ MDB_cmp_func *dcmp = txn->mt_dbxs[dbi].md_dcmp;
+#if UINT_MAX < SIZE_MAX
+ if (dcmp == mdb_cmp_int && a->mv_size == sizeof(size_t))
+ dcmp = mdb_cmp_clong;
+#endif
+ return dcmp(a, b);
+}
+
+/** Allocate memory for a page.
+ * Re-use old malloc'd pages first for singletons, otherwise just malloc.
+ * Set #MDB_TXN_ERROR on failure.
+ */
+static MDB_page *
+mdb_page_malloc(MDB_txn *txn, unsigned num)
+{
+ MDB_env *env = txn->mt_env;
+ MDB_page *ret = env->me_dpages;
+ size_t psize = env->me_psize, sz = psize, off;
+ /* For ! #MDB_NOMEMINIT, psize counts how much to init.
+ * For a single page alloc, we init everything after the page header.
+ * For multi-page, we init the final page; if the caller needed that
+ * many pages they will be filling in at least up to the last page.
+ */
+ if (num == 1) {
+ if (ret) {
+ VGMEMP_ALLOC(env, ret, sz);
+ VGMEMP_DEFINED(ret, sizeof(ret->mp_next));
+ env->me_dpages = ret->mp_next;
+ return ret;
+ }
+ psize -= off = PAGEHDRSZ;
+ } else {
+ sz *= num;
+ off = sz - psize;
+ }
+ if ((ret = malloc(sz)) != NULL) {
+ VGMEMP_ALLOC(env, ret, sz);
+ if (!(env->me_flags & MDB_NOMEMINIT)) {
+ memset((char *)ret + off, 0, psize);
+ ret->mp_pad = 0;
+ }
+ } else {
+ txn->mt_flags |= MDB_TXN_ERROR;
+ }
+ return ret;
+}
+/** Free a single page.
+ * Saves single pages to a list, for future reuse.
+ * (This is not used for multi-page overflow pages.)
+ */
+static void
+mdb_page_free(MDB_env *env, MDB_page *mp)
+{
+ mp->mp_next = env->me_dpages;
+ VGMEMP_FREE(env, mp);
+ env->me_dpages = mp;
+}
+
+/** Free a dirty page */
+static void
+mdb_dpage_free(MDB_env *env, MDB_page *dp)
+{
+ if (!IS_OVERFLOW(dp) || dp->mp_pages == 1) {
+ mdb_page_free(env, dp);
+ } else {
+ /* large pages just get freed directly */
+ VGMEMP_FREE(env, dp);
+ free(dp);
+ }
+}
+
+/** Return all dirty pages to dpage list */
+static void
+mdb_dlist_free(MDB_txn *txn)
+{
+ MDB_env *env = txn->mt_env;
+ MDB_ID2L dl = txn->mt_u.dirty_list;
+ unsigned i, n = dl[0].mid;
+
+ for (i = 1; i <= n; i++) {
+ mdb_dpage_free(env, dl[i].mptr);
+ }
+ dl[0].mid = 0;
+}
+
+/** Loosen or free a single page.
+ * Saves single pages to a list for future reuse
+ * in this same txn. It has been pulled from the freeDB
+ * and already resides on the dirty list, but has been
+ * deleted. Use these pages first before pulling again
+ * from the freeDB.
+ *
+ * If the page wasn't dirtied in this txn, just add it
+ * to this txn's free list.
+ */
+static int
+mdb_page_loose(MDB_cursor *mc, MDB_page *mp)
+{
+ int loose = 0;
+ pgno_t pgno = mp->mp_pgno;
+ MDB_txn *txn = mc->mc_txn;
+
+ if ((mp->mp_flags & P_DIRTY) && mc->mc_dbi != FREE_DBI) {
+ if (txn->mt_parent) {
+ MDB_ID2 *dl = txn->mt_u.dirty_list;
+ /* If txn has a parent, make sure the page is in our
+ * dirty list.
+ */
+ if (dl[0].mid) {
+ unsigned x = mdb_mid2l_search(dl, pgno);
+ if (x <= dl[0].mid && dl[x].mid == pgno) {
+ if (mp != dl[x].mptr) { /* bad cursor? */
+ mc->mc_flags &= ~(C_INITIALIZED|C_EOF);
+ txn->mt_flags |= MDB_TXN_ERROR;
+ return MDB_CORRUPTED;
+ }
+ /* ok, it's ours */
+ loose = 1;
+ }
+ }
+ } else {
+ /* no parent txn, so it's just ours */
+ loose = 1;
+ }
+ }
+ if (loose) {
+ DPRINTF(("loosen db %d page %"Z"u", DDBI(mc),
+ mp->mp_pgno));
+ NEXT_LOOSE_PAGE(mp) = txn->mt_loose_pgs;
+ txn->mt_loose_pgs = mp;
+ txn->mt_loose_count++;
+ mp->mp_flags |= P_LOOSE;
+ } else {
+ int rc = mdb_midl_append(&txn->mt_free_pgs, pgno);
+ if (rc)
+ return rc;
+ }
+
+ return MDB_SUCCESS;
+}
+
+/** Set or clear P_KEEP in dirty, non-overflow, non-sub pages watched by txn.
+ * @param[in] mc A cursor handle for the current operation.
+ * @param[in] pflags Flags of the pages to update:
+ * P_DIRTY to set P_KEEP, P_DIRTY|P_KEEP to clear it.
+ * @param[in] all No shortcuts. Needed except after a full #mdb_page_flush().
+ * @return 0 on success, non-zero on failure.
+ */
+static int
+mdb_pages_xkeep(MDB_cursor *mc, unsigned pflags, int all)
+{
+ enum { Mask = P_SUBP|P_DIRTY|P_LOOSE|P_KEEP };
+ MDB_txn *txn = mc->mc_txn;
+ MDB_cursor *m3, *m0 = mc;
+ MDB_xcursor *mx;
+ MDB_page *dp, *mp;
+ MDB_node *leaf;
+ unsigned i, j;
+ int rc = MDB_SUCCESS, level;
+
+ /* Mark pages seen by cursors */
+ if (mc->mc_flags & C_UNTRACK)
+ mc = NULL; /* will find mc in mt_cursors */
+ for (i = txn->mt_numdbs;; mc = txn->mt_cursors[--i]) {
+ for (; mc; mc=mc->mc_next) {
+ if (!(mc->mc_flags & C_INITIALIZED))
+ continue;
+ for (m3 = mc;; m3 = &mx->mx_cursor) {
+ mp = NULL;
+ for (j=0; j<m3->mc_snum; j++) {
+ mp = m3->mc_pg[j];
+ if ((mp->mp_flags & Mask) == pflags)
+ mp->mp_flags ^= P_KEEP;
+ }
+ mx = m3->mc_xcursor;
+ /* Proceed to mx if it is at a sub-database */
+ if (! (mx && (mx->mx_cursor.mc_flags & C_INITIALIZED)))
+ break;
+ if (! (mp && (mp->mp_flags & P_LEAF)))
+ break;
+ leaf = NODEPTR(mp, m3->mc_ki[j-1]);
+ if (!(leaf->mn_flags & F_SUBDATA))
+ break;
+ }
+ }
+ if (i == 0)
+ break;
+ }
+
+ if (all) {
+ /* Mark dirty root pages */
+ for (i=0; i<txn->mt_numdbs; i++) {
+ if (txn->mt_dbflags[i] & DB_DIRTY) {
+ pgno_t pgno = txn->mt_dbs[i].md_root;
+ if (pgno == P_INVALID)
+ continue;
+ if ((rc = mdb_page_get(m0, pgno, &dp, &level)) != MDB_SUCCESS)
+ break;
+ if ((dp->mp_flags & Mask) == pflags && level <= 1)
+ dp->mp_flags ^= P_KEEP;
+ }
+ }
+ }
+
+ return rc;
+}
+
+static int mdb_page_flush(MDB_txn *txn, int keep);
+
+/** Spill pages from the dirty list back to disk.
+ * This is intended to prevent running into #MDB_TXN_FULL situations,
+ * but note that they may still occur in a few cases:
+ * 1) our estimate of the txn size could be too small. Currently this
+ * seems unlikely, except with a large number of #MDB_MULTIPLE items.
+ * 2) child txns may run out of space if their parents dirtied a
+ * lot of pages and never spilled them. TODO: we probably should do
+ * a preemptive spill during #mdb_txn_begin() of a child txn, if
+ * the parent's dirty_room is below a given threshold.
+ *
+ * Otherwise, if not using nested txns, it is expected that apps will
+ * not run into #MDB_TXN_FULL any more. The pages are flushed to disk
+ * the same way as for a txn commit, e.g. their P_DIRTY flag is cleared.
+ * If the txn never references them again, they can be left alone.
+ * If the txn only reads them, they can be used without any fuss.
+ * If the txn writes them again, they can be dirtied immediately without
+ * going thru all of the work of #mdb_page_touch(). Such references are
+ * handled by #mdb_page_unspill().
+ *
+ * Also note, we never spill DB root pages, nor pages of active cursors,
+ * because we'll need these back again soon anyway. And in nested txns,
+ * we can't spill a page in a child txn if it was already spilled in a
+ * parent txn. That would alter the parent txns' data even though
+ * the child hasn't committed yet, and we'd have no way to undo it if
+ * the child aborted.
+ *
+ * @param[in] m0 cursor A cursor handle identifying the transaction and
+ * database for which we are checking space.
+ * @param[in] key For a put operation, the key being stored.
+ * @param[in] data For a put operation, the data being stored.
+ * @return 0 on success, non-zero on failure.
+ */
+static int
+mdb_page_spill(MDB_cursor *m0, MDB_val *key, MDB_val *data)
+{
+ MDB_txn *txn = m0->mc_txn;
+ MDB_page *dp;
+ MDB_ID2L dl = txn->mt_u.dirty_list;
+ unsigned int i, j, need;
+ int rc;
+
+ if (m0->mc_flags & C_SUB)
+ return MDB_SUCCESS;
+
+ /* Estimate how much space this op will take */
+ i = m0->mc_db->md_depth;
+ /* Named DBs also dirty the main DB */
+ if (m0->mc_dbi >= CORE_DBS)
+ i += txn->mt_dbs[MAIN_DBI].md_depth;
+ /* For puts, roughly factor in the key+data size */
+ if (key)
+ i += (LEAFSIZE(key, data) + txn->mt_env->me_psize) / txn->mt_env->me_psize;
+ i += i; /* double it for good measure */
+ need = i;
+
+ if (txn->mt_dirty_room > i)
+ return MDB_SUCCESS;
+
+ if (!txn->mt_spill_pgs) {
+ txn->mt_spill_pgs = mdb_midl_alloc(MDB_IDL_UM_MAX);
+ if (!txn->mt_spill_pgs)
+ return ENOMEM;
+ } else {
+ /* purge deleted slots */
+ MDB_IDL sl = txn->mt_spill_pgs;
+ unsigned int num = sl[0];
+ j=0;
+ for (i=1; i<=num; i++) {
+ if (!(sl[i] & 1))
+ sl[++j] = sl[i];
+ }
+ sl[0] = j;
+ }
+
+ /* Preserve pages which may soon be dirtied again */
+ if ((rc = mdb_pages_xkeep(m0, P_DIRTY, 1)) != MDB_SUCCESS)
+ goto done;
+
+ /* Less aggressive spill - we originally spilled the entire dirty list,
+ * with a few exceptions for cursor pages and DB root pages. But this
+ * turns out to be a lot of wasted effort because in a large txn many
+ * of those pages will need to be used again. So now we spill only 1/8th
+ * of the dirty pages. Testing revealed this to be a good tradeoff,
+ * better than 1/2, 1/4, or 1/10.
+ */
+ if (need < MDB_IDL_UM_MAX / 8)
+ need = MDB_IDL_UM_MAX / 8;
+
+ /* Save the page IDs of all the pages we're flushing */
+ /* flush from the tail forward, this saves a lot of shifting later on. */
+ for (i=dl[0].mid; i && need; i--) {
+ MDB_ID pn = dl[i].mid << 1;
+ dp = dl[i].mptr;
+ if (dp->mp_flags & (P_LOOSE|P_KEEP))
+ continue;
+ /* Can't spill twice, make sure it's not already in a parent's
+ * spill list.
+ */
+ if (txn->mt_parent) {
+ MDB_txn *tx2;
+ for (tx2 = txn->mt_parent; tx2; tx2 = tx2->mt_parent) {
+ if (tx2->mt_spill_pgs) {
+ j = mdb_midl_search(tx2->mt_spill_pgs, pn);
+ if (j <= tx2->mt_spill_pgs[0] && tx2->mt_spill_pgs[j] == pn) {
+ dp->mp_flags |= P_KEEP;
+ break;
+ }
+ }
+ }
+ if (tx2)
+ continue;
+ }
+ if ((rc = mdb_midl_append(&txn->mt_spill_pgs, pn)))
+ goto done;
+ need--;
+ }
+ mdb_midl_sort(txn->mt_spill_pgs);
+
+ /* Flush the spilled part of dirty list */
+ if ((rc = mdb_page_flush(txn, i)) != MDB_SUCCESS)
+ goto done;
+
+ /* Reset any dirty pages we kept that page_flush didn't see */
+ rc = mdb_pages_xkeep(m0, P_DIRTY|P_KEEP, i);
+
+done:
+ txn->mt_flags |= rc ? MDB_TXN_ERROR : MDB_TXN_SPILLS;
+ return rc;
+}
+
+/** Find oldest txnid still referenced. Expects txn->mt_txnid > 0. */
+static txnid_t
+mdb_find_oldest(MDB_txn *txn)
+{
+ int i;
+ txnid_t mr, oldest = txn->mt_txnid - 1;
+ if (txn->mt_env->me_txns) {
+ MDB_reader *r = txn->mt_env->me_txns->mti_readers;
+ for (i = txn->mt_env->me_txns->mti_numreaders; --i >= 0; ) {
+ if (r[i].mr_pid) {
+ mr = r[i].mr_txnid;
+ if (oldest > mr)
+ oldest = mr;
+ }
+ }
+ }
+ return oldest;
+}
+
+/** Add a page to the txn's dirty list */
+static void
+mdb_page_dirty(MDB_txn *txn, MDB_page *mp)
+{
+ MDB_ID2 mid;
+ int rc, (*insert)(MDB_ID2L, MDB_ID2 *);
+
+ if (txn->mt_flags & MDB_TXN_WRITEMAP) {
+ insert = mdb_mid2l_append;
+ } else {
+ insert = mdb_mid2l_insert;
+ }
+ mid.mid = mp->mp_pgno;
+ mid.mptr = mp;
+ rc = insert(txn->mt_u.dirty_list, &mid);
+ mdb_tassert(txn, rc == 0);
+ txn->mt_dirty_room--;
+}
+
+/** Allocate page numbers and memory for writing. Maintain me_pglast,
+ * me_pghead and mt_next_pgno. Set #MDB_TXN_ERROR on failure.
+ *
+ * If there are free pages available from older transactions, they
+ * are re-used first. Otherwise allocate a new page at mt_next_pgno.
+ * Do not modify the freedB, just merge freeDB records into me_pghead[]
+ * and move me_pglast to say which records were consumed. Only this
+ * function can create me_pghead and move me_pglast/mt_next_pgno.
+ * @param[in] mc cursor A cursor handle identifying the transaction and
+ * database for which we are allocating.
+ * @param[in] num the number of pages to allocate.
+ * @param[out] mp Address of the allocated page(s). Requests for multiple pages
+ * will always be satisfied by a single contiguous chunk of memory.
+ * @return 0 on success, non-zero on failure.
+ */
+static int
+mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp)
+{
+#ifdef MDB_PARANOID /* Seems like we can ignore this now */
+ /* Get at most <Max_retries> more freeDB records once me_pghead
+ * has enough pages. If not enough, use new pages from the map.
+ * If <Paranoid> and mc is updating the freeDB, only get new
+ * records if me_pghead is empty. Then the freelist cannot play
+ * catch-up with itself by growing while trying to save it.
+ */
+ enum { Paranoid = 1, Max_retries = 500 };
+#else
+ enum { Paranoid = 0, Max_retries = INT_MAX /*infinite*/ };
+#endif
+ int rc, retry = num * 60;
+ MDB_txn *txn = mc->mc_txn;
+ MDB_env *env = txn->mt_env;
+ pgno_t pgno, *mop = env->me_pghead;
+ unsigned i, j, mop_len = mop ? mop[0] : 0, n2 = num-1;
+ MDB_page *np;
+ txnid_t oldest = 0, last;
+ MDB_cursor_op op;
+ MDB_cursor m2;
+ int found_old = 0;
+
+ /* If there are any loose pages, just use them */
+ if (num == 1 && txn->mt_loose_pgs) {
+ np = txn->mt_loose_pgs;
+ txn->mt_loose_pgs = NEXT_LOOSE_PAGE(np);
+ txn->mt_loose_count--;
+ DPRINTF(("db %d use loose page %"Z"u", DDBI(mc),
+ np->mp_pgno));
+ *mp = np;
+ return MDB_SUCCESS;
+ }
+
+ *mp = NULL;
+
+ /* If our dirty list is already full, we can't do anything */
+ if (txn->mt_dirty_room == 0) {
+ rc = MDB_TXN_FULL;
+ goto fail;
+ }
+
+ for (op = MDB_FIRST;; op = MDB_NEXT) {
+ MDB_val key, data;
+ MDB_node *leaf;
+ pgno_t *idl;
+
+ /* Seek a big enough contiguous page range. Prefer
+ * pages at the tail, just truncating the list.
+ */
+ if (mop_len > n2) {
+ i = mop_len;
+ do {
+ pgno = mop[i];
+ if (mop[i-n2] == pgno+n2)
+ goto search_done;
+ } while (--i > n2);
+ if (--retry < 0)
+ break;
+ }
+
+ if (op == MDB_FIRST) { /* 1st iteration */
+ /* Prepare to fetch more and coalesce */
+ last = env->me_pglast;
+ oldest = env->me_pgoldest;
+ mdb_cursor_init(&m2, txn, FREE_DBI, NULL);
+ if (last) {
+ op = MDB_SET_RANGE;
+ key.mv_data = &last; /* will look up last+1 */
+ key.mv_size = sizeof(last);
+ }
+ if (Paranoid && mc->mc_dbi == FREE_DBI)
+ retry = -1;
+ }
+ if (Paranoid && retry < 0 && mop_len)
+ break;
+
+ last++;
+ /* Do not fetch more if the record will be too recent */
+ if (oldest <= last) {
+ if (!found_old) {
+ oldest = mdb_find_oldest(txn);
+ env->me_pgoldest = oldest;
+ found_old = 1;
+ }
+ if (oldest <= last)
+ break;
+ }
+ rc = mdb_cursor_get(&m2, &key, NULL, op);
+ if (rc) {
+ if (rc == MDB_NOTFOUND)
+ break;
+ goto fail;
+ }
+ last = *(txnid_t*)key.mv_data;
+ if (oldest <= last) {
+ if (!found_old) {
+ oldest = mdb_find_oldest(txn);
+ env->me_pgoldest = oldest;
+ found_old = 1;
+ }
+ if (oldest <= last)
+ break;
+ }
+ np = m2.mc_pg[m2.mc_top];
+ leaf = NODEPTR(np, m2.mc_ki[m2.mc_top]);
+ if ((rc = mdb_node_read(&m2, leaf, &data)) != MDB_SUCCESS)
+ goto fail;
+
+ idl = (MDB_ID *) data.mv_data;
+ i = idl[0];
+ if (!mop) {
+ if (!(env->me_pghead = mop = mdb_midl_alloc(i))) {
+ rc = ENOMEM;
+ goto fail;
+ }
+ } else {
+ if ((rc = mdb_midl_need(&env->me_pghead, i)) != 0)
+ goto fail;
+ mop = env->me_pghead;
+ }
+ env->me_pglast = last;
+#if (MDB_DEBUG) > 1
+ DPRINTF(("IDL read txn %"Z"u root %"Z"u num %u",
+ last, txn->mt_dbs[FREE_DBI].md_root, i));
+ for (j = i; j; j--)
+ DPRINTF(("IDL %"Z"u", idl[j]));
+#endif
+ /* Merge in descending sorted order */
+ mdb_midl_xmerge(mop, idl);
+ mop_len = mop[0];
+ }
+
+ /* Use new pages from the map when nothing suitable in the freeDB */
+ i = 0;
+ pgno = txn->mt_next_pgno;
+ if (pgno + num >= env->me_maxpg) {
+ DPUTS("DB size maxed out");
+ rc = MDB_MAP_FULL;
+ goto fail;
+ }
+
+search_done:
+ if (env->me_flags & MDB_WRITEMAP) {
+ np = (MDB_page *)(env->me_map + env->me_psize * pgno);
+ } else {
+ if (!(np = mdb_page_malloc(txn, num))) {
+ rc = ENOMEM;
+ goto fail;
+ }
+ }
+ if (i) {
+ mop[0] = mop_len -= num;
+ /* Move any stragglers down */
+ for (j = i-num; j < mop_len; )
+ mop[++j] = mop[++i];
+ } else {
+ txn->mt_next_pgno = pgno + num;
+ }
+ np->mp_pgno = pgno;
+ mdb_page_dirty(txn, np);
+ *mp = np;
+
+ return MDB_SUCCESS;
+
+fail:
+ txn->mt_flags |= MDB_TXN_ERROR;
+ return rc;
+}
+
+/** Copy the used portions of a non-overflow page.
+ * @param[in] dst page to copy into
+ * @param[in] src page to copy from
+ * @param[in] psize size of a page
+ */
+static void
+mdb_page_copy(MDB_page *dst, MDB_page *src, unsigned int psize)
+{
+ enum { Align = sizeof(pgno_t) };
+ indx_t upper = src->mp_upper, lower = src->mp_lower, unused = upper-lower;
+
+ /* If page isn't full, just copy the used portion. Adjust
+ * alignment so memcpy may copy words instead of bytes.
+ */
+ if ((unused &= -Align) && !IS_LEAF2(src)) {
+ upper = (upper + PAGEBASE) & -Align;
+ memcpy(dst, src, (lower + PAGEBASE + (Align-1)) & -Align);
+ memcpy((pgno_t *)((char *)dst+upper), (pgno_t *)((char *)src+upper),
+ psize - upper);
+ } else {
+ memcpy(dst, src, psize - unused);
+ }
+}
+
+/** Pull a page off the txn's spill list, if present.
+ * If a page being referenced was spilled to disk in this txn, bring
+ * it back and make it dirty/writable again.
+ * @param[in] txn the transaction handle.
+ * @param[in] mp the page being referenced. It must not be dirty.
+ * @param[out] ret the writable page, if any. ret is unchanged if
+ * mp wasn't spilled.
+ */
+static int
+mdb_page_unspill(MDB_txn *txn, MDB_page *mp, MDB_page **ret)
+{
+ MDB_env *env = txn->mt_env;
+ const MDB_txn *tx2;
+ unsigned x;
+ pgno_t pgno = mp->mp_pgno, pn = pgno << 1;
+
+ for (tx2 = txn; tx2; tx2=tx2->mt_parent) {
+ if (!tx2->mt_spill_pgs)
+ continue;
+ x = mdb_midl_search(tx2->mt_spill_pgs, pn);
+ if (x <= tx2->mt_spill_pgs[0] && tx2->mt_spill_pgs[x] == pn) {
+ MDB_page *np;
+ int num;
+ if (txn->mt_dirty_room == 0)
+ return MDB_TXN_FULL;
+ if (IS_OVERFLOW(mp))
+ num = mp->mp_pages;
+ else
+ num = 1;
+ if (env->me_flags & MDB_WRITEMAP) {
+ np = mp;
+ } else {
+ np = mdb_page_malloc(txn, num);
+ if (!np)
+ return ENOMEM;
+ if (num > 1)
+ memcpy(np, mp, num * env->me_psize);
+ else
+ mdb_page_copy(np, mp, env->me_psize);
+ }
+ if (tx2 == txn) {
+ /* If in current txn, this page is no longer spilled.
+ * If it happens to be the last page, truncate the spill list.
+ * Otherwise mark it as deleted by setting the LSB.
+ */
+ if (x == txn->mt_spill_pgs[0])
+ txn->mt_spill_pgs[0]--;
+ else
+ txn->mt_spill_pgs[x] |= 1;
+ } /* otherwise, if belonging to a parent txn, the
+ * page remains spilled until child commits
+ */
+
+ mdb_page_dirty(txn, np);
+ np->mp_flags |= P_DIRTY;
+ *ret = np;
+ break;
+ }
+ }
+ return MDB_SUCCESS;
+}
+
+/** Touch a page: make it dirty and re-insert into tree with updated pgno.
+ * Set #MDB_TXN_ERROR on failure.
+ * @param[in] mc cursor pointing to the page to be touched
+ * @return 0 on success, non-zero on failure.
+ */
+static int
+mdb_page_touch(MDB_cursor *mc)
+{
+ MDB_page *mp = mc->mc_pg[mc->mc_top], *np;
+ MDB_txn *txn = mc->mc_txn;
+ MDB_cursor *m2, *m3;
+ pgno_t pgno;
+ int rc;
+
+ if (!F_ISSET(mp->mp_flags, P_DIRTY)) {
+ if (txn->mt_flags & MDB_TXN_SPILLS) {
+ np = NULL;
+ rc = mdb_page_unspill(txn, mp, &np);
+ if (rc)
+ goto fail;
+ if (np)
+ goto done;
+ }
+ if ((rc = mdb_midl_need(&txn->mt_free_pgs, 1)) ||
+ (rc = mdb_page_alloc(mc, 1, &np)))
+ goto fail;
+ pgno = np->mp_pgno;
+ DPRINTF(("touched db %d page %"Z"u -> %"Z"u", DDBI(mc),
+ mp->mp_pgno, pgno));
+ mdb_cassert(mc, mp->mp_pgno != pgno);
+ mdb_midl_xappend(txn->mt_free_pgs, mp->mp_pgno);
+ /* Update the parent page, if any, to point to the new page */
+ if (mc->mc_top) {
+ MDB_page *parent = mc->mc_pg[mc->mc_top-1];
+ MDB_node *node = NODEPTR(parent, mc->mc_ki[mc->mc_top-1]);
+ SETPGNO(node, pgno);
+ } else {
+ mc->mc_db->md_root = pgno;
+ }
+ } else if (txn->mt_parent && !IS_SUBP(mp)) {
+ MDB_ID2 mid, *dl = txn->mt_u.dirty_list;
+ pgno = mp->mp_pgno;
+ /* If txn has a parent, make sure the page is in our
+ * dirty list.
+ */
+ if (dl[0].mid) {
+ unsigned x = mdb_mid2l_search(dl, pgno);
+ if (x <= dl[0].mid && dl[x].mid == pgno) {
+ if (mp != dl[x].mptr) { /* bad cursor? */
+ mc->mc_flags &= ~(C_INITIALIZED|C_EOF);
+ txn->mt_flags |= MDB_TXN_ERROR;
+ return MDB_CORRUPTED;
+ }
+ return 0;
+ }
+ }
+ mdb_cassert(mc, dl[0].mid < MDB_IDL_UM_MAX);
+ /* No - copy it */
+ np = mdb_page_malloc(txn, 1);
+ if (!np)
+ return ENOMEM;
+ mid.mid = pgno;
+ mid.mptr = np;
+ rc = mdb_mid2l_insert(dl, &mid);
+ mdb_cassert(mc, rc == 0);
+ } else {
+ return 0;
+ }
+
+ mdb_page_copy(np, mp, txn->mt_env->me_psize);
+ np->mp_pgno = pgno;
+ np->mp_flags |= P_DIRTY;
+
+done:
+ /* Adjust cursors pointing to mp */
+ mc->mc_pg[mc->mc_top] = np;
+ m2 = txn->mt_cursors[mc->mc_dbi];
+ if (mc->mc_flags & C_SUB) {
+ for (; m2; m2=m2->mc_next) {
+ m3 = &m2->mc_xcursor->mx_cursor;
+ if (m3->mc_snum < mc->mc_snum) continue;
+ if (m3->mc_pg[mc->mc_top] == mp)
+ m3->mc_pg[mc->mc_top] = np;
+ }
+ } else {
+ for (; m2; m2=m2->mc_next) {
+ if (m2->mc_snum < mc->mc_snum) continue;
+ if (m2 == mc) continue;
+ if (m2->mc_pg[mc->mc_top] == mp) {
+ m2->mc_pg[mc->mc_top] = np;
+ if (IS_LEAF(np))
+ XCURSOR_REFRESH(m2, mc->mc_top, np);
+ }
+ }
+ }
+ return 0;
+
+fail:
+ txn->mt_flags |= MDB_TXN_ERROR;
+ return rc;
+}
+
+int
+mdb_env_sync(MDB_env *env, int force)
+{
+ int rc = 0;
+ if (env->me_flags & MDB_RDONLY)
+ return EACCES;
+ if (force || !F_ISSET(env->me_flags, MDB_NOSYNC)) {
+ if (env->me_flags & MDB_WRITEMAP) {
+ int flags = ((env->me_flags & MDB_MAPASYNC) && !force)
+ ? MS_ASYNC : MS_SYNC;
+ if (MDB_MSYNC(env->me_map, env->me_mapsize, flags))
+ rc = ErrCode();
+#ifdef _WIN32
+ else if (flags == MS_SYNC && MDB_FDATASYNC(env->me_fd))
+ rc = ErrCode();
+#endif
+ } else {
+#ifdef BROKEN_FDATASYNC
+ if (env->me_flags & MDB_FSYNCONLY) {
+ if (fsync(env->me_fd))
+ rc = ErrCode();
+ } else
+#endif
+ if (MDB_FDATASYNC(env->me_fd))
+ rc = ErrCode();
+ }
+ }
+ return rc;
+}
+
+/** Back up parent txn's cursors, then grab the originals for tracking */
+static int
+mdb_cursor_shadow(MDB_txn *src, MDB_txn *dst)
+{
+ MDB_cursor *mc, *bk;
+ MDB_xcursor *mx;
+ size_t size;
+ int i;
+
+ for (i = src->mt_numdbs; --i >= 0; ) {
+ if ((mc = src->mt_cursors[i]) != NULL) {
+ size = sizeof(MDB_cursor);
+ if (mc->mc_xcursor)
+ size += sizeof(MDB_xcursor);
+ for (; mc; mc = bk->mc_next) {
+ bk = malloc(size);
+ if (!bk)
+ return ENOMEM;
+ *bk = *mc;
+ mc->mc_backup = bk;
+ mc->mc_db = &dst->mt_dbs[i];
+ /* Kill pointers into src to reduce abuse: The
+ * user may not use mc until dst ends. But we need a valid
+ * txn pointer here for cursor fixups to keep working.
+ */
+ mc->mc_txn = dst;
+ mc->mc_dbflag = &dst->mt_dbflags[i];
+ if ((mx = mc->mc_xcursor) != NULL) {
+ *(MDB_xcursor *)(bk+1) = *mx;
+ mx->mx_cursor.mc_txn = dst;
+ }
+ mc->mc_next = dst->mt_cursors[i];
+ dst->mt_cursors[i] = mc;
+ }
+ }
+ }
+ return MDB_SUCCESS;
+}
+
+/** Close this write txn's cursors, give parent txn's cursors back to parent.
+ * @param[in] txn the transaction handle.
+ * @param[in] merge true to keep changes to parent cursors, false to revert.
+ * @return 0 on success, non-zero on failure.
+ */
+static void
+mdb_cursors_close(MDB_txn *txn, unsigned merge)
+{
+ MDB_cursor **cursors = txn->mt_cursors, *mc, *next, *bk;
+ MDB_xcursor *mx;
+ int i;
+
+ for (i = txn->mt_numdbs; --i >= 0; ) {
+ for (mc = cursors[i]; mc; mc = next) {
+ next = mc->mc_next;
+ if ((bk = mc->mc_backup) != NULL) {
+ if (merge) {
+ /* Commit changes to parent txn */
+ mc->mc_next = bk->mc_next;
+ mc->mc_backup = bk->mc_backup;
+ mc->mc_txn = bk->mc_txn;
+ mc->mc_db = bk->mc_db;
+ mc->mc_dbflag = bk->mc_dbflag;
+ if ((mx = mc->mc_xcursor) != NULL)
+ mx->mx_cursor.mc_txn = bk->mc_txn;
+ } else {
+ /* Abort nested txn */
+ *mc = *bk;
+ if ((mx = mc->mc_xcursor) != NULL)
+ *mx = *(MDB_xcursor *)(bk+1);
+ }
+ mc = bk;
+ }
+ /* Only malloced cursors are permanently tracked. */
+ free(mc);
+ }
+ cursors[i] = NULL;
+ }
+}
+
+#if !(MDB_PIDLOCK) /* Currently the same as defined(_WIN32) */
+enum Pidlock_op {
+ Pidset, Pidcheck
+};
+#else
+enum Pidlock_op {
+ Pidset = F_SETLK, Pidcheck = F_GETLK
+};
+#endif
+
+/** Set or check a pid lock. Set returns 0 on success.
+ * Check returns 0 if the process is certainly dead, nonzero if it may
+ * be alive (the lock exists or an error happened so we do not know).
+ *
+ * On Windows Pidset is a no-op, we merely check for the existence
+ * of the process with the given pid. On POSIX we use a single byte
+ * lock on the lockfile, set at an offset equal to the pid.
+ */
+static int
+mdb_reader_pid(MDB_env *env, enum Pidlock_op op, MDB_PID_T pid)
+{
+#if !(MDB_PIDLOCK) /* Currently the same as defined(_WIN32) */
+ int ret = 0;
+ HANDLE h;
+ if (op == Pidcheck) {
+ h = OpenProcess(env->me_pidquery, FALSE, pid);
+ /* No documented "no such process" code, but other program use this: */
+ if (!h)
+ return ErrCode() != ERROR_INVALID_PARAMETER;
+ /* A process exists until all handles to it close. Has it exited? */
+ ret = WaitForSingleObject(h, 0) != 0;
+ CloseHandle(h);
+ }
+ return ret;
+#else
+ for (;;) {
+ int rc;
+ struct flock lock_info;
+ memset(&lock_info, 0, sizeof(lock_info));
+ lock_info.l_type = F_WRLCK;
+ lock_info.l_whence = SEEK_SET;
+ lock_info.l_start = pid;
+ lock_info.l_len = 1;
+ if ((rc = fcntl(env->me_lfd, op, &lock_info)) == 0) {
+ if (op == F_GETLK && lock_info.l_type != F_UNLCK)
+ rc = -1;
+ } else if ((rc = ErrCode()) == EINTR) {
+ continue;
+ }
+ return rc;
+ }
+#endif
+}
+
+/** Common code for #mdb_txn_begin() and #mdb_txn_renew().
+ * @param[in] txn the transaction handle to initialize
+ * @return 0 on success, non-zero on failure.
+ */
+static int
+mdb_txn_renew0(MDB_txn *txn)
+{
+ MDB_env *env = txn->mt_env;
+ MDB_txninfo *ti = env->me_txns;
+ MDB_meta *meta;
+ unsigned int i, nr, flags = txn->mt_flags;
+ uint16_t x;
+ int rc, new_notls = 0;
+
+ if ((flags &= MDB_TXN_RDONLY) != 0) {
+ if (!ti) {
+ meta = mdb_env_pick_meta(env);
+ txn->mt_txnid = meta->mm_txnid;
+ txn->mt_u.reader = NULL;
+ } else {
+ MDB_reader *r = (env->me_flags & MDB_NOTLS) ? txn->mt_u.reader :
+ pthread_getspecific(env->me_txkey);
+ if (r) {
+ if (r->mr_pid != env->me_pid || r->mr_txnid != (txnid_t)-1)
+ return MDB_BAD_RSLOT;
+ } else {
+ MDB_PID_T pid = env->me_pid;
+ MDB_THR_T tid = pthread_self();
+ mdb_mutexref_t rmutex = env->me_rmutex;
+
+ if (!env->me_live_reader) {
+ rc = mdb_reader_pid(env, Pidset, pid);
+ if (rc)
+ return rc;
+ env->me_live_reader = 1;
+ }
+
+ if (LOCK_MUTEX(rc, env, rmutex))
+ return rc;
+ nr = ti->mti_numreaders;
+ for (i=0; i<nr; i++)
+ if (ti->mti_readers[i].mr_pid == 0)
+ break;
+ if (i == env->me_maxreaders) {
+ UNLOCK_MUTEX(rmutex);
+ return MDB_READERS_FULL;
+ }
+ r = &ti->mti_readers[i];
+ /* Claim the reader slot, carefully since other code
+ * uses the reader table un-mutexed: First reset the
+ * slot, next publish it in mti_numreaders. After
+ * that, it is safe for mdb_env_close() to touch it.
+ * When it will be closed, we can finally claim it.
+ */
+ r->mr_pid = 0;
+ r->mr_txnid = (txnid_t)-1;
+ r->mr_tid = tid;
+ if (i == nr)
+ ti->mti_numreaders = ++nr;
+ env->me_close_readers = nr;
+ r->mr_pid = pid;
+ UNLOCK_MUTEX(rmutex);
+
+ new_notls = (env->me_flags & MDB_NOTLS);
+ if (!new_notls && (rc=pthread_setspecific(env->me_txkey, r))) {
+ r->mr_pid = 0;
+ return rc;
+ }
+ }
+ do /* LY: Retry on a race, ITS#7970. */
+ r->mr_txnid = ti->mti_txnid;
+ while(r->mr_txnid != ti->mti_txnid);
+ txn->mt_txnid = r->mr_txnid;
+ txn->mt_u.reader = r;
+ meta = env->me_metas[txn->mt_txnid & 1];
+ }
+
+ } else {
+ /* Not yet touching txn == env->me_txn0, it may be active */
+ if (ti) {
+ if (LOCK_MUTEX(rc, env, env->me_wmutex))
+ return rc;
+ txn->mt_txnid = ti->mti_txnid;
+ meta = env->me_metas[txn->mt_txnid & 1];
+ } else {
+ meta = mdb_env_pick_meta(env);
+ txn->mt_txnid = meta->mm_txnid;
+ }
+ txn->mt_txnid++;
+#if MDB_DEBUG
+ if (txn->mt_txnid == mdb_debug_start)
+ mdb_debug = 1;
+#endif
+ txn->mt_child = NULL;
+ txn->mt_loose_pgs = NULL;
+ txn->mt_loose_count = 0;
+ txn->mt_dirty_room = MDB_IDL_UM_MAX;
+ txn->mt_u.dirty_list = env->me_dirty_list;
+ txn->mt_u.dirty_list[0].mid = 0;
+ txn->mt_free_pgs = env->me_free_pgs;
+ txn->mt_free_pgs[0] = 0;
+ txn->mt_spill_pgs = NULL;
+ env->me_txn = txn;
+ memcpy(txn->mt_dbiseqs, env->me_dbiseqs, env->me_maxdbs * sizeof(unsigned int));
+ }
+
+ /* Copy the DB info and flags */
+ memcpy(txn->mt_dbs, meta->mm_dbs, CORE_DBS * sizeof(MDB_db));
+
+ /* Moved to here to avoid a data race in read TXNs */
+ txn->mt_next_pgno = meta->mm_last_pg+1;
+
+ txn->mt_flags = flags;
+
+ /* Setup db info */
+ txn->mt_numdbs = env->me_numdbs;
+ for (i=CORE_DBS; i<txn->mt_numdbs; i++) {
+ x = env->me_dbflags[i];
+ txn->mt_dbs[i].md_flags = x & PERSISTENT_FLAGS;
+ txn->mt_dbflags[i] = (x & MDB_VALID) ? DB_VALID|DB_USRVALID|DB_STALE : 0;
+ }
+ txn->mt_dbflags[MAIN_DBI] = DB_VALID|DB_USRVALID;
+ txn->mt_dbflags[FREE_DBI] = DB_VALID;
+
+ if (env->me_flags & MDB_FATAL_ERROR) {
+ DPUTS("environment had fatal error, must shutdown!");
+ rc = MDB_PANIC;
+ } else if (env->me_maxpg < txn->mt_next_pgno) {
+ rc = MDB_MAP_RESIZED;
+ } else {
+ return MDB_SUCCESS;
+ }
+ mdb_txn_end(txn, new_notls /*0 or MDB_END_SLOT*/ | MDB_END_FAIL_BEGIN);
+ return rc;
+}
+
+int
+mdb_txn_renew(MDB_txn *txn)
+{
+ int rc;
+
+ if (!txn || !F_ISSET(txn->mt_flags, MDB_TXN_RDONLY|MDB_TXN_FINISHED))
+ return EINVAL;
+
+ rc = mdb_txn_renew0(txn);
+ if (rc == MDB_SUCCESS) {
+ DPRINTF(("renew txn %"Z"u%c %p on mdbenv %p, root page %"Z"u",
+ txn->mt_txnid, (txn->mt_flags & MDB_TXN_RDONLY) ? 'r' : 'w',
+ (void *)txn, (void *)txn->mt_env, txn->mt_dbs[MAIN_DBI].md_root));
+ }
+ return rc;
+}
+
+int
+mdb_txn_begin(MDB_env *env, MDB_txn *parent, unsigned int flags, MDB_txn **ret)
+{
+ MDB_txn *txn;
+ MDB_ntxn *ntxn;
+ int rc, size, tsize;
+
+ flags &= MDB_TXN_BEGIN_FLAGS;
+ flags |= env->me_flags & MDB_WRITEMAP;
+
+ if (env->me_flags & MDB_RDONLY & ~flags) /* write txn in RDONLY env */
+ return EACCES;
+
+ if (parent) {
+ /* Nested transactions: Max 1 child, write txns only, no writemap */
+ flags |= parent->mt_flags;
+ if (flags & (MDB_RDONLY|MDB_WRITEMAP|MDB_TXN_BLOCKED)) {
+ return (parent->mt_flags & MDB_TXN_RDONLY) ? EINVAL : MDB_BAD_TXN;
+ }
+ /* Child txns save MDB_pgstate and use own copy of cursors */
+ size = env->me_maxdbs * (sizeof(MDB_db)+sizeof(MDB_cursor *)+1);
+ size += tsize = sizeof(MDB_ntxn);
+ } else if (flags & MDB_RDONLY) {
+ size = env->me_maxdbs * (sizeof(MDB_db)+1);
+ size += tsize = sizeof(MDB_txn);
+ } else {
+ /* Reuse preallocated write txn. However, do not touch it until
+ * mdb_txn_renew0() succeeds, since it currently may be active.
+ */
+ txn = env->me_txn0;
+ goto renew;
+ }
+ if ((txn = calloc(1, size)) == NULL) {
+ DPRINTF(("calloc: %s", strerror(errno)));
+ return ENOMEM;
+ }
+ txn->mt_dbxs = env->me_dbxs; /* static */
+ txn->mt_dbs = (MDB_db *) ((char *)txn + tsize);
+ txn->mt_dbflags = (unsigned char *)txn + size - env->me_maxdbs;
+ txn->mt_flags = flags;
+ txn->mt_env = env;
+
+ if (parent) {
+ unsigned int i;
+ txn->mt_cursors = (MDB_cursor **)(txn->mt_dbs + env->me_maxdbs);
+ txn->mt_dbiseqs = parent->mt_dbiseqs;
+ txn->mt_u.dirty_list = malloc(sizeof(MDB_ID2)*MDB_IDL_UM_SIZE);
+ if (!txn->mt_u.dirty_list ||
+ !(txn->mt_free_pgs = mdb_midl_alloc(MDB_IDL_UM_MAX)))
+ {
+ free(txn->mt_u.dirty_list);
+ free(txn);
+ return ENOMEM;
+ }
+ txn->mt_txnid = parent->mt_txnid;
+ txn->mt_dirty_room = parent->mt_dirty_room;
+ txn->mt_u.dirty_list[0].mid = 0;
+ txn->mt_spill_pgs = NULL;
+ txn->mt_next_pgno = parent->mt_next_pgno;
+ parent->mt_flags |= MDB_TXN_HAS_CHILD;
+ parent->mt_child = txn;
+ txn->mt_parent = parent;
+ txn->mt_numdbs = parent->mt_numdbs;
+ memcpy(txn->mt_dbs, parent->mt_dbs, txn->mt_numdbs * sizeof(MDB_db));
+ /* Copy parent's mt_dbflags, but clear DB_NEW */
+ for (i=0; i<txn->mt_numdbs; i++)
+ txn->mt_dbflags[i] = parent->mt_dbflags[i] & ~DB_NEW;
+ rc = 0;
+ ntxn = (MDB_ntxn *)txn;
+ ntxn->mnt_pgstate = env->me_pgstate; /* save parent me_pghead & co */
+ if (env->me_pghead) {
+ size = MDB_IDL_SIZEOF(env->me_pghead);
+ env->me_pghead = mdb_midl_alloc(env->me_pghead[0]);
+ if (env->me_pghead)
+ memcpy(env->me_pghead, ntxn->mnt_pgstate.mf_pghead, size);
+ else
+ rc = ENOMEM;
+ }
+ if (!rc)
+ rc = mdb_cursor_shadow(parent, txn);
+ if (rc)
+ mdb_txn_end(txn, MDB_END_FAIL_BEGINCHILD);
+ } else { /* MDB_RDONLY */
+ txn->mt_dbiseqs = env->me_dbiseqs;
+renew:
+ rc = mdb_txn_renew0(txn);
+ }
+ if (rc) {
+ if (txn != env->me_txn0)
+ free(txn);
+ } else {
+ txn->mt_flags |= flags; /* could not change txn=me_txn0 earlier */
+ *ret = txn;
+ DPRINTF(("begin txn %"Z"u%c %p on mdbenv %p, root page %"Z"u",
+ txn->mt_txnid, (flags & MDB_RDONLY) ? 'r' : 'w',
+ (void *) txn, (void *) env, txn->mt_dbs[MAIN_DBI].md_root));
+ }
+
+ return rc;
+}
+
+MDB_env *
+mdb_txn_env(MDB_txn *txn)
+{
+ if(!txn) return NULL;
+ return txn->mt_env;
+}
+
+size_t
+mdb_txn_id(MDB_txn *txn)
+{
+ if(!txn) return 0;
+ return txn->mt_txnid;
+}
+
+/** Export or close DBI handles opened in this txn. */
+static void
+mdb_dbis_update(MDB_txn *txn, int keep)
+{
+ int i;
+ MDB_dbi n = txn->mt_numdbs;
+ MDB_env *env = txn->mt_env;
+ unsigned char *tdbflags = txn->mt_dbflags;
+
+ for (i = n; --i >= CORE_DBS;) {
+ if (tdbflags[i] & DB_NEW) {
+ if (keep) {
+ env->me_dbflags[i] = txn->mt_dbs[i].md_flags | MDB_VALID;
+ } else {
+ char *ptr = env->me_dbxs[i].md_name.mv_data;
+ if (ptr) {
+ env->me_dbxs[i].md_name.mv_data = NULL;
+ env->me_dbxs[i].md_name.mv_size = 0;
+ env->me_dbflags[i] = 0;
+ env->me_dbiseqs[i]++;
+ free(ptr);
+ }
+ }
+ }
+ }
+ if (keep && env->me_numdbs < n)
+ env->me_numdbs = n;
+}
+
+/** End a transaction, except successful commit of a nested transaction.
+ * May be called twice for readonly txns: First reset it, then abort.
+ * @param[in] txn the transaction handle to end
+ * @param[in] mode why and how to end the transaction
+ */
+static void
+mdb_txn_end(MDB_txn *txn, unsigned mode)
+{
+ MDB_env *env = txn->mt_env;
+#if MDB_DEBUG
+ static const char *const names[] = MDB_END_NAMES;
+#endif
+
+ /* Export or close DBI handles opened in this txn */
+ mdb_dbis_update(txn, mode & MDB_END_UPDATE);
+
+ DPRINTF(("%s txn %"Z"u%c %p on mdbenv %p, root page %"Z"u",
+ names[mode & MDB_END_OPMASK],
+ txn->mt_txnid, (txn->mt_flags & MDB_TXN_RDONLY) ? 'r' : 'w',
+ (void *) txn, (void *)env, txn->mt_dbs[MAIN_DBI].md_root));
+
+ if (F_ISSET(txn->mt_flags, MDB_TXN_RDONLY)) {
+ if (txn->mt_u.reader) {
+ txn->mt_u.reader->mr_txnid = (txnid_t)-1;
+ if (!(env->me_flags & MDB_NOTLS)) {
+ txn->mt_u.reader = NULL; /* txn does not own reader */
+ } else if (mode & MDB_END_SLOT) {
+ txn->mt_u.reader->mr_pid = 0;
+ txn->mt_u.reader = NULL;
+ } /* else txn owns the slot until it does MDB_END_SLOT */
+ }
+ txn->mt_numdbs = 0; /* prevent further DBI activity */
+ txn->mt_flags |= MDB_TXN_FINISHED;
+
+ } else if (!F_ISSET(txn->mt_flags, MDB_TXN_FINISHED)) {
+ pgno_t *pghead = env->me_pghead;
+
+ if (!(mode & MDB_END_UPDATE)) /* !(already closed cursors) */
+ mdb_cursors_close(txn, 0);
+ if (!(env->me_flags & MDB_WRITEMAP)) {
+ mdb_dlist_free(txn);
+ }
+
+ txn->mt_numdbs = 0;
+ txn->mt_flags = MDB_TXN_FINISHED;
+
+ if (!txn->mt_parent) {
+ mdb_midl_shrink(&txn->mt_free_pgs);
+ env->me_free_pgs = txn->mt_free_pgs;
+ /* me_pgstate: */
+ env->me_pghead = NULL;
+ env->me_pglast = 0;
+
+ env->me_txn = NULL;
+ mode = 0; /* txn == env->me_txn0, do not free() it */
+
+ /* The writer mutex was locked in mdb_txn_begin. */
+ if (env->me_txns)
+ UNLOCK_MUTEX(env->me_wmutex);
+ } else {
+ txn->mt_parent->mt_child = NULL;
+ txn->mt_parent->mt_flags &= ~MDB_TXN_HAS_CHILD;
+ env->me_pgstate = ((MDB_ntxn *)txn)->mnt_pgstate;
+ mdb_midl_free(txn->mt_free_pgs);
+ mdb_midl_free(txn->mt_spill_pgs);
+ free(txn->mt_u.dirty_list);
+ }
+
+ mdb_midl_free(pghead);
+ }
+
+ if (mode & MDB_END_FREE)
+ free(txn);
+}
+
+void
+mdb_txn_reset(MDB_txn *txn)
+{
+ if (txn == NULL)
+ return;
+
+ /* This call is only valid for read-only txns */
+ if (!(txn->mt_flags & MDB_TXN_RDONLY))
+ return;
+
+ mdb_txn_end(txn, MDB_END_RESET);
+}
+
+void
+mdb_txn_abort(MDB_txn *txn)
+{
+ if (txn == NULL)
+ return;
+
+ if (txn->mt_child)
+ mdb_txn_abort(txn->mt_child);
+
+ mdb_txn_end(txn, MDB_END_ABORT|MDB_END_SLOT|MDB_END_FREE);
+}
+
+/** Save the freelist as of this transaction to the freeDB.
+ * This changes the freelist. Keep trying until it stabilizes.
+ */
+static int
+mdb_freelist_save(MDB_txn *txn)
+{
+ /* env->me_pghead[] can grow and shrink during this call.
+ * env->me_pglast and txn->mt_free_pgs[] can only grow.
+ * Page numbers cannot disappear from txn->mt_free_pgs[].
+ */
+ MDB_cursor mc;
+ MDB_env *env = txn->mt_env;
+ int rc, maxfree_1pg = env->me_maxfree_1pg, more = 1;
+ txnid_t pglast = 0, head_id = 0;
+ pgno_t freecnt = 0, *free_pgs, *mop;
+ ssize_t head_room = 0, total_room = 0, mop_len, clean_limit;
+
+ mdb_cursor_init(&mc, txn, FREE_DBI, NULL);
+
+ if (env->me_pghead) {
+ /* Make sure first page of freeDB is touched and on freelist */
+ rc = mdb_page_search(&mc, NULL, MDB_PS_FIRST|MDB_PS_MODIFY);
+ if (rc && rc != MDB_NOTFOUND)
+ return rc;
+ }
+
+ if (!env->me_pghead && txn->mt_loose_pgs) {
+ /* Put loose page numbers in mt_free_pgs, since
+ * we may be unable to return them to me_pghead.
+ */
+ MDB_page *mp = txn->mt_loose_pgs;
+ if ((rc = mdb_midl_need(&txn->mt_free_pgs, txn->mt_loose_count)) != 0)
+ return rc;
+ for (; mp; mp = NEXT_LOOSE_PAGE(mp))
+ mdb_midl_xappend(txn->mt_free_pgs, mp->mp_pgno);
+ txn->mt_loose_pgs = NULL;
+ txn->mt_loose_count = 0;
+ }
+
+ /* MDB_RESERVE cancels meminit in ovpage malloc (when no WRITEMAP) */
+ clean_limit = (env->me_flags & (MDB_NOMEMINIT|MDB_WRITEMAP))
+ ? SSIZE_MAX : maxfree_1pg;
+
+ for (;;) {
+ /* Come back here after each Put() in case freelist changed */
+ MDB_val key, data;
+ pgno_t *pgs;
+ ssize_t j;
+
+ /* If using records from freeDB which we have not yet
+ * deleted, delete them and any we reserved for me_pghead.
+ */
+ while (pglast < env->me_pglast) {
+ rc = mdb_cursor_first(&mc, &key, NULL);
+ if (rc)
+ return rc;
+ pglast = head_id = *(txnid_t *)key.mv_data;
+ total_room = head_room = 0;
+ mdb_tassert(txn, pglast <= env->me_pglast);
+ rc = mdb_cursor_del(&mc, 0);
+ if (rc)
+ return rc;
+ }
+
+ /* Save the IDL of pages freed by this txn, to a single record */
+ if (freecnt < txn->mt_free_pgs[0]) {
+ if (!freecnt) {
+ /* Make sure last page of freeDB is touched and on freelist */
+ rc = mdb_page_search(&mc, NULL, MDB_PS_LAST|MDB_PS_MODIFY);
+ if (rc && rc != MDB_NOTFOUND)
+ return rc;
+ }
+ free_pgs = txn->mt_free_pgs;
+ /* Write to last page of freeDB */
+ key.mv_size = sizeof(txn->mt_txnid);
+ key.mv_data = &txn->mt_txnid;
+ do {
+ freecnt = free_pgs[0];
+ data.mv_size = MDB_IDL_SIZEOF(free_pgs);
+ rc = mdb_cursor_put(&mc, &key, &data, MDB_RESERVE);
+ if (rc)
+ return rc;
+ /* Retry if mt_free_pgs[] grew during the Put() */
+ free_pgs = txn->mt_free_pgs;
+ } while (freecnt < free_pgs[0]);
+ mdb_midl_sort(free_pgs);
+ memcpy(data.mv_data, free_pgs, data.mv_size);
+#if (MDB_DEBUG) > 1
+ {
+ unsigned int i = free_pgs[0];
+ DPRINTF(("IDL write txn %"Z"u root %"Z"u num %u",
+ txn->mt_txnid, txn->mt_dbs[FREE_DBI].md_root, i));
+ for (; i; i--)
+ DPRINTF(("IDL %"Z"u", free_pgs[i]));
+ }
+#endif
+ continue;
+ }
+
+ mop = env->me_pghead;
+ mop_len = (mop ? mop[0] : 0) + txn->mt_loose_count;
+
+ /* Reserve records for me_pghead[]. Split it if multi-page,
+ * to avoid searching freeDB for a page range. Use keys in
+ * range [1,me_pglast]: Smaller than txnid of oldest reader.
+ */
+ if (total_room >= mop_len) {
+ if (total_room == mop_len || --more < 0)
+ break;
+ } else if (head_room >= maxfree_1pg && head_id > 1) {
+ /* Keep current record (overflow page), add a new one */
+ head_id--;
+ head_room = 0;
+ }
+ /* (Re)write {key = head_id, IDL length = head_room} */
+ total_room -= head_room;
+ head_room = mop_len - total_room;
+ if (head_room > maxfree_1pg && head_id > 1) {
+ /* Overflow multi-page for part of me_pghead */
+ head_room /= head_id; /* amortize page sizes */
+ head_room += maxfree_1pg - head_room % (maxfree_1pg + 1);
+ } else if (head_room < 0) {
+ /* Rare case, not bothering to delete this record */
+ head_room = 0;
+ }
+ key.mv_size = sizeof(head_id);
+ key.mv_data = &head_id;
+ data.mv_size = (head_room + 1) * sizeof(pgno_t);
+ rc = mdb_cursor_put(&mc, &key, &data, MDB_RESERVE);
+ if (rc)
+ return rc;
+ /* IDL is initially empty, zero out at least the length */
+ pgs = (pgno_t *)data.mv_data;
+ j = head_room > clean_limit ? head_room : 0;
+ do {
+ pgs[j] = 0;
+ } while (--j >= 0);
+ total_room += head_room;
+ }
+
+ /* Return loose page numbers to me_pghead, though usually none are
+ * left at this point. The pages themselves remain in dirty_list.
+ */
+ if (txn->mt_loose_pgs) {
+ MDB_page *mp = txn->mt_loose_pgs;
+ unsigned count = txn->mt_loose_count;
+ MDB_IDL loose;
+ /* Room for loose pages + temp IDL with same */
+ if ((rc = mdb_midl_need(&env->me_pghead, 2*count+1)) != 0)
+ return rc;
+ mop = env->me_pghead;
+ loose = mop + MDB_IDL_ALLOCLEN(mop) - count;
+ for (count = 0; mp; mp = NEXT_LOOSE_PAGE(mp))
+ loose[ ++count ] = mp->mp_pgno;
+ loose[0] = count;
+ mdb_midl_sort(loose);
+ mdb_midl_xmerge(mop, loose);
+ txn->mt_loose_pgs = NULL;
+ txn->mt_loose_count = 0;
+ mop_len = mop[0];
+ }
+
+ /* Fill in the reserved me_pghead records */
+ rc = MDB_SUCCESS;
+ if (mop_len) {
+ MDB_val key, data;
+
+ mop += mop_len;
+ rc = mdb_cursor_first(&mc, &key, &data);
+ for (; !rc; rc = mdb_cursor_next(&mc, &key, &data, MDB_NEXT)) {
+ txnid_t id = *(txnid_t *)key.mv_data;
+ ssize_t len = (ssize_t)(data.mv_size / sizeof(MDB_ID)) - 1;
+ MDB_ID save;
+
+ mdb_tassert(txn, len >= 0 && id <= env->me_pglast);
+ key.mv_data = &id;
+ if (len > mop_len) {
+ len = mop_len;
+ data.mv_size = (len + 1) * sizeof(MDB_ID);
+ }
+ data.mv_data = mop -= len;
+ save = mop[0];
+ mop[0] = len;
+ rc = mdb_cursor_put(&mc, &key, &data, MDB_CURRENT);
+ mop[0] = save;
+ if (rc || !(mop_len -= len))
+ break;
+ }
+ }
+ return rc;
+}
+
+/** Flush (some) dirty pages to the map, after clearing their dirty flag.
+ * @param[in] txn the transaction that's being committed
+ * @param[in] keep number of initial pages in dirty_list to keep dirty.
+ * @return 0 on success, non-zero on failure.
+ */
+static int
+mdb_page_flush(MDB_txn *txn, int keep)
+{
+ MDB_env *env = txn->mt_env;
+ MDB_ID2L dl = txn->mt_u.dirty_list;
+ unsigned psize = env->me_psize, j;
+ int i, pagecount = dl[0].mid, rc;
+ size_t size = 0, pos = 0;
+ pgno_t pgno = 0;
+ MDB_page *dp = NULL;
+#ifdef _WIN32
+ OVERLAPPED ov;
+#else
+ struct iovec iov[MDB_COMMIT_PAGES];
+ ssize_t wpos = 0, wsize = 0, wres;
+ size_t next_pos = 1; /* impossible pos, so pos != next_pos */
+ int n = 0;
+#endif
+
+ j = i = keep;
+
+ if (env->me_flags & MDB_WRITEMAP) {
+ /* Clear dirty flags */
+ while (++i <= pagecount) {
+ dp = dl[i].mptr;
+ /* Don't flush this page yet */
+ if (dp->mp_flags & (P_LOOSE|P_KEEP)) {
+ dp->mp_flags &= ~P_KEEP;
+ dl[++j] = dl[i];
+ continue;
+ }
+ dp->mp_flags &= ~P_DIRTY;
+ }
+ goto done;
+ }
+
+ /* Write the pages */
+ for (;;) {
+ if (++i <= pagecount) {
+ dp = dl[i].mptr;
+ /* Don't flush this page yet */
+ if (dp->mp_flags & (P_LOOSE|P_KEEP)) {
+ dp->mp_flags &= ~P_KEEP;
+ dl[i].mid = 0;
+ continue;
+ }
+ pgno = dl[i].mid;
+ /* clear dirty flag */
+ dp->mp_flags &= ~P_DIRTY;
+ pos = pgno * psize;
+ size = psize;
+ if (IS_OVERFLOW(dp)) size *= dp->mp_pages;
+ }
+#ifdef _WIN32
+ else break;
+
+ /* Windows actually supports scatter/gather I/O, but only on
+ * unbuffered file handles. Since we're relying on the OS page
+ * cache for all our data, that's self-defeating. So we just
+ * write pages one at a time. We use the ov structure to set
+ * the write offset, to at least save the overhead of a Seek
+ * system call.
+ */
+ DPRINTF(("committing page %"Z"u", pgno));
+ memset(&ov, 0, sizeof(ov));
+ ov.Offset = pos & 0xffffffff;
+ ov.OffsetHigh = pos >> 16 >> 16;
+ if (!WriteFile(env->me_fd, dp, size, NULL, &ov)) {
+ rc = ErrCode();
+ DPRINTF(("WriteFile: %d", rc));
+ return rc;
+ }
+#else
+ /* Write up to MDB_COMMIT_PAGES dirty pages at a time. */
+ if (pos!=next_pos || n==MDB_COMMIT_PAGES || wsize+size>MAX_WRITE) {
+ if (n) {
+retry_write:
+ /* Write previous page(s) */
+#ifdef MDB_USE_PWRITEV
+ wres = pwritev(env->me_fd, iov, n, wpos);
+#else
+ if (n == 1) {
+ wres = pwrite(env->me_fd, iov[0].iov_base, wsize, wpos);
+ } else {
+retry_seek:
+ if (lseek(env->me_fd, wpos, SEEK_SET) == -1) {
+ rc = ErrCode();
+ if (rc == EINTR)
+ goto retry_seek;
+ DPRINTF(("lseek: %s", strerror(rc)));
+ return rc;
+ }
+ wres = writev(env->me_fd, iov, n);
+ }
+#endif
+ if (wres != wsize) {
+ if (wres < 0) {
+ rc = ErrCode();
+ if (rc == EINTR)
+ goto retry_write;
+ DPRINTF(("Write error: %s", strerror(rc)));
+ } else {
+ rc = EIO; /* TODO: Use which error code? */
+ DPUTS("short write, filesystem full?");
+ }
+ return rc;
+ }
+ n = 0;
+ }
+ if (i > pagecount)
+ break;
+ wpos = pos;
+ wsize = 0;
+ }
+ DPRINTF(("committing page %"Z"u", pgno));
+ next_pos = pos + size;
+ iov[n].iov_len = size;
+ iov[n].iov_base = (char *)dp;
+ wsize += size;
+ n++;
+#endif /* _WIN32 */
+ }
+
+ /* MIPS has cache coherency issues, this is a no-op everywhere else
+ * Note: for any size >= on-chip cache size, entire on-chip cache is
+ * flushed.
+ */
+ CACHEFLUSH(env->me_map, txn->mt_next_pgno * env->me_psize, DCACHE);
+
+ for (i = keep; ++i <= pagecount; ) {
+ dp = dl[i].mptr;
+ /* This is a page we skipped above */
+ if (!dl[i].mid) {
+ dl[++j] = dl[i];
+ dl[j].mid = dp->mp_pgno;
+ continue;
+ }
+ mdb_dpage_free(env, dp);
+ }
+
+done:
+ i--;
+ txn->mt_dirty_room += i - j;
+ dl[0].mid = j;
+ return MDB_SUCCESS;
+}
+
+int
+mdb_txn_commit(MDB_txn *txn)
+{
+ int rc;
+ unsigned int i, end_mode;
+ MDB_env *env;
+
+ if (txn == NULL)
+ return EINVAL;
+
+ /* mdb_txn_end() mode for a commit which writes nothing */
+ end_mode = MDB_END_EMPTY_COMMIT|MDB_END_UPDATE|MDB_END_SLOT|MDB_END_FREE;
+
+ if (txn->mt_child) {
+ rc = mdb_txn_commit(txn->mt_child);
+ if (rc)
+ goto fail;
+ }
+
+ env = txn->mt_env;
+
+ if (F_ISSET(txn->mt_flags, MDB_TXN_RDONLY)) {
+ goto done;
+ }
+
+ if (txn->mt_flags & (MDB_TXN_FINISHED|MDB_TXN_ERROR)) {
+ DPUTS("txn has failed/finished, can't commit");
+ if (txn->mt_parent)
+ txn->mt_parent->mt_flags |= MDB_TXN_ERROR;
+ rc = MDB_BAD_TXN;
+ goto fail;
+ }
+
+ if (txn->mt_parent) {
+ MDB_txn *parent = txn->mt_parent;
+ MDB_page **lp;
+ MDB_ID2L dst, src;
+ MDB_IDL pspill;
+ unsigned x, y, len, ps_len;
+
+ /* Append our free list to parent's */
+ rc = mdb_midl_append_list(&parent->mt_free_pgs, txn->mt_free_pgs);
+ if (rc)
+ goto fail;
+ mdb_midl_free(txn->mt_free_pgs);
+ /* Failures after this must either undo the changes
+ * to the parent or set MDB_TXN_ERROR in the parent.
+ */
+
+ parent->mt_next_pgno = txn->mt_next_pgno;
+ parent->mt_flags = txn->mt_flags;
+
+ /* Merge our cursors into parent's and close them */
+ mdb_cursors_close(txn, 1);
+
+ /* Update parent's DB table. */
+ memcpy(parent->mt_dbs, txn->mt_dbs, txn->mt_numdbs * sizeof(MDB_db));
+ parent->mt_numdbs = txn->mt_numdbs;
+ parent->mt_dbflags[FREE_DBI] = txn->mt_dbflags[FREE_DBI];
+ parent->mt_dbflags[MAIN_DBI] = txn->mt_dbflags[MAIN_DBI];
+ for (i=CORE_DBS; i<txn->mt_numdbs; i++) {
+ /* preserve parent's DB_NEW status */
+ x = parent->mt_dbflags[i] & DB_NEW;
+ parent->mt_dbflags[i] = txn->mt_dbflags[i] | x;
+ }
+
+ dst = parent->mt_u.dirty_list;
+ src = txn->mt_u.dirty_list;
+ /* Remove anything in our dirty list from parent's spill list */
+ if ((pspill = parent->mt_spill_pgs) && (ps_len = pspill[0])) {
+ x = y = ps_len;
+ pspill[0] = (pgno_t)-1;
+ /* Mark our dirty pages as deleted in parent spill list */
+ for (i=0, len=src[0].mid; ++i <= len; ) {
+ MDB_ID pn = src[i].mid << 1;
+ while (pn > pspill[x])
+ x--;
+ if (pn == pspill[x]) {
+ pspill[x] = 1;
+ y = --x;
+ }
+ }
+ /* Squash deleted pagenums if we deleted any */
+ for (x=y; ++x <= ps_len; )
+ if (!(pspill[x] & 1))
+ pspill[++y] = pspill[x];
+ pspill[0] = y;
+ }
+
+ /* Remove anything in our spill list from parent's dirty list */
+ if (txn->mt_spill_pgs && txn->mt_spill_pgs[0]) {
+ for (i=1; i<=txn->mt_spill_pgs[0]; i++) {
+ MDB_ID pn = txn->mt_spill_pgs[i];
+ if (pn & 1)
+ continue; /* deleted spillpg */
+ pn >>= 1;
+ y = mdb_mid2l_search(dst, pn);
+ if (y <= dst[0].mid && dst[y].mid == pn) {
+ free(dst[y].mptr);
+ while (y < dst[0].mid) {
+ dst[y] = dst[y+1];
+ y++;
+ }
+ dst[0].mid--;
+ }
+ }
+ }
+
+ /* Find len = length of merging our dirty list with parent's */
+ x = dst[0].mid;
+ dst[0].mid = 0; /* simplify loops */
+ if (parent->mt_parent) {
+ len = x + src[0].mid;
+ y = mdb_mid2l_search(src, dst[x].mid + 1) - 1;
+ for (i = x; y && i; y--) {
+ pgno_t yp = src[y].mid;
+ while (yp < dst[i].mid)
+ i--;
+ if (yp == dst[i].mid) {
+ i--;
+ len--;
+ }
+ }
+ } else { /* Simplify the above for single-ancestor case */
+ len = MDB_IDL_UM_MAX - txn->mt_dirty_room;
+ }
+ /* Merge our dirty list with parent's */
+ y = src[0].mid;
+ for (i = len; y; dst[i--] = src[y--]) {
+ pgno_t yp = src[y].mid;
+ while (yp < dst[x].mid)
+ dst[i--] = dst[x--];
+ if (yp == dst[x].mid)
+ free(dst[x--].mptr);
+ }
+ mdb_tassert(txn, i == x);
+ dst[0].mid = len;
+ free(txn->mt_u.dirty_list);
+ parent->mt_dirty_room = txn->mt_dirty_room;
+ if (txn->mt_spill_pgs) {
+ if (parent->mt_spill_pgs) {
+ /* TODO: Prevent failure here, so parent does not fail */
+ rc = mdb_midl_append_list(&parent->mt_spill_pgs, txn->mt_spill_pgs);
+ if (rc)
+ parent->mt_flags |= MDB_TXN_ERROR;
+ mdb_midl_free(txn->mt_spill_pgs);
+ mdb_midl_sort(parent->mt_spill_pgs);
+ } else {
+ parent->mt_spill_pgs = txn->mt_spill_pgs;
+ }
+ }
+
+ /* Append our loose page list to parent's */
+ for (lp = &parent->mt_loose_pgs; *lp; lp = &NEXT_LOOSE_PAGE(*lp))
+ ;
+ *lp = txn->mt_loose_pgs;
+ parent->mt_loose_count += txn->mt_loose_count;
+
+ parent->mt_child = NULL;
+ mdb_midl_free(((MDB_ntxn *)txn)->mnt_pgstate.mf_pghead);
+ free(txn);
+ return rc;
+ }
+
+ if (txn != env->me_txn) {
+ DPUTS("attempt to commit unknown transaction");
+ rc = EINVAL;
+ goto fail;
+ }
+
+ mdb_cursors_close(txn, 0);
+
+ if (!txn->mt_u.dirty_list[0].mid &&
+ !(txn->mt_flags & (MDB_TXN_DIRTY|MDB_TXN_SPILLS)))
+ goto done;
+
+ DPRINTF(("committing txn %"Z"u %p on mdbenv %p, root page %"Z"u",
+ txn->mt_txnid, (void*)txn, (void*)env, txn->mt_dbs[MAIN_DBI].md_root));
+
+ /* Update DB root pointers */
+ if (txn->mt_numdbs > CORE_DBS) {
+ MDB_cursor mc;
+ MDB_dbi i;
+ MDB_val data;
+ data.mv_size = sizeof(MDB_db);
+
+ mdb_cursor_init(&mc, txn, MAIN_DBI, NULL);
+ for (i = CORE_DBS; i < txn->mt_numdbs; i++) {
+ if (txn->mt_dbflags[i] & DB_DIRTY) {
+ if (TXN_DBI_CHANGED(txn, i)) {
+ rc = MDB_BAD_DBI;
+ goto fail;
+ }
+ data.mv_data = &txn->mt_dbs[i];
+ rc = mdb_cursor_put(&mc, &txn->mt_dbxs[i].md_name, &data,
+ F_SUBDATA);
+ if (rc)
+ goto fail;
+ }
+ }
+ }
+
+ rc = mdb_freelist_save(txn);
+ if (rc)
+ goto fail;
+
+ mdb_midl_free(env->me_pghead);
+ env->me_pghead = NULL;
+ mdb_midl_shrink(&txn->mt_free_pgs);
+
+#if (MDB_DEBUG) > 2
+ mdb_audit(txn);
+#endif
+
+ if ((rc = mdb_page_flush(txn, 0)) ||
+ (rc = mdb_env_sync(env, 0)) ||
+ (rc = mdb_env_write_meta(txn)))
+ goto fail;
+ end_mode = MDB_END_COMMITTED|MDB_END_UPDATE;
+
+done:
+ mdb_txn_end(txn, end_mode);
+ return MDB_SUCCESS;
+
+fail:
+ mdb_txn_abort(txn);
+ return rc;
+}
+
+/** Read the environment parameters of a DB environment before
+ * mapping it into memory.
+ * @param[in] env the environment handle
+ * @param[out] meta address of where to store the meta information
+ * @return 0 on success, non-zero on failure.
+ */
+static int ESECT
+mdb_env_read_header(MDB_env *env, MDB_meta *meta)
+{
+ MDB_metabuf pbuf;
+ MDB_page *p;
+ MDB_meta *m;
+ int i, rc, off;
+ enum { Size = sizeof(pbuf) };
+
+ /* We don't know the page size yet, so use a minimum value.
+ * Read both meta pages so we can use the latest one.
+ */
+
+ for (i=off=0; i<NUM_METAS; i++, off += meta->mm_psize) {
+#ifdef _WIN32
+ DWORD len;
+ OVERLAPPED ov;
+ memset(&ov, 0, sizeof(ov));
+ ov.Offset = off;
+ rc = ReadFile(env->me_fd, &pbuf, Size, &len, &ov) ? (int)len : -1;
+ if (rc == -1 && ErrCode() == ERROR_HANDLE_EOF)
+ rc = 0;
+#else
+ rc = pread(env->me_fd, &pbuf, Size, off);
+#endif
+ if (rc != Size) {
+ if (rc == 0 && off == 0)
+ return ENOENT;
+ rc = rc < 0 ? (int) ErrCode() : MDB_INVALID;
+ DPRINTF(("read: %s", mdb_strerror(rc)));
+ return rc;
+ }
+
+ p = (MDB_page *)&pbuf;
+
+ if (!F_ISSET(p->mp_flags, P_META)) {
+ DPRINTF(("page %"Z"u not a meta page", p->mp_pgno));
+ return MDB_INVALID;
+ }
+
+ m = METADATA(p);
+ if (m->mm_magic != MDB_MAGIC) {
+ DPUTS("meta has invalid magic");
+ return MDB_INVALID;
+ }
+
+ if (m->mm_version != MDB_DATA_VERSION) {
+ DPRINTF(("database is version %u, expected version %u",
+ m->mm_version, MDB_DATA_VERSION));
+ return MDB_VERSION_MISMATCH;
+ }
+
+ if (off == 0 || m->mm_txnid > meta->mm_txnid)
+ *meta = *m;
+ }
+ return 0;
+}
+
+/** Fill in most of the zeroed #MDB_meta for an empty database environment */
+static void ESECT
+mdb_env_init_meta0(MDB_env *env, MDB_meta *meta)
+{
+ meta->mm_magic = MDB_MAGIC;
+ meta->mm_version = MDB_DATA_VERSION;
+ meta->mm_mapsize = env->me_mapsize;
+ meta->mm_psize = env->me_psize;
+ meta->mm_last_pg = NUM_METAS-1;
+ meta->mm_flags = env->me_flags & 0xffff;
+ meta->mm_flags |= MDB_INTEGERKEY; /* this is mm_dbs[FREE_DBI].md_flags */
+ meta->mm_dbs[FREE_DBI].md_root = P_INVALID;
+ meta->mm_dbs[MAIN_DBI].md_root = P_INVALID;
+}
+
+/** Write the environment parameters of a freshly created DB environment.
+ * @param[in] env the environment handle
+ * @param[in] meta the #MDB_meta to write
+ * @return 0 on success, non-zero on failure.
+ */
+static int ESECT
+mdb_env_init_meta(MDB_env *env, MDB_meta *meta)
+{
+ MDB_page *p, *q;
+ int rc;
+ unsigned int psize;
+#ifdef _WIN32
+ DWORD len;
+ OVERLAPPED ov;
+ memset(&ov, 0, sizeof(ov));
+#define DO_PWRITE(rc, fd, ptr, size, len, pos) do { \
+ ov.Offset = pos; \
+ rc = WriteFile(fd, ptr, size, &len, &ov); } while(0)
+#else
+ int len;
+#define DO_PWRITE(rc, fd, ptr, size, len, pos) do { \
+ len = pwrite(fd, ptr, size, pos); \
+ if (len == -1 && ErrCode() == EINTR) continue; \
+ rc = (len >= 0); break; } while(1)
+#endif
+
+ DPUTS("writing new meta page");
+
+ psize = env->me_psize;
+
+ p = calloc(NUM_METAS, psize);
+ if (!p)
+ return ENOMEM;
+
+ p->mp_pgno = 0;
+ p->mp_flags = P_META;
+ *(MDB_meta *)METADATA(p) = *meta;
+
+ q = (MDB_page *)((char *)p + psize);
+ q->mp_pgno = 1;
+ q->mp_flags = P_META;
+ *(MDB_meta *)METADATA(q) = *meta;
+
+ DO_PWRITE(rc, env->me_fd, p, psize * NUM_METAS, len, 0);
+ if (!rc)
+ rc = ErrCode();
+ else if ((unsigned) len == psize * NUM_METAS)
+ rc = MDB_SUCCESS;
+ else
+ rc = ENOSPC;
+ free(p);
+ return rc;
+}
+
+/** Update the environment info to commit a transaction.
+ * @param[in] txn the transaction that's being committed
+ * @return 0 on success, non-zero on failure.
+ */
+static int
+mdb_env_write_meta(MDB_txn *txn)
+{
+ MDB_env *env;
+ MDB_meta meta, metab, *mp;
+ unsigned flags;
+ size_t mapsize;
+ off_t off;
+ int rc, len, toggle;
+ char *ptr;
+ HANDLE mfd;
+#ifdef _WIN32
+ OVERLAPPED ov;
+#else
+ int r2;
+#endif
+
+ toggle = txn->mt_txnid & 1;
+ DPRINTF(("writing meta page %d for root page %"Z"u",
+ toggle, txn->mt_dbs[MAIN_DBI].md_root));
+
+ env = txn->mt_env;
+ flags = env->me_flags;
+ mp = env->me_metas[toggle];
+ mapsize = env->me_metas[toggle ^ 1]->mm_mapsize;
+ /* Persist any increases of mapsize config */
+ if (mapsize < env->me_mapsize)
+ mapsize = env->me_mapsize;
+
+ if (flags & MDB_WRITEMAP) {
+ mp->mm_mapsize = mapsize;
+ mp->mm_dbs[FREE_DBI] = txn->mt_dbs[FREE_DBI];
+ mp->mm_dbs[MAIN_DBI] = txn->mt_dbs[MAIN_DBI];
+ mp->mm_last_pg = txn->mt_next_pgno - 1;
+#if (__GNUC__ * 100 + __GNUC_MINOR__ >= 404) && /* TODO: portability */ \
+ !(defined(__i386__) || defined(__x86_64__))
+ /* LY: issue a memory barrier, if not x86. ITS#7969 */
+ __sync_synchronize();
+#endif
+ mp->mm_txnid = txn->mt_txnid;
+ if (!(flags & (MDB_NOMETASYNC|MDB_NOSYNC))) {
+ unsigned meta_size = env->me_psize;
+ rc = (env->me_flags & MDB_MAPASYNC) ? MS_ASYNC : MS_SYNC;
+ ptr = (char *)mp - PAGEHDRSZ;
+#ifndef _WIN32 /* POSIX msync() requires ptr = start of OS page */
+ r2 = (ptr - env->me_map) & (env->me_os_psize - 1);
+ ptr -= r2;
+ meta_size += r2;
+#endif
+ if (MDB_MSYNC(ptr, meta_size, rc)) {
+ rc = ErrCode();
+ goto fail;
+ }
+ }
+ goto done;
+ }
+ metab.mm_txnid = mp->mm_txnid;
+ metab.mm_last_pg = mp->mm_last_pg;
+
+ meta.mm_mapsize = mapsize;
+ meta.mm_dbs[FREE_DBI] = txn->mt_dbs[FREE_DBI];
+ meta.mm_dbs[MAIN_DBI] = txn->mt_dbs[MAIN_DBI];
+ meta.mm_last_pg = txn->mt_next_pgno - 1;
+ meta.mm_txnid = txn->mt_txnid;
+
+ off = offsetof(MDB_meta, mm_mapsize);
+ ptr = (char *)&meta + off;
+ len = sizeof(MDB_meta) - off;
+ off += (char *)mp - env->me_map;
+
+ /* Write to the SYNC fd unless MDB_NOSYNC/MDB_NOMETASYNC.
+ * (me_mfd goes to the same file as me_fd, but writing to it
+ * also syncs to disk. Avoids a separate fdatasync() call.)
+ */
+ mfd = (flags & (MDB_NOSYNC|MDB_NOMETASYNC)) ? env->me_fd : env->me_mfd;
+#ifdef _WIN32
+ {
+ memset(&ov, 0, sizeof(ov));
+ ov.Offset = off;
+ if (!WriteFile(mfd, ptr, len, (DWORD *)&rc, &ov))
+ rc = -1;
+ }
+#else
+retry_write:
+ rc = pwrite(mfd, ptr, len, off);
+#endif
+ if (rc != len) {
+ rc = rc < 0 ? ErrCode() : EIO;
+#ifndef _WIN32
+ if (rc == EINTR)
+ goto retry_write;
+#endif
+ DPUTS("write failed, disk error?");
+ /* On a failure, the pagecache still contains the new data.
+ * Write some old data back, to prevent it from being used.
+ * Use the non-SYNC fd; we know it will fail anyway.
+ */
+ meta.mm_last_pg = metab.mm_last_pg;
+ meta.mm_txnid = metab.mm_txnid;
+#ifdef _WIN32
+ memset(&ov, 0, sizeof(ov));
+ ov.Offset = off;
+ WriteFile(env->me_fd, ptr, len, NULL, &ov);
+#else
+ r2 = pwrite(env->me_fd, ptr, len, off);
+ (void)r2; /* Silence warnings. We don't care about pwrite's return value */
+#endif
+fail:
+ env->me_flags |= MDB_FATAL_ERROR;
+ return rc;
+ }
+ /* MIPS has cache coherency issues, this is a no-op everywhere else */
+ CACHEFLUSH(env->me_map + off, len, DCACHE);
+done:
+ /* Memory ordering issues are irrelevant; since the entire writer
+ * is wrapped by wmutex, all of these changes will become visible
+ * after the wmutex is unlocked. Since the DB is multi-version,
+ * readers will get consistent data regardless of how fresh or
+ * how stale their view of these values is.
+ */
+ if (env->me_txns)
+ env->me_txns->mti_txnid = txn->mt_txnid;
+
+ return MDB_SUCCESS;
+}
+
+/** Check both meta pages to see which one is newer.
+ * @param[in] env the environment handle
+ * @return newest #MDB_meta.
+ */
+static MDB_meta *
+mdb_env_pick_meta(const MDB_env *env)
+{
+ MDB_meta *const *metas = env->me_metas;
+ return metas[ metas[0]->mm_txnid < metas[1]->mm_txnid ];
+}
+
+int ESECT
+mdb_env_create(MDB_env **env)
+{
+ MDB_env *e;
+
+ e = calloc(1, sizeof(MDB_env));
+ if (!e)
+ return ENOMEM;
+
+ e->me_maxreaders = DEFAULT_READERS;
+ e->me_maxdbs = e->me_numdbs = CORE_DBS;
+ e->me_fd = INVALID_HANDLE_VALUE;
+ e->me_lfd = INVALID_HANDLE_VALUE;
+ e->me_mfd = INVALID_HANDLE_VALUE;
+#ifdef MDB_USE_POSIX_SEM
+ e->me_rmutex = SEM_FAILED;
+ e->me_wmutex = SEM_FAILED;
+#endif
+ e->me_pid = getpid();
+ GET_PAGESIZE(e->me_os_psize);
+ VGMEMP_CREATE(e,0,0);
+ *env = e;
+ return MDB_SUCCESS;
+}
+
+static int ESECT
+mdb_env_map(MDB_env *env, void *addr)
+{
+ MDB_page *p;
+ unsigned int flags = env->me_flags;
+#ifdef _WIN32
+ int rc;
+ HANDLE mh;
+ LONG sizelo, sizehi;
+ size_t msize;
+
+ if (flags & MDB_RDONLY) {
+ /* Don't set explicit map size, use whatever exists */
+ msize = 0;
+ sizelo = 0;
+ sizehi = 0;
+ } else {
+ msize = env->me_mapsize;
+ sizelo = msize & 0xffffffff;
+ sizehi = msize >> 16 >> 16; /* only needed on Win64 */
+
+ /* Windows won't create mappings for zero length files.
+ * and won't map more than the file size.
+ * Just set the maxsize right now.
+ */
+ if (SetFilePointer(env->me_fd, sizelo, &sizehi, 0) != (DWORD)sizelo
+ || !SetEndOfFile(env->me_fd)
+ || SetFilePointer(env->me_fd, 0, NULL, 0) != 0)
+ return ErrCode();
+ }
+
+ mh = CreateFileMapping(env->me_fd, NULL, flags & MDB_WRITEMAP ?
+ PAGE_READWRITE : PAGE_READONLY,
+ sizehi, sizelo, NULL);
+ if (!mh)
+ return ErrCode();
+ env->me_map = MapViewOfFileEx(mh, flags & MDB_WRITEMAP ?
+ FILE_MAP_WRITE : FILE_MAP_READ,
+ 0, 0, msize, addr);
+ rc = env->me_map ? 0 : ErrCode();
+ CloseHandle(mh);
+ if (rc)
+ return rc;
+#else
+ int prot = PROT_READ;
+ if (flags & MDB_WRITEMAP) {
+ prot |= PROT_WRITE;
+ if (ftruncate(env->me_fd, env->me_mapsize) < 0)
+ return ErrCode();
+ }
+ env->me_map = mmap(addr, env->me_mapsize, prot, MAP_SHARED,
+ env->me_fd, 0);
+ if (env->me_map == MAP_FAILED) {
+ env->me_map = NULL;
+ return ErrCode();
+ }
+
+ if (flags & MDB_NORDAHEAD) {
+ /* Turn off readahead. It's harmful when the DB is larger than RAM. */
+#ifdef MADV_RANDOM
+ madvise(env->me_map, env->me_mapsize, MADV_RANDOM);
+#else
+#ifdef POSIX_MADV_RANDOM
+ posix_madvise(env->me_map, env->me_mapsize, POSIX_MADV_RANDOM);
+#endif /* POSIX_MADV_RANDOM */
+#endif /* MADV_RANDOM */
+ }
+#endif /* _WIN32 */
+
+ /* Can happen because the address argument to mmap() is just a
+ * hint. mmap() can pick another, e.g. if the range is in use.
+ * The MAP_FIXED flag would prevent that, but then mmap could
+ * instead unmap existing pages to make room for the new map.
+ */
+ if (addr && env->me_map != addr)
+ return EBUSY; /* TODO: Make a new MDB_* error code? */
+
+ p = (MDB_page *)env->me_map;
+ env->me_metas[0] = METADATA(p);
+ env->me_metas[1] = (MDB_meta *)((char *)env->me_metas[0] + env->me_psize);
+
+ return MDB_SUCCESS;
+}
+
+int ESECT
+mdb_env_set_mapsize(MDB_env *env, size_t size)
+{
+ /* If env is already open, caller is responsible for making
+ * sure there are no active txns.
+ */
+ if (env->me_map) {
+ int rc;
+ MDB_meta *meta;
+ void *old;
+ if (env->me_txn)
+ return EINVAL;
+ meta = mdb_env_pick_meta(env);
+ if (!size)
+ size = meta->mm_mapsize;
+ {
+ /* Silently round up to minimum if the size is too small */
+ size_t minsize = (meta->mm_last_pg + 1) * env->me_psize;
+ if (size < minsize)
+ size = minsize;
+ }
+ munmap(env->me_map, env->me_mapsize);
+ env->me_mapsize = size;
+ old = (env->me_flags & MDB_FIXEDMAP) ? env->me_map : NULL;
+ rc = mdb_env_map(env, old);
+ if (rc)
+ return rc;
+ }
+ env->me_mapsize = size;
+ if (env->me_psize)
+ env->me_maxpg = env->me_mapsize / env->me_psize;
+ return MDB_SUCCESS;
+}
+
+int ESECT
+mdb_env_set_maxdbs(MDB_env *env, MDB_dbi dbs)
+{
+ if (env->me_map)
+ return EINVAL;
+ env->me_maxdbs = dbs + CORE_DBS;
+ return MDB_SUCCESS;
+}
+
+int ESECT
+mdb_env_set_maxreaders(MDB_env *env, unsigned int readers)
+{
+ if (env->me_map || readers < 1)
+ return EINVAL;
+ env->me_maxreaders = readers;
+ return MDB_SUCCESS;
+}
+
+int ESECT
+mdb_env_get_maxreaders(MDB_env *env, unsigned int *readers)
+{
+ if (!env || !readers)
+ return EINVAL;
+ *readers = env->me_maxreaders;
+ return MDB_SUCCESS;
+}
+
+static int ESECT
+mdb_fsize(HANDLE fd, size_t *size)
+{
+#ifdef _WIN32
+ LARGE_INTEGER fsize;
+
+ if (!GetFileSizeEx(fd, &fsize))
+ return ErrCode();
+
+ *size = fsize.QuadPart;
+#else
+ struct stat st;
+
+ if (fstat(fd, &st))
+ return ErrCode();
+
+ *size = st.st_size;
+#endif
+ return MDB_SUCCESS;
+}
+
+
+#ifdef _WIN32
+typedef wchar_t mdb_nchar_t;
+# define MDB_NAME(str) L##str
+# define mdb_name_cpy wcscpy
+#else
+/** Character type for file names: char on Unix, wchar_t on Windows */
+typedef char mdb_nchar_t;
+# define MDB_NAME(str) str /**< #mdb_nchar_t[] string literal */
+# define mdb_name_cpy strcpy /**< Copy name (#mdb_nchar_t string) */
+#endif
+
+/** Filename - string of #mdb_nchar_t[] */
+typedef struct MDB_name {
+ int mn_len; /**< Length */
+ int mn_alloced; /**< True if #mn_val was malloced */
+ mdb_nchar_t *mn_val; /**< Contents */
+} MDB_name;
+
+/** Filename suffixes [datafile,lockfile][without,with MDB_NOSUBDIR] */
+static const mdb_nchar_t *const mdb_suffixes[2][2] = {
+ { MDB_NAME("/data.mdb"), MDB_NAME("") },
+ { MDB_NAME("/lock.mdb"), MDB_NAME("-lock") }
+};
+
+#define MDB_SUFFLEN 9 /**< Max string length in #mdb_suffixes[] */
+
+/** Set up filename + scratch area for filename suffix, for opening files.
+ * It should be freed with #mdb_fname_destroy().
+ * On Windows, paths are converted from char *UTF-8 to wchar_t *UTF-16.
+ *
+ * @param[in] path Pathname for #mdb_env_open().
+ * @param[in] envflags Whether a subdir and/or lockfile will be used.
+ * @param[out] fname Resulting filename, with room for a suffix if necessary.
+ */
+static int ESECT
+mdb_fname_init(const char *path, unsigned envflags, MDB_name *fname)
+{
+ int no_suffix = F_ISSET(envflags, MDB_NOSUBDIR|MDB_NOLOCK);
+ fname->mn_alloced = 0;
+#ifdef _WIN32
+ return utf8_to_utf16(path, fname, no_suffix ? 0 : MDB_SUFFLEN);
+#else
+ fname->mn_len = strlen(path);
+ if (no_suffix)
+ fname->mn_val = (char *) path;
+ else if ((fname->mn_val = malloc(fname->mn_len + MDB_SUFFLEN+1)) != NULL) {
+ fname->mn_alloced = 1;
+ strcpy(fname->mn_val, path);
+ }
+ else
+ return ENOMEM;
+ return MDB_SUCCESS;
+#endif
+}
+
+/** Destroy \b fname from #mdb_fname_init() */
+#define mdb_fname_destroy(fname) \
+ do { if ((fname).mn_alloced) free((fname).mn_val); } while (0)
+
+#ifdef O_CLOEXEC /* POSIX.1-2008: Set FD_CLOEXEC atomically at open() */
+# define MDB_CLOEXEC O_CLOEXEC
+#else
+# define MDB_CLOEXEC 0
+#endif
+
+/** File type, access mode etc. for #mdb_fopen() */
+enum mdb_fopen_type {
+#ifdef _WIN32
+ MDB_O_RDONLY, MDB_O_RDWR, MDB_O_META, MDB_O_COPY, MDB_O_LOCKS
+#else
+ /* A comment in mdb_fopen() explains some O_* flag choices. */
+ MDB_O_RDONLY= O_RDONLY, /**< for RDONLY me_fd */
+ MDB_O_RDWR = O_RDWR |O_CREAT, /**< for me_fd */
+ MDB_O_META = O_WRONLY|MDB_DSYNC |MDB_CLOEXEC, /**< for me_mfd */
+ MDB_O_COPY = O_WRONLY|O_CREAT|O_EXCL|MDB_CLOEXEC, /**< for #mdb_env_copy() */
+ /** Bitmask for open() flags in enum #mdb_fopen_type. The other bits
+ * distinguish otherwise-equal MDB_O_* constants from each other.
+ */
+ MDB_O_MASK = MDB_O_RDWR|MDB_CLOEXEC | MDB_O_RDONLY|MDB_O_META|MDB_O_COPY,
+ MDB_O_LOCKS = MDB_O_RDWR|MDB_CLOEXEC | ((MDB_O_MASK+1) & ~MDB_O_MASK) /**< for me_lfd */
+#endif
+};
+
+/** Open an LMDB file.
+ * @param[in] env The LMDB environment.
+ * @param[in,out] fname Path from from #mdb_fname_init(). A suffix is
+ * appended if necessary to create the filename, without changing mn_len.
+ * @param[in] which Determines file type, access mode, etc.
+ * @param[in] mode The Unix permissions for the file, if we create it.
+ * @param[out] res Resulting file handle.
+ * @return 0 on success, non-zero on failure.
+ */
+static int ESECT
+mdb_fopen(const MDB_env *env, MDB_name *fname,
+ enum mdb_fopen_type which, mdb_mode_t mode,
+ HANDLE *res)
+{
+ int rc = MDB_SUCCESS;
+ HANDLE fd;
+#ifdef _WIN32
+ DWORD acc, share, disp, attrs;
+#else
+ int flags;
+#endif
+
+ if (fname->mn_alloced) /* modifiable copy */
+ mdb_name_cpy(fname->mn_val + fname->mn_len,
+ mdb_suffixes[which==MDB_O_LOCKS][F_ISSET(env->me_flags, MDB_NOSUBDIR)]);
+
+ /* The directory must already exist. Usually the file need not.
+ * MDB_O_META requires the file because we already created it using
+ * MDB_O_RDWR. MDB_O_COPY must not overwrite an existing file.
+ *
+ * With MDB_O_COPY we do not want the OS to cache the writes, since
+ * the source data is already in the OS cache.
+ *
+ * The lockfile needs FD_CLOEXEC (close file descriptor on exec*())
+ * to avoid the flock() issues noted under Caveats in lmdb.h.
+ * Also set it for other filehandles which the user cannot get at
+ * and close himself, which he may need after fork(). I.e. all but
+ * me_fd, which programs do use via mdb_env_get_fd().
+ */
+
+#ifdef _WIN32
+ acc = GENERIC_READ|GENERIC_WRITE;
+ share = FILE_SHARE_READ|FILE_SHARE_WRITE;
+ disp = OPEN_ALWAYS;
+ attrs = FILE_ATTRIBUTE_NORMAL;
+ switch (which) {
+ case MDB_O_RDONLY: /* read-only datafile */
+ acc = GENERIC_READ;
+ disp = OPEN_EXISTING;
+ break;
+ case MDB_O_META: /* for writing metapages */
+ acc = GENERIC_WRITE;
+ disp = OPEN_EXISTING;
+ attrs = FILE_ATTRIBUTE_NORMAL|FILE_FLAG_WRITE_THROUGH;
+ break;
+ case MDB_O_COPY: /* mdb_env_copy() & co */
+ acc = GENERIC_WRITE;
+ share = 0;
+ disp = CREATE_NEW;
+ attrs = FILE_FLAG_NO_BUFFERING|FILE_FLAG_WRITE_THROUGH;
+ break;
+ default: break; /* silence gcc -Wswitch (not all enum values handled) */
+ }
+ fd = CreateFileW(fname->mn_val, acc, share, NULL, disp, attrs, NULL);
+#else
+ fd = open(fname->mn_val, which & MDB_O_MASK, mode);
+#endif
+
+ if (fd == INVALID_HANDLE_VALUE)
+ rc = ErrCode();
+#ifndef _WIN32
+ else {
+ if (which != MDB_O_RDONLY && which != MDB_O_RDWR) {
+ /* Set CLOEXEC if we could not pass it to open() */
+ if (!MDB_CLOEXEC && (flags = fcntl(fd, F_GETFD)) != -1)
+ (void) fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
+ }
+ if (which == MDB_O_COPY && env->me_psize >= env->me_os_psize) {
+ /* This may require buffer alignment. There is no portable
+ * way to ask how much, so we require OS pagesize alignment.
+ */
+# ifdef F_NOCACHE /* __APPLE__ */
+ (void) fcntl(fd, F_NOCACHE, 1);
+# elif defined O_DIRECT
+ /* open(...O_DIRECT...) would break on filesystems without
+ * O_DIRECT support (ITS#7682). Try to set it here instead.
+ */
+ if ((flags = fcntl(fd, F_GETFL)) != -1)
+ (void) fcntl(fd, F_SETFL, flags | O_DIRECT);
+# endif
+ }
+ }
+#endif /* !_WIN32 */
+
+ *res = fd;
+ return rc;
+}
+
+
+#ifdef BROKEN_FDATASYNC
+#include <sys/utsname.h>
+#include <sys/vfs.h>
+#endif
+
+/** Further setup required for opening an LMDB environment
+ */
+static int ESECT
+mdb_env_open2(MDB_env *env)
+{
+ unsigned int flags = env->me_flags;
+ int i, newenv = 0, rc;
+ MDB_meta meta;
+
+#ifdef _WIN32
+ /* See if we should use QueryLimited */
+ rc = GetVersion();
+ if ((rc & 0xff) > 5)
+ env->me_pidquery = MDB_PROCESS_QUERY_LIMITED_INFORMATION;
+ else
+ env->me_pidquery = PROCESS_QUERY_INFORMATION;
+#endif /* _WIN32 */
+
+#ifdef BROKEN_FDATASYNC
+ /* ext3/ext4 fdatasync is broken on some older Linux kernels.
+ * https://lkml.org/lkml/2012/9/3/83
+ * Kernels after 3.6-rc6 are known good.
+ * https://lkml.org/lkml/2012/9/10/556
+ * See if the DB is on ext3/ext4, then check for new enough kernel
+ * Kernels 2.6.32.60, 2.6.34.15, 3.2.30, and 3.5.4 are also known
+ * to be patched.
+ */
+ {
+ struct statfs st;
+ fstatfs(env->me_fd, &st);
+ while (st.f_type == 0xEF53) {
+ struct utsname uts;
+ int i;
+ uname(&uts);
+ if (uts.release[0] < '3') {
+ if (!strncmp(uts.release, "2.6.32.", 7)) {
+ i = atoi(uts.release+7);
+ if (i >= 60)
+ break; /* 2.6.32.60 and newer is OK */
+ } else if (!strncmp(uts.release, "2.6.34.", 7)) {
+ i = atoi(uts.release+7);
+ if (i >= 15)
+ break; /* 2.6.34.15 and newer is OK */
+ }
+ } else if (uts.release[0] == '3') {
+ i = atoi(uts.release+2);
+ if (i > 5)
+ break; /* 3.6 and newer is OK */
+ if (i == 5) {
+ i = atoi(uts.release+4);
+ if (i >= 4)
+ break; /* 3.5.4 and newer is OK */
+ } else if (i == 2) {
+ i = atoi(uts.release+4);
+ if (i >= 30)
+ break; /* 3.2.30 and newer is OK */
+ }
+ } else { /* 4.x and newer is OK */
+ break;
+ }
+ env->me_flags |= MDB_FSYNCONLY;
+ break;
+ }
+ }
+#endif
+
+ if ((i = mdb_env_read_header(env, &meta)) != 0) {
+ if (i != ENOENT)
+ return i;
+ DPUTS("new mdbenv");
+ newenv = 1;
+ env->me_psize = env->me_os_psize;
+ if (env->me_psize > MAX_PAGESIZE)
+ env->me_psize = MAX_PAGESIZE;
+ memset(&meta, 0, sizeof(meta));
+ mdb_env_init_meta0(env, &meta);
+ meta.mm_mapsize = DEFAULT_MAPSIZE;
+ } else {
+ env->me_psize = meta.mm_psize;
+ }
+
+ /* Was a mapsize configured? */
+ if (!env->me_mapsize) {
+ env->me_mapsize = meta.mm_mapsize;
+ }
+ {
+ /* Make sure mapsize >= committed data size. Even when using
+ * mm_mapsize, which could be broken in old files (ITS#7789).
+ */
+ size_t minsize = (meta.mm_last_pg + 1) * meta.mm_psize;
+ if (env->me_mapsize < minsize)
+ env->me_mapsize = minsize;
+ }
+ meta.mm_mapsize = env->me_mapsize;
+
+ if (newenv && !(flags & MDB_FIXEDMAP)) {
+ /* mdb_env_map() may grow the datafile. Write the metapages
+ * first, so the file will be valid if initialization fails.
+ * Except with FIXEDMAP, since we do not yet know mm_address.
+ * We could fill in mm_address later, but then a different
+ * program might end up doing that - one with a memory layout
+ * and map address which does not suit the main program.
+ */
+ rc = mdb_env_init_meta(env, &meta);
+ if (rc)
+ return rc;
+ newenv = 0;
+ }
+
+ rc = mdb_env_map(env, (flags & MDB_FIXEDMAP) ? meta.mm_address : NULL);
+ if (rc)
+ return rc;
+
+ if (newenv) {
+ if (flags & MDB_FIXEDMAP)
+ meta.mm_address = env->me_map;
+ i = mdb_env_init_meta(env, &meta);
+ if (i != MDB_SUCCESS) {
+ return i;
+ }
+ }
+
+ env->me_maxfree_1pg = (env->me_psize - PAGEHDRSZ) / sizeof(pgno_t) - 1;
+ env->me_nodemax = (((env->me_psize - PAGEHDRSZ) / MDB_MINKEYS) & -2)
+ - sizeof(indx_t);
+#if !(MDB_MAXKEYSIZE)
+ env->me_maxkey = env->me_nodemax - (NODESIZE + sizeof(MDB_db));
+#endif
+ env->me_maxpg = env->me_mapsize / env->me_psize;
+
+#if MDB_DEBUG
+ {
+ MDB_meta *meta = mdb_env_pick_meta(env);
+ MDB_db *db = &meta->mm_dbs[MAIN_DBI];
+
+ DPRINTF(("opened database version %u, pagesize %u",
+ meta->mm_version, env->me_psize));
+ DPRINTF(("using meta page %d", (int) (meta->mm_txnid & 1)));
+ DPRINTF(("depth: %u", db->md_depth));
+ DPRINTF(("entries: %"Z"u", db->md_entries));
+ DPRINTF(("branch pages: %"Z"u", db->md_branch_pages));
+ DPRINTF(("leaf pages: %"Z"u", db->md_leaf_pages));
+ DPRINTF(("overflow pages: %"Z"u", db->md_overflow_pages));
+ DPRINTF(("root: %"Z"u", db->md_root));
+ }
+#endif
+
+ return MDB_SUCCESS;
+}
+
+
+/** Release a reader thread's slot in the reader lock table.
+ * This function is called automatically when a thread exits.
+ * @param[in] ptr This points to the slot in the reader lock table.
+ */
+static void
+mdb_env_reader_dest(void *ptr)
+{
+ MDB_reader *reader = ptr;
+
+#ifndef _WIN32
+ if (reader->mr_pid == getpid()) /* catch pthread_exit() in child process */
+#endif
+ /* We omit the mutex, so do this atomically (i.e. skip mr_txnid) */
+ reader->mr_pid = 0;
+}
+
+#ifdef _WIN32
+/** Junk for arranging thread-specific callbacks on Windows. This is
+ * necessarily platform and compiler-specific. Windows supports up
+ * to 1088 keys. Let's assume nobody opens more than 64 environments
+ * in a single process, for now. They can override this if needed.
+ */
+#ifndef MAX_TLS_KEYS
+#define MAX_TLS_KEYS 64
+#endif
+static pthread_key_t mdb_tls_keys[MAX_TLS_KEYS];
+static int mdb_tls_nkeys;
+
+static void NTAPI mdb_tls_callback(PVOID module, DWORD reason, PVOID ptr)
+{
+ int i;
+ switch(reason) {
+ case DLL_PROCESS_ATTACH: break;
+ case DLL_THREAD_ATTACH: break;
+ case DLL_THREAD_DETACH:
+ for (i=0; i<mdb_tls_nkeys; i++) {
+ MDB_reader *r = pthread_getspecific(mdb_tls_keys[i]);
+ if (r) {
+ mdb_env_reader_dest(r);
+ }
+ }
+ break;
+ case DLL_PROCESS_DETACH: break;
+ }
+}
+#ifdef __GNUC__
+#ifdef _WIN64
+const PIMAGE_TLS_CALLBACK mdb_tls_cbp __attribute__((section (".CRT$XLB"))) = mdb_tls_callback;
+#else
+PIMAGE_TLS_CALLBACK mdb_tls_cbp __attribute__((section (".CRT$XLB"))) = mdb_tls_callback;
+#endif
+#else
+#ifdef _WIN64
+/* Force some symbol references.
+ * _tls_used forces the linker to create the TLS directory if not already done
+ * mdb_tls_cbp prevents whole-program-optimizer from dropping the symbol.
+ */
+#pragma comment(linker, "/INCLUDE:_tls_used")
+#pragma comment(linker, "/INCLUDE:mdb_tls_cbp")
+#pragma const_seg(".CRT$XLB")
+extern const PIMAGE_TLS_CALLBACK mdb_tls_cbp;
+const PIMAGE_TLS_CALLBACK mdb_tls_cbp = mdb_tls_callback;
+#pragma const_seg()
+#else /* _WIN32 */
+#pragma comment(linker, "/INCLUDE:__tls_used")
+#pragma comment(linker, "/INCLUDE:_mdb_tls_cbp")
+#pragma data_seg(".CRT$XLB")
+PIMAGE_TLS_CALLBACK mdb_tls_cbp = mdb_tls_callback;
+#pragma data_seg()
+#endif /* WIN 32/64 */
+#endif /* !__GNUC__ */
+#endif
+
+/** Downgrade the exclusive lock on the region back to shared */
+static int ESECT
+mdb_env_share_locks(MDB_env *env, int *excl)
+{
+ int rc = 0;
+ MDB_meta *meta = mdb_env_pick_meta(env);
+
+ env->me_txns->mti_txnid = meta->mm_txnid;
+
+#ifdef _WIN32
+ {
+ OVERLAPPED ov;
+ /* First acquire a shared lock. The Unlock will
+ * then release the existing exclusive lock.
+ */
+ memset(&ov, 0, sizeof(ov));
+ if (!LockFileEx(env->me_lfd, 0, 0, 1, 0, &ov)) {
+ rc = ErrCode();
+ } else {
+ UnlockFile(env->me_lfd, 0, 0, 1, 0);
+ *excl = 0;
+ }
+ }
+#else
+ {
+ struct flock lock_info;
+ /* The shared lock replaces the existing lock */
+ memset((void *)&lock_info, 0, sizeof(lock_info));
+ lock_info.l_type = F_RDLCK;
+ lock_info.l_whence = SEEK_SET;
+ lock_info.l_start = 0;
+ lock_info.l_len = 1;
+ while ((rc = fcntl(env->me_lfd, F_SETLK, &lock_info)) &&
+ (rc = ErrCode()) == EINTR) ;
+ *excl = rc ? -1 : 0; /* error may mean we lost the lock */
+ }
+#endif
+
+ return rc;
+}
+
+/** Try to get exclusive lock, otherwise shared.
+ * Maintain *excl = -1: no/unknown lock, 0: shared, 1: exclusive.
+ */
+static int ESECT
+mdb_env_excl_lock(MDB_env *env, int *excl)
+{
+ int rc = 0;
+#ifdef _WIN32
+ if (LockFile(env->me_lfd, 0, 0, 1, 0)) {
+ *excl = 1;
+ } else {
+ OVERLAPPED ov;
+ memset(&ov, 0, sizeof(ov));
+ if (LockFileEx(env->me_lfd, 0, 0, 1, 0, &ov)) {
+ *excl = 0;
+ } else {
+ rc = ErrCode();
+ }
+ }
+#else
+ struct flock lock_info;
+ memset((void *)&lock_info, 0, sizeof(lock_info));
+ lock_info.l_type = F_WRLCK;
+ lock_info.l_whence = SEEK_SET;
+ lock_info.l_start = 0;
+ lock_info.l_len = 1;
+ while ((rc = fcntl(env->me_lfd, F_SETLK, &lock_info)) &&
+ (rc = ErrCode()) == EINTR) ;
+ if (!rc) {
+ *excl = 1;
+ } else
+# ifndef MDB_USE_POSIX_MUTEX
+ if (*excl < 0) /* always true when MDB_USE_POSIX_MUTEX */
+# endif
+ {
+ lock_info.l_type = F_RDLCK;
+ while ((rc = fcntl(env->me_lfd, F_SETLKW, &lock_info)) &&
+ (rc = ErrCode()) == EINTR) ;
+ if (rc == 0)
+ *excl = 0;
+ }
+#endif
+ return rc;
+}
+
+#ifdef MDB_USE_HASH
+/*
+ * hash_64 - 64 bit Fowler/Noll/Vo-0 FNV-1a hash code
+ *
+ * @(#) $Revision: 5.1 $
+ * @(#) $Id: hash_64a.c,v 5.1 2009/06/30 09:01:38 chongo Exp $
+ * @(#) $Source: /usr/local/src/cmd/fnv/RCS/hash_64a.c,v $
+ *
+ * http://www.isthe.com/chongo/tech/comp/fnv/index.html
+ *
+ ***
+ *
+ * Please do not copyright this code. This code is in the public domain.
+ *
+ * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
+ * EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ *
+ * By:
+ * chongo <Landon Curt Noll> /\oo/\
+ * http://www.isthe.com/chongo/
+ *
+ * Share and Enjoy! :-)
+ */
+
+typedef unsigned long long mdb_hash_t;
+#define MDB_HASH_INIT ((mdb_hash_t)0xcbf29ce484222325ULL)
+
+/** perform a 64 bit Fowler/Noll/Vo FNV-1a hash on a buffer
+ * @param[in] val value to hash
+ * @param[in] hval initial value for hash
+ * @return 64 bit hash
+ *
+ * NOTE: To use the recommended 64 bit FNV-1a hash, use MDB_HASH_INIT as the
+ * hval arg on the first call.
+ */
+static mdb_hash_t
+mdb_hash_val(MDB_val *val, mdb_hash_t hval)
+{
+ unsigned char *s = (unsigned char *)val->mv_data; /* unsigned string */
+ unsigned char *end = s + val->mv_size;
+ /*
+ * FNV-1a hash each octet of the string
+ */
+ while (s < end) {
+ /* xor the bottom with the current octet */
+ hval ^= (mdb_hash_t)*s++;
+
+ /* multiply by the 64 bit FNV magic prime mod 2^64 */
+ hval += (hval << 1) + (hval << 4) + (hval << 5) +
+ (hval << 7) + (hval << 8) + (hval << 40);
+ }
+ /* return our new hash value */
+ return hval;
+}
+
+/** Hash the string and output the encoded hash.
+ * This uses modified RFC1924 Ascii85 encoding to accommodate systems with
+ * very short name limits. We don't care about the encoding being reversible,
+ * we just want to preserve as many bits of the input as possible in a
+ * small printable string.
+ * @param[in] str string to hash
+ * @param[out] encbuf an array of 11 chars to hold the hash
+ */
+static const char mdb_a85[]= "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~";
+
+static void ESECT
+mdb_pack85(unsigned long l, char *out)
+{
+ int i;
+
+ for (i=0; i<5; i++) {
+ *out++ = mdb_a85[l % 85];
+ l /= 85;
+ }
+}
+
+static void ESECT
+mdb_hash_enc(MDB_val *val, char *encbuf)
+{
+ mdb_hash_t h = mdb_hash_val(val, MDB_HASH_INIT);
+
+ mdb_pack85(h, encbuf);
+ mdb_pack85(h>>32, encbuf+5);
+ encbuf[10] = '\0';
+}
+#endif
+
+/** Open and/or initialize the lock region for the environment.
+ * @param[in] env The LMDB environment.
+ * @param[in] fname Filename + scratch area, from #mdb_fname_init().
+ * @param[in] mode The Unix permissions for the file, if we create it.
+ * @param[in,out] excl In -1, out lock type: -1 none, 0 shared, 1 exclusive
+ * @return 0 on success, non-zero on failure.
+ */
+static int ESECT
+mdb_env_setup_locks(MDB_env *env, MDB_name *fname, int mode, int *excl)
+{
+#ifdef _WIN32
+# define MDB_ERRCODE_ROFS ERROR_WRITE_PROTECT
+#else
+# define MDB_ERRCODE_ROFS EROFS
+#endif
+ int rc;
+ off_t size, rsize;
+
+ rc = mdb_fopen(env, fname, MDB_O_LOCKS, mode, &env->me_lfd);
+ if (rc) {
+ /* Omit lockfile if read-only env on read-only filesystem */
+ if (rc == MDB_ERRCODE_ROFS && (env->me_flags & MDB_RDONLY)) {
+ return MDB_SUCCESS;
+ }
+ goto fail;
+ }
+
+ if (!(env->me_flags & MDB_NOTLS)) {
+ rc = pthread_key_create(&env->me_txkey, mdb_env_reader_dest);
+ if (rc)
+ goto fail;
+ env->me_flags |= MDB_ENV_TXKEY;
+#ifdef _WIN32
+ /* Windows TLS callbacks need help finding their TLS info. */
+ if (mdb_tls_nkeys >= MAX_TLS_KEYS) {
+ rc = MDB_TLS_FULL;
+ goto fail;
+ }
+ mdb_tls_keys[mdb_tls_nkeys++] = env->me_txkey;
+#endif
+ }
+
+ /* Try to get exclusive lock. If we succeed, then
+ * nobody is using the lock region and we should initialize it.
+ */
+ if ((rc = mdb_env_excl_lock(env, excl))) goto fail;
+
+#ifdef _WIN32
+ size = GetFileSize(env->me_lfd, NULL);
+#else
+ size = lseek(env->me_lfd, 0, SEEK_END);
+ if (size == -1) goto fail_errno;
+#endif
+ rsize = (env->me_maxreaders-1) * sizeof(MDB_reader) + sizeof(MDB_txninfo);
+ if (size < rsize && *excl > 0) {
+#ifdef _WIN32
+ if (SetFilePointer(env->me_lfd, rsize, NULL, FILE_BEGIN) != (DWORD)rsize
+ || !SetEndOfFile(env->me_lfd))
+ goto fail_errno;
+#else
+ if (ftruncate(env->me_lfd, rsize) != 0) goto fail_errno;
+#endif
+ } else {
+ rsize = size;
+ size = rsize - sizeof(MDB_txninfo);
+ env->me_maxreaders = size/sizeof(MDB_reader) + 1;
+ }
+ {
+#ifdef _WIN32
+ HANDLE mh;
+ mh = CreateFileMapping(env->me_lfd, NULL, PAGE_READWRITE,
+ 0, 0, NULL);
+ if (!mh) goto fail_errno;
+ env->me_txns = MapViewOfFileEx(mh, FILE_MAP_WRITE, 0, 0, rsize, NULL);
+ CloseHandle(mh);
+ if (!env->me_txns) goto fail_errno;
+#else
+ void *m = mmap(NULL, rsize, PROT_READ|PROT_WRITE, MAP_SHARED,
+ env->me_lfd, 0);
+ if (m == MAP_FAILED) goto fail_errno;
+ env->me_txns = m;
+#endif
+ }
+ if (*excl > 0) {
+#ifdef _WIN32
+ BY_HANDLE_FILE_INFORMATION stbuf;
+ struct {
+ DWORD volume;
+ DWORD nhigh;
+ DWORD nlow;
+ } idbuf;
+ MDB_val val;
+ char encbuf[11];
+
+ if (!mdb_sec_inited) {
+ InitializeSecurityDescriptor(&mdb_null_sd,
+ SECURITY_DESCRIPTOR_REVISION);
+ SetSecurityDescriptorDacl(&mdb_null_sd, TRUE, 0, FALSE);
+ mdb_all_sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+ mdb_all_sa.bInheritHandle = FALSE;
+ mdb_all_sa.lpSecurityDescriptor = &mdb_null_sd;
+ mdb_sec_inited = 1;
+ }
+ if (!GetFileInformationByHandle(env->me_lfd, &stbuf)) goto fail_errno;
+ idbuf.volume = stbuf.dwVolumeSerialNumber;
+ idbuf.nhigh = stbuf.nFileIndexHigh;
+ idbuf.nlow = stbuf.nFileIndexLow;
+ val.mv_data = &idbuf;
+ val.mv_size = sizeof(idbuf);
+ mdb_hash_enc(&val, encbuf);
+ sprintf(env->me_txns->mti_rmname, "Global\\MDBr%s", encbuf);
+ sprintf(env->me_txns->mti_wmname, "Global\\MDBw%s", encbuf);
+ env->me_rmutex = CreateMutexA(&mdb_all_sa, FALSE, env->me_txns->mti_rmname);
+ if (!env->me_rmutex) goto fail_errno;
+ env->me_wmutex = CreateMutexA(&mdb_all_sa, FALSE, env->me_txns->mti_wmname);
+ if (!env->me_wmutex) goto fail_errno;
+#elif defined(MDB_USE_POSIX_SEM)
+ struct stat stbuf;
+ struct {
+ dev_t dev;
+ ino_t ino;
+ } idbuf;
+ MDB_val val;
+ char encbuf[11];
+
+#if defined(__NetBSD__)
+#define MDB_SHORT_SEMNAMES 1 /* limited to 14 chars */
+#endif
+ if (fstat(env->me_lfd, &stbuf)) goto fail_errno;
+ idbuf.dev = stbuf.st_dev;
+ idbuf.ino = stbuf.st_ino;
+ val.mv_data = &idbuf;
+ val.mv_size = sizeof(idbuf);
+ mdb_hash_enc(&val, encbuf);
+#ifdef MDB_SHORT_SEMNAMES
+ encbuf[9] = '\0'; /* drop name from 15 chars to 14 chars */
+#endif
+ sprintf(env->me_txns->mti_rmname, "/MDBr%s", encbuf);
+ sprintf(env->me_txns->mti_wmname, "/MDBw%s", encbuf);
+ /* Clean up after a previous run, if needed: Try to
+ * remove both semaphores before doing anything else.
+ */
+ sem_unlink(env->me_txns->mti_rmname);
+ sem_unlink(env->me_txns->mti_wmname);
+ env->me_rmutex = sem_open(env->me_txns->mti_rmname,
+ O_CREAT|O_EXCL, mode, 1);
+ if (env->me_rmutex == SEM_FAILED) goto fail_errno;
+ env->me_wmutex = sem_open(env->me_txns->mti_wmname,
+ O_CREAT|O_EXCL, mode, 1);
+ if (env->me_wmutex == SEM_FAILED) goto fail_errno;
+#else /* MDB_USE_POSIX_MUTEX: */
+ pthread_mutexattr_t mattr;
+
+ /* Solaris needs this before initing a robust mutex. Otherwise
+ * it may skip the init and return EBUSY "seems someone already
+ * inited" or EINVAL "it was inited differently".
+ */
+ memset(env->me_txns->mti_rmutex, 0, sizeof(*env->me_txns->mti_rmutex));
+ memset(env->me_txns->mti_wmutex, 0, sizeof(*env->me_txns->mti_wmutex));
+
+ if ((rc = pthread_mutexattr_init(&mattr)))
+ goto fail;
+
+ rc = pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
+#ifdef MDB_ROBUST_SUPPORTED
+ if (!rc) rc = pthread_mutexattr_setrobust(&mattr, PTHREAD_MUTEX_ROBUST);
+#endif
+ if (!rc) rc = pthread_mutex_init(env->me_txns->mti_rmutex, &mattr);
+ if (!rc) rc = pthread_mutex_init(env->me_txns->mti_wmutex, &mattr);
+ pthread_mutexattr_destroy(&mattr);
+ if (rc)
+ goto fail;
+#endif /* _WIN32 || MDB_USE_POSIX_SEM */
+
+ env->me_txns->mti_magic = MDB_MAGIC;
+ env->me_txns->mti_format = MDB_LOCK_FORMAT;
+ env->me_txns->mti_txnid = 0;
+ env->me_txns->mti_numreaders = 0;
+
+ } else {
+ if (env->me_txns->mti_magic != MDB_MAGIC) {
+ DPUTS("lock region has invalid magic");
+ rc = MDB_INVALID;
+ goto fail;
+ }
+ if (env->me_txns->mti_format != MDB_LOCK_FORMAT) {
+ DPRINTF(("lock region has format+version 0x%x, expected 0x%x",
+ env->me_txns->mti_format, MDB_LOCK_FORMAT));
+ rc = MDB_VERSION_MISMATCH;
+ goto fail;
+ }
+ rc = ErrCode();
+ if (rc && rc != EACCES && rc != EAGAIN) {
+ goto fail;
+ }
+#ifdef _WIN32
+ env->me_rmutex = OpenMutexA(SYNCHRONIZE, FALSE, env->me_txns->mti_rmname);
+ if (!env->me_rmutex) goto fail_errno;
+ env->me_wmutex = OpenMutexA(SYNCHRONIZE, FALSE, env->me_txns->mti_wmname);
+ if (!env->me_wmutex) goto fail_errno;
+#elif defined(MDB_USE_POSIX_SEM)
+ env->me_rmutex = sem_open(env->me_txns->mti_rmname, 0);
+ if (env->me_rmutex == SEM_FAILED) goto fail_errno;
+ env->me_wmutex = sem_open(env->me_txns->mti_wmname, 0);
+ if (env->me_wmutex == SEM_FAILED) goto fail_errno;
+#endif
+ }
+ return MDB_SUCCESS;
+
+fail_errno:
+ rc = ErrCode();
+fail:
+ return rc;
+}
+
+ /** Only a subset of the @ref mdb_env flags can be changed
+ * at runtime. Changing other flags requires closing the
+ * environment and re-opening it with the new flags.
+ */
+#define CHANGEABLE (MDB_NOSYNC|MDB_NOMETASYNC|MDB_MAPASYNC|MDB_NOMEMINIT)
+#define CHANGELESS (MDB_FIXEDMAP|MDB_NOSUBDIR|MDB_RDONLY| \
+ MDB_WRITEMAP|MDB_NOTLS|MDB_NOLOCK|MDB_NORDAHEAD)
+
+#if VALID_FLAGS & PERSISTENT_FLAGS & (CHANGEABLE|CHANGELESS)
+# error "Persistent DB flags & env flags overlap, but both go in mm_flags"
+#endif
+
+int ESECT
+mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode)
+{
+ int rc, excl = -1;
+ MDB_name fname;
+
+ if (env->me_fd!=INVALID_HANDLE_VALUE || (flags & ~(CHANGEABLE|CHANGELESS)))
+ return EINVAL;
+
+ flags |= env->me_flags;
+
+ rc = mdb_fname_init(path, flags, &fname);
+ if (rc)
+ return rc;
+
+ if (flags & MDB_RDONLY) {
+ /* silently ignore WRITEMAP when we're only getting read access */
+ flags &= ~MDB_WRITEMAP;
+ } else {
+ if (!((env->me_free_pgs = mdb_midl_alloc(MDB_IDL_UM_MAX)) &&
+ (env->me_dirty_list = calloc(MDB_IDL_UM_SIZE, sizeof(MDB_ID2)))))
+ rc = ENOMEM;
+ }
+ env->me_flags = flags |= MDB_ENV_ACTIVE;
+ if (rc)
+ goto leave;
+
+ env->me_path = strdup(path);
+ env->me_dbxs = calloc(env->me_maxdbs, sizeof(MDB_dbx));
+ env->me_dbflags = calloc(env->me_maxdbs, sizeof(uint16_t));
+ env->me_dbiseqs = calloc(env->me_maxdbs, sizeof(unsigned int));
+ if (!(env->me_dbxs && env->me_path && env->me_dbflags && env->me_dbiseqs)) {
+ rc = ENOMEM;
+ goto leave;
+ }
+ env->me_dbxs[FREE_DBI].md_cmp = mdb_cmp_long; /* aligned MDB_INTEGERKEY */
+
+ /* For RDONLY, get lockfile after we know datafile exists */
+ if (!(flags & (MDB_RDONLY|MDB_NOLOCK))) {
+ rc = mdb_env_setup_locks(env, &fname, mode, &excl);
+ if (rc)
+ goto leave;
+ }
+
+ rc = mdb_fopen(env, &fname,
+ (flags & MDB_RDONLY) ? MDB_O_RDONLY : MDB_O_RDWR,
+ mode, &env->me_fd);
+ if (rc)
+ goto leave;
+
+ if ((flags & (MDB_RDONLY|MDB_NOLOCK)) == MDB_RDONLY) {
+ rc = mdb_env_setup_locks(env, &fname, mode, &excl);
+ if (rc)
+ goto leave;
+ }
+
+ if ((rc = mdb_env_open2(env)) == MDB_SUCCESS) {
+ if (!(flags & (MDB_RDONLY|MDB_WRITEMAP))) {
+ /* Synchronous fd for meta writes. Needed even with
+ * MDB_NOSYNC/MDB_NOMETASYNC, in case these get reset.
+ */
+ rc = mdb_fopen(env, &fname, MDB_O_META, mode, &env->me_mfd);
+ if (rc)
+ goto leave;
+ }
+ DPRINTF(("opened dbenv %p", (void *) env));
+ if (excl > 0) {
+ rc = mdb_env_share_locks(env, &excl);
+ if (rc)
+ goto leave;
+ }
+ if (!(flags & MDB_RDONLY)) {
+ MDB_txn *txn;
+ int tsize = sizeof(MDB_txn), size = tsize + env->me_maxdbs *
+ (sizeof(MDB_db)+sizeof(MDB_cursor *)+sizeof(unsigned int)+1);
+ if ((env->me_pbuf = calloc(1, env->me_psize)) &&
+ (txn = calloc(1, size)))
+ {
+ txn->mt_dbs = (MDB_db *)((char *)txn + tsize);
+ txn->mt_cursors = (MDB_cursor **)(txn->mt_dbs + env->me_maxdbs);
+ txn->mt_dbiseqs = (unsigned int *)(txn->mt_cursors + env->me_maxdbs);
+ txn->mt_dbflags = (unsigned char *)(txn->mt_dbiseqs + env->me_maxdbs);
+ txn->mt_env = env;
+ txn->mt_dbxs = env->me_dbxs;
+ txn->mt_flags = MDB_TXN_FINISHED;
+ env->me_txn0 = txn;
+ } else {
+ rc = ENOMEM;
+ }
+ }
+ }
+
+leave:
+ if (rc) {
+ mdb_env_close0(env, excl);
+ }
+ mdb_fname_destroy(fname);
+ return rc;
+}
+
+/** Destroy resources from mdb_env_open(), clear our readers & DBIs */
+static void ESECT
+mdb_env_close0(MDB_env *env, int excl)
+{
+ int i;
+
+ if (!(env->me_flags & MDB_ENV_ACTIVE))
+ return;
+
+ /* Doing this here since me_dbxs may not exist during mdb_env_close */
+ if (env->me_dbxs) {
+ for (i = env->me_maxdbs; --i >= CORE_DBS; )
+ free(env->me_dbxs[i].md_name.mv_data);
+ free(env->me_dbxs);
+ }
+
+ free(env->me_pbuf);
+ free(env->me_dbiseqs);
+ free(env->me_dbflags);
+ free(env->me_path);
+ free(env->me_dirty_list);
+ free(env->me_txn0);
+ mdb_midl_free(env->me_free_pgs);
+
+ if (env->me_flags & MDB_ENV_TXKEY) {
+ pthread_key_delete(env->me_txkey);
+#ifdef _WIN32
+ /* Delete our key from the global list */
+ for (i=0; i<mdb_tls_nkeys; i++)
+ if (mdb_tls_keys[i] == env->me_txkey) {
+ mdb_tls_keys[i] = mdb_tls_keys[mdb_tls_nkeys-1];
+ mdb_tls_nkeys--;
+ break;
+ }
+#endif
+ }
+
+ if (env->me_map) {
+ munmap(env->me_map, env->me_mapsize);
+ }
+ if (env->me_mfd != INVALID_HANDLE_VALUE)
+ (void) close(env->me_mfd);
+ if (env->me_fd != INVALID_HANDLE_VALUE)
+ (void) close(env->me_fd);
+ if (env->me_txns) {
+ MDB_PID_T pid = env->me_pid;
+ /* Clearing readers is done in this function because
+ * me_txkey with its destructor must be disabled first.
+ *
+ * We skip the the reader mutex, so we touch only
+ * data owned by this process (me_close_readers and
+ * our readers), and clear each reader atomically.
+ */
+ for (i = env->me_close_readers; --i >= 0; )
+ if (env->me_txns->mti_readers[i].mr_pid == pid)
+ env->me_txns->mti_readers[i].mr_pid = 0;
+#ifdef _WIN32
+ if (env->me_rmutex) {
+ CloseHandle(env->me_rmutex);
+ if (env->me_wmutex) CloseHandle(env->me_wmutex);
+ }
+ /* Windows automatically destroys the mutexes when
+ * the last handle closes.
+ */
+#elif defined(MDB_USE_POSIX_SEM)
+ if (env->me_rmutex != SEM_FAILED) {
+ sem_close(env->me_rmutex);
+ if (env->me_wmutex != SEM_FAILED)
+ sem_close(env->me_wmutex);
+ /* If we have the filelock: If we are the
+ * only remaining user, clean up semaphores.
+ */
+ if (excl == 0)
+ mdb_env_excl_lock(env, &excl);
+ if (excl > 0) {
+ sem_unlink(env->me_txns->mti_rmname);
+ sem_unlink(env->me_txns->mti_wmname);
+ }
+ }
+#endif
+ munmap((void *)env->me_txns, (env->me_maxreaders-1)*sizeof(MDB_reader)+sizeof(MDB_txninfo));
+ }
+ if (env->me_lfd != INVALID_HANDLE_VALUE) {
+#ifdef _WIN32
+ if (excl >= 0) {
+ /* Unlock the lockfile. Windows would have unlocked it
+ * after closing anyway, but not necessarily at once.
+ */
+ UnlockFile(env->me_lfd, 0, 0, 1, 0);
+ }
+#endif
+ (void) close(env->me_lfd);
+ }
+
+ env->me_flags &= ~(MDB_ENV_ACTIVE|MDB_ENV_TXKEY);
+}
+
+void ESECT
+mdb_env_close(MDB_env *env)
+{
+ MDB_page *dp;
+
+ if (env == NULL)
+ return;
+
+ VGMEMP_DESTROY(env);
+ while ((dp = env->me_dpages) != NULL) {
+ VGMEMP_DEFINED(&dp->mp_next, sizeof(dp->mp_next));
+ env->me_dpages = dp->mp_next;
+ free(dp);
+ }
+
+ mdb_env_close0(env, 0);
+ free(env);
+}
+
+/** Compare two items pointing at aligned size_t's */
+static int
+mdb_cmp_long(const MDB_val *a, const MDB_val *b)
+{
+ return (*(size_t *)a->mv_data < *(size_t *)b->mv_data) ? -1 :
+ *(size_t *)a->mv_data > *(size_t *)b->mv_data;
+}
+
+/** Compare two items pointing at aligned unsigned int's.
+ *
+ * This is also set as #MDB_INTEGERDUP|#MDB_DUPFIXED's #MDB_dbx.%md_dcmp,
+ * but #mdb_cmp_clong() is called instead if the data type is size_t.
+ */
+static int
+mdb_cmp_int(const MDB_val *a, const MDB_val *b)
+{
+ return (*(unsigned int *)a->mv_data < *(unsigned int *)b->mv_data) ? -1 :
+ *(unsigned int *)a->mv_data > *(unsigned int *)b->mv_data;
+}
+
+/** Compare two items pointing at unsigned ints of unknown alignment.
+ * Nodes and keys are guaranteed to be 2-byte aligned.
+ */
+static int
+mdb_cmp_cint(const MDB_val *a, const MDB_val *b)
+{
+#if BYTE_ORDER == LITTLE_ENDIAN
+ unsigned short *u, *c;
+ int x;
+
+ u = (unsigned short *) ((char *) a->mv_data + a->mv_size);
+ c = (unsigned short *) ((char *) b->mv_data + a->mv_size);
+ do {
+ x = *--u - *--c;
+ } while(!x && u > (unsigned short *)a->mv_data);
+ return x;
+#else
+ unsigned short *u, *c, *end;
+ int x;
+
+ end = (unsigned short *) ((char *) a->mv_data + a->mv_size);
+ u = (unsigned short *)a->mv_data;
+ c = (unsigned short *)b->mv_data;
+ do {
+ x = *u++ - *c++;
+ } while(!x && u < end);
+ return x;
+#endif
+}
+
+/** Compare two items lexically */
+static int
+mdb_cmp_memn(const MDB_val *a, const MDB_val *b)
+{
+ int diff;
+ ssize_t len_diff;
+ unsigned int len;
+
+ len = a->mv_size;
+ len_diff = (ssize_t) a->mv_size - (ssize_t) b->mv_size;
+ if (len_diff > 0) {
+ len = b->mv_size;
+ len_diff = 1;
+ }
+
+ diff = memcmp(a->mv_data, b->mv_data, len);
+ return diff ? diff : len_diff<0 ? -1 : len_diff;
+}
+
+/** Compare two items in reverse byte order */
+static int
+mdb_cmp_memnr(const MDB_val *a, const MDB_val *b)
+{
+ const unsigned char *p1, *p2, *p1_lim;
+ ssize_t len_diff;
+ int diff;
+
+ p1_lim = (const unsigned char *)a->mv_data;
+ p1 = (const unsigned char *)a->mv_data + a->mv_size;
+ p2 = (const unsigned char *)b->mv_data + b->mv_size;
+
+ len_diff = (ssize_t) a->mv_size - (ssize_t) b->mv_size;
+ if (len_diff > 0) {
+ p1_lim += len_diff;
+ len_diff = 1;
+ }
+
+ while (p1 > p1_lim) {
+ diff = *--p1 - *--p2;
+ if (diff)
+ return diff;
+ }
+ return len_diff<0 ? -1 : len_diff;
+}
+
+/** Search for key within a page, using binary search.
+ * Returns the smallest entry larger or equal to the key.
+ * If exactp is non-null, stores whether the found entry was an exact match
+ * in *exactp (1 or 0).
+ * Updates the cursor index with the index of the found entry.
+ * If no entry larger or equal to the key is found, returns NULL.
+ */
+static MDB_node *
+mdb_node_search(MDB_cursor *mc, MDB_val *key, int *exactp)
+{
+ unsigned int i = 0, nkeys;
+ int low, high;
+ int rc = 0;
+ MDB_page *mp = mc->mc_pg[mc->mc_top];
+ MDB_node *node = NULL;
+ MDB_val nodekey;
+ MDB_cmp_func *cmp;
+ DKBUF;
+
+ nkeys = NUMKEYS(mp);
+
+ DPRINTF(("searching %u keys in %s %spage %"Z"u",
+ nkeys, IS_LEAF(mp) ? "leaf" : "branch", IS_SUBP(mp) ? "sub-" : "",
+ mdb_dbg_pgno(mp)));
+
+ low = IS_LEAF(mp) ? 0 : 1;
+ high = nkeys - 1;
+ cmp = mc->mc_dbx->md_cmp;
+
+ /* Branch pages have no data, so if using integer keys,
+ * alignment is guaranteed. Use faster mdb_cmp_int.
+ */
+ if (cmp == mdb_cmp_cint && IS_BRANCH(mp)) {
+ if (NODEPTR(mp, 1)->mn_ksize == sizeof(size_t))
+ cmp = mdb_cmp_long;
+ else
+ cmp = mdb_cmp_int;
+ }
+
+ if (IS_LEAF2(mp)) {
+ nodekey.mv_size = mc->mc_db->md_pad;
+ node = NODEPTR(mp, 0); /* fake */
+ while (low <= high) {
+ i = (low + high) >> 1;
+ nodekey.mv_data = LEAF2KEY(mp, i, nodekey.mv_size);
+ rc = cmp(key, &nodekey);
+ DPRINTF(("found leaf index %u [%s], rc = %i",
+ i, DKEY(&nodekey), rc));
+ if (rc == 0)
+ break;
+ if (rc > 0)
+ low = i + 1;
+ else
+ high = i - 1;
+ }
+ } else {
+ while (low <= high) {
+ i = (low + high) >> 1;
+
+ node = NODEPTR(mp, i);
+ nodekey.mv_size = NODEKSZ(node);
+ nodekey.mv_data = NODEKEY(node);
+
+ rc = cmp(key, &nodekey);
+#if MDB_DEBUG
+ if (IS_LEAF(mp))
+ DPRINTF(("found leaf index %u [%s], rc = %i",
+ i, DKEY(&nodekey), rc));
+ else
+ DPRINTF(("found branch index %u [%s -> %"Z"u], rc = %i",
+ i, DKEY(&nodekey), NODEPGNO(node), rc));
+#endif
+ if (rc == 0)
+ break;
+ if (rc > 0)
+ low = i + 1;
+ else
+ high = i - 1;
+ }
+ }
+
+ if (rc > 0) { /* Found entry is less than the key. */
+ i++; /* Skip to get the smallest entry larger than key. */
+ if (!IS_LEAF2(mp))
+ node = NODEPTR(mp, i);
+ }
+ if (exactp)
+ *exactp = (rc == 0 && nkeys > 0);
+ /* store the key index */
+ mc->mc_ki[mc->mc_top] = i;
+ if (i >= nkeys)
+ /* There is no entry larger or equal to the key. */
+ return NULL;
+
+ /* nodeptr is fake for LEAF2 */
+ return node;
+}
+
+#if 0
+static void
+mdb_cursor_adjust(MDB_cursor *mc, func)
+{
+ MDB_cursor *m2;
+
+ for (m2 = mc->mc_txn->mt_cursors[mc->mc_dbi]; m2; m2=m2->mc_next) {
+ if (m2->mc_pg[m2->mc_top] == mc->mc_pg[mc->mc_top]) {
+ func(mc, m2);
+ }
+ }
+}
+#endif
+
+/** Pop a page off the top of the cursor's stack. */
+static void
+mdb_cursor_pop(MDB_cursor *mc)
+{
+ if (mc->mc_snum) {
+ DPRINTF(("popping page %"Z"u off db %d cursor %p",
+ mc->mc_pg[mc->mc_top]->mp_pgno, DDBI(mc), (void *) mc));
+
+ mc->mc_snum--;
+ if (mc->mc_snum) {
+ mc->mc_top--;
+ } else {
+ mc->mc_flags &= ~C_INITIALIZED;
+ }
+ }
+}
+
+/** Push a page onto the top of the cursor's stack.
+ * Set #MDB_TXN_ERROR on failure.
+ */
+static int
+mdb_cursor_push(MDB_cursor *mc, MDB_page *mp)
+{
+ DPRINTF(("pushing page %"Z"u on db %d cursor %p", mp->mp_pgno,
+ DDBI(mc), (void *) mc));
+
+ if (mc->mc_snum >= CURSOR_STACK) {
+ mc->mc_txn->mt_flags |= MDB_TXN_ERROR;
+ return MDB_CURSOR_FULL;
+ }
+
+ mc->mc_top = mc->mc_snum++;
+ mc->mc_pg[mc->mc_top] = mp;
+ mc->mc_ki[mc->mc_top] = 0;
+
+ return MDB_SUCCESS;
+}
+
+/** Find the address of the page corresponding to a given page number.
+ * Set #MDB_TXN_ERROR on failure.
+ * @param[in] mc the cursor accessing the page.
+ * @param[in] pgno the page number for the page to retrieve.
+ * @param[out] ret address of a pointer where the page's address will be stored.
+ * @param[out] lvl dirty_list inheritance level of found page. 1=current txn, 0=mapped page.
+ * @return 0 on success, non-zero on failure.
+ */
+static int
+mdb_page_get(MDB_cursor *mc, pgno_t pgno, MDB_page **ret, int *lvl)
+{
+ MDB_txn *txn = mc->mc_txn;
+ MDB_env *env = txn->mt_env;
+ MDB_page *p = NULL;
+ int level;
+
+ if (! (txn->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_WRITEMAP))) {
+ MDB_txn *tx2 = txn;
+ level = 1;
+ do {
+ MDB_ID2L dl = tx2->mt_u.dirty_list;
+ unsigned x;
+ /* Spilled pages were dirtied in this txn and flushed
+ * because the dirty list got full. Bring this page
+ * back in from the map (but don't unspill it here,
+ * leave that unless page_touch happens again).
+ */
+ if (tx2->mt_spill_pgs) {
+ MDB_ID pn = pgno << 1;
+ x = mdb_midl_search(tx2->mt_spill_pgs, pn);
+ if (x <= tx2->mt_spill_pgs[0] && tx2->mt_spill_pgs[x] == pn) {
+ p = (MDB_page *)(env->me_map + env->me_psize * pgno);
+ goto done;
+ }
+ }
+ if (dl[0].mid) {
+ unsigned x = mdb_mid2l_search(dl, pgno);
+ if (x <= dl[0].mid && dl[x].mid == pgno) {
+ p = dl[x].mptr;
+ goto done;
+ }
+ }
+ level++;
+ } while ((tx2 = tx2->mt_parent) != NULL);
+ }
+
+ if (pgno < txn->mt_next_pgno) {
+ level = 0;
+ p = (MDB_page *)(env->me_map + env->me_psize * pgno);
+ } else {
+ DPRINTF(("page %"Z"u not found", pgno));
+ txn->mt_flags |= MDB_TXN_ERROR;
+ return MDB_PAGE_NOTFOUND;
+ }
+
+done:
+ *ret = p;
+ if (lvl)
+ *lvl = level;
+ return MDB_SUCCESS;
+}
+
+/** Finish #mdb_page_search() / #mdb_page_search_lowest().
+ * The cursor is at the root page, set up the rest of it.
+ */
+static int
+mdb_page_search_root(MDB_cursor *mc, MDB_val *key, int flags)
+{
+ MDB_page *mp = mc->mc_pg[mc->mc_top];
+ int rc;
+ DKBUF;
+
+ while (IS_BRANCH(mp)) {
+ MDB_node *node;
+ indx_t i;
+
+ DPRINTF(("branch page %"Z"u has %u keys", mp->mp_pgno, NUMKEYS(mp)));
+ /* Don't assert on branch pages in the FreeDB. We can get here
+ * while in the process of rebalancing a FreeDB branch page; we must
+ * let that proceed. ITS#8336
+ */
+ mdb_cassert(mc, !mc->mc_dbi || NUMKEYS(mp) > 1);
+ DPRINTF(("found index 0 to page %"Z"u", NODEPGNO(NODEPTR(mp, 0))));
+
+ if (flags & (MDB_PS_FIRST|MDB_PS_LAST)) {
+ i = 0;
+ if (flags & MDB_PS_LAST) {
+ i = NUMKEYS(mp) - 1;
+ /* if already init'd, see if we're already in right place */
+ if (mc->mc_flags & C_INITIALIZED) {
+ if (mc->mc_ki[mc->mc_top] == i) {
+ mc->mc_top = mc->mc_snum++;
+ mp = mc->mc_pg[mc->mc_top];
+ goto ready;
+ }
+ }
+ }
+ } else {
+ int exact;
+ node = mdb_node_search(mc, key, &exact);
+ if (node == NULL)
+ i = NUMKEYS(mp) - 1;
+ else {
+ i = mc->mc_ki[mc->mc_top];
+ if (!exact) {
+ mdb_cassert(mc, i > 0);
+ i--;
+ }
+ }
+ DPRINTF(("following index %u for key [%s]", i, DKEY(key)));
+ }
+
+ mdb_cassert(mc, i < NUMKEYS(mp));
+ node = NODEPTR(mp, i);
+
+ if ((rc = mdb_page_get(mc, NODEPGNO(node), &mp, NULL)) != 0)
+ return rc;
+
+ mc->mc_ki[mc->mc_top] = i;
+ if ((rc = mdb_cursor_push(mc, mp)))
+ return rc;
+
+ready:
+ if (flags & MDB_PS_MODIFY) {
+ if ((rc = mdb_page_touch(mc)) != 0)
+ return rc;
+ mp = mc->mc_pg[mc->mc_top];
+ }
+ }
+
+ if (!IS_LEAF(mp)) {
+ DPRINTF(("internal error, index points to a %02X page!?",
+ mp->mp_flags));
+ mc->mc_txn->mt_flags |= MDB_TXN_ERROR;
+ return MDB_CORRUPTED;
+ }
+
+ DPRINTF(("found leaf page %"Z"u for key [%s]", mp->mp_pgno,
+ key ? DKEY(key) : "null"));
+ mc->mc_flags |= C_INITIALIZED;
+ mc->mc_flags &= ~C_EOF;
+
+ return MDB_SUCCESS;
+}
+
+/** Search for the lowest key under the current branch page.
+ * This just bypasses a NUMKEYS check in the current page
+ * before calling mdb_page_search_root(), because the callers
+ * are all in situations where the current page is known to
+ * be underfilled.
+ */
+static int
+mdb_page_search_lowest(MDB_cursor *mc)
+{
+ MDB_page *mp = mc->mc_pg[mc->mc_top];
+ MDB_node *node = NODEPTR(mp, 0);
+ int rc;
+
+ if ((rc = mdb_page_get(mc, NODEPGNO(node), &mp, NULL)) != 0)
+ return rc;
+
+ mc->mc_ki[mc->mc_top] = 0;
+ if ((rc = mdb_cursor_push(mc, mp)))
+ return rc;
+ return mdb_page_search_root(mc, NULL, MDB_PS_FIRST);
+}
+
+/** Search for the page a given key should be in.
+ * Push it and its parent pages on the cursor stack.
+ * @param[in,out] mc the cursor for this operation.
+ * @param[in] key the key to search for, or NULL for first/last page.
+ * @param[in] flags If MDB_PS_MODIFY is set, visited pages in the DB
+ * are touched (updated with new page numbers).
+ * If MDB_PS_FIRST or MDB_PS_LAST is set, find first or last leaf.
+ * This is used by #mdb_cursor_first() and #mdb_cursor_last().
+ * If MDB_PS_ROOTONLY set, just fetch root node, no further lookups.
+ * @return 0 on success, non-zero on failure.
+ */
+static int
+mdb_page_search(MDB_cursor *mc, MDB_val *key, int flags)
+{
+ int rc;
+ pgno_t root;
+
+ /* Make sure the txn is still viable, then find the root from
+ * the txn's db table and set it as the root of the cursor's stack.
+ */
+ if (mc->mc_txn->mt_flags & MDB_TXN_BLOCKED) {
+ DPUTS("transaction may not be used now");
+ return MDB_BAD_TXN;
+ } else {
+ /* Make sure we're using an up-to-date root */
+ if (*mc->mc_dbflag & DB_STALE) {
+ MDB_cursor mc2;
+ if (TXN_DBI_CHANGED(mc->mc_txn, mc->mc_dbi))
+ return MDB_BAD_DBI;
+ mdb_cursor_init(&mc2, mc->mc_txn, MAIN_DBI, NULL);
+ rc = mdb_page_search(&mc2, &mc->mc_dbx->md_name, 0);
+ if (rc)
+ return rc;
+ {
+ MDB_val data;
+ int exact = 0;
+ uint16_t flags;
+ MDB_node *leaf = mdb_node_search(&mc2,
+ &mc->mc_dbx->md_name, &exact);
+ if (!exact)
+ return MDB_NOTFOUND;
+ if ((leaf->mn_flags & (F_DUPDATA|F_SUBDATA)) != F_SUBDATA)
+ return MDB_INCOMPATIBLE; /* not a named DB */
+ rc = mdb_node_read(&mc2, leaf, &data);
+ if (rc)
+ return rc;
+ memcpy(&flags, ((char *) data.mv_data + offsetof(MDB_db, md_flags)),
+ sizeof(uint16_t));
+ /* The txn may not know this DBI, or another process may
+ * have dropped and recreated the DB with other flags.
+ */
+ if ((mc->mc_db->md_flags & PERSISTENT_FLAGS) != flags)
+ return MDB_INCOMPATIBLE;
+ memcpy(mc->mc_db, data.mv_data, sizeof(MDB_db));
+ }
+ *mc->mc_dbflag &= ~DB_STALE;
+ }
+ root = mc->mc_db->md_root;
+
+ if (root == P_INVALID) { /* Tree is empty. */
+ DPUTS("tree is empty");
+ return MDB_NOTFOUND;
+ }
+ }
+
+ mdb_cassert(mc, root > 1);
+ if (!mc->mc_pg[0] || mc->mc_pg[0]->mp_pgno != root)
+ if ((rc = mdb_page_get(mc, root, &mc->mc_pg[0], NULL)) != 0)
+ return rc;
+
+ mc->mc_snum = 1;
+ mc->mc_top = 0;
+
+ DPRINTF(("db %d root page %"Z"u has flags 0x%X",
+ DDBI(mc), root, mc->mc_pg[0]->mp_flags));
+
+ if (flags & MDB_PS_MODIFY) {
+ if ((rc = mdb_page_touch(mc)))
+ return rc;
+ }
+
+ if (flags & MDB_PS_ROOTONLY)
+ return MDB_SUCCESS;
+
+ return mdb_page_search_root(mc, key, flags);
+}
+
+static int
+mdb_ovpage_free(MDB_cursor *mc, MDB_page *mp)
+{
+ MDB_txn *txn = mc->mc_txn;
+ pgno_t pg = mp->mp_pgno;
+ unsigned x = 0, ovpages = mp->mp_pages;
+ MDB_env *env = txn->mt_env;
+ MDB_IDL sl = txn->mt_spill_pgs;
+ MDB_ID pn = pg << 1;
+ int rc;
+
+ DPRINTF(("free ov page %"Z"u (%d)", pg, ovpages));
+ /* If the page is dirty or on the spill list we just acquired it,
+ * so we should give it back to our current free list, if any.
+ * Otherwise put it onto the list of pages we freed in this txn.
+ *
+ * Won't create me_pghead: me_pglast must be inited along with it.
+ * Unsupported in nested txns: They would need to hide the page
+ * range in ancestor txns' dirty and spilled lists.
+ */
+ if (env->me_pghead &&
+ !txn->mt_parent &&
+ ((mp->mp_flags & P_DIRTY) ||
+ (sl && (x = mdb_midl_search(sl, pn)) <= sl[0] && sl[x] == pn)))
+ {
+ unsigned i, j;
+ pgno_t *mop;
+ MDB_ID2 *dl, ix, iy;
+ rc = mdb_midl_need(&env->me_pghead, ovpages);
+ if (rc)
+ return rc;
+ if (!(mp->mp_flags & P_DIRTY)) {
+ /* This page is no longer spilled */
+ if (x == sl[0])
+ sl[0]--;
+ else
+ sl[x] |= 1;
+ goto release;
+ }
+ /* Remove from dirty list */
+ dl = txn->mt_u.dirty_list;
+ x = dl[0].mid--;
+ for (ix = dl[x]; ix.mptr != mp; ix = iy) {
+ if (x > 1) {
+ x--;
+ iy = dl[x];
+ dl[x] = ix;
+ } else {
+ mdb_cassert(mc, x > 1);
+ j = ++(dl[0].mid);
+ dl[j] = ix; /* Unsorted. OK when MDB_TXN_ERROR. */
+ txn->mt_flags |= MDB_TXN_ERROR;
+ return MDB_CORRUPTED;
+ }
+ }
+ txn->mt_dirty_room++;
+ if (!(env->me_flags & MDB_WRITEMAP))
+ mdb_dpage_free(env, mp);
+release:
+ /* Insert in me_pghead */
+ mop = env->me_pghead;
+ j = mop[0] + ovpages;
+ for (i = mop[0]; i && mop[i] < pg; i--)
+ mop[j--] = mop[i];
+ while (j>i)
+ mop[j--] = pg++;
+ mop[0] += ovpages;
+ } else {
+ rc = mdb_midl_append_range(&txn->mt_free_pgs, pg, ovpages);
+ if (rc)
+ return rc;
+ }
+ mc->mc_db->md_overflow_pages -= ovpages;
+ return 0;
+}
+
+/** Return the data associated with a given node.
+ * @param[in] mc The cursor for this operation.
+ * @param[in] leaf The node being read.
+ * @param[out] data Updated to point to the node's data.
+ * @return 0 on success, non-zero on failure.
+ */
+static int
+mdb_node_read(MDB_cursor *mc, MDB_node *leaf, MDB_val *data)
+{
+ MDB_page *omp; /* overflow page */
+ pgno_t pgno;
+ int rc;
+
+ if (!F_ISSET(leaf->mn_flags, F_BIGDATA)) {
+ data->mv_size = NODEDSZ(leaf);
+ data->mv_data = NODEDATA(leaf);
+ return MDB_SUCCESS;
+ }
+
+ /* Read overflow data.
+ */
+ data->mv_size = NODEDSZ(leaf);
+ memcpy(&pgno, NODEDATA(leaf), sizeof(pgno));
+ if ((rc = mdb_page_get(mc, pgno, &omp, NULL)) != 0) {
+ DPRINTF(("read overflow page %"Z"u failed", pgno));
+ return rc;
+ }
+ data->mv_data = METADATA(omp);
+
+ return MDB_SUCCESS;
+}
+
+int
+mdb_get(MDB_txn *txn, MDB_dbi dbi,
+ MDB_val *key, MDB_val *data)
+{
+ MDB_cursor mc;
+ MDB_xcursor mx;
+ int exact = 0;
+ DKBUF;
+
+ DPRINTF(("===> get db %u key [%s]", dbi, DKEY(key)));
+
+ if (!key || !data || !TXN_DBI_EXIST(txn, dbi, DB_USRVALID))
+ return EINVAL;
+
+ if (txn->mt_flags & MDB_TXN_BLOCKED)
+ return MDB_BAD_TXN;
+
+ mdb_cursor_init(&mc, txn, dbi, &mx);
+ return mdb_cursor_set(&mc, key, data, MDB_SET, &exact);
+}
+
+/** Find a sibling for a page.
+ * Replaces the page at the top of the cursor's stack with the
+ * specified sibling, if one exists.
+ * @param[in] mc The cursor for this operation.
+ * @param[in] move_right Non-zero if the right sibling is requested,
+ * otherwise the left sibling.
+ * @return 0 on success, non-zero on failure.
+ */
+static int
+mdb_cursor_sibling(MDB_cursor *mc, int move_right)
+{
+ int rc;
+ MDB_node *indx;
+ MDB_page *mp;
+
+ if (mc->mc_snum < 2) {
+ return MDB_NOTFOUND; /* root has no siblings */
+ }
+
+ mdb_cursor_pop(mc);
+ DPRINTF(("parent page is page %"Z"u, index %u",
+ mc->mc_pg[mc->mc_top]->mp_pgno, mc->mc_ki[mc->mc_top]));
+
+ if (move_right ? (mc->mc_ki[mc->mc_top] + 1u >= NUMKEYS(mc->mc_pg[mc->mc_top]))
+ : (mc->mc_ki[mc->mc_top] == 0)) {
+ DPRINTF(("no more keys left, moving to %s sibling",
+ move_right ? "right" : "left"));
+ if ((rc = mdb_cursor_sibling(mc, move_right)) != MDB_SUCCESS) {
+ /* undo cursor_pop before returning */
+ mc->mc_top++;
+ mc->mc_snum++;
+ return rc;
+ }
+ } else {
+ if (move_right)
+ mc->mc_ki[mc->mc_top]++;
+ else
+ mc->mc_ki[mc->mc_top]--;
+ DPRINTF(("just moving to %s index key %u",
+ move_right ? "right" : "left", mc->mc_ki[mc->mc_top]));
+ }
+ mdb_cassert(mc, IS_BRANCH(mc->mc_pg[mc->mc_top]));
+
+ indx = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]);
+ if ((rc = mdb_page_get(mc, NODEPGNO(indx), &mp, NULL)) != 0) {
+ /* mc will be inconsistent if caller does mc_snum++ as above */
+ mc->mc_flags &= ~(C_INITIALIZED|C_EOF);
+ return rc;
+ }
+
+ mdb_cursor_push(mc, mp);
+ if (!move_right)
+ mc->mc_ki[mc->mc_top] = NUMKEYS(mp)-1;
+
+ return MDB_SUCCESS;
+}
+
+/** Move the cursor to the next data item. */
+static int
+mdb_cursor_next(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op)
+{
+ MDB_page *mp;
+ MDB_node *leaf;
+ int rc;
+
+ if ((mc->mc_flags & C_DEL && op == MDB_NEXT_DUP))
+ return MDB_NOTFOUND;
+
+ if (!(mc->mc_flags & C_INITIALIZED))
+ return mdb_cursor_first(mc, key, data);
+
+ mp = mc->mc_pg[mc->mc_top];
+
+ if (mc->mc_flags & C_EOF) {
+ if (mc->mc_ki[mc->mc_top] >= NUMKEYS(mp)-1)
+ return MDB_NOTFOUND;
+ mc->mc_flags ^= C_EOF;
+ }
+
+ if (mc->mc_db->md_flags & MDB_DUPSORT) {
+ leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]);
+ if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
+ if (op == MDB_NEXT || op == MDB_NEXT_DUP) {
+ rc = mdb_cursor_next(&mc->mc_xcursor->mx_cursor, data, NULL, MDB_NEXT);
+ if (op != MDB_NEXT || rc != MDB_NOTFOUND) {
+ if (rc == MDB_SUCCESS)
+ MDB_GET_KEY(leaf, key);
+ return rc;
+ }
+ }
+ } else {
+ mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED|C_EOF);
+ if (op == MDB_NEXT_DUP)
+ return MDB_NOTFOUND;
+ }
+ }
+
+ DPRINTF(("cursor_next: top page is %"Z"u in cursor %p",
+ mdb_dbg_pgno(mp), (void *) mc));
+ if (mc->mc_flags & C_DEL) {
+ mc->mc_flags ^= C_DEL;
+ goto skip;
+ }
+
+ if (mc->mc_ki[mc->mc_top] + 1u >= NUMKEYS(mp)) {
+ DPUTS("=====> move to next sibling page");
+ if ((rc = mdb_cursor_sibling(mc, 1)) != MDB_SUCCESS) {
+ mc->mc_flags |= C_EOF;
+ return rc;
+ }
+ mp = mc->mc_pg[mc->mc_top];
+ DPRINTF(("next page is %"Z"u, key index %u", mp->mp_pgno, mc->mc_ki[mc->mc_top]));
+ } else
+ mc->mc_ki[mc->mc_top]++;
+
+skip:
+ DPRINTF(("==> cursor points to page %"Z"u with %u keys, key index %u",
+ mdb_dbg_pgno(mp), NUMKEYS(mp), mc->mc_ki[mc->mc_top]));
+
+ if (IS_LEAF2(mp)) {
+ key->mv_size = mc->mc_db->md_pad;
+ key->mv_data = LEAF2KEY(mp, mc->mc_ki[mc->mc_top], key->mv_size);
+ return MDB_SUCCESS;
+ }
+
+ mdb_cassert(mc, IS_LEAF(mp));
+ leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]);
+
+ if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
+ mdb_xcursor_init1(mc, leaf);
+ }
+ if (data) {
+ if ((rc = mdb_node_read(mc, leaf, data)) != MDB_SUCCESS)
+ return rc;
+
+ if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
+ rc = mdb_cursor_first(&mc->mc_xcursor->mx_cursor, data, NULL);
+ if (rc != MDB_SUCCESS)
+ return rc;
+ }
+ }
+
+ MDB_GET_KEY(leaf, key);
+ return MDB_SUCCESS;
+}
+
+/** Move the cursor to the previous data item. */
+static int
+mdb_cursor_prev(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op)
+{
+ MDB_page *mp;
+ MDB_node *leaf;
+ int rc;
+
+ if (!(mc->mc_flags & C_INITIALIZED)) {
+ rc = mdb_cursor_last(mc, key, data);
+ if (rc)
+ return rc;
+ mc->mc_ki[mc->mc_top]++;
+ }
+
+ mp = mc->mc_pg[mc->mc_top];
+
+ if (mc->mc_db->md_flags & MDB_DUPSORT) {
+ leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]);
+ if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
+ if (op == MDB_PREV || op == MDB_PREV_DUP) {
+ rc = mdb_cursor_prev(&mc->mc_xcursor->mx_cursor, data, NULL, MDB_PREV);
+ if (op != MDB_PREV || rc != MDB_NOTFOUND) {
+ if (rc == MDB_SUCCESS) {
+ MDB_GET_KEY(leaf, key);
+ mc->mc_flags &= ~C_EOF;
+ }
+ return rc;
+ }
+ }
+ } else {
+ mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED|C_EOF);
+ if (op == MDB_PREV_DUP)
+ return MDB_NOTFOUND;
+ }
+ }
+
+ DPRINTF(("cursor_prev: top page is %"Z"u in cursor %p",
+ mdb_dbg_pgno(mp), (void *) mc));
+
+ mc->mc_flags &= ~(C_EOF|C_DEL);
+
+ if (mc->mc_ki[mc->mc_top] == 0) {
+ DPUTS("=====> move to prev sibling page");
+ if ((rc = mdb_cursor_sibling(mc, 0)) != MDB_SUCCESS) {
+ return rc;
+ }
+ mp = mc->mc_pg[mc->mc_top];
+ mc->mc_ki[mc->mc_top] = NUMKEYS(mp) - 1;
+ DPRINTF(("prev page is %"Z"u, key index %u", mp->mp_pgno, mc->mc_ki[mc->mc_top]));
+ } else
+ mc->mc_ki[mc->mc_top]--;
+
+ DPRINTF(("==> cursor points to page %"Z"u with %u keys, key index %u",
+ mdb_dbg_pgno(mp), NUMKEYS(mp), mc->mc_ki[mc->mc_top]));
+
+ if (IS_LEAF2(mp)) {
+ key->mv_size = mc->mc_db->md_pad;
+ key->mv_data = LEAF2KEY(mp, mc->mc_ki[mc->mc_top], key->mv_size);
+ return MDB_SUCCESS;
+ }
+
+ mdb_cassert(mc, IS_LEAF(mp));
+ leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]);
+
+ if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
+ mdb_xcursor_init1(mc, leaf);
+ }
+ if (data) {
+ if ((rc = mdb_node_read(mc, leaf, data)) != MDB_SUCCESS)
+ return rc;
+
+ if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
+ rc = mdb_cursor_last(&mc->mc_xcursor->mx_cursor, data, NULL);
+ if (rc != MDB_SUCCESS)
+ return rc;
+ }
+ }
+
+ MDB_GET_KEY(leaf, key);
+ return MDB_SUCCESS;
+}
+
+/** Set the cursor on a specific data item. */
+static int
+mdb_cursor_set(MDB_cursor *mc, MDB_val *key, MDB_val *data,
+ MDB_cursor_op op, int *exactp)
+{
+ int rc;
+ MDB_page *mp;
+ MDB_node *leaf = NULL;
+ DKBUF;
+
+ if (key->mv_size == 0)
+ return MDB_BAD_VALSIZE;
+
+ if (mc->mc_xcursor)
+ mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED|C_EOF);
+
+ /* See if we're already on the right page */
+ if (mc->mc_flags & C_INITIALIZED) {
+ MDB_val nodekey;
+
+ mp = mc->mc_pg[mc->mc_top];
+ if (!NUMKEYS(mp)) {
+ mc->mc_ki[mc->mc_top] = 0;
+ return MDB_NOTFOUND;
+ }
+ if (mp->mp_flags & P_LEAF2) {
+ nodekey.mv_size = mc->mc_db->md_pad;
+ nodekey.mv_data = LEAF2KEY(mp, 0, nodekey.mv_size);
+ } else {
+ leaf = NODEPTR(mp, 0);
+ MDB_GET_KEY2(leaf, nodekey);
+ }
+ rc = mc->mc_dbx->md_cmp(key, &nodekey);
+ if (rc == 0) {
+ /* Probably happens rarely, but first node on the page
+ * was the one we wanted.
+ */
+ mc->mc_ki[mc->mc_top] = 0;
+ if (exactp)
+ *exactp = 1;
+ goto set1;
+ }
+ if (rc > 0) {
+ unsigned int i;
+ unsigned int nkeys = NUMKEYS(mp);
+ if (nkeys > 1) {
+ if (mp->mp_flags & P_LEAF2) {
+ nodekey.mv_data = LEAF2KEY(mp,
+ nkeys-1, nodekey.mv_size);
+ } else {
+ leaf = NODEPTR(mp, nkeys-1);
+ MDB_GET_KEY2(leaf, nodekey);
+ }
+ rc = mc->mc_dbx->md_cmp(key, &nodekey);
+ if (rc == 0) {
+ /* last node was the one we wanted */
+ mc->mc_ki[mc->mc_top] = nkeys-1;
+ if (exactp)
+ *exactp = 1;
+ goto set1;
+ }
+ if (rc < 0) {
+ if (mc->mc_ki[mc->mc_top] < NUMKEYS(mp)) {
+ /* This is definitely the right page, skip search_page */
+ if (mp->mp_flags & P_LEAF2) {
+ nodekey.mv_data = LEAF2KEY(mp,
+ mc->mc_ki[mc->mc_top], nodekey.mv_size);
+ } else {
+ leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]);
+ MDB_GET_KEY2(leaf, nodekey);
+ }
+ rc = mc->mc_dbx->md_cmp(key, &nodekey);
+ if (rc == 0) {
+ /* current node was the one we wanted */
+ if (exactp)
+ *exactp = 1;
+ goto set1;
+ }
+ }
+ rc = 0;
+ mc->mc_flags &= ~C_EOF;
+ goto set2;
+ }
+ }
+ /* If any parents have right-sibs, search.
+ * Otherwise, there's nothing further.
+ */
+ for (i=0; i<mc->mc_top; i++)
+ if (mc->mc_ki[i] <
+ NUMKEYS(mc->mc_pg[i])-1)
+ break;
+ if (i == mc->mc_top) {
+ /* There are no other pages */
+ mc->mc_ki[mc->mc_top] = nkeys;
+ return MDB_NOTFOUND;
+ }
+ }
+ if (!mc->mc_top) {
+ /* There are no other pages */
+ mc->mc_ki[mc->mc_top] = 0;
+ if (op == MDB_SET_RANGE && !exactp) {
+ rc = 0;
+ goto set1;
+ } else
+ return MDB_NOTFOUND;
+ }
+ } else {
+ mc->mc_pg[0] = 0;
+ }
+
+ rc = mdb_page_search(mc, key, 0);
+ if (rc != MDB_SUCCESS)
+ return rc;
+
+ mp = mc->mc_pg[mc->mc_top];
+ mdb_cassert(mc, IS_LEAF(mp));
+
+set2:
+ leaf = mdb_node_search(mc, key, exactp);
+ if (exactp != NULL && !*exactp) {
+ /* MDB_SET specified and not an exact match. */
+ return MDB_NOTFOUND;
+ }
+
+ if (leaf == NULL) {
+ DPUTS("===> inexact leaf not found, goto sibling");
+ if ((rc = mdb_cursor_sibling(mc, 1)) != MDB_SUCCESS) {
+ mc->mc_flags |= C_EOF;
+ return rc; /* no entries matched */
+ }
+ mp = mc->mc_pg[mc->mc_top];
+ mdb_cassert(mc, IS_LEAF(mp));
+ leaf = NODEPTR(mp, 0);
+ }
+
+set1:
+ mc->mc_flags |= C_INITIALIZED;
+ mc->mc_flags &= ~C_EOF;
+
+ if (IS_LEAF2(mp)) {
+ if (op == MDB_SET_RANGE || op == MDB_SET_KEY) {
+ key->mv_size = mc->mc_db->md_pad;
+ key->mv_data = LEAF2KEY(mp, mc->mc_ki[mc->mc_top], key->mv_size);
+ }
+ return MDB_SUCCESS;
+ }
+
+ if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
+ mdb_xcursor_init1(mc, leaf);
+ }
+ if (data) {
+ if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
+ if (op == MDB_SET || op == MDB_SET_KEY || op == MDB_SET_RANGE) {
+ rc = mdb_cursor_first(&mc->mc_xcursor->mx_cursor, data, NULL);
+ } else {
+ int ex2, *ex2p;
+ if (op == MDB_GET_BOTH) {
+ ex2p = &ex2;
+ ex2 = 0;
+ } else {
+ ex2p = NULL;
+ }
+ rc = mdb_cursor_set(&mc->mc_xcursor->mx_cursor, data, NULL, MDB_SET_RANGE, ex2p);
+ if (rc != MDB_SUCCESS)
+ return rc;
+ }
+ } else if (op == MDB_GET_BOTH || op == MDB_GET_BOTH_RANGE) {
+ MDB_val olddata;
+ MDB_cmp_func *dcmp;
+ if ((rc = mdb_node_read(mc, leaf, &olddata)) != MDB_SUCCESS)
+ return rc;
+ dcmp = mc->mc_dbx->md_dcmp;
+#if UINT_MAX < SIZE_MAX
+ if (dcmp == mdb_cmp_int && olddata.mv_size == sizeof(size_t))
+ dcmp = mdb_cmp_clong;
+#endif
+ rc = dcmp(data, &olddata);
+ if (rc) {
+ if (op == MDB_GET_BOTH || rc > 0)
+ return MDB_NOTFOUND;
+ rc = 0;
+ }
+ *data = olddata;
+
+ } else {
+ if (mc->mc_xcursor)
+ mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED|C_EOF);
+ if ((rc = mdb_node_read(mc, leaf, data)) != MDB_SUCCESS)
+ return rc;
+ }
+ }
+
+ /* The key already matches in all other cases */
+ if (op == MDB_SET_RANGE || op == MDB_SET_KEY)
+ MDB_GET_KEY(leaf, key);
+ DPRINTF(("==> cursor placed on key [%s]", DKEY(key)));
+
+ return rc;
+}
+
+/** Move the cursor to the first item in the database. */
+static int
+mdb_cursor_first(MDB_cursor *mc, MDB_val *key, MDB_val *data)
+{
+ int rc;
+ MDB_node *leaf;
+
+ if (mc->mc_xcursor)
+ mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED|C_EOF);
+
+ if (!(mc->mc_flags & C_INITIALIZED) || mc->mc_top) {
+ rc = mdb_page_search(mc, NULL, MDB_PS_FIRST);
+ if (rc != MDB_SUCCESS)
+ return rc;
+ }
+ mdb_cassert(mc, IS_LEAF(mc->mc_pg[mc->mc_top]));
+
+ leaf = NODEPTR(mc->mc_pg[mc->mc_top], 0);
+ mc->mc_flags |= C_INITIALIZED;
+ mc->mc_flags &= ~C_EOF;
+
+ mc->mc_ki[mc->mc_top] = 0;
+
+ if (IS_LEAF2(mc->mc_pg[mc->mc_top])) {
+ key->mv_size = mc->mc_db->md_pad;
+ key->mv_data = LEAF2KEY(mc->mc_pg[mc->mc_top], 0, key->mv_size);
+ return MDB_SUCCESS;
+ }
+
+ if (data) {
+ if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
+ mdb_xcursor_init1(mc, leaf);
+ rc = mdb_cursor_first(&mc->mc_xcursor->mx_cursor, data, NULL);
+ if (rc)
+ return rc;
+ } else {
+ if ((rc = mdb_node_read(mc, leaf, data)) != MDB_SUCCESS)
+ return rc;
+ }
+ }
+ MDB_GET_KEY(leaf, key);
+ return MDB_SUCCESS;
+}
+
+/** Move the cursor to the last item in the database. */
+static int
+mdb_cursor_last(MDB_cursor *mc, MDB_val *key, MDB_val *data)
+{
+ int rc;
+ MDB_node *leaf;
+
+ if (mc->mc_xcursor)
+ mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED|C_EOF);
+
+ if (!(mc->mc_flags & C_INITIALIZED) || mc->mc_top) {
+ rc = mdb_page_search(mc, NULL, MDB_PS_LAST);
+ if (rc != MDB_SUCCESS)
+ return rc;
+ }
+ mdb_cassert(mc, IS_LEAF(mc->mc_pg[mc->mc_top]));
+
+ mc->mc_ki[mc->mc_top] = NUMKEYS(mc->mc_pg[mc->mc_top]) - 1;
+ mc->mc_flags |= C_INITIALIZED|C_EOF;
+ leaf = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]);
+
+ if (IS_LEAF2(mc->mc_pg[mc->mc_top])) {
+ key->mv_size = mc->mc_db->md_pad;
+ key->mv_data = LEAF2KEY(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top], key->mv_size);
+ return MDB_SUCCESS;
+ }
+
+ if (data) {
+ if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
+ mdb_xcursor_init1(mc, leaf);
+ rc = mdb_cursor_last(&mc->mc_xcursor->mx_cursor, data, NULL);
+ if (rc)
+ return rc;
+ } else {
+ if ((rc = mdb_node_read(mc, leaf, data)) != MDB_SUCCESS)
+ return rc;
+ }
+ }
+
+ MDB_GET_KEY(leaf, key);
+ return MDB_SUCCESS;
+}
+
+int
+mdb_cursor_get(MDB_cursor *mc, MDB_val *key, MDB_val *data,
+ MDB_cursor_op op)
+{
+ int rc;
+ int exact = 0;
+ int (*mfunc)(MDB_cursor *mc, MDB_val *key, MDB_val *data);
+
+ if (mc == NULL)
+ return EINVAL;
+
+ if (mc->mc_txn->mt_flags & MDB_TXN_BLOCKED)
+ return MDB_BAD_TXN;
+
+ switch (op) {
+ case MDB_GET_CURRENT:
+ if (!(mc->mc_flags & C_INITIALIZED)) {
+ rc = EINVAL;
+ } else {
+ MDB_page *mp = mc->mc_pg[mc->mc_top];
+ int nkeys = NUMKEYS(mp);
+ if (!nkeys || mc->mc_ki[mc->mc_top] >= nkeys) {
+ mc->mc_ki[mc->mc_top] = nkeys;
+ rc = MDB_NOTFOUND;
+ break;
+ }
+ rc = MDB_SUCCESS;
+ if (IS_LEAF2(mp)) {
+ key->mv_size = mc->mc_db->md_pad;
+ key->mv_data = LEAF2KEY(mp, mc->mc_ki[mc->mc_top], key->mv_size);
+ } else {
+ MDB_node *leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]);
+ MDB_GET_KEY(leaf, key);
+ if (data) {
+ if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
+ rc = mdb_cursor_get(&mc->mc_xcursor->mx_cursor, data, NULL, MDB_GET_CURRENT);
+ } else {
+ rc = mdb_node_read(mc, leaf, data);
+ }
+ }
+ }
+ }
+ break;
+ case MDB_GET_BOTH:
+ case MDB_GET_BOTH_RANGE:
+ if (data == NULL) {
+ rc = EINVAL;
+ break;
+ }
+ if (mc->mc_xcursor == NULL) {
+ rc = MDB_INCOMPATIBLE;
+ break;
+ }
+ /* FALLTHRU */
+ case MDB_SET:
+ case MDB_SET_KEY:
+ case MDB_SET_RANGE:
+ if (key == NULL) {
+ rc = EINVAL;
+ } else {
+ rc = mdb_cursor_set(mc, key, data, op,
+ op == MDB_SET_RANGE ? NULL : &exact);
+ }
+ break;
+ case MDB_GET_MULTIPLE:
+ if (data == NULL || !(mc->mc_flags & C_INITIALIZED)) {
+ rc = EINVAL;
+ break;
+ }
+ if (!(mc->mc_db->md_flags & MDB_DUPFIXED)) {
+ rc = MDB_INCOMPATIBLE;
+ break;
+ }
+ rc = MDB_SUCCESS;
+ if (!(mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) ||
+ (mc->mc_xcursor->mx_cursor.mc_flags & C_EOF))
+ break;
+ goto fetchm;
+ case MDB_NEXT_MULTIPLE:
+ if (data == NULL) {
+ rc = EINVAL;
+ break;
+ }
+ if (!(mc->mc_db->md_flags & MDB_DUPFIXED)) {
+ rc = MDB_INCOMPATIBLE;
+ break;
+ }
+ rc = mdb_cursor_next(mc, key, data, MDB_NEXT_DUP);
+ if (rc == MDB_SUCCESS) {
+ if (mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) {
+ MDB_cursor *mx;
+fetchm:
+ mx = &mc->mc_xcursor->mx_cursor;
+ data->mv_size = NUMKEYS(mx->mc_pg[mx->mc_top]) *
+ mx->mc_db->md_pad;
+ data->mv_data = METADATA(mx->mc_pg[mx->mc_top]);
+ mx->mc_ki[mx->mc_top] = NUMKEYS(mx->mc_pg[mx->mc_top])-1;
+ } else {
+ rc = MDB_NOTFOUND;
+ }
+ }
+ break;
+ case MDB_PREV_MULTIPLE:
+ if (data == NULL) {
+ rc = EINVAL;
+ break;
+ }
+ if (!(mc->mc_db->md_flags & MDB_DUPFIXED)) {
+ rc = MDB_INCOMPATIBLE;
+ break;
+ }
+ if (!(mc->mc_flags & C_INITIALIZED))
+ rc = mdb_cursor_last(mc, key, data);
+ else
+ rc = MDB_SUCCESS;
+ if (rc == MDB_SUCCESS) {
+ MDB_cursor *mx = &mc->mc_xcursor->mx_cursor;
+ if (mx->mc_flags & C_INITIALIZED) {
+ rc = mdb_cursor_sibling(mx, 0);
+ if (rc == MDB_SUCCESS)
+ goto fetchm;
+ } else {
+ rc = MDB_NOTFOUND;
+ }
+ }
+ break;
+ case MDB_NEXT:
+ case MDB_NEXT_DUP:
+ case MDB_NEXT_NODUP:
+ rc = mdb_cursor_next(mc, key, data, op);
+ break;
+ case MDB_PREV:
+ case MDB_PREV_DUP:
+ case MDB_PREV_NODUP:
+ rc = mdb_cursor_prev(mc, key, data, op);
+ break;
+ case MDB_FIRST:
+ rc = mdb_cursor_first(mc, key, data);
+ break;
+ case MDB_FIRST_DUP:
+ mfunc = mdb_cursor_first;
+ mmove:
+ if (data == NULL || !(mc->mc_flags & C_INITIALIZED)) {
+ rc = EINVAL;
+ break;
+ }
+ if (mc->mc_xcursor == NULL) {
+ rc = MDB_INCOMPATIBLE;
+ break;
+ }
+ if (mc->mc_ki[mc->mc_top] >= NUMKEYS(mc->mc_pg[mc->mc_top])) {
+ mc->mc_ki[mc->mc_top] = NUMKEYS(mc->mc_pg[mc->mc_top]);
+ rc = MDB_NOTFOUND;
+ break;
+ }
+ {
+ MDB_node *leaf = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]);
+ if (!F_ISSET(leaf->mn_flags, F_DUPDATA)) {
+ MDB_GET_KEY(leaf, key);
+ rc = mdb_node_read(mc, leaf, data);
+ break;
+ }
+ }
+ if (!(mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED)) {
+ rc = EINVAL;
+ break;
+ }
+ rc = mfunc(&mc->mc_xcursor->mx_cursor, data, NULL);
+ break;
+ case MDB_LAST:
+ rc = mdb_cursor_last(mc, key, data);
+ break;
+ case MDB_LAST_DUP:
+ mfunc = mdb_cursor_last;
+ goto mmove;
+ default:
+ DPRINTF(("unhandled/unimplemented cursor operation %u", op));
+ rc = EINVAL;
+ break;
+ }
+
+ if (mc->mc_flags & C_DEL)
+ mc->mc_flags ^= C_DEL;
+
+ return rc;
+}
+
+/** Touch all the pages in the cursor stack. Set mc_top.
+ * Makes sure all the pages are writable, before attempting a write operation.
+ * @param[in] mc The cursor to operate on.
+ */
+static int
+mdb_cursor_touch(MDB_cursor *mc)
+{
+ int rc = MDB_SUCCESS;
+
+ if (mc->mc_dbi >= CORE_DBS && !(*mc->mc_dbflag & (DB_DIRTY|DB_DUPDATA))) {
+ /* Touch DB record of named DB */
+ MDB_cursor mc2;
+ MDB_xcursor mcx;
+ if (TXN_DBI_CHANGED(mc->mc_txn, mc->mc_dbi))
+ return MDB_BAD_DBI;
+ mdb_cursor_init(&mc2, mc->mc_txn, MAIN_DBI, &mcx);
+ rc = mdb_page_search(&mc2, &mc->mc_dbx->md_name, MDB_PS_MODIFY);
+ if (rc)
+ return rc;
+ *mc->mc_dbflag |= DB_DIRTY;
+ }
+ mc->mc_top = 0;
+ if (mc->mc_snum) {
+ do {
+ rc = mdb_page_touch(mc);
+ } while (!rc && ++(mc->mc_top) < mc->mc_snum);
+ mc->mc_top = mc->mc_snum-1;
+ }
+ return rc;
+}
+
+/** Do not spill pages to disk if txn is getting full, may fail instead */
+#define MDB_NOSPILL 0x8000
+
+int
+mdb_cursor_put(MDB_cursor *mc, MDB_val *key, MDB_val *data,
+ unsigned int flags)
+{
+ MDB_env *env;
+ MDB_node *leaf = NULL;
+ MDB_page *fp, *mp, *sub_root = NULL;
+ uint16_t fp_flags;
+ MDB_val xdata, *rdata, dkey, olddata;
+ MDB_db dummy;
+ int do_sub = 0, insert_key, insert_data;
+ unsigned int mcount = 0, dcount = 0, nospill;
+ size_t nsize;
+ int rc, rc2;
+ unsigned int nflags;
+ DKBUF;
+
+ if (mc == NULL || key == NULL)
+ return EINVAL;
+
+ env = mc->mc_txn->mt_env;
+
+ /* Check this first so counter will always be zero on any
+ * early failures.
+ */
+ if (flags & MDB_MULTIPLE) {
+ dcount = data[1].mv_size;
+ data[1].mv_size = 0;
+ if (!F_ISSET(mc->mc_db->md_flags, MDB_DUPFIXED))
+ return MDB_INCOMPATIBLE;
+ }
+
+ nospill = flags & MDB_NOSPILL;
+ flags &= ~MDB_NOSPILL;
+
+ if (mc->mc_txn->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_BLOCKED))
+ return (mc->mc_txn->mt_flags & MDB_TXN_RDONLY) ? EACCES : MDB_BAD_TXN;
+
+ if (key->mv_size-1 >= ENV_MAXKEY(env))
+ return MDB_BAD_VALSIZE;
+
+#if SIZE_MAX > MAXDATASIZE
+ if (data->mv_size > ((mc->mc_db->md_flags & MDB_DUPSORT) ? ENV_MAXKEY(env) : MAXDATASIZE))
+ return MDB_BAD_VALSIZE;
+#else
+ if ((mc->mc_db->md_flags & MDB_DUPSORT) && data->mv_size > ENV_MAXKEY(env))
+ return MDB_BAD_VALSIZE;
+#endif
+
+ DPRINTF(("==> put db %d key [%s], size %"Z"u, data size %"Z"u",
+ DDBI(mc), DKEY(key), key ? key->mv_size : 0, data->mv_size));
+
+ dkey.mv_size = 0;
+
+ if (flags == MDB_CURRENT) {
+ if (!(mc->mc_flags & C_INITIALIZED))
+ return EINVAL;
+ rc = MDB_SUCCESS;
+ } else if (mc->mc_db->md_root == P_INVALID) {
+ /* new database, cursor has nothing to point to */
+ mc->mc_snum = 0;
+ mc->mc_top = 0;
+ mc->mc_flags &= ~C_INITIALIZED;
+ rc = MDB_NO_ROOT;
+ } else {
+ int exact = 0;
+ MDB_val d2;
+ if (flags & MDB_APPEND) {
+ MDB_val k2;
+ rc = mdb_cursor_last(mc, &k2, &d2);
+ if (rc == 0) {
+ rc = mc->mc_dbx->md_cmp(key, &k2);
+ if (rc > 0) {
+ rc = MDB_NOTFOUND;
+ mc->mc_ki[mc->mc_top]++;
+ } else {
+ /* new key is <= last key */
+ rc = MDB_KEYEXIST;
+ }
+ }
+ } else {
+ rc = mdb_cursor_set(mc, key, &d2, MDB_SET, &exact);
+ }
+ if ((flags & MDB_NOOVERWRITE) && rc == 0) {
+ DPRINTF(("duplicate key [%s]", DKEY(key)));
+ *data = d2;
+ return MDB_KEYEXIST;
+ }
+ if (rc && rc != MDB_NOTFOUND)
+ return rc;
+ }
+
+ if (mc->mc_flags & C_DEL)
+ mc->mc_flags ^= C_DEL;
+
+ /* Cursor is positioned, check for room in the dirty list */
+ if (!nospill) {
+ if (flags & MDB_MULTIPLE) {
+ rdata = &xdata;
+ xdata.mv_size = data->mv_size * dcount;
+ } else {
+ rdata = data;
+ }
+ if ((rc2 = mdb_page_spill(mc, key, rdata)))
+ return rc2;
+ }
+
+ if (rc == MDB_NO_ROOT) {
+ MDB_page *np;
+ /* new database, write a root leaf page */
+ DPUTS("allocating new root leaf page");
+ if ((rc2 = mdb_page_new(mc, P_LEAF, 1, &np))) {
+ return rc2;
+ }
+ mdb_cursor_push(mc, np);
+ mc->mc_db->md_root = np->mp_pgno;
+ mc->mc_db->md_depth++;
+ *mc->mc_dbflag |= DB_DIRTY;
+ if ((mc->mc_db->md_flags & (MDB_DUPSORT|MDB_DUPFIXED))
+ == MDB_DUPFIXED)
+ np->mp_flags |= P_LEAF2;
+ mc->mc_flags |= C_INITIALIZED;
+ } else {
+ /* make sure all cursor pages are writable */
+ rc2 = mdb_cursor_touch(mc);
+ if (rc2)
+ return rc2;
+ }
+
+ insert_key = insert_data = rc;
+ if (insert_key) {
+ /* The key does not exist */
+ DPRINTF(("inserting key at index %i", mc->mc_ki[mc->mc_top]));
+ if ((mc->mc_db->md_flags & MDB_DUPSORT) &&
+ LEAFSIZE(key, data) > env->me_nodemax)
+ {
+ /* Too big for a node, insert in sub-DB. Set up an empty
+ * "old sub-page" for prep_subDB to expand to a full page.
+ */
+ fp_flags = P_LEAF|P_DIRTY;
+ fp = env->me_pbuf;
+ fp->mp_pad = data->mv_size; /* used if MDB_DUPFIXED */
+ fp->mp_lower = fp->mp_upper = (PAGEHDRSZ-PAGEBASE);
+ olddata.mv_size = PAGEHDRSZ;
+ goto prep_subDB;
+ }
+ } else {
+ /* there's only a key anyway, so this is a no-op */
+ if (IS_LEAF2(mc->mc_pg[mc->mc_top])) {
+ char *ptr;
+ unsigned int ksize = mc->mc_db->md_pad;
+ if (key->mv_size != ksize)
+ return MDB_BAD_VALSIZE;
+ ptr = LEAF2KEY(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top], ksize);
+ memcpy(ptr, key->mv_data, ksize);
+fix_parent:
+ /* if overwriting slot 0 of leaf, need to
+ * update branch key if there is a parent page
+ */
+ if (mc->mc_top && !mc->mc_ki[mc->mc_top]) {
+ unsigned short dtop = 1;
+ mc->mc_top--;
+ /* slot 0 is always an empty key, find real slot */
+ while (mc->mc_top && !mc->mc_ki[mc->mc_top]) {
+ mc->mc_top--;
+ dtop++;
+ }
+ if (mc->mc_ki[mc->mc_top])
+ rc2 = mdb_update_key(mc, key);
+ else
+ rc2 = MDB_SUCCESS;
+ mc->mc_top += dtop;
+ if (rc2)
+ return rc2;
+ }
+ return MDB_SUCCESS;
+ }
+
+more:
+ leaf = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]);
+ olddata.mv_size = NODEDSZ(leaf);
+ olddata.mv_data = NODEDATA(leaf);
+
+ /* DB has dups? */
+ if (F_ISSET(mc->mc_db->md_flags, MDB_DUPSORT)) {
+ /* Prepare (sub-)page/sub-DB to accept the new item,
+ * if needed. fp: old sub-page or a header faking
+ * it. mp: new (sub-)page. offset: growth in page
+ * size. xdata: node data with new page or DB.
+ */
+ unsigned i, offset = 0;
+ mp = fp = xdata.mv_data = env->me_pbuf;
+ mp->mp_pgno = mc->mc_pg[mc->mc_top]->mp_pgno;
+
+ /* Was a single item before, must convert now */
+ if (!F_ISSET(leaf->mn_flags, F_DUPDATA)) {
+ MDB_cmp_func *dcmp;
+ /* Just overwrite the current item */
+ if (flags == MDB_CURRENT)
+ goto current;
+ dcmp = mc->mc_dbx->md_dcmp;
+#if UINT_MAX < SIZE_MAX
+ if (dcmp == mdb_cmp_int && olddata.mv_size == sizeof(size_t))
+ dcmp = mdb_cmp_clong;
+#endif
+ /* does data match? */
+ if (!dcmp(data, &olddata)) {
+ if (flags & (MDB_NODUPDATA|MDB_APPENDDUP))
+ return MDB_KEYEXIST;
+ /* overwrite it */
+ goto current;
+ }
+
+ /* Back up original data item */
+ dkey.mv_size = olddata.mv_size;
+ dkey.mv_data = memcpy(fp+1, olddata.mv_data, olddata.mv_size);
+
+ /* Make sub-page header for the dup items, with dummy body */
+ fp->mp_flags = P_LEAF|P_DIRTY|P_SUBP;
+ fp->mp_lower = (PAGEHDRSZ-PAGEBASE);
+ xdata.mv_size = PAGEHDRSZ + dkey.mv_size + data->mv_size;
+ if (mc->mc_db->md_flags & MDB_DUPFIXED) {
+ fp->mp_flags |= P_LEAF2;
+ fp->mp_pad = data->mv_size;
+ xdata.mv_size += 2 * data->mv_size; /* leave space for 2 more */
+ } else {
+ xdata.mv_size += 2 * (sizeof(indx_t) + NODESIZE) +
+ (dkey.mv_size & 1) + (data->mv_size & 1);
+ }
+ fp->mp_upper = xdata.mv_size - PAGEBASE;
+ olddata.mv_size = xdata.mv_size; /* pretend olddata is fp */
+ } else if (leaf->mn_flags & F_SUBDATA) {
+ /* Data is on sub-DB, just store it */
+ flags |= F_DUPDATA|F_SUBDATA;
+ goto put_sub;
+ } else {
+ /* Data is on sub-page */
+ fp = olddata.mv_data;
+ switch (flags) {
+ default:
+ if (!(mc->mc_db->md_flags & MDB_DUPFIXED)) {
+ offset = EVEN(NODESIZE + sizeof(indx_t) +
+ data->mv_size);
+ break;
+ }
+ offset = fp->mp_pad;
+ if (SIZELEFT(fp) < offset) {
+ offset *= 4; /* space for 4 more */
+ break;
+ }
+ /* FALLTHRU: Big enough MDB_DUPFIXED sub-page */
+ case MDB_CURRENT:
+ fp->mp_flags |= P_DIRTY;
+ COPY_PGNO(fp->mp_pgno, mp->mp_pgno);
+ mc->mc_xcursor->mx_cursor.mc_pg[0] = fp;
+ flags |= F_DUPDATA;
+ goto put_sub;
+ }
+ xdata.mv_size = olddata.mv_size + offset;
+ }
+
+ fp_flags = fp->mp_flags;
+ if (NODESIZE + NODEKSZ(leaf) + xdata.mv_size > env->me_nodemax) {
+ /* Too big for a sub-page, convert to sub-DB */
+ fp_flags &= ~P_SUBP;
+prep_subDB:
+ if (mc->mc_db->md_flags & MDB_DUPFIXED) {
+ fp_flags |= P_LEAF2;
+ dummy.md_pad = fp->mp_pad;
+ dummy.md_flags = MDB_DUPFIXED;
+ if (mc->mc_db->md_flags & MDB_INTEGERDUP)
+ dummy.md_flags |= MDB_INTEGERKEY;
+ } else {
+ dummy.md_pad = 0;
+ dummy.md_flags = 0;
+ }
+ dummy.md_depth = 1;
+ dummy.md_branch_pages = 0;
+ dummy.md_leaf_pages = 1;
+ dummy.md_overflow_pages = 0;
+ dummy.md_entries = NUMKEYS(fp);
+ xdata.mv_size = sizeof(MDB_db);
+ xdata.mv_data = &dummy;
+ if ((rc = mdb_page_alloc(mc, 1, &mp)))
+ return rc;
+ offset = env->me_psize - olddata.mv_size;
+ flags |= F_DUPDATA|F_SUBDATA;
+ dummy.md_root = mp->mp_pgno;
+ sub_root = mp;
+ }
+ if (mp != fp) {
+ mp->mp_flags = fp_flags | P_DIRTY;
+ mp->mp_pad = fp->mp_pad;
+ mp->mp_lower = fp->mp_lower;
+ mp->mp_upper = fp->mp_upper + offset;
+ if (fp_flags & P_LEAF2) {
+ memcpy(METADATA(mp), METADATA(fp), NUMKEYS(fp) * fp->mp_pad);
+ } else {
+ memcpy((char *)mp + mp->mp_upper + PAGEBASE, (char *)fp + fp->mp_upper + PAGEBASE,
+ olddata.mv_size - fp->mp_upper - PAGEBASE);
+ memcpy((char *)(&mp->mp_ptrs), (char *)(&fp->mp_ptrs), NUMKEYS(fp) * sizeof(mp->mp_ptrs[0]));
+ for (i=0; i<NUMKEYS(fp); i++)
+ mp->mp_ptrs[i] += offset;
+ }
+ }
+
+ rdata = &xdata;
+ flags |= F_DUPDATA;
+ do_sub = 1;
+ if (!insert_key)
+ mdb_node_del(mc, 0);
+ goto new_sub;
+ }
+current:
+ /* LMDB passes F_SUBDATA in 'flags' to write a DB record */
+ if ((leaf->mn_flags ^ flags) & F_SUBDATA)
+ return MDB_INCOMPATIBLE;
+ /* overflow page overwrites need special handling */
+ if (F_ISSET(leaf->mn_flags, F_BIGDATA)) {
+ MDB_page *omp;
+ pgno_t pg;
+ int level, ovpages, dpages = OVPAGES(data->mv_size, env->me_psize);
+
+ memcpy(&pg, olddata.mv_data, sizeof(pg));
+ if ((rc2 = mdb_page_get(mc, pg, &omp, &level)) != 0)
+ return rc2;
+ ovpages = omp->mp_pages;
+
+ /* Is the ov page large enough? */
+ if (ovpages >= dpages) {
+ if (!(omp->mp_flags & P_DIRTY) &&
+ (level || (env->me_flags & MDB_WRITEMAP)))
+ {
+ rc = mdb_page_unspill(mc->mc_txn, omp, &omp);
+ if (rc)
+ return rc;
+ level = 0; /* dirty in this txn or clean */
+ }
+ /* Is it dirty? */
+ if (omp->mp_flags & P_DIRTY) {
+ /* yes, overwrite it. Note in this case we don't
+ * bother to try shrinking the page if the new data
+ * is smaller than the overflow threshold.
+ */
+ if (level > 1) {
+ /* It is writable only in a parent txn */
+ size_t sz = (size_t) env->me_psize * ovpages, off;
+ MDB_page *np = mdb_page_malloc(mc->mc_txn, ovpages);
+ MDB_ID2 id2;
+ if (!np)
+ return ENOMEM;
+ id2.mid = pg;
+ id2.mptr = np;
+ /* Note - this page is already counted in parent's dirty_room */
+ rc2 = mdb_mid2l_insert(mc->mc_txn->mt_u.dirty_list, &id2);
+ mdb_cassert(mc, rc2 == 0);
+ /* Currently we make the page look as with put() in the
+ * parent txn, in case the user peeks at MDB_RESERVEd
+ * or unused parts. Some users treat ovpages specially.
+ */
+ if (!(flags & MDB_RESERVE)) {
+ /* Skip the part where LMDB will put *data.
+ * Copy end of page, adjusting alignment so
+ * compiler may copy words instead of bytes.
+ */
+ off = (PAGEHDRSZ + data->mv_size) & -sizeof(size_t);
+ memcpy((size_t *)((char *)np + off),
+ (size_t *)((char *)omp + off), sz - off);
+ sz = PAGEHDRSZ;
+ }
+ memcpy(np, omp, sz); /* Copy beginning of page */
+ omp = np;
+ }
+ SETDSZ(leaf, data->mv_size);
+ if (F_ISSET(flags, MDB_RESERVE))
+ data->mv_data = METADATA(omp);
+ else
+ memcpy(METADATA(omp), data->mv_data, data->mv_size);
+ return MDB_SUCCESS;
+ }
+ }
+ if ((rc2 = mdb_ovpage_free(mc, omp)) != MDB_SUCCESS)
+ return rc2;
+ } else if (data->mv_size == olddata.mv_size) {
+ /* same size, just replace it. Note that we could
+ * also reuse this node if the new data is smaller,
+ * but instead we opt to shrink the node in that case.
+ */
+ if (F_ISSET(flags, MDB_RESERVE))
+ data->mv_data = olddata.mv_data;
+ else if (!(mc->mc_flags & C_SUB))
+ memcpy(olddata.mv_data, data->mv_data, data->mv_size);
+ else {
+ memcpy(NODEKEY(leaf), key->mv_data, key->mv_size);
+ goto fix_parent;
+ }
+ return MDB_SUCCESS;
+ }
+ mdb_node_del(mc, 0);
+ }
+
+ rdata = data;
+
+new_sub:
+ nflags = flags & NODE_ADD_FLAGS;
+ nsize = IS_LEAF2(mc->mc_pg[mc->mc_top]) ? key->mv_size : mdb_leaf_size(env, key, rdata);
+ if (SIZELEFT(mc->mc_pg[mc->mc_top]) < nsize) {
+ if (( flags & (F_DUPDATA|F_SUBDATA)) == F_DUPDATA )
+ nflags &= ~MDB_APPEND; /* sub-page may need room to grow */
+ if (!insert_key)
+ nflags |= MDB_SPLIT_REPLACE;
+ rc = mdb_page_split(mc, key, rdata, P_INVALID, nflags);
+ } else {
+ /* There is room already in this leaf page. */
+ rc = mdb_node_add(mc, mc->mc_ki[mc->mc_top], key, rdata, 0, nflags);
+ if (rc == 0) {
+ /* Adjust other cursors pointing to mp */
+ MDB_cursor *m2, *m3;
+ MDB_dbi dbi = mc->mc_dbi;
+ unsigned i = mc->mc_top;
+ MDB_page *mp = mc->mc_pg[i];
+
+ for (m2 = mc->mc_txn->mt_cursors[dbi]; m2; m2=m2->mc_next) {
+ if (mc->mc_flags & C_SUB)
+ m3 = &m2->mc_xcursor->mx_cursor;
+ else
+ m3 = m2;
+ if (m3 == mc || m3->mc_snum < mc->mc_snum || m3->mc_pg[i] != mp) continue;
+ if (m3->mc_ki[i] >= mc->mc_ki[i] && insert_key) {
+ m3->mc_ki[i]++;
+ }
+ XCURSOR_REFRESH(m3, i, mp);
+ }
+ }
+ }
+
+ if (rc == MDB_SUCCESS) {
+ /* Now store the actual data in the child DB. Note that we're
+ * storing the user data in the keys field, so there are strict
+ * size limits on dupdata. The actual data fields of the child
+ * DB are all zero size.
+ */
+ if (do_sub) {
+ int xflags, new_dupdata;
+ size_t ecount;
+put_sub:
+ xdata.mv_size = 0;
+ xdata.mv_data = "";
+ leaf = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]);
+ if (flags & MDB_CURRENT) {
+ xflags = MDB_CURRENT|MDB_NOSPILL;
+ } else {
+ mdb_xcursor_init1(mc, leaf);
+ xflags = (flags & MDB_NODUPDATA) ?
+ MDB_NOOVERWRITE|MDB_NOSPILL : MDB_NOSPILL;
+ }
+ if (sub_root)
+ mc->mc_xcursor->mx_cursor.mc_pg[0] = sub_root;
+ new_dupdata = (int)dkey.mv_size;
+ /* converted, write the original data first */
+ if (dkey.mv_size) {
+ rc = mdb_cursor_put(&mc->mc_xcursor->mx_cursor, &dkey, &xdata, xflags);
+ if (rc)
+ goto bad_sub;
+ /* we've done our job */
+ dkey.mv_size = 0;
+ }
+ if (!(leaf->mn_flags & F_SUBDATA) || sub_root) {
+ /* Adjust other cursors pointing to mp */
+ MDB_cursor *m2;
+ MDB_xcursor *mx = mc->mc_xcursor;
+ unsigned i = mc->mc_top;
+ MDB_page *mp = mc->mc_pg[i];
+
+ for (m2 = mc->mc_txn->mt_cursors[mc->mc_dbi]; m2; m2=m2->mc_next) {
+ if (m2 == mc || m2->mc_snum < mc->mc_snum) continue;
+ if (!(m2->mc_flags & C_INITIALIZED)) continue;
+ if (m2->mc_pg[i] == mp) {
+ if (m2->mc_ki[i] == mc->mc_ki[i]) {
+ mdb_xcursor_init2(m2, mx, new_dupdata);
+ } else if (!insert_key) {
+ XCURSOR_REFRESH(m2, i, mp);
+ }
+ }
+ }
+ }
+ ecount = mc->mc_xcursor->mx_db.md_entries;
+ if (flags & MDB_APPENDDUP)
+ xflags |= MDB_APPEND;
+ rc = mdb_cursor_put(&mc->mc_xcursor->mx_cursor, data, &xdata, xflags);
+ if (flags & F_SUBDATA) {
+ void *db = NODEDATA(leaf);
+ memcpy(db, &mc->mc_xcursor->mx_db, sizeof(MDB_db));
+ }
+ insert_data = mc->mc_xcursor->mx_db.md_entries - ecount;
+ }
+ /* Increment count unless we just replaced an existing item. */
+ if (insert_data)
+ mc->mc_db->md_entries++;
+ if (insert_key) {
+ /* Invalidate txn if we created an empty sub-DB */
+ if (rc)
+ goto bad_sub;
+ /* If we succeeded and the key didn't exist before,
+ * make sure the cursor is marked valid.
+ */
+ mc->mc_flags |= C_INITIALIZED;
+ }
+ if (flags & MDB_MULTIPLE) {
+ if (!rc) {
+ mcount++;
+ /* let caller know how many succeeded, if any */
+ data[1].mv_size = mcount;
+ if (mcount < dcount) {
+ data[0].mv_data = (char *)data[0].mv_data + data[0].mv_size;
+ insert_key = insert_data = 0;
+ goto more;
+ }
+ }
+ }
+ return rc;
+bad_sub:
+ if (rc == MDB_KEYEXIST) /* should not happen, we deleted that item */
+ rc = MDB_CORRUPTED;
+ }
+ mc->mc_txn->mt_flags |= MDB_TXN_ERROR;
+ return rc;
+}
+
+int
+mdb_cursor_del(MDB_cursor *mc, unsigned int flags)
+{
+ MDB_node *leaf;
+ MDB_page *mp;
+ int rc;
+
+ if (mc->mc_txn->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_BLOCKED))
+ return (mc->mc_txn->mt_flags & MDB_TXN_RDONLY) ? EACCES : MDB_BAD_TXN;
+
+ if (!(mc->mc_flags & C_INITIALIZED))
+ return EINVAL;
+
+ if (mc->mc_ki[mc->mc_top] >= NUMKEYS(mc->mc_pg[mc->mc_top]))
+ return MDB_NOTFOUND;
+
+ if (!(flags & MDB_NOSPILL) && (rc = mdb_page_spill(mc, NULL, NULL)))
+ return rc;
+
+ rc = mdb_cursor_touch(mc);
+ if (rc)
+ return rc;
+
+ mp = mc->mc_pg[mc->mc_top];
+ if (IS_LEAF2(mp))
+ goto del_key;
+ leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]);
+
+ if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
+ if (flags & MDB_NODUPDATA) {
+ /* mdb_cursor_del0() will subtract the final entry */
+ mc->mc_db->md_entries -= mc->mc_xcursor->mx_db.md_entries - 1;
+ mc->mc_xcursor->mx_cursor.mc_flags &= ~C_INITIALIZED;
+ } else {
+ if (!F_ISSET(leaf->mn_flags, F_SUBDATA)) {
+ mc->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(leaf);
+ }
+ rc = mdb_cursor_del(&mc->mc_xcursor->mx_cursor, MDB_NOSPILL);
+ if (rc)
+ return rc;
+ /* If sub-DB still has entries, we're done */
+ if (mc->mc_xcursor->mx_db.md_entries) {
+ if (leaf->mn_flags & F_SUBDATA) {
+ /* update subDB info */
+ void *db = NODEDATA(leaf);
+ memcpy(db, &mc->mc_xcursor->mx_db, sizeof(MDB_db));
+ } else {
+ MDB_cursor *m2;
+ /* shrink fake page */
+ mdb_node_shrink(mp, mc->mc_ki[mc->mc_top]);
+ leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]);
+ mc->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(leaf);
+ /* fix other sub-DB cursors pointed at fake pages on this page */
+ for (m2 = mc->mc_txn->mt_cursors[mc->mc_dbi]; m2; m2=m2->mc_next) {
+ if (m2 == mc || m2->mc_snum < mc->mc_snum) continue;
+ if (!(m2->mc_flags & C_INITIALIZED)) continue;
+ if (m2->mc_pg[mc->mc_top] == mp) {
+ XCURSOR_REFRESH(m2, mc->mc_top, mp);
+ }
+ }
+ }
+ mc->mc_db->md_entries--;
+ return rc;
+ } else {
+ mc->mc_xcursor->mx_cursor.mc_flags &= ~C_INITIALIZED;
+ }
+ /* otherwise fall thru and delete the sub-DB */
+ }
+
+ if (leaf->mn_flags & F_SUBDATA) {
+ /* add all the child DB's pages to the free list */
+ rc = mdb_drop0(&mc->mc_xcursor->mx_cursor, 0);
+ if (rc)
+ goto fail;
+ }
+ }
+ /* LMDB passes F_SUBDATA in 'flags' to delete a DB record */
+ else if ((leaf->mn_flags ^ flags) & F_SUBDATA) {
+ rc = MDB_INCOMPATIBLE;
+ goto fail;
+ }
+
+ /* add overflow pages to free list */
+ if (F_ISSET(leaf->mn_flags, F_BIGDATA)) {
+ MDB_page *omp;
+ pgno_t pg;
+
+ memcpy(&pg, NODEDATA(leaf), sizeof(pg));
+ if ((rc = mdb_page_get(mc, pg, &omp, NULL)) ||
+ (rc = mdb_ovpage_free(mc, omp)))
+ goto fail;
+ }
+
+del_key:
+ return mdb_cursor_del0(mc);
+
+fail:
+ mc->mc_txn->mt_flags |= MDB_TXN_ERROR;
+ return rc;
+}
+
+/** Allocate and initialize new pages for a database.
+ * Set #MDB_TXN_ERROR on failure.
+ * @param[in] mc a cursor on the database being added to.
+ * @param[in] flags flags defining what type of page is being allocated.
+ * @param[in] num the number of pages to allocate. This is usually 1,
+ * unless allocating overflow pages for a large record.
+ * @param[out] mp Address of a page, or NULL on failure.
+ * @return 0 on success, non-zero on failure.
+ */
+static int
+mdb_page_new(MDB_cursor *mc, uint32_t flags, int num, MDB_page **mp)
+{
+ MDB_page *np;
+ int rc;
+
+ if ((rc = mdb_page_alloc(mc, num, &np)))
+ return rc;
+ DPRINTF(("allocated new mpage %"Z"u, page size %u",
+ np->mp_pgno, mc->mc_txn->mt_env->me_psize));
+ np->mp_flags = flags | P_DIRTY;
+ np->mp_lower = (PAGEHDRSZ-PAGEBASE);
+ np->mp_upper = mc->mc_txn->mt_env->me_psize - PAGEBASE;
+
+ if (IS_BRANCH(np))
+ mc->mc_db->md_branch_pages++;
+ else if (IS_LEAF(np))
+ mc->mc_db->md_leaf_pages++;
+ else if (IS_OVERFLOW(np)) {
+ mc->mc_db->md_overflow_pages += num;
+ np->mp_pages = num;
+ }
+ *mp = np;
+
+ return 0;
+}
+
+/** Calculate the size of a leaf node.
+ * The size depends on the environment's page size; if a data item
+ * is too large it will be put onto an overflow page and the node
+ * size will only include the key and not the data. Sizes are always
+ * rounded up to an even number of bytes, to guarantee 2-byte alignment
+ * of the #MDB_node headers.
+ * @param[in] env The environment handle.
+ * @param[in] key The key for the node.
+ * @param[in] data The data for the node.
+ * @return The number of bytes needed to store the node.
+ */
+static size_t
+mdb_leaf_size(MDB_env *env, MDB_val *key, MDB_val *data)
+{
+ size_t sz;
+
+ sz = LEAFSIZE(key, data);
+ if (sz > env->me_nodemax) {
+ /* put on overflow page */
+ sz -= data->mv_size - sizeof(pgno_t);
+ }
+
+ return EVEN(sz + sizeof(indx_t));
+}
+
+/** Calculate the size of a branch node.
+ * The size should depend on the environment's page size but since
+ * we currently don't support spilling large keys onto overflow
+ * pages, it's simply the size of the #MDB_node header plus the
+ * size of the key. Sizes are always rounded up to an even number
+ * of bytes, to guarantee 2-byte alignment of the #MDB_node headers.
+ * @param[in] env The environment handle.
+ * @param[in] key The key for the node.
+ * @return The number of bytes needed to store the node.
+ */
+static size_t
+mdb_branch_size(MDB_env *env, MDB_val *key)
+{
+ size_t sz;
+
+ sz = INDXSIZE(key);
+ if (sz > env->me_nodemax) {
+ /* put on overflow page */
+ /* not implemented */
+ /* sz -= key->size - sizeof(pgno_t); */
+ }
+
+ return sz + sizeof(indx_t);
+}
+
+/** Add a node to the page pointed to by the cursor.
+ * Set #MDB_TXN_ERROR on failure.
+ * @param[in] mc The cursor for this operation.
+ * @param[in] indx The index on the page where the new node should be added.
+ * @param[in] key The key for the new node.
+ * @param[in] data The data for the new node, if any.
+ * @param[in] pgno The page number, if adding a branch node.
+ * @param[in] flags Flags for the node.
+ * @return 0 on success, non-zero on failure. Possible errors are:
+ * <ul>
+ * <li>ENOMEM - failed to allocate overflow pages for the node.
+ * <li>MDB_PAGE_FULL - there is insufficient room in the page. This error
+ * should never happen since all callers already calculate the
+ * page's free space before calling this function.
+ * </ul>
+ */
+static int
+mdb_node_add(MDB_cursor *mc, indx_t indx,
+ MDB_val *key, MDB_val *data, pgno_t pgno, unsigned int flags)
+{
+ unsigned int i;
+ size_t node_size = NODESIZE;
+ ssize_t room;
+ indx_t ofs;
+ MDB_node *node;
+ MDB_page *mp = mc->mc_pg[mc->mc_top];
+ MDB_page *ofp = NULL; /* overflow page */
+ void *ndata;
+ DKBUF;
+
+ mdb_cassert(mc, mp->mp_upper >= mp->mp_lower);
+
+ DPRINTF(("add to %s %spage %"Z"u index %i, data size %"Z"u key size %"Z"u [%s]",
+ IS_LEAF(mp) ? "leaf" : "branch",
+ IS_SUBP(mp) ? "sub-" : "",
+ mdb_dbg_pgno(mp), indx, data ? data->mv_size : 0,
+ key ? key->mv_size : 0, key ? DKEY(key) : "null"));
+
+ if (IS_LEAF2(mp)) {
+ /* Move higher keys up one slot. */
+ int ksize = mc->mc_db->md_pad, dif;
+ char *ptr = LEAF2KEY(mp, indx, ksize);
+ dif = NUMKEYS(mp) - indx;
+ if (dif > 0)
+ memmove(ptr+ksize, ptr, dif*ksize);
+ /* insert new key */
+ memcpy(ptr, key->mv_data, ksize);
+
+ /* Just using these for counting */
+ mp->mp_lower += sizeof(indx_t);
+ mp->mp_upper -= ksize - sizeof(indx_t);
+ return MDB_SUCCESS;
+ }
+
+ room = (ssize_t)SIZELEFT(mp) - (ssize_t)sizeof(indx_t);
+ if (key != NULL)
+ node_size += key->mv_size;
+ if (IS_LEAF(mp)) {
+ mdb_cassert(mc, key && data);
+ if (F_ISSET(flags, F_BIGDATA)) {
+ /* Data already on overflow page. */
+ node_size += sizeof(pgno_t);
+ } else if (node_size + data->mv_size > mc->mc_txn->mt_env->me_nodemax) {
+ int ovpages = OVPAGES(data->mv_size, mc->mc_txn->mt_env->me_psize);
+ int rc;
+ /* Put data on overflow page. */
+ DPRINTF(("data size is %"Z"u, node would be %"Z"u, put data on overflow page",
+ data->mv_size, node_size+data->mv_size));
+ node_size = EVEN(node_size + sizeof(pgno_t));
+ if ((ssize_t)node_size > room)
+ goto full;
+ if ((rc = mdb_page_new(mc, P_OVERFLOW, ovpages, &ofp)))
+ return rc;
+ DPRINTF(("allocated overflow page %"Z"u", ofp->mp_pgno));
+ flags |= F_BIGDATA;
+ goto update;
+ } else {
+ node_size += data->mv_size;
+ }
+ }
+ node_size = EVEN(node_size);
+ if ((ssize_t)node_size > room)
+ goto full;
+
+update:
+ /* Move higher pointers up one slot. */
+ for (i = NUMKEYS(mp); i > indx; i--)
+ mp->mp_ptrs[i] = mp->mp_ptrs[i - 1];
+
+ /* Adjust free space offsets. */
+ ofs = mp->mp_upper - node_size;
+ mdb_cassert(mc, ofs >= mp->mp_lower + sizeof(indx_t));
+ mp->mp_ptrs[indx] = ofs;
+ mp->mp_upper = ofs;
+ mp->mp_lower += sizeof(indx_t);
+
+ /* Write the node data. */
+ node = NODEPTR(mp, indx);
+ node->mn_ksize = (key == NULL) ? 0 : key->mv_size;
+ node->mn_flags = flags;
+ if (IS_LEAF(mp))
+ SETDSZ(node,data->mv_size);
+ else
+ SETPGNO(node,pgno);
+
+ if (key)
+ memcpy(NODEKEY(node), key->mv_data, key->mv_size);
+
+ if (IS_LEAF(mp)) {
+ ndata = NODEDATA(node);
+ if (ofp == NULL) {
+ if (F_ISSET(flags, F_BIGDATA))
+ memcpy(ndata, data->mv_data, sizeof(pgno_t));
+ else if (F_ISSET(flags, MDB_RESERVE))
+ data->mv_data = ndata;
+ else
+ memcpy(ndata, data->mv_data, data->mv_size);
+ } else {
+ memcpy(ndata, &ofp->mp_pgno, sizeof(pgno_t));
+ ndata = METADATA(ofp);
+ if (F_ISSET(flags, MDB_RESERVE))
+ data->mv_data = ndata;
+ else
+ memcpy(ndata, data->mv_data, data->mv_size);
+ }
+ }
+
+ return MDB_SUCCESS;
+
+full:
+ DPRINTF(("not enough room in page %"Z"u, got %u ptrs",
+ mdb_dbg_pgno(mp), NUMKEYS(mp)));
+ DPRINTF(("upper-lower = %u - %u = %"Z"d", mp->mp_upper,mp->mp_lower,room));
+ DPRINTF(("node size = %"Z"u", node_size));
+ mc->mc_txn->mt_flags |= MDB_TXN_ERROR;
+ return MDB_PAGE_FULL;
+}
+
+/** Delete the specified node from a page.
+ * @param[in] mc Cursor pointing to the node to delete.
+ * @param[in] ksize The size of a node. Only used if the page is
+ * part of a #MDB_DUPFIXED database.
+ */
+static void
+mdb_node_del(MDB_cursor *mc, int ksize)
+{
+ MDB_page *mp = mc->mc_pg[mc->mc_top];
+ indx_t indx = mc->mc_ki[mc->mc_top];
+ unsigned int sz;
+ indx_t i, j, numkeys, ptr;
+ MDB_node *node;
+ char *base;
+
+ DPRINTF(("delete node %u on %s page %"Z"u", indx,
+ IS_LEAF(mp) ? "leaf" : "branch", mdb_dbg_pgno(mp)));
+ numkeys = NUMKEYS(mp);
+ mdb_cassert(mc, indx < numkeys);
+
+ if (IS_LEAF2(mp)) {
+ int x = numkeys - 1 - indx;
+ base = LEAF2KEY(mp, indx, ksize);
+ if (x)
+ memmove(base, base + ksize, x * ksize);
+ mp->mp_lower -= sizeof(indx_t);
+ mp->mp_upper += ksize - sizeof(indx_t);
+ return;
+ }
+
+ node = NODEPTR(mp, indx);
+ sz = NODESIZE + node->mn_ksize;
+ if (IS_LEAF(mp)) {
+ if (F_ISSET(node->mn_flags, F_BIGDATA))
+ sz += sizeof(pgno_t);
+ else
+ sz += NODEDSZ(node);
+ }
+ sz = EVEN(sz);
+
+ ptr = mp->mp_ptrs[indx];
+ for (i = j = 0; i < numkeys; i++) {
+ if (i != indx) {
+ mp->mp_ptrs[j] = mp->mp_ptrs[i];
+ if (mp->mp_ptrs[i] < ptr)
+ mp->mp_ptrs[j] += sz;
+ j++;
+ }
+ }
+
+ base = (char *)mp + mp->mp_upper + PAGEBASE;
+ memmove(base + sz, base, ptr - mp->mp_upper);
+
+ mp->mp_lower -= sizeof(indx_t);
+ mp->mp_upper += sz;
+}
+
+/** Compact the main page after deleting a node on a subpage.
+ * @param[in] mp The main page to operate on.
+ * @param[in] indx The index of the subpage on the main page.
+ */
+static void
+mdb_node_shrink(MDB_page *mp, indx_t indx)
+{
+ MDB_node *node;
+ MDB_page *sp, *xp;
+ char *base;
+ indx_t delta, nsize, len, ptr;
+ int i;
+
+ node = NODEPTR(mp, indx);
+ sp = (MDB_page *)NODEDATA(node);
+ delta = SIZELEFT(sp);
+ nsize = NODEDSZ(node) - delta;
+
+ /* Prepare to shift upward, set len = length(subpage part to shift) */
+ if (IS_LEAF2(sp)) {
+ len = nsize;
+ if (nsize & 1)
+ return; /* do not make the node uneven-sized */
+ } else {
+ xp = (MDB_page *)((char *)sp + delta); /* destination subpage */
+ for (i = NUMKEYS(sp); --i >= 0; )
+ xp->mp_ptrs[i] = sp->mp_ptrs[i] - delta;
+ len = PAGEHDRSZ;
+ }
+ sp->mp_upper = sp->mp_lower;
+ COPY_PGNO(sp->mp_pgno, mp->mp_pgno);
+ SETDSZ(node, nsize);
+
+ /* Shift <lower nodes...initial part of subpage> upward */
+ base = (char *)mp + mp->mp_upper + PAGEBASE;
+ memmove(base + delta, base, (char *)sp + len - base);
+
+ ptr = mp->mp_ptrs[indx];
+ for (i = NUMKEYS(mp); --i >= 0; ) {
+ if (mp->mp_ptrs[i] <= ptr)
+ mp->mp_ptrs[i] += delta;
+ }
+ mp->mp_upper += delta;
+}
+
+/** Initial setup of a sorted-dups cursor.
+ * Sorted duplicates are implemented as a sub-database for the given key.
+ * The duplicate data items are actually keys of the sub-database.
+ * Operations on the duplicate data items are performed using a sub-cursor
+ * initialized when the sub-database is first accessed. This function does
+ * the preliminary setup of the sub-cursor, filling in the fields that
+ * depend only on the parent DB.
+ * @param[in] mc The main cursor whose sorted-dups cursor is to be initialized.
+ */
+static void
+mdb_xcursor_init0(MDB_cursor *mc)
+{
+ MDB_xcursor *mx = mc->mc_xcursor;
+
+ mx->mx_cursor.mc_xcursor = NULL;
+ mx->mx_cursor.mc_txn = mc->mc_txn;
+ mx->mx_cursor.mc_db = &mx->mx_db;
+ mx->mx_cursor.mc_dbx = &mx->mx_dbx;
+ mx->mx_cursor.mc_dbi = mc->mc_dbi;
+ mx->mx_cursor.mc_dbflag = &mx->mx_dbflag;
+ mx->mx_cursor.mc_snum = 0;
+ mx->mx_cursor.mc_top = 0;
+ mx->mx_cursor.mc_flags = C_SUB;
+ mx->mx_dbx.md_name.mv_size = 0;
+ mx->mx_dbx.md_name.mv_data = NULL;
+ mx->mx_dbx.md_cmp = mc->mc_dbx->md_dcmp;
+ mx->mx_dbx.md_dcmp = NULL;
+ mx->mx_dbx.md_rel = mc->mc_dbx->md_rel;
+}
+
+/** Final setup of a sorted-dups cursor.
+ * Sets up the fields that depend on the data from the main cursor.
+ * @param[in] mc The main cursor whose sorted-dups cursor is to be initialized.
+ * @param[in] node The data containing the #MDB_db record for the
+ * sorted-dup database.
+ */
+static void
+mdb_xcursor_init1(MDB_cursor *mc, MDB_node *node)
+{
+ MDB_xcursor *mx = mc->mc_xcursor;
+
+ if (node->mn_flags & F_SUBDATA) {
+ memcpy(&mx->mx_db, NODEDATA(node), sizeof(MDB_db));
+ mx->mx_cursor.mc_pg[0] = 0;
+ mx->mx_cursor.mc_snum = 0;
+ mx->mx_cursor.mc_top = 0;
+ mx->mx_cursor.mc_flags = C_SUB;
+ } else {
+ MDB_page *fp = NODEDATA(node);
+ mx->mx_db.md_pad = 0;
+ mx->mx_db.md_flags = 0;
+ mx->mx_db.md_depth = 1;
+ mx->mx_db.md_branch_pages = 0;
+ mx->mx_db.md_leaf_pages = 1;
+ mx->mx_db.md_overflow_pages = 0;
+ mx->mx_db.md_entries = NUMKEYS(fp);
+ COPY_PGNO(mx->mx_db.md_root, fp->mp_pgno);
+ mx->mx_cursor.mc_snum = 1;
+ mx->mx_cursor.mc_top = 0;
+ mx->mx_cursor.mc_flags = C_INITIALIZED|C_SUB;
+ mx->mx_cursor.mc_pg[0] = fp;
+ mx->mx_cursor.mc_ki[0] = 0;
+ if (mc->mc_db->md_flags & MDB_DUPFIXED) {
+ mx->mx_db.md_flags = MDB_DUPFIXED;
+ mx->mx_db.md_pad = fp->mp_pad;
+ if (mc->mc_db->md_flags & MDB_INTEGERDUP)
+ mx->mx_db.md_flags |= MDB_INTEGERKEY;
+ }
+ }
+ DPRINTF(("Sub-db -%u root page %"Z"u", mx->mx_cursor.mc_dbi,
+ mx->mx_db.md_root));
+ mx->mx_dbflag = DB_VALID|DB_USRVALID|DB_DUPDATA;
+#if UINT_MAX < SIZE_MAX
+ if (mx->mx_dbx.md_cmp == mdb_cmp_int && mx->mx_db.md_pad == sizeof(size_t))
+ mx->mx_dbx.md_cmp = mdb_cmp_clong;
+#endif
+}
+
+
+/** Fixup a sorted-dups cursor due to underlying update.
+ * Sets up some fields that depend on the data from the main cursor.
+ * Almost the same as init1, but skips initialization steps if the
+ * xcursor had already been used.
+ * @param[in] mc The main cursor whose sorted-dups cursor is to be fixed up.
+ * @param[in] src_mx The xcursor of an up-to-date cursor.
+ * @param[in] new_dupdata True if converting from a non-#F_DUPDATA item.
+ */
+static void
+mdb_xcursor_init2(MDB_cursor *mc, MDB_xcursor *src_mx, int new_dupdata)
+{
+ MDB_xcursor *mx = mc->mc_xcursor;
+
+ if (new_dupdata) {
+ mx->mx_cursor.mc_snum = 1;
+ mx->mx_cursor.mc_top = 0;
+ mx->mx_cursor.mc_flags |= C_INITIALIZED;
+ mx->mx_cursor.mc_ki[0] = 0;
+ mx->mx_dbflag = DB_VALID|DB_USRVALID|DB_DUPDATA;
+#if UINT_MAX < SIZE_MAX
+ mx->mx_dbx.md_cmp = src_mx->mx_dbx.md_cmp;
+#endif
+ } else if (!(mx->mx_cursor.mc_flags & C_INITIALIZED)) {
+ return;
+ }
+ mx->mx_db = src_mx->mx_db;
+ mx->mx_cursor.mc_pg[0] = src_mx->mx_cursor.mc_pg[0];
+ DPRINTF(("Sub-db -%u root page %"Z"u", mx->mx_cursor.mc_dbi,
+ mx->mx_db.md_root));
+}
+
+/** Initialize a cursor for a given transaction and database. */
+static void
+mdb_cursor_init(MDB_cursor *mc, MDB_txn *txn, MDB_dbi dbi, MDB_xcursor *mx)
+{
+ mc->mc_next = NULL;
+ mc->mc_backup = NULL;
+ mc->mc_dbi = dbi;
+ mc->mc_txn = txn;
+ mc->mc_db = &txn->mt_dbs[dbi];
+ mc->mc_dbx = &txn->mt_dbxs[dbi];
+ mc->mc_dbflag = &txn->mt_dbflags[dbi];
+ mc->mc_snum = 0;
+ mc->mc_top = 0;
+ mc->mc_pg[0] = 0;
+ mc->mc_ki[0] = 0;
+ mc->mc_flags = 0;
+ if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT) {
+ mdb_tassert(txn, mx != NULL);
+ mc->mc_xcursor = mx;
+ mdb_xcursor_init0(mc);
+ } else {
+ mc->mc_xcursor = NULL;
+ }
+ if (*mc->mc_dbflag & DB_STALE) {
+ mdb_page_search(mc, NULL, MDB_PS_ROOTONLY);
+ }
+}
+
+int
+mdb_cursor_open(MDB_txn *txn, MDB_dbi dbi, MDB_cursor **ret)
+{
+ MDB_cursor *mc;
+ size_t size = sizeof(MDB_cursor);
+
+ if (!ret || !TXN_DBI_EXIST(txn, dbi, DB_VALID))
+ return EINVAL;
+
+ if (txn->mt_flags & MDB_TXN_BLOCKED)
+ return MDB_BAD_TXN;
+
+ if (dbi == FREE_DBI && !F_ISSET(txn->mt_flags, MDB_TXN_RDONLY))
+ return EINVAL;
+
+ if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT)
+ size += sizeof(MDB_xcursor);
+
+ if ((mc = malloc(size)) != NULL) {
+ mdb_cursor_init(mc, txn, dbi, (MDB_xcursor *)(mc + 1));
+ if (txn->mt_cursors) {
+ mc->mc_next = txn->mt_cursors[dbi];
+ txn->mt_cursors[dbi] = mc;
+ mc->mc_flags |= C_UNTRACK;
+ }
+ } else {
+ return ENOMEM;
+ }
+
+ *ret = mc;
+
+ return MDB_SUCCESS;
+}
+
+int
+mdb_cursor_renew(MDB_txn *txn, MDB_cursor *mc)
+{
+ if (!mc || !TXN_DBI_EXIST(txn, mc->mc_dbi, DB_VALID))
+ return EINVAL;
+
+ if ((mc->mc_flags & C_UNTRACK) || txn->mt_cursors)
+ return EINVAL;
+
+ if (txn->mt_flags & MDB_TXN_BLOCKED)
+ return MDB_BAD_TXN;
+
+ mdb_cursor_init(mc, txn, mc->mc_dbi, mc->mc_xcursor);
+ return MDB_SUCCESS;
+}
+
+/* Return the count of duplicate data items for the current key */
+int
+mdb_cursor_count(MDB_cursor *mc, size_t *countp)
+{
+ MDB_node *leaf;
+
+ if (mc == NULL || countp == NULL)
+ return EINVAL;
+
+ if (mc->mc_xcursor == NULL)
+ return MDB_INCOMPATIBLE;
+
+ if (mc->mc_txn->mt_flags & MDB_TXN_BLOCKED)
+ return MDB_BAD_TXN;
+
+ if (!(mc->mc_flags & C_INITIALIZED))
+ return EINVAL;
+
+ if (!mc->mc_snum)
+ return MDB_NOTFOUND;
+
+ if (mc->mc_flags & C_EOF) {
+ if (mc->mc_ki[mc->mc_top] >= NUMKEYS(mc->mc_pg[mc->mc_top]))
+ return MDB_NOTFOUND;
+ mc->mc_flags ^= C_EOF;
+ }
+
+ leaf = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]);
+ if (!F_ISSET(leaf->mn_flags, F_DUPDATA)) {
+ *countp = 1;
+ } else {
+ if (!(mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED))
+ return EINVAL;
+
+ *countp = mc->mc_xcursor->mx_db.md_entries;
+ }
+ return MDB_SUCCESS;
+}
+
+void
+mdb_cursor_close(MDB_cursor *mc)
+{
+ if (mc && !mc->mc_backup) {
+ /* remove from txn, if tracked */
+ if ((mc->mc_flags & C_UNTRACK) && mc->mc_txn->mt_cursors) {
+ MDB_cursor **prev = &mc->mc_txn->mt_cursors[mc->mc_dbi];
+ while (*prev && *prev != mc) prev = &(*prev)->mc_next;
+ if (*prev == mc)
+ *prev = mc->mc_next;
+ }
+ free(mc);
+ }
+}
+
+MDB_txn *
+mdb_cursor_txn(MDB_cursor *mc)
+{
+ if (!mc) return NULL;
+ return mc->mc_txn;
+}
+
+MDB_dbi
+mdb_cursor_dbi(MDB_cursor *mc)
+{
+ return mc->mc_dbi;
+}
+
+/** Replace the key for a branch node with a new key.
+ * Set #MDB_TXN_ERROR on failure.
+ * @param[in] mc Cursor pointing to the node to operate on.
+ * @param[in] key The new key to use.
+ * @return 0 on success, non-zero on failure.
+ */
+static int
+mdb_update_key(MDB_cursor *mc, MDB_val *key)
+{
+ MDB_page *mp;
+ MDB_node *node;
+ char *base;
+ size_t len;
+ int delta, ksize, oksize;
+ indx_t ptr, i, numkeys, indx;
+ DKBUF;
+
+ indx = mc->mc_ki[mc->mc_top];
+ mp = mc->mc_pg[mc->mc_top];
+ node = NODEPTR(mp, indx);
+ ptr = mp->mp_ptrs[indx];
+#if MDB_DEBUG
+ {
+ MDB_val k2;
+ char kbuf2[DKBUF_MAXKEYSIZE*2+1];
+ k2.mv_data = NODEKEY(node);
+ k2.mv_size = node->mn_ksize;
+ DPRINTF(("update key %u (ofs %u) [%s] to [%s] on page %"Z"u",
+ indx, ptr,
+ mdb_dkey(&k2, kbuf2),
+ DKEY(key),
+ mp->mp_pgno));
+ }
+#endif
+
+ /* Sizes must be 2-byte aligned. */
+ ksize = EVEN(key->mv_size);
+ oksize = EVEN(node->mn_ksize);
+ delta = ksize - oksize;
+
+ /* Shift node contents if EVEN(key length) changed. */
+ if (delta) {
+ if (delta > 0 && SIZELEFT(mp) < delta) {
+ pgno_t pgno;
+ /* not enough space left, do a delete and split */
+ DPRINTF(("Not enough room, delta = %d, splitting...", delta));
+ pgno = NODEPGNO(node);
+ mdb_node_del(mc, 0);
+ return mdb_page_split(mc, key, NULL, pgno, MDB_SPLIT_REPLACE);
+ }
+
+ numkeys = NUMKEYS(mp);
+ for (i = 0; i < numkeys; i++) {
+ if (mp->mp_ptrs[i] <= ptr)
+ mp->mp_ptrs[i] -= delta;
+ }
+
+ base = (char *)mp + mp->mp_upper + PAGEBASE;
+ len = ptr - mp->mp_upper + NODESIZE;
+ memmove(base - delta, base, len);
+ mp->mp_upper -= delta;
+
+ node = NODEPTR(mp, indx);
+ }
+
+ /* But even if no shift was needed, update ksize */
+ if (node->mn_ksize != key->mv_size)
+ node->mn_ksize = key->mv_size;
+
+ if (key->mv_size)
+ memcpy(NODEKEY(node), key->mv_data, key->mv_size);
+
+ return MDB_SUCCESS;
+}
+
+static void
+mdb_cursor_copy(const MDB_cursor *csrc, MDB_cursor *cdst);
+
+/** Perform \b act while tracking temporary cursor \b mn */
+#define WITH_CURSOR_TRACKING(mn, act) do { \
+ MDB_cursor dummy, *tracked, **tp = &(mn).mc_txn->mt_cursors[mn.mc_dbi]; \
+ if ((mn).mc_flags & C_SUB) { \
+ dummy.mc_flags = C_INITIALIZED; \
+ dummy.mc_xcursor = (MDB_xcursor *)&(mn); \
+ tracked = &dummy; \
+ } else { \
+ tracked = &(mn); \
+ } \
+ tracked->mc_next = *tp; \
+ *tp = tracked; \
+ { act; } \
+ *tp = tracked->mc_next; \
+} while (0)
+
+/** Move a node from csrc to cdst.
+ */
+static int
+mdb_node_move(MDB_cursor *csrc, MDB_cursor *cdst, int fromleft)
+{
+ MDB_node *srcnode;
+ MDB_val key, data;
+ pgno_t srcpg;
+ MDB_cursor mn;
+ int rc;
+ unsigned short flags;
+
+ DKBUF;
+
+ /* Mark src and dst as dirty. */
+ if ((rc = mdb_page_touch(csrc)) ||
+ (rc = mdb_page_touch(cdst)))
+ return rc;
+
+ if (IS_LEAF2(csrc->mc_pg[csrc->mc_top])) {
+ key.mv_size = csrc->mc_db->md_pad;
+ key.mv_data = LEAF2KEY(csrc->mc_pg[csrc->mc_top], csrc->mc_ki[csrc->mc_top], key.mv_size);
+ data.mv_size = 0;
+ data.mv_data = NULL;
+ srcpg = 0;
+ flags = 0;
+ } else {
+ srcnode = NODEPTR(csrc->mc_pg[csrc->mc_top], csrc->mc_ki[csrc->mc_top]);
+ mdb_cassert(csrc, !((size_t)srcnode & 1));
+ srcpg = NODEPGNO(srcnode);
+ flags = srcnode->mn_flags;
+ if (csrc->mc_ki[csrc->mc_top] == 0 && IS_BRANCH(csrc->mc_pg[csrc->mc_top])) {
+ unsigned int snum = csrc->mc_snum;
+ MDB_node *s2;
+ /* must find the lowest key below src */
+ rc = mdb_page_search_lowest(csrc);
+ if (rc)
+ return rc;
+ if (IS_LEAF2(csrc->mc_pg[csrc->mc_top])) {
+ key.mv_size = csrc->mc_db->md_pad;
+ key.mv_data = LEAF2KEY(csrc->mc_pg[csrc->mc_top], 0, key.mv_size);
+ } else {
+ s2 = NODEPTR(csrc->mc_pg[csrc->mc_top], 0);
+ key.mv_size = NODEKSZ(s2);
+ key.mv_data = NODEKEY(s2);
+ }
+ csrc->mc_snum = snum--;
+ csrc->mc_top = snum;
+ } else {
+ key.mv_size = NODEKSZ(srcnode);
+ key.mv_data = NODEKEY(srcnode);
+ }
+ data.mv_size = NODEDSZ(srcnode);
+ data.mv_data = NODEDATA(srcnode);
+ }
+ mn.mc_xcursor = NULL;
+ if (IS_BRANCH(cdst->mc_pg[cdst->mc_top]) && cdst->mc_ki[cdst->mc_top] == 0) {
+ unsigned int snum = cdst->mc_snum;
+ MDB_node *s2;
+ MDB_val bkey;
+ /* must find the lowest key below dst */
+ mdb_cursor_copy(cdst, &mn);
+ rc = mdb_page_search_lowest(&mn);
+ if (rc)
+ return rc;
+ if (IS_LEAF2(mn.mc_pg[mn.mc_top])) {
+ bkey.mv_size = mn.mc_db->md_pad;
+ bkey.mv_data = LEAF2KEY(mn.mc_pg[mn.mc_top], 0, bkey.mv_size);
+ } else {
+ s2 = NODEPTR(mn.mc_pg[mn.mc_top], 0);
+ bkey.mv_size = NODEKSZ(s2);
+ bkey.mv_data = NODEKEY(s2);
+ }
+ mn.mc_snum = snum--;
+ mn.mc_top = snum;
+ mn.mc_ki[snum] = 0;
+ rc = mdb_update_key(&mn, &bkey);
+ if (rc)
+ return rc;
+ }
+
+ DPRINTF(("moving %s node %u [%s] on page %"Z"u to node %u on page %"Z"u",
+ IS_LEAF(csrc->mc_pg[csrc->mc_top]) ? "leaf" : "branch",
+ csrc->mc_ki[csrc->mc_top],
+ DKEY(&key),
+ csrc->mc_pg[csrc->mc_top]->mp_pgno,
+ cdst->mc_ki[cdst->mc_top], cdst->mc_pg[cdst->mc_top]->mp_pgno));
+
+ /* Add the node to the destination page.
+ */
+ rc = mdb_node_add(cdst, cdst->mc_ki[cdst->mc_top], &key, &data, srcpg, flags);
+ if (rc != MDB_SUCCESS)
+ return rc;
+
+ /* Delete the node from the source page.
+ */
+ mdb_node_del(csrc, key.mv_size);
+
+ {
+ /* Adjust other cursors pointing to mp */
+ MDB_cursor *m2, *m3;
+ MDB_dbi dbi = csrc->mc_dbi;
+ MDB_page *mpd, *mps;
+
+ mps = csrc->mc_pg[csrc->mc_top];
+ /* If we're adding on the left, bump others up */
+ if (fromleft) {
+ mpd = cdst->mc_pg[csrc->mc_top];
+ for (m2 = csrc->mc_txn->mt_cursors[dbi]; m2; m2=m2->mc_next) {
+ if (csrc->mc_flags & C_SUB)
+ m3 = &m2->mc_xcursor->mx_cursor;
+ else
+ m3 = m2;
+ if (!(m3->mc_flags & C_INITIALIZED) || m3->mc_top < csrc->mc_top)
+ continue;
+ if (m3 != cdst &&
+ m3->mc_pg[csrc->mc_top] == mpd &&
+ m3->mc_ki[csrc->mc_top] >= cdst->mc_ki[csrc->mc_top]) {
+ m3->mc_ki[csrc->mc_top]++;
+ }
+ if (m3 !=csrc &&
+ m3->mc_pg[csrc->mc_top] == mps &&
+ m3->mc_ki[csrc->mc_top] == csrc->mc_ki[csrc->mc_top]) {
+ m3->mc_pg[csrc->mc_top] = cdst->mc_pg[cdst->mc_top];
+ m3->mc_ki[csrc->mc_top] = cdst->mc_ki[cdst->mc_top];
+ m3->mc_ki[csrc->mc_top-1]++;
+ }
+ if (IS_LEAF(mps))
+ XCURSOR_REFRESH(m3, csrc->mc_top, m3->mc_pg[csrc->mc_top]);
+ }
+ } else
+ /* Adding on the right, bump others down */
+ {
+ for (m2 = csrc->mc_txn->mt_cursors[dbi]; m2; m2=m2->mc_next) {
+ if (csrc->mc_flags & C_SUB)
+ m3 = &m2->mc_xcursor->mx_cursor;
+ else
+ m3 = m2;
+ if (m3 == csrc) continue;
+ if (!(m3->mc_flags & C_INITIALIZED) || m3->mc_top < csrc->mc_top)
+ continue;
+ if (m3->mc_pg[csrc->mc_top] == mps) {
+ if (!m3->mc_ki[csrc->mc_top]) {
+ m3->mc_pg[csrc->mc_top] = cdst->mc_pg[cdst->mc_top];
+ m3->mc_ki[csrc->mc_top] = cdst->mc_ki[cdst->mc_top];
+ m3->mc_ki[csrc->mc_top-1]--;
+ } else {
+ m3->mc_ki[csrc->mc_top]--;
+ }
+ if (IS_LEAF(mps))
+ XCURSOR_REFRESH(m3, csrc->mc_top, m3->mc_pg[csrc->mc_top]);
+ }
+ }
+ }
+ }
+
+ /* Update the parent separators.
+ */
+ if (csrc->mc_ki[csrc->mc_top] == 0) {
+ if (csrc->mc_ki[csrc->mc_top-1] != 0) {
+ if (IS_LEAF2(csrc->mc_pg[csrc->mc_top])) {
+ key.mv_data = LEAF2KEY(csrc->mc_pg[csrc->mc_top], 0, key.mv_size);
+ } else {
+ srcnode = NODEPTR(csrc->mc_pg[csrc->mc_top], 0);
+ key.mv_size = NODEKSZ(srcnode);
+ key.mv_data = NODEKEY(srcnode);
+ }
+ DPRINTF(("update separator for source page %"Z"u to [%s]",
+ csrc->mc_pg[csrc->mc_top]->mp_pgno, DKEY(&key)));
+ mdb_cursor_copy(csrc, &mn);
+ mn.mc_snum--;
+ mn.mc_top--;
+ /* We want mdb_rebalance to find mn when doing fixups */
+ WITH_CURSOR_TRACKING(mn,
+ rc = mdb_update_key(&mn, &key));
+ if (rc)
+ return rc;
+ }
+ if (IS_BRANCH(csrc->mc_pg[csrc->mc_top])) {
+ MDB_val nullkey;
+ indx_t ix = csrc->mc_ki[csrc->mc_top];
+ nullkey.mv_size = 0;
+ csrc->mc_ki[csrc->mc_top] = 0;
+ rc = mdb_update_key(csrc, &nullkey);
+ csrc->mc_ki[csrc->mc_top] = ix;
+ mdb_cassert(csrc, rc == MDB_SUCCESS);
+ }
+ }
+
+ if (cdst->mc_ki[cdst->mc_top] == 0) {
+ if (cdst->mc_ki[cdst->mc_top-1] != 0) {
+ if (IS_LEAF2(csrc->mc_pg[csrc->mc_top])) {
+ key.mv_data = LEAF2KEY(cdst->mc_pg[cdst->mc_top], 0, key.mv_size);
+ } else {
+ srcnode = NODEPTR(cdst->mc_pg[cdst->mc_top], 0);
+ key.mv_size = NODEKSZ(srcnode);
+ key.mv_data = NODEKEY(srcnode);
+ }
+ DPRINTF(("update separator for destination page %"Z"u to [%s]",
+ cdst->mc_pg[cdst->mc_top]->mp_pgno, DKEY(&key)));
+ mdb_cursor_copy(cdst, &mn);
+ mn.mc_snum--;
+ mn.mc_top--;
+ /* We want mdb_rebalance to find mn when doing fixups */
+ WITH_CURSOR_TRACKING(mn,
+ rc = mdb_update_key(&mn, &key));
+ if (rc)
+ return rc;
+ }
+ if (IS_BRANCH(cdst->mc_pg[cdst->mc_top])) {
+ MDB_val nullkey;
+ indx_t ix = cdst->mc_ki[cdst->mc_top];
+ nullkey.mv_size = 0;
+ cdst->mc_ki[cdst->mc_top] = 0;
+ rc = mdb_update_key(cdst, &nullkey);
+ cdst->mc_ki[cdst->mc_top] = ix;
+ mdb_cassert(cdst, rc == MDB_SUCCESS);
+ }
+ }
+
+ return MDB_SUCCESS;
+}
+
+/** Merge one page into another.
+ * The nodes from the page pointed to by \b csrc will
+ * be copied to the page pointed to by \b cdst and then
+ * the \b csrc page will be freed.
+ * @param[in] csrc Cursor pointing to the source page.
+ * @param[in] cdst Cursor pointing to the destination page.
+ * @return 0 on success, non-zero on failure.
+ */
+static int
+mdb_page_merge(MDB_cursor *csrc, MDB_cursor *cdst)
+{
+ MDB_page *psrc, *pdst;
+ MDB_node *srcnode;
+ MDB_val key, data;
+ unsigned nkeys;
+ int rc;
+ indx_t i, j;
+
+ psrc = csrc->mc_pg[csrc->mc_top];
+ pdst = cdst->mc_pg[cdst->mc_top];
+
+ DPRINTF(("merging page %"Z"u into %"Z"u", psrc->mp_pgno, pdst->mp_pgno));
+
+ mdb_cassert(csrc, csrc->mc_snum > 1); /* can't merge root page */
+ mdb_cassert(csrc, cdst->mc_snum > 1);
+
+ /* Mark dst as dirty. */
+ if ((rc = mdb_page_touch(cdst)))
+ return rc;
+
+ /* get dst page again now that we've touched it. */
+ pdst = cdst->mc_pg[cdst->mc_top];
+
+ /* Move all nodes from src to dst.
+ */
+ j = nkeys = NUMKEYS(pdst);
+ if (IS_LEAF2(psrc)) {
+ key.mv_size = csrc->mc_db->md_pad;
+ key.mv_data = METADATA(psrc);
+ for (i = 0; i < NUMKEYS(psrc); i++, j++) {
+ rc = mdb_node_add(cdst, j, &key, NULL, 0, 0);
+ if (rc != MDB_SUCCESS)
+ return rc;
+ key.mv_data = (char *)key.mv_data + key.mv_size;
+ }
+ } else {
+ for (i = 0; i < NUMKEYS(psrc); i++, j++) {
+ srcnode = NODEPTR(psrc, i);
+ if (i == 0 && IS_BRANCH(psrc)) {
+ MDB_cursor mn;
+ MDB_node *s2;
+ mdb_cursor_copy(csrc, &mn);
+ mn.mc_xcursor = NULL;
+ /* must find the lowest key below src */
+ rc = mdb_page_search_lowest(&mn);
+ if (rc)
+ return rc;
+ if (IS_LEAF2(mn.mc_pg[mn.mc_top])) {
+ key.mv_size = mn.mc_db->md_pad;
+ key.mv_data = LEAF2KEY(mn.mc_pg[mn.mc_top], 0, key.mv_size);
+ } else {
+ s2 = NODEPTR(mn.mc_pg[mn.mc_top], 0);
+ key.mv_size = NODEKSZ(s2);
+ key.mv_data = NODEKEY(s2);
+ }
+ } else {
+ key.mv_size = srcnode->mn_ksize;
+ key.mv_data = NODEKEY(srcnode);
+ }
+
+ data.mv_size = NODEDSZ(srcnode);
+ data.mv_data = NODEDATA(srcnode);
+ rc = mdb_node_add(cdst, j, &key, &data, NODEPGNO(srcnode), srcnode->mn_flags);
+ if (rc != MDB_SUCCESS)
+ return rc;
+ }
+ }
+
+ DPRINTF(("dst page %"Z"u now has %u keys (%.1f%% filled)",
+ pdst->mp_pgno, NUMKEYS(pdst),
+ (float)PAGEFILL(cdst->mc_txn->mt_env, pdst) / 10));
+
+ /* Unlink the src page from parent and add to free list.
+ */
+ csrc->mc_top--;
+ mdb_node_del(csrc, 0);
+ if (csrc->mc_ki[csrc->mc_top] == 0) {
+ key.mv_size = 0;
+ rc = mdb_update_key(csrc, &key);
+ if (rc) {
+ csrc->mc_top++;
+ return rc;
+ }
+ }
+ csrc->mc_top++;
+
+ psrc = csrc->mc_pg[csrc->mc_top];
+ /* If not operating on FreeDB, allow this page to be reused
+ * in this txn. Otherwise just add to free list.
+ */
+ rc = mdb_page_loose(csrc, psrc);
+ if (rc)
+ return rc;
+ if (IS_LEAF(psrc))
+ csrc->mc_db->md_leaf_pages--;
+ else
+ csrc->mc_db->md_branch_pages--;
+ {
+ /* Adjust other cursors pointing to mp */
+ MDB_cursor *m2, *m3;
+ MDB_dbi dbi = csrc->mc_dbi;
+ unsigned int top = csrc->mc_top;
+
+ for (m2 = csrc->mc_txn->mt_cursors[dbi]; m2; m2=m2->mc_next) {
+ if (csrc->mc_flags & C_SUB)
+ m3 = &m2->mc_xcursor->mx_cursor;
+ else
+ m3 = m2;
+ if (m3 == csrc) continue;
+ if (m3->mc_snum < csrc->mc_snum) continue;
+ if (m3->mc_pg[top] == psrc) {
+ m3->mc_pg[top] = pdst;
+ m3->mc_ki[top] += nkeys;
+ m3->mc_ki[top-1] = cdst->mc_ki[top-1];
+ } else if (m3->mc_pg[top-1] == csrc->mc_pg[top-1] &&
+ m3->mc_ki[top-1] > csrc->mc_ki[top-1]) {
+ m3->mc_ki[top-1]--;
+ }
+ if (IS_LEAF(psrc))
+ XCURSOR_REFRESH(m3, top, m3->mc_pg[top]);
+ }
+ }
+ {
+ unsigned int snum = cdst->mc_snum;
+ uint16_t depth = cdst->mc_db->md_depth;
+ mdb_cursor_pop(cdst);
+ rc = mdb_rebalance(cdst);
+ /* Did the tree height change? */
+ if (depth != cdst->mc_db->md_depth)
+ snum += cdst->mc_db->md_depth - depth;
+ cdst->mc_snum = snum;
+ cdst->mc_top = snum-1;
+ }
+ return rc;
+}
+
+/** Copy the contents of a cursor.
+ * @param[in] csrc The cursor to copy from.
+ * @param[out] cdst The cursor to copy to.
+ */
+static void
+mdb_cursor_copy(const MDB_cursor *csrc, MDB_cursor *cdst)
+{
+ unsigned int i;
+
+ cdst->mc_txn = csrc->mc_txn;
+ cdst->mc_dbi = csrc->mc_dbi;
+ cdst->mc_db = csrc->mc_db;
+ cdst->mc_dbx = csrc->mc_dbx;
+ cdst->mc_snum = csrc->mc_snum;
+ cdst->mc_top = csrc->mc_top;
+ cdst->mc_flags = csrc->mc_flags;
+
+ for (i=0; i<csrc->mc_snum; i++) {
+ cdst->mc_pg[i] = csrc->mc_pg[i];
+ cdst->mc_ki[i] = csrc->mc_ki[i];
+ }
+}
+
+/** Rebalance the tree after a delete operation.
+ * @param[in] mc Cursor pointing to the page where rebalancing
+ * should begin.
+ * @return 0 on success, non-zero on failure.
+ */
+static int
+mdb_rebalance(MDB_cursor *mc)
+{
+ MDB_node *node;
+ int rc, fromleft;
+ unsigned int ptop, minkeys, thresh;
+ MDB_cursor mn;
+ indx_t oldki;
+
+ if (IS_BRANCH(mc->mc_pg[mc->mc_top])) {
+ minkeys = 2;
+ thresh = 1;
+ } else {
+ minkeys = 1;
+ thresh = FILL_THRESHOLD;
+ }
+ DPRINTF(("rebalancing %s page %"Z"u (has %u keys, %.1f%% full)",
+ IS_LEAF(mc->mc_pg[mc->mc_top]) ? "leaf" : "branch",
+ mdb_dbg_pgno(mc->mc_pg[mc->mc_top]), NUMKEYS(mc->mc_pg[mc->mc_top]),
+ (float)PAGEFILL(mc->mc_txn->mt_env, mc->mc_pg[mc->mc_top]) / 10));
+
+ if (PAGEFILL(mc->mc_txn->mt_env, mc->mc_pg[mc->mc_top]) >= thresh &&
+ NUMKEYS(mc->mc_pg[mc->mc_top]) >= minkeys) {
+ DPRINTF(("no need to rebalance page %"Z"u, above fill threshold",
+ mdb_dbg_pgno(mc->mc_pg[mc->mc_top])));
+ return MDB_SUCCESS;
+ }
+
+ if (mc->mc_snum < 2) {
+ MDB_page *mp = mc->mc_pg[0];
+ if (IS_SUBP(mp)) {
+ DPUTS("Can't rebalance a subpage, ignoring");
+ return MDB_SUCCESS;
+ }
+ if (NUMKEYS(mp) == 0) {
+ DPUTS("tree is completely empty");
+ mc->mc_db->md_root = P_INVALID;
+ mc->mc_db->md_depth = 0;
+ mc->mc_db->md_leaf_pages = 0;
+ rc = mdb_midl_append(&mc->mc_txn->mt_free_pgs, mp->mp_pgno);
+ if (rc)
+ return rc;
+ /* Adjust cursors pointing to mp */
+ mc->mc_snum = 0;
+ mc->mc_top = 0;
+ mc->mc_flags &= ~C_INITIALIZED;
+ {
+ MDB_cursor *m2, *m3;
+ MDB_dbi dbi = mc->mc_dbi;
+
+ for (m2 = mc->mc_txn->mt_cursors[dbi]; m2; m2=m2->mc_next) {
+ if (mc->mc_flags & C_SUB)
+ m3 = &m2->mc_xcursor->mx_cursor;
+ else
+ m3 = m2;
+ if (!(m3->mc_flags & C_INITIALIZED) || (m3->mc_snum < mc->mc_snum))
+ continue;
+ if (m3->mc_pg[0] == mp) {
+ m3->mc_snum = 0;
+ m3->mc_top = 0;
+ m3->mc_flags &= ~C_INITIALIZED;
+ }
+ }
+ }
+ } else if (IS_BRANCH(mp) && NUMKEYS(mp) == 1) {
+ int i;
+ DPUTS("collapsing root page!");
+ rc = mdb_midl_append(&mc->mc_txn->mt_free_pgs, mp->mp_pgno);
+ if (rc)
+ return rc;
+ mc->mc_db->md_root = NODEPGNO(NODEPTR(mp, 0));
+ rc = mdb_page_get(mc, mc->mc_db->md_root, &mc->mc_pg[0], NULL);
+ if (rc)
+ return rc;
+ mc->mc_db->md_depth--;
+ mc->mc_db->md_branch_pages--;
+ mc->mc_ki[0] = mc->mc_ki[1];
+ for (i = 1; i<mc->mc_db->md_depth; i++) {
+ mc->mc_pg[i] = mc->mc_pg[i+1];
+ mc->mc_ki[i] = mc->mc_ki[i+1];
+ }
+ {
+ /* Adjust other cursors pointing to mp */
+ MDB_cursor *m2, *m3;
+ MDB_dbi dbi = mc->mc_dbi;
+
+ for (m2 = mc->mc_txn->mt_cursors[dbi]; m2; m2=m2->mc_next) {
+ if (mc->mc_flags & C_SUB)
+ m3 = &m2->mc_xcursor->mx_cursor;
+ else
+ m3 = m2;
+ if (m3 == mc) continue;
+ if (!(m3->mc_flags & C_INITIALIZED))
+ continue;
+ if (m3->mc_pg[0] == mp) {
+ for (i=0; i<mc->mc_db->md_depth; i++) {
+ m3->mc_pg[i] = m3->mc_pg[i+1];
+ m3->mc_ki[i] = m3->mc_ki[i+1];
+ }
+ m3->mc_snum--;
+ m3->mc_top--;
+ }
+ }
+ }
+ } else
+ DPUTS("root page doesn't need rebalancing");
+ return MDB_SUCCESS;
+ }
+
+ /* The parent (branch page) must have at least 2 pointers,
+ * otherwise the tree is invalid.
+ */
+ ptop = mc->mc_top-1;
+ mdb_cassert(mc, NUMKEYS(mc->mc_pg[ptop]) > 1);
+
+ /* Leaf page fill factor is below the threshold.
+ * Try to move keys from left or right neighbor, or
+ * merge with a neighbor page.
+ */
+
+ /* Find neighbors.
+ */
+ mdb_cursor_copy(mc, &mn);
+ mn.mc_xcursor = NULL;
+
+ oldki = mc->mc_ki[mc->mc_top];
+ if (mc->mc_ki[ptop] == 0) {
+ /* We're the leftmost leaf in our parent.
+ */
+ DPUTS("reading right neighbor");
+ mn.mc_ki[ptop]++;
+ node = NODEPTR(mc->mc_pg[ptop], mn.mc_ki[ptop]);
+ rc = mdb_page_get(mc, NODEPGNO(node), &mn.mc_pg[mn.mc_top], NULL);
+ if (rc)
+ return rc;
+ mn.mc_ki[mn.mc_top] = 0;
+ mc->mc_ki[mc->mc_top] = NUMKEYS(mc->mc_pg[mc->mc_top]);
+ fromleft = 0;
+ } else {
+ /* There is at least one neighbor to the left.
+ */
+ DPUTS("reading left neighbor");
+ mn.mc_ki[ptop]--;
+ node = NODEPTR(mc->mc_pg[ptop], mn.mc_ki[ptop]);
+ rc = mdb_page_get(mc, NODEPGNO(node), &mn.mc_pg[mn.mc_top], NULL);
+ if (rc)
+ return rc;
+ mn.mc_ki[mn.mc_top] = NUMKEYS(mn.mc_pg[mn.mc_top]) - 1;
+ mc->mc_ki[mc->mc_top] = 0;
+ fromleft = 1;
+ }
+
+ DPRINTF(("found neighbor page %"Z"u (%u keys, %.1f%% full)",
+ mn.mc_pg[mn.mc_top]->mp_pgno, NUMKEYS(mn.mc_pg[mn.mc_top]),
+ (float)PAGEFILL(mc->mc_txn->mt_env, mn.mc_pg[mn.mc_top]) / 10));
+
+ /* If the neighbor page is above threshold and has enough keys,
+ * move one key from it. Otherwise we should try to merge them.
+ * (A branch page must never have less than 2 keys.)
+ */
+ if (PAGEFILL(mc->mc_txn->mt_env, mn.mc_pg[mn.mc_top]) >= thresh && NUMKEYS(mn.mc_pg[mn.mc_top]) > minkeys) {
+ rc = mdb_node_move(&mn, mc, fromleft);
+ if (fromleft) {
+ /* if we inserted on left, bump position up */
+ oldki++;
+ }
+ } else {
+ if (!fromleft) {
+ rc = mdb_page_merge(&mn, mc);
+ } else {
+ oldki += NUMKEYS(mn.mc_pg[mn.mc_top]);
+ mn.mc_ki[mn.mc_top] += mc->mc_ki[mn.mc_top] + 1;
+ /* We want mdb_rebalance to find mn when doing fixups */
+ WITH_CURSOR_TRACKING(mn,
+ rc = mdb_page_merge(mc, &mn));
+ mdb_cursor_copy(&mn, mc);
+ }
+ mc->mc_flags &= ~C_EOF;
+ }
+ mc->mc_ki[mc->mc_top] = oldki;
+ return rc;
+}
+
+/** Complete a delete operation started by #mdb_cursor_del(). */
+static int
+mdb_cursor_del0(MDB_cursor *mc)
+{
+ int rc;
+ MDB_page *mp;
+ indx_t ki;
+ unsigned int nkeys;
+ MDB_cursor *m2, *m3;
+ MDB_dbi dbi = mc->mc_dbi;
+
+ ki = mc->mc_ki[mc->mc_top];
+ mp = mc->mc_pg[mc->mc_top];
+ mdb_node_del(mc, mc->mc_db->md_pad);
+ mc->mc_db->md_entries--;
+ {
+ /* Adjust other cursors pointing to mp */
+ for (m2 = mc->mc_txn->mt_cursors[dbi]; m2; m2=m2->mc_next) {
+ m3 = (mc->mc_flags & C_SUB) ? &m2->mc_xcursor->mx_cursor : m2;
+ if (! (m2->mc_flags & m3->mc_flags & C_INITIALIZED))
+ continue;
+ if (m3 == mc || m3->mc_snum < mc->mc_snum)
+ continue;
+ if (m3->mc_pg[mc->mc_top] == mp) {
+ if (m3->mc_ki[mc->mc_top] == ki) {
+ m3->mc_flags |= C_DEL;
+ if (mc->mc_db->md_flags & MDB_DUPSORT) {
+ /* Sub-cursor referred into dataset which is gone */
+ m3->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED|C_EOF);
+ }
+ continue;
+ } else if (m3->mc_ki[mc->mc_top] > ki) {
+ m3->mc_ki[mc->mc_top]--;
+ }
+ XCURSOR_REFRESH(m3, mc->mc_top, mp);
+ }
+ }
+ }
+ rc = mdb_rebalance(mc);
+
+ if (rc == MDB_SUCCESS) {
+ /* DB is totally empty now, just bail out.
+ * Other cursors adjustments were already done
+ * by mdb_rebalance and aren't needed here.
+ */
+ if (!mc->mc_snum)
+ return rc;
+
+ mp = mc->mc_pg[mc->mc_top];
+ nkeys = NUMKEYS(mp);
+
+ /* Adjust other cursors pointing to mp */
+ for (m2 = mc->mc_txn->mt_cursors[dbi]; !rc && m2; m2=m2->mc_next) {
+ m3 = (mc->mc_flags & C_SUB) ? &m2->mc_xcursor->mx_cursor : m2;
+ if (! (m2->mc_flags & m3->mc_flags & C_INITIALIZED))
+ continue;
+ if (m3->mc_snum < mc->mc_snum)
+ continue;
+ if (m3->mc_pg[mc->mc_top] == mp) {
+ /* if m3 points past last node in page, find next sibling */
+ if (m3->mc_ki[mc->mc_top] >= mc->mc_ki[mc->mc_top]) {
+ if (m3->mc_ki[mc->mc_top] >= nkeys) {
+ rc = mdb_cursor_sibling(m3, 1);
+ if (rc == MDB_NOTFOUND) {
+ m3->mc_flags |= C_EOF;
+ rc = MDB_SUCCESS;
+ continue;
+ }
+ }
+ if (mc->mc_db->md_flags & MDB_DUPSORT) {
+ MDB_node *node = NODEPTR(m3->mc_pg[m3->mc_top], m3->mc_ki[m3->mc_top]);
+ /* If this node has dupdata, it may need to be reinited
+ * because its data has moved.
+ * If the xcursor was not initd it must be reinited.
+ * Else if node points to a subDB, nothing is needed.
+ * Else (xcursor was initd, not a subDB) needs mc_pg[0] reset.
+ */
+ if (node->mn_flags & F_DUPDATA) {
+ if (m3->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) {
+ if (!(node->mn_flags & F_SUBDATA))
+ m3->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(node);
+ } else {
+ mdb_xcursor_init1(m3, node);
+ m3->mc_xcursor->mx_cursor.mc_flags |= C_DEL;
+ }
+ }
+ }
+ }
+ }
+ }
+ mc->mc_flags |= C_DEL;
+ }
+
+ if (rc)
+ mc->mc_txn->mt_flags |= MDB_TXN_ERROR;
+ return rc;
+}
+
+int
+mdb_del(MDB_txn *txn, MDB_dbi dbi,
+ MDB_val *key, MDB_val *data)
+{
+ if (!key || !TXN_DBI_EXIST(txn, dbi, DB_USRVALID))
+ return EINVAL;
+
+ if (txn->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_BLOCKED))
+ return (txn->mt_flags & MDB_TXN_RDONLY) ? EACCES : MDB_BAD_TXN;
+
+ if (!F_ISSET(txn->mt_dbs[dbi].md_flags, MDB_DUPSORT)) {
+ /* must ignore any data */
+ data = NULL;
+ }
+
+ return mdb_del0(txn, dbi, key, data, 0);
+}
+
+static int
+mdb_del0(MDB_txn *txn, MDB_dbi dbi,
+ MDB_val *key, MDB_val *data, unsigned flags)
+{
+ MDB_cursor mc;
+ MDB_xcursor mx;
+ MDB_cursor_op op;
+ MDB_val rdata, *xdata;
+ int rc, exact = 0;
+ DKBUF;
+
+ DPRINTF(("====> delete db %u key [%s]", dbi, DKEY(key)));
+
+ mdb_cursor_init(&mc, txn, dbi, &mx);
+
+ if (data) {
+ op = MDB_GET_BOTH;
+ rdata = *data;
+ xdata = &rdata;
+ } else {
+ op = MDB_SET;
+ xdata = NULL;
+ flags |= MDB_NODUPDATA;
+ }
+ rc = mdb_cursor_set(&mc, key, xdata, op, &exact);
+ if (rc == 0) {
+ /* let mdb_page_split know about this cursor if needed:
+ * delete will trigger a rebalance; if it needs to move
+ * a node from one page to another, it will have to
+ * update the parent's separator key(s). If the new sepkey
+ * is larger than the current one, the parent page may
+ * run out of space, triggering a split. We need this
+ * cursor to be consistent until the end of the rebalance.
+ */
+ mc.mc_flags |= C_UNTRACK;
+ mc.mc_next = txn->mt_cursors[dbi];
+ txn->mt_cursors[dbi] = &mc;
+ rc = mdb_cursor_del(&mc, flags);
+ txn->mt_cursors[dbi] = mc.mc_next;
+ }
+ return rc;
+}
+
+/** Split a page and insert a new node.
+ * Set #MDB_TXN_ERROR on failure.
+ * @param[in,out] mc Cursor pointing to the page and desired insertion index.
+ * The cursor will be updated to point to the actual page and index where
+ * the node got inserted after the split.
+ * @param[in] newkey The key for the newly inserted node.
+ * @param[in] newdata The data for the newly inserted node.
+ * @param[in] newpgno The page number, if the new node is a branch node.
+ * @param[in] nflags The #NODE_ADD_FLAGS for the new node.
+ * @return 0 on success, non-zero on failure.
+ */
+static int
+mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno,
+ unsigned int nflags)
+{
+ unsigned int flags;
+ int rc = MDB_SUCCESS, new_root = 0, did_split = 0;
+ indx_t newindx;
+ pgno_t pgno = 0;
+ int i, j, split_indx, nkeys, pmax;
+ MDB_env *env = mc->mc_txn->mt_env;
+ MDB_node *node;
+ MDB_val sepkey, rkey, xdata, *rdata = &xdata;
+ MDB_page *copy = NULL;
+ MDB_page *mp, *rp, *pp;
+ int ptop;
+ MDB_cursor mn;
+ DKBUF;
+
+ mp = mc->mc_pg[mc->mc_top];
+ newindx = mc->mc_ki[mc->mc_top];
+ nkeys = NUMKEYS(mp);
+
+ DPRINTF(("-----> splitting %s page %"Z"u and adding [%s] at index %i/%i",
+ IS_LEAF(mp) ? "leaf" : "branch", mp->mp_pgno,
+ DKEY(newkey), mc->mc_ki[mc->mc_top], nkeys));
+
+ /* Create a right sibling. */
+ if ((rc = mdb_page_new(mc, mp->mp_flags, 1, &rp)))
+ return rc;
+ rp->mp_pad = mp->mp_pad;
+ DPRINTF(("new right sibling: page %"Z"u", rp->mp_pgno));
+
+ /* Usually when splitting the root page, the cursor
+ * height is 1. But when called from mdb_update_key,
+ * the cursor height may be greater because it walks
+ * up the stack while finding the branch slot to update.
+ */
+ if (mc->mc_top < 1) {
+ if ((rc = mdb_page_new(mc, P_BRANCH, 1, &pp)))
+ goto done;
+ /* shift current top to make room for new parent */
+ for (i=mc->mc_snum; i>0; i--) {
+ mc->mc_pg[i] = mc->mc_pg[i-1];
+ mc->mc_ki[i] = mc->mc_ki[i-1];
+ }
+ mc->mc_pg[0] = pp;
+ mc->mc_ki[0] = 0;
+ mc->mc_db->md_root = pp->mp_pgno;
+ DPRINTF(("root split! new root = %"Z"u", pp->mp_pgno));
+ new_root = mc->mc_db->md_depth++;
+
+ /* Add left (implicit) pointer. */
+ if ((rc = mdb_node_add(mc, 0, NULL, NULL, mp->mp_pgno, 0)) != MDB_SUCCESS) {
+ /* undo the pre-push */
+ mc->mc_pg[0] = mc->mc_pg[1];
+ mc->mc_ki[0] = mc->mc_ki[1];
+ mc->mc_db->md_root = mp->mp_pgno;
+ mc->mc_db->md_depth--;
+ goto done;
+ }
+ mc->mc_snum++;
+ mc->mc_top++;
+ ptop = 0;
+ } else {
+ ptop = mc->mc_top-1;
+ DPRINTF(("parent branch page is %"Z"u", mc->mc_pg[ptop]->mp_pgno));
+ }
+
+ mdb_cursor_copy(mc, &mn);
+ mn.mc_xcursor = NULL;
+ mn.mc_pg[mn.mc_top] = rp;
+ mn.mc_ki[ptop] = mc->mc_ki[ptop]+1;
+
+ if (nflags & MDB_APPEND) {
+ mn.mc_ki[mn.mc_top] = 0;
+ sepkey = *newkey;
+ split_indx = newindx;
+ nkeys = 0;
+ } else {
+
+ split_indx = (nkeys+1) / 2;
+
+ if (IS_LEAF2(rp)) {
+ char *split, *ins;
+ int x;
+ unsigned int lsize, rsize, ksize;
+ /* Move half of the keys to the right sibling */
+ x = mc->mc_ki[mc->mc_top] - split_indx;
+ ksize = mc->mc_db->md_pad;
+ split = LEAF2KEY(mp, split_indx, ksize);
+ rsize = (nkeys - split_indx) * ksize;
+ lsize = (nkeys - split_indx) * sizeof(indx_t);
+ mp->mp_lower -= lsize;
+ rp->mp_lower += lsize;
+ mp->mp_upper += rsize - lsize;
+ rp->mp_upper -= rsize - lsize;
+ sepkey.mv_size = ksize;
+ if (newindx == split_indx) {
+ sepkey.mv_data = newkey->mv_data;
+ } else {
+ sepkey.mv_data = split;
+ }
+ if (x<0) {
+ ins = LEAF2KEY(mp, mc->mc_ki[mc->mc_top], ksize);
+ memcpy(rp->mp_ptrs, split, rsize);
+ sepkey.mv_data = rp->mp_ptrs;
+ memmove(ins+ksize, ins, (split_indx - mc->mc_ki[mc->mc_top]) * ksize);
+ memcpy(ins, newkey->mv_data, ksize);
+ mp->mp_lower += sizeof(indx_t);
+ mp->mp_upper -= ksize - sizeof(indx_t);
+ } else {
+ if (x)
+ memcpy(rp->mp_ptrs, split, x * ksize);
+ ins = LEAF2KEY(rp, x, ksize);
+ memcpy(ins, newkey->mv_data, ksize);
+ memcpy(ins+ksize, split + x * ksize, rsize - x * ksize);
+ rp->mp_lower += sizeof(indx_t);
+ rp->mp_upper -= ksize - sizeof(indx_t);
+ mc->mc_ki[mc->mc_top] = x;
+ }
+ } else {
+ int psize, nsize, k;
+ /* Maximum free space in an empty page */
+ pmax = env->me_psize - PAGEHDRSZ;
+ if (IS_LEAF(mp))
+ nsize = mdb_leaf_size(env, newkey, newdata);
+ else
+ nsize = mdb_branch_size(env, newkey);
+ nsize = EVEN(nsize);
+
+ /* grab a page to hold a temporary copy */
+ copy = mdb_page_malloc(mc->mc_txn, 1);
+ if (copy == NULL) {
+ rc = ENOMEM;
+ goto done;
+ }
+ copy->mp_pgno = mp->mp_pgno;
+ copy->mp_flags = mp->mp_flags;
+ copy->mp_lower = (PAGEHDRSZ-PAGEBASE);
+ copy->mp_upper = env->me_psize - PAGEBASE;
+
+ /* prepare to insert */
+ for (i=0, j=0; i<nkeys; i++) {
+ if (i == newindx) {
+ copy->mp_ptrs[j++] = 0;
+ }
+ copy->mp_ptrs[j++] = mp->mp_ptrs[i];
+ }
+
+ /* When items are relatively large the split point needs
+ * to be checked, because being off-by-one will make the
+ * difference between success or failure in mdb_node_add.
+ *
+ * It's also relevant if a page happens to be laid out
+ * such that one half of its nodes are all "small" and
+ * the other half of its nodes are "large." If the new
+ * item is also "large" and falls on the half with
+ * "large" nodes, it also may not fit.
+ *
+ * As a final tweak, if the new item goes on the last
+ * spot on the page (and thus, onto the new page), bias
+ * the split so the new page is emptier than the old page.
+ * This yields better packing during sequential inserts.
+ */
+ if (nkeys < 20 || nsize > pmax/16 || newindx >= nkeys) {
+ /* Find split point */
+ psize = 0;
+ if (newindx <= split_indx || newindx >= nkeys) {
+ i = 0; j = 1;
+ k = newindx >= nkeys ? nkeys : split_indx+1+IS_LEAF(mp);
+ } else {
+ i = nkeys; j = -1;
+ k = split_indx-1;
+ }
+ for (; i!=k; i+=j) {
+ if (i == newindx) {
+ psize += nsize;
+ node = NULL;
+ } else {
+ node = (MDB_node *)((char *)mp + copy->mp_ptrs[i] + PAGEBASE);
+ psize += NODESIZE + NODEKSZ(node) + sizeof(indx_t);
+ if (IS_LEAF(mp)) {
+ if (F_ISSET(node->mn_flags, F_BIGDATA))
+ psize += sizeof(pgno_t);
+ else
+ psize += NODEDSZ(node);
+ }
+ psize = EVEN(psize);
+ }
+ if (psize > pmax || i == k-j) {
+ split_indx = i + (j<0);
+ break;
+ }
+ }
+ }
+ if (split_indx == newindx) {
+ sepkey.mv_size = newkey->mv_size;
+ sepkey.mv_data = newkey->mv_data;
+ } else {
+ node = (MDB_node *)((char *)mp + copy->mp_ptrs[split_indx] + PAGEBASE);
+ sepkey.mv_size = node->mn_ksize;
+ sepkey.mv_data = NODEKEY(node);
+ }
+ }
+ }
+
+ DPRINTF(("separator is %d [%s]", split_indx, DKEY(&sepkey)));
+
+ /* Copy separator key to the parent.
+ */
+ if (SIZELEFT(mn.mc_pg[ptop]) < mdb_branch_size(env, &sepkey)) {
+ int snum = mc->mc_snum;
+ mn.mc_snum--;
+ mn.mc_top--;
+ did_split = 1;
+ /* We want other splits to find mn when doing fixups */
+ WITH_CURSOR_TRACKING(mn,
+ rc = mdb_page_split(&mn, &sepkey, NULL, rp->mp_pgno, 0));
+ if (rc)
+ goto done;
+
+ /* root split? */
+ if (mc->mc_snum > snum) {
+ ptop++;
+ }
+ /* Right page might now have changed parent.
+ * Check if left page also changed parent.
+ */
+ if (mn.mc_pg[ptop] != mc->mc_pg[ptop] &&
+ mc->mc_ki[ptop] >= NUMKEYS(mc->mc_pg[ptop])) {
+ for (i=0; i<ptop; i++) {
+ mc->mc_pg[i] = mn.mc_pg[i];
+ mc->mc_ki[i] = mn.mc_ki[i];
+ }
+ mc->mc_pg[ptop] = mn.mc_pg[ptop];
+ if (mn.mc_ki[ptop]) {
+ mc->mc_ki[ptop] = mn.mc_ki[ptop] - 1;
+ } else {
+ /* find right page's left sibling */
+ mc->mc_ki[ptop] = mn.mc_ki[ptop];
+ mdb_cursor_sibling(mc, 0);
+ }
+ }
+ } else {
+ mn.mc_top--;
+ rc = mdb_node_add(&mn, mn.mc_ki[ptop], &sepkey, NULL, rp->mp_pgno, 0);
+ mn.mc_top++;
+ }
+ if (rc != MDB_SUCCESS) {
+ goto done;
+ }
+ if (nflags & MDB_APPEND) {
+ mc->mc_pg[mc->mc_top] = rp;
+ mc->mc_ki[mc->mc_top] = 0;
+ rc = mdb_node_add(mc, 0, newkey, newdata, newpgno, nflags);
+ if (rc)
+ goto done;
+ for (i=0; i<mc->mc_top; i++)
+ mc->mc_ki[i] = mn.mc_ki[i];
+ } else if (!IS_LEAF2(mp)) {
+ /* Move nodes */
+ mc->mc_pg[mc->mc_top] = rp;
+ i = split_indx;
+ j = 0;
+ do {
+ if (i == newindx) {
+ rkey.mv_data = newkey->mv_data;
+ rkey.mv_size = newkey->mv_size;
+ if (IS_LEAF(mp)) {
+ rdata = newdata;
+ } else
+ pgno = newpgno;
+ flags = nflags;
+ /* Update index for the new key. */
+ mc->mc_ki[mc->mc_top] = j;
+ } else {
+ node = (MDB_node *)((char *)mp + copy->mp_ptrs[i] + PAGEBASE);
+ rkey.mv_data = NODEKEY(node);
+ rkey.mv_size = node->mn_ksize;
+ if (IS_LEAF(mp)) {
+ xdata.mv_data = NODEDATA(node);
+ xdata.mv_size = NODEDSZ(node);
+ rdata = &xdata;
+ } else
+ pgno = NODEPGNO(node);
+ flags = node->mn_flags;
+ }
+
+ if (!IS_LEAF(mp) && j == 0) {
+ /* First branch index doesn't need key data. */
+ rkey.mv_size = 0;
+ }
+
+ rc = mdb_node_add(mc, j, &rkey, rdata, pgno, flags);
+ if (rc)
+ goto done;
+ if (i == nkeys) {
+ i = 0;
+ j = 0;
+ mc->mc_pg[mc->mc_top] = copy;
+ } else {
+ i++;
+ j++;
+ }
+ } while (i != split_indx);
+
+ nkeys = NUMKEYS(copy);
+ for (i=0; i<nkeys; i++)
+ mp->mp_ptrs[i] = copy->mp_ptrs[i];
+ mp->mp_lower = copy->mp_lower;
+ mp->mp_upper = copy->mp_upper;
+ memcpy(NODEPTR(mp, nkeys-1), NODEPTR(copy, nkeys-1),
+ env->me_psize - copy->mp_upper - PAGEBASE);
+
+ /* reset back to original page */
+ if (newindx < split_indx) {
+ mc->mc_pg[mc->mc_top] = mp;
+ } else {
+ mc->mc_pg[mc->mc_top] = rp;
+ mc->mc_ki[ptop]++;
+ /* Make sure mc_ki is still valid.
+ */
+ if (mn.mc_pg[ptop] != mc->mc_pg[ptop] &&
+ mc->mc_ki[ptop] >= NUMKEYS(mc->mc_pg[ptop])) {
+ for (i=0; i<=ptop; i++) {
+ mc->mc_pg[i] = mn.mc_pg[i];
+ mc->mc_ki[i] = mn.mc_ki[i];
+ }
+ }
+ }
+ if (nflags & MDB_RESERVE) {
+ node = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]);
+ if (!(node->mn_flags & F_BIGDATA))
+ newdata->mv_data = NODEDATA(node);
+ }
+ } else {
+ if (newindx >= split_indx) {
+ mc->mc_pg[mc->mc_top] = rp;
+ mc->mc_ki[ptop]++;
+ /* Make sure mc_ki is still valid.
+ */
+ if (mn.mc_pg[ptop] != mc->mc_pg[ptop] &&
+ mc->mc_ki[ptop] >= NUMKEYS(mc->mc_pg[ptop])) {
+ for (i=0; i<=ptop; i++) {
+ mc->mc_pg[i] = mn.mc_pg[i];
+ mc->mc_ki[i] = mn.mc_ki[i];
+ }
+ }
+ }
+ }
+
+ {
+ /* Adjust other cursors pointing to mp */
+ MDB_cursor *m2, *m3;
+ MDB_dbi dbi = mc->mc_dbi;
+ nkeys = NUMKEYS(mp);
+
+ for (m2 = mc->mc_txn->mt_cursors[dbi]; m2; m2=m2->mc_next) {
+ if (mc->mc_flags & C_SUB)
+ m3 = &m2->mc_xcursor->mx_cursor;
+ else
+ m3 = m2;
+ if (m3 == mc)
+ continue;
+ if (!(m2->mc_flags & m3->mc_flags & C_INITIALIZED))
+ continue;
+ if (new_root) {
+ int k;
+ /* sub cursors may be on different DB */
+ if (m3->mc_pg[0] != mp)
+ continue;
+ /* root split */
+ for (k=new_root; k>=0; k--) {
+ m3->mc_ki[k+1] = m3->mc_ki[k];
+ m3->mc_pg[k+1] = m3->mc_pg[k];
+ }
+ if (m3->mc_ki[0] >= nkeys) {
+ m3->mc_ki[0] = 1;
+ } else {
+ m3->mc_ki[0] = 0;
+ }
+ m3->mc_pg[0] = mc->mc_pg[0];
+ m3->mc_snum++;
+ m3->mc_top++;
+ }
+ if (m3->mc_top >= mc->mc_top && m3->mc_pg[mc->mc_top] == mp) {
+ if (m3->mc_ki[mc->mc_top] >= newindx && !(nflags & MDB_SPLIT_REPLACE))
+ m3->mc_ki[mc->mc_top]++;
+ if (m3->mc_ki[mc->mc_top] >= nkeys) {
+ m3->mc_pg[mc->mc_top] = rp;
+ m3->mc_ki[mc->mc_top] -= nkeys;
+ for (i=0; i<mc->mc_top; i++) {
+ m3->mc_ki[i] = mn.mc_ki[i];
+ m3->mc_pg[i] = mn.mc_pg[i];
+ }
+ }
+ } else if (!did_split && m3->mc_top >= ptop && m3->mc_pg[ptop] == mc->mc_pg[ptop] &&
+ m3->mc_ki[ptop] >= mc->mc_ki[ptop]) {
+ m3->mc_ki[ptop]++;
+ }
+ if (IS_LEAF(mp))
+ XCURSOR_REFRESH(m3, mc->mc_top, m3->mc_pg[mc->mc_top]);
+ }
+ }
+ DPRINTF(("mp left: %d, rp left: %d", SIZELEFT(mp), SIZELEFT(rp)));
+
+done:
+ if (copy) /* tmp page */
+ mdb_page_free(env, copy);
+ if (rc)
+ mc->mc_txn->mt_flags |= MDB_TXN_ERROR;
+ return rc;
+}
+
+int
+mdb_put(MDB_txn *txn, MDB_dbi dbi,
+ MDB_val *key, MDB_val *data, unsigned int flags)
+{
+ MDB_cursor mc;
+ MDB_xcursor mx;
+ int rc;
+
+ if (!key || !data || !TXN_DBI_EXIST(txn, dbi, DB_USRVALID))
+ return EINVAL;
+
+ if (flags & ~(MDB_NOOVERWRITE|MDB_NODUPDATA|MDB_RESERVE|MDB_APPEND|MDB_APPENDDUP))
+ return EINVAL;
+
+ if (txn->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_BLOCKED))
+ return (txn->mt_flags & MDB_TXN_RDONLY) ? EACCES : MDB_BAD_TXN;
+
+ mdb_cursor_init(&mc, txn, dbi, &mx);
+ mc.mc_next = txn->mt_cursors[dbi];
+ txn->mt_cursors[dbi] = &mc;
+ rc = mdb_cursor_put(&mc, key, data, flags);
+ txn->mt_cursors[dbi] = mc.mc_next;
+ return rc;
+}
+
+#ifndef MDB_WBUF
+#define MDB_WBUF (1024*1024)
+#endif
+#define MDB_EOF 0x10 /**< #mdb_env_copyfd1() is done reading */
+
+ /** State needed for a double-buffering compacting copy. */
+typedef struct mdb_copy {
+ MDB_env *mc_env;
+ MDB_txn *mc_txn;
+ pthread_mutex_t mc_mutex;
+ pthread_cond_t mc_cond; /**< Condition variable for #mc_new */
+ char *mc_wbuf[2];
+ char *mc_over[2];
+ int mc_wlen[2];
+ int mc_olen[2];
+ pgno_t mc_next_pgno;
+ HANDLE mc_fd;
+ int mc_toggle; /**< Buffer number in provider */
+ int mc_new; /**< (0-2 buffers to write) | (#MDB_EOF at end) */
+ /** Error code. Never cleared if set. Both threads can set nonzero
+ * to fail the copy. Not mutex-protected, LMDB expects atomic int.
+ */
+ volatile int mc_error;
+} mdb_copy;
+
+ /** Dedicated writer thread for compacting copy. */
+static THREAD_RET ESECT CALL_CONV
+mdb_env_copythr(void *arg)
+{
+ mdb_copy *my = arg;
+ char *ptr;
+ int toggle = 0, wsize, rc;
+#ifdef _WIN32
+ DWORD len;
+#define DO_WRITE(rc, fd, ptr, w2, len) rc = WriteFile(fd, ptr, w2, &len, NULL)
+#else
+ int len;
+#define DO_WRITE(rc, fd, ptr, w2, len) len = write(fd, ptr, w2); rc = (len >= 0)
+#ifdef SIGPIPE
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set, SIGPIPE);
+ if ((rc = pthread_sigmask(SIG_BLOCK, &set, NULL)) != 0)
+ my->mc_error = rc;
+#endif
+#endif
+
+ pthread_mutex_lock(&my->mc_mutex);
+ for(;;) {
+ while (!my->mc_new)
+ pthread_cond_wait(&my->mc_cond, &my->mc_mutex);
+ if (my->mc_new == 0 + MDB_EOF) /* 0 buffers, just EOF */
+ break;
+ wsize = my->mc_wlen[toggle];
+ ptr = my->mc_wbuf[toggle];
+again:
+ rc = MDB_SUCCESS;
+ while (wsize > 0 && !my->mc_error) {
+ DO_WRITE(rc, my->mc_fd, ptr, wsize, len);
+ if (!rc) {
+ rc = ErrCode();
+#if defined(SIGPIPE) && !defined(_WIN32)
+ if (rc == EPIPE) {
+ /* Collect the pending SIGPIPE, otherwise at least OS X
+ * gives it to the process on thread-exit (ITS#8504).
+ */
+ int tmp;
+ sigwait(&set, &tmp);
+ }
+#endif
+ break;
+ } else if (len > 0) {
+ rc = MDB_SUCCESS;
+ ptr += len;
+ wsize -= len;
+ continue;
+ } else {
+ rc = EIO;
+ break;
+ }
+ }
+ if (rc) {
+ my->mc_error = rc;
+ }
+ /* If there's an overflow page tail, write it too */
+ if (my->mc_olen[toggle]) {
+ wsize = my->mc_olen[toggle];
+ ptr = my->mc_over[toggle];
+ my->mc_olen[toggle] = 0;
+ goto again;
+ }
+ my->mc_wlen[toggle] = 0;
+ toggle ^= 1;
+ /* Return the empty buffer to provider */
+ my->mc_new--;
+ pthread_cond_signal(&my->mc_cond);
+ }
+ pthread_mutex_unlock(&my->mc_mutex);
+ return (THREAD_RET)0;
+#undef DO_WRITE
+}
+
+ /** Give buffer and/or #MDB_EOF to writer thread, await unused buffer.
+ *
+ * @param[in] my control structure.
+ * @param[in] adjust (1 to hand off 1 buffer) | (MDB_EOF when ending).
+ */
+static int ESECT
+mdb_env_cthr_toggle(mdb_copy *my, int adjust)
+{
+ pthread_mutex_lock(&my->mc_mutex);
+ my->mc_new += adjust;
+ pthread_cond_signal(&my->mc_cond);
+ while (my->mc_new & 2) /* both buffers in use */
+ pthread_cond_wait(&my->mc_cond, &my->mc_mutex);
+ pthread_mutex_unlock(&my->mc_mutex);
+
+ my->mc_toggle ^= (adjust & 1);
+ /* Both threads reset mc_wlen, to be safe from threading errors */
+ my->mc_wlen[my->mc_toggle] = 0;
+ return my->mc_error;
+}
+
+ /** Depth-first tree traversal for compacting copy.
+ * @param[in] my control structure.
+ * @param[in,out] pg database root.
+ * @param[in] flags includes #F_DUPDATA if it is a sorted-duplicate sub-DB.
+ */
+static int ESECT
+mdb_env_cwalk(mdb_copy *my, pgno_t *pg, int flags)
+{
+ MDB_cursor mc = {0};
+ MDB_node *ni;
+ MDB_page *mo, *mp, *leaf;
+ char *buf, *ptr;
+ int rc, toggle;
+ unsigned int i;
+
+ /* Empty DB, nothing to do */
+ if (*pg == P_INVALID)
+ return MDB_SUCCESS;
+
+ mc.mc_snum = 1;
+ mc.mc_txn = my->mc_txn;
+
+ rc = mdb_page_get(&mc, *pg, &mc.mc_pg[0], NULL);
+ if (rc)
+ return rc;
+ rc = mdb_page_search_root(&mc, NULL, MDB_PS_FIRST);
+ if (rc)
+ return rc;
+
+ /* Make cursor pages writable */
+ buf = ptr = malloc(my->mc_env->me_psize * mc.mc_snum);
+ if (buf == NULL)
+ return ENOMEM;
+
+ for (i=0; i<mc.mc_top; i++) {
+ mdb_page_copy((MDB_page *)ptr, mc.mc_pg[i], my->mc_env->me_psize);
+ mc.mc_pg[i] = (MDB_page *)ptr;
+ ptr += my->mc_env->me_psize;
+ }
+
+ /* This is writable space for a leaf page. Usually not needed. */
+ leaf = (MDB_page *)ptr;
+
+ toggle = my->mc_toggle;
+ while (mc.mc_snum > 0) {
+ unsigned n;
+ mp = mc.mc_pg[mc.mc_top];
+ n = NUMKEYS(mp);
+
+ if (IS_LEAF(mp)) {
+ if (!IS_LEAF2(mp) && !(flags & F_DUPDATA)) {
+ for (i=0; i<n; i++) {
+ ni = NODEPTR(mp, i);
+ if (ni->mn_flags & F_BIGDATA) {
+ MDB_page *omp;
+ pgno_t pg;
+
+ /* Need writable leaf */
+ if (mp != leaf) {
+ mc.mc_pg[mc.mc_top] = leaf;
+ mdb_page_copy(leaf, mp, my->mc_env->me_psize);
+ mp = leaf;
+ ni = NODEPTR(mp, i);
+ }
+
+ memcpy(&pg, NODEDATA(ni), sizeof(pg));
+ memcpy(NODEDATA(ni), &my->mc_next_pgno, sizeof(pgno_t));
+ rc = mdb_page_get(&mc, pg, &omp, NULL);
+ if (rc)
+ goto done;
+ if (my->mc_wlen[toggle] >= MDB_WBUF) {
+ rc = mdb_env_cthr_toggle(my, 1);
+ if (rc)
+ goto done;
+ toggle = my->mc_toggle;
+ }
+ mo = (MDB_page *)(my->mc_wbuf[toggle] + my->mc_wlen[toggle]);
+ memcpy(mo, omp, my->mc_env->me_psize);
+ mo->mp_pgno = my->mc_next_pgno;
+ my->mc_next_pgno += omp->mp_pages;
+ my->mc_wlen[toggle] += my->mc_env->me_psize;
+ if (omp->mp_pages > 1) {
+ my->mc_olen[toggle] = my->mc_env->me_psize * (omp->mp_pages - 1);
+ my->mc_over[toggle] = (char *)omp + my->mc_env->me_psize;
+ rc = mdb_env_cthr_toggle(my, 1);
+ if (rc)
+ goto done;
+ toggle = my->mc_toggle;
+ }
+ } else if (ni->mn_flags & F_SUBDATA) {
+ MDB_db db;
+
+ /* Need writable leaf */
+ if (mp != leaf) {
+ mc.mc_pg[mc.mc_top] = leaf;
+ mdb_page_copy(leaf, mp, my->mc_env->me_psize);
+ mp = leaf;
+ ni = NODEPTR(mp, i);
+ }
+
+ memcpy(&db, NODEDATA(ni), sizeof(db));
+ my->mc_toggle = toggle;
+ rc = mdb_env_cwalk(my, &db.md_root, ni->mn_flags & F_DUPDATA);
+ if (rc)
+ goto done;
+ toggle = my->mc_toggle;
+ memcpy(NODEDATA(ni), &db, sizeof(db));
+ }
+ }
+ }
+ } else {
+ mc.mc_ki[mc.mc_top]++;
+ if (mc.mc_ki[mc.mc_top] < n) {
+ pgno_t pg;
+again:
+ ni = NODEPTR(mp, mc.mc_ki[mc.mc_top]);
+ pg = NODEPGNO(ni);
+ rc = mdb_page_get(&mc, pg, &mp, NULL);
+ if (rc)
+ goto done;
+ mc.mc_top++;
+ mc.mc_snum++;
+ mc.mc_ki[mc.mc_top] = 0;
+ if (IS_BRANCH(mp)) {
+ /* Whenever we advance to a sibling branch page,
+ * we must proceed all the way down to its first leaf.
+ */
+ mdb_page_copy(mc.mc_pg[mc.mc_top], mp, my->mc_env->me_psize);
+ goto again;
+ } else
+ mc.mc_pg[mc.mc_top] = mp;
+ continue;
+ }
+ }
+ if (my->mc_wlen[toggle] >= MDB_WBUF) {
+ rc = mdb_env_cthr_toggle(my, 1);
+ if (rc)
+ goto done;
+ toggle = my->mc_toggle;
+ }
+ mo = (MDB_page *)(my->mc_wbuf[toggle] + my->mc_wlen[toggle]);
+ mdb_page_copy(mo, mp, my->mc_env->me_psize);
+ mo->mp_pgno = my->mc_next_pgno++;
+ my->mc_wlen[toggle] += my->mc_env->me_psize;
+ if (mc.mc_top) {
+ /* Update parent if there is one */
+ ni = NODEPTR(mc.mc_pg[mc.mc_top-1], mc.mc_ki[mc.mc_top-1]);
+ SETPGNO(ni, mo->mp_pgno);
+ mdb_cursor_pop(&mc);
+ } else {
+ /* Otherwise we're done */
+ *pg = mo->mp_pgno;
+ break;
+ }
+ }
+done:
+ free(buf);
+ return rc;
+}
+
+ /** Copy environment with compaction. */
+static int ESECT
+mdb_env_copyfd1(MDB_env *env, HANDLE fd)
+{
+ MDB_meta *mm;
+ MDB_page *mp;
+ mdb_copy my = {0};
+ MDB_txn *txn = NULL;
+ pthread_t thr;
+ pgno_t root, new_root;
+ int rc = MDB_SUCCESS;
+
+#ifdef _WIN32
+ if (!(my.mc_mutex = CreateMutex(NULL, FALSE, NULL)) ||
+ !(my.mc_cond = CreateEvent(NULL, FALSE, FALSE, NULL))) {
+ rc = ErrCode();
+ goto done;
+ }
+ my.mc_wbuf[0] = _aligned_malloc(MDB_WBUF*2, env->me_os_psize);
+ if (my.mc_wbuf[0] == NULL) {
+ /* _aligned_malloc() sets errno, but we use Windows error codes */
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+#else
+ if ((rc = pthread_mutex_init(&my.mc_mutex, NULL)) != 0)
+ return rc;
+ if ((rc = pthread_cond_init(&my.mc_cond, NULL)) != 0)
+ goto done2;
+#ifdef HAVE_MEMALIGN
+ my.mc_wbuf[0] = memalign(env->me_os_psize, MDB_WBUF*2);
+ if (my.mc_wbuf[0] == NULL) {
+ rc = errno;
+ goto done;
+ }
+#else
+ {
+ void *p;
+ if ((rc = posix_memalign(&p, env->me_os_psize, MDB_WBUF*2)) != 0)
+ goto done;
+ my.mc_wbuf[0] = p;
+ }
+#endif
+#endif
+ memset(my.mc_wbuf[0], 0, MDB_WBUF*2);
+ my.mc_wbuf[1] = my.mc_wbuf[0] + MDB_WBUF;
+ my.mc_next_pgno = NUM_METAS;
+ my.mc_env = env;
+ my.mc_fd = fd;
+ rc = THREAD_CREATE(thr, mdb_env_copythr, &my);
+ if (rc)
+ goto done;
+
+ rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn);
+ if (rc)
+ goto finish;
+
+ mp = (MDB_page *)my.mc_wbuf[0];
+ memset(mp, 0, NUM_METAS * env->me_psize);
+ mp->mp_pgno = 0;
+ mp->mp_flags = P_META;
+ mm = (MDB_meta *)METADATA(mp);
+ mdb_env_init_meta0(env, mm);
+ mm->mm_address = env->me_metas[0]->mm_address;
+
+ mp = (MDB_page *)(my.mc_wbuf[0] + env->me_psize);
+ mp->mp_pgno = 1;
+ mp->mp_flags = P_META;
+ *(MDB_meta *)METADATA(mp) = *mm;
+ mm = (MDB_meta *)METADATA(mp);
+
+ /* Set metapage 1 with current main DB */
+ root = new_root = txn->mt_dbs[MAIN_DBI].md_root;
+ if (root != P_INVALID) {
+ /* Count free pages + freeDB pages. Subtract from last_pg
+ * to find the new last_pg, which also becomes the new root.
+ */
+ MDB_ID freecount = 0;
+ MDB_cursor mc;
+ MDB_val key, data;
+ mdb_cursor_init(&mc, txn, FREE_DBI, NULL);
+ while ((rc = mdb_cursor_get(&mc, &key, &data, MDB_NEXT)) == 0)
+ freecount += *(MDB_ID *)data.mv_data;
+ if (rc != MDB_NOTFOUND)
+ goto finish;
+ freecount += txn->mt_dbs[FREE_DBI].md_branch_pages +
+ txn->mt_dbs[FREE_DBI].md_leaf_pages +
+ txn->mt_dbs[FREE_DBI].md_overflow_pages;
+
+ new_root = txn->mt_next_pgno - 1 - freecount;
+ mm->mm_last_pg = new_root;
+ mm->mm_dbs[MAIN_DBI] = txn->mt_dbs[MAIN_DBI];
+ mm->mm_dbs[MAIN_DBI].md_root = new_root;
+ } else {
+ /* When the DB is empty, handle it specially to
+ * fix any breakage like page leaks from ITS#8174.
+ */
+ mm->mm_dbs[MAIN_DBI].md_flags = txn->mt_dbs[MAIN_DBI].md_flags;
+ }
+ if (root != P_INVALID || mm->mm_dbs[MAIN_DBI].md_flags) {
+ mm->mm_txnid = 1; /* use metapage 1 */
+ }
+
+ my.mc_wlen[0] = env->me_psize * NUM_METAS;
+ my.mc_txn = txn;
+ rc = mdb_env_cwalk(&my, &root, 0);
+ if (rc == MDB_SUCCESS && root != new_root) {
+ rc = MDB_INCOMPATIBLE; /* page leak or corrupt DB */
+ }
+
+finish:
+ if (rc)
+ my.mc_error = rc;
+ mdb_env_cthr_toggle(&my, 1 | MDB_EOF);
+ rc = THREAD_FINISH(thr);
+ mdb_txn_abort(txn);
+
+done:
+#ifdef _WIN32
+ if (my.mc_wbuf[0]) _aligned_free(my.mc_wbuf[0]);
+ if (my.mc_cond) CloseHandle(my.mc_cond);
+ if (my.mc_mutex) CloseHandle(my.mc_mutex);
+#else
+ free(my.mc_wbuf[0]);
+ pthread_cond_destroy(&my.mc_cond);
+done2:
+ pthread_mutex_destroy(&my.mc_mutex);
+#endif
+ return rc ? rc : my.mc_error;
+}
+
+ /** Copy environment as-is. */
+static int ESECT
+mdb_env_copyfd0(MDB_env *env, HANDLE fd)
+{
+ MDB_txn *txn = NULL;
+ mdb_mutexref_t wmutex = NULL;
+ int rc;
+ size_t wsize, w3;
+ char *ptr;
+#ifdef _WIN32
+ DWORD len, w2;
+#define DO_WRITE(rc, fd, ptr, w2, len) rc = WriteFile(fd, ptr, w2, &len, NULL)
+#else
+ ssize_t len;
+ size_t w2;
+#define DO_WRITE(rc, fd, ptr, w2, len) len = write(fd, ptr, w2); rc = (len >= 0)
+#endif
+
+ /* Do the lock/unlock of the reader mutex before starting the
+ * write txn. Otherwise other read txns could block writers.
+ */
+ rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn);
+ if (rc)
+ return rc;
+
+ if (env->me_txns) {
+ /* We must start the actual read txn after blocking writers */
+ mdb_txn_end(txn, MDB_END_RESET_TMP);
+
+ /* Temporarily block writers until we snapshot the meta pages */
+ wmutex = env->me_wmutex;
+ if (LOCK_MUTEX(rc, env, wmutex))
+ goto leave;
+
+ rc = mdb_txn_renew0(txn);
+ if (rc) {
+ UNLOCK_MUTEX(wmutex);
+ goto leave;
+ }
+ }
+
+ wsize = env->me_psize * NUM_METAS;
+ ptr = env->me_map;
+ w2 = wsize;
+ while (w2 > 0) {
+ DO_WRITE(rc, fd, ptr, w2, len);
+ if (!rc) {
+ rc = ErrCode();
+ break;
+ } else if (len > 0) {
+ rc = MDB_SUCCESS;
+ ptr += len;
+ w2 -= len;
+ continue;
+ } else {
+ /* Non-blocking or async handles are not supported */
+ rc = EIO;
+ break;
+ }
+ }
+ if (wmutex)
+ UNLOCK_MUTEX(wmutex);
+
+ if (rc)
+ goto leave;
+
+ w3 = txn->mt_next_pgno * env->me_psize;
+ {
+ size_t fsize = 0;
+ if ((rc = mdb_fsize(env->me_fd, &fsize)))
+ goto leave;
+ if (w3 > fsize)
+ w3 = fsize;
+ }
+ wsize = w3 - wsize;
+ while (wsize > 0) {
+ if (wsize > MAX_WRITE)
+ w2 = MAX_WRITE;
+ else
+ w2 = wsize;
+ DO_WRITE(rc, fd, ptr, w2, len);
+ if (!rc) {
+ rc = ErrCode();
+ break;
+ } else if (len > 0) {
+ rc = MDB_SUCCESS;
+ ptr += len;
+ wsize -= len;
+ continue;
+ } else {
+ rc = EIO;
+ break;
+ }
+ }
+
+leave:
+ mdb_txn_abort(txn);
+ return rc;
+}
+
+int ESECT
+mdb_env_copyfd2(MDB_env *env, HANDLE fd, unsigned int flags)
+{
+ if (flags & MDB_CP_COMPACT)
+ return mdb_env_copyfd1(env, fd);
+ else
+ return mdb_env_copyfd0(env, fd);
+}
+
+int ESECT
+mdb_env_copyfd(MDB_env *env, HANDLE fd)
+{
+ return mdb_env_copyfd2(env, fd, 0);
+}
+
+int ESECT
+mdb_env_copy2(MDB_env *env, const char *path, unsigned int flags)
+{
+ int rc;
+ MDB_name fname;
+ HANDLE newfd = INVALID_HANDLE_VALUE;
+
+ rc = mdb_fname_init(path, env->me_flags | MDB_NOLOCK, &fname);
+ if (rc == MDB_SUCCESS) {
+ rc = mdb_fopen(env, &fname, MDB_O_COPY, 0666, &newfd);
+ mdb_fname_destroy(fname);
+ }
+ if (rc == MDB_SUCCESS) {
+ rc = mdb_env_copyfd2(env, newfd, flags);
+ if (close(newfd) < 0 && rc == MDB_SUCCESS)
+ rc = ErrCode();
+ }
+ return rc;
+}
+
+int ESECT
+mdb_env_copy(MDB_env *env, const char *path)
+{
+ return mdb_env_copy2(env, path, 0);
+}
+
+int ESECT
+mdb_env_set_flags(MDB_env *env, unsigned int flag, int onoff)
+{
+ if (flag & ~CHANGEABLE)
+ return EINVAL;
+ if (onoff)
+ env->me_flags |= flag;
+ else
+ env->me_flags &= ~flag;
+ return MDB_SUCCESS;
+}
+
+int ESECT
+mdb_env_get_flags(MDB_env *env, unsigned int *arg)
+{
+ if (!env || !arg)
+ return EINVAL;
+
+ *arg = env->me_flags & (CHANGEABLE|CHANGELESS);
+ return MDB_SUCCESS;
+}
+
+int ESECT
+mdb_env_set_userctx(MDB_env *env, void *ctx)
+{
+ if (!env)
+ return EINVAL;
+ env->me_userctx = ctx;
+ return MDB_SUCCESS;
+}
+
+void * ESECT
+mdb_env_get_userctx(MDB_env *env)
+{
+ return env ? env->me_userctx : NULL;
+}
+
+int ESECT
+mdb_env_set_assert(MDB_env *env, MDB_assert_func *func)
+{
+ if (!env)
+ return EINVAL;
+#ifndef NDEBUG
+ env->me_assert_func = func;
+#endif
+ return MDB_SUCCESS;
+}
+
+int ESECT
+mdb_env_get_path(MDB_env *env, const char **arg)
+{
+ if (!env || !arg)
+ return EINVAL;
+
+ *arg = env->me_path;
+ return MDB_SUCCESS;
+}
+
+int ESECT
+mdb_env_get_fd(MDB_env *env, mdb_filehandle_t *arg)
+{
+ if (!env || !arg)
+ return EINVAL;
+
+ *arg = env->me_fd;
+ return MDB_SUCCESS;
+}
+
+/** Common code for #mdb_stat() and #mdb_env_stat().
+ * @param[in] env the environment to operate in.
+ * @param[in] db the #MDB_db record containing the stats to return.
+ * @param[out] arg the address of an #MDB_stat structure to receive the stats.
+ * @return 0, this function always succeeds.
+ */
+static int ESECT
+mdb_stat0(MDB_env *env, MDB_db *db, MDB_stat *arg)
+{
+ arg->ms_psize = env->me_psize;
+ arg->ms_depth = db->md_depth;
+ arg->ms_branch_pages = db->md_branch_pages;
+ arg->ms_leaf_pages = db->md_leaf_pages;
+ arg->ms_overflow_pages = db->md_overflow_pages;
+ arg->ms_entries = db->md_entries;
+
+ return MDB_SUCCESS;
+}
+
+int ESECT
+mdb_env_stat(MDB_env *env, MDB_stat *arg)
+{
+ MDB_meta *meta;
+
+ if (env == NULL || arg == NULL)
+ return EINVAL;
+
+ meta = mdb_env_pick_meta(env);
+
+ return mdb_stat0(env, &meta->mm_dbs[MAIN_DBI], arg);
+}
+
+int ESECT
+mdb_env_info(MDB_env *env, MDB_envinfo *arg)
+{
+ MDB_meta *meta;
+
+ if (env == NULL || arg == NULL)
+ return EINVAL;
+
+ meta = mdb_env_pick_meta(env);
+ arg->me_mapaddr = meta->mm_address;
+ arg->me_last_pgno = meta->mm_last_pg;
+ arg->me_last_txnid = meta->mm_txnid;
+
+ arg->me_mapsize = env->me_mapsize;
+ arg->me_maxreaders = env->me_maxreaders;
+ arg->me_numreaders = env->me_txns ? env->me_txns->mti_numreaders : 0;
+ return MDB_SUCCESS;
+}
+
+/** Set the default comparison functions for a database.
+ * Called immediately after a database is opened to set the defaults.
+ * The user can then override them with #mdb_set_compare() or
+ * #mdb_set_dupsort().
+ * @param[in] txn A transaction handle returned by #mdb_txn_begin()
+ * @param[in] dbi A database handle returned by #mdb_dbi_open()
+ */
+static void
+mdb_default_cmp(MDB_txn *txn, MDB_dbi dbi)
+{
+ uint16_t f = txn->mt_dbs[dbi].md_flags;
+
+ txn->mt_dbxs[dbi].md_cmp =
+ (f & MDB_REVERSEKEY) ? mdb_cmp_memnr :
+ (f & MDB_INTEGERKEY) ? mdb_cmp_cint : mdb_cmp_memn;
+
+ txn->mt_dbxs[dbi].md_dcmp =
+ !(f & MDB_DUPSORT) ? 0 :
+ ((f & MDB_INTEGERDUP)
+ ? ((f & MDB_DUPFIXED) ? mdb_cmp_int : mdb_cmp_cint)
+ : ((f & MDB_REVERSEDUP) ? mdb_cmp_memnr : mdb_cmp_memn));
+}
+
+int mdb_dbi_open(MDB_txn *txn, const char *name, unsigned int flags, MDB_dbi *dbi)
+{
+ MDB_val key, data;
+ MDB_dbi i;
+ MDB_cursor mc;
+ MDB_db dummy;
+ int rc, dbflag, exact;
+ unsigned int unused = 0, seq;
+ char *namedup;
+ size_t len;
+
+ if (flags & ~VALID_FLAGS)
+ return EINVAL;
+ if (txn->mt_flags & MDB_TXN_BLOCKED)
+ return MDB_BAD_TXN;
+
+ /* main DB? */
+ if (!name) {
+ *dbi = MAIN_DBI;
+ if (flags & PERSISTENT_FLAGS) {
+ uint16_t f2 = flags & PERSISTENT_FLAGS;
+ /* make sure flag changes get committed */
+ if ((txn->mt_dbs[MAIN_DBI].md_flags | f2) != txn->mt_dbs[MAIN_DBI].md_flags) {
+ txn->mt_dbs[MAIN_DBI].md_flags |= f2;
+ txn->mt_flags |= MDB_TXN_DIRTY;
+ }
+ }
+ mdb_default_cmp(txn, MAIN_DBI);
+ return MDB_SUCCESS;
+ }
+
+ if (txn->mt_dbxs[MAIN_DBI].md_cmp == NULL) {
+ mdb_default_cmp(txn, MAIN_DBI);
+ }
+
+ /* Is the DB already open? */
+ len = strlen(name);
+ for (i=CORE_DBS; i<txn->mt_numdbs; i++) {
+ if (!txn->mt_dbxs[i].md_name.mv_size) {
+ /* Remember this free slot */
+ if (!unused) unused = i;
+ continue;
+ }
+ if (len == txn->mt_dbxs[i].md_name.mv_size &&
+ !strncmp(name, txn->mt_dbxs[i].md_name.mv_data, len)) {
+ *dbi = i;
+ return MDB_SUCCESS;
+ }
+ }
+
+ /* If no free slot and max hit, fail */
+ if (!unused && txn->mt_numdbs >= txn->mt_env->me_maxdbs)
+ return MDB_DBS_FULL;
+
+ /* Cannot mix named databases with some mainDB flags */
+ if (txn->mt_dbs[MAIN_DBI].md_flags & (MDB_DUPSORT|MDB_INTEGERKEY))
+ return (flags & MDB_CREATE) ? MDB_INCOMPATIBLE : MDB_NOTFOUND;
+
+ /* Find the DB info */
+ dbflag = DB_NEW|DB_VALID|DB_USRVALID;
+ exact = 0;
+ key.mv_size = len;
+ key.mv_data = (void *)name;
+ mdb_cursor_init(&mc, txn, MAIN_DBI, NULL);
+ rc = mdb_cursor_set(&mc, &key, &data, MDB_SET, &exact);
+ if (rc == MDB_SUCCESS) {
+ /* make sure this is actually a DB */
+ MDB_node *node = NODEPTR(mc.mc_pg[mc.mc_top], mc.mc_ki[mc.mc_top]);
+ if ((node->mn_flags & (F_DUPDATA|F_SUBDATA)) != F_SUBDATA)
+ return MDB_INCOMPATIBLE;
+ } else {
+ if (rc != MDB_NOTFOUND || !(flags & MDB_CREATE))
+ return rc;
+ if (F_ISSET(txn->mt_flags, MDB_TXN_RDONLY))
+ return EACCES;
+ }
+
+ /* Done here so we cannot fail after creating a new DB */
+ if ((namedup = strdup(name)) == NULL)
+ return ENOMEM;
+
+ if (rc) {
+ /* MDB_NOTFOUND and MDB_CREATE: Create new DB */
+ data.mv_size = sizeof(MDB_db);
+ data.mv_data = &dummy;
+ memset(&dummy, 0, sizeof(dummy));
+ dummy.md_root = P_INVALID;
+ dummy.md_flags = flags & PERSISTENT_FLAGS;
+ WITH_CURSOR_TRACKING(mc,
+ rc = mdb_cursor_put(&mc, &key, &data, F_SUBDATA));
+ dbflag |= DB_DIRTY;
+ }
+
+ if (rc) {
+ free(namedup);
+ } else {
+ /* Got info, register DBI in this txn */
+ unsigned int slot = unused ? unused : txn->mt_numdbs;
+ txn->mt_dbxs[slot].md_name.mv_data = namedup;
+ txn->mt_dbxs[slot].md_name.mv_size = len;
+ txn->mt_dbxs[slot].md_rel = NULL;
+ txn->mt_dbflags[slot] = dbflag;
+ /* txn-> and env-> are the same in read txns, use
+ * tmp variable to avoid undefined assignment
+ */
+ seq = ++txn->mt_env->me_dbiseqs[slot];
+ txn->mt_dbiseqs[slot] = seq;
+
+ memcpy(&txn->mt_dbs[slot], data.mv_data, sizeof(MDB_db));
+ *dbi = slot;
+ mdb_default_cmp(txn, slot);
+ if (!unused) {
+ txn->mt_numdbs++;
+ }
+ }
+
+ return rc;
+}
+
+int ESECT
+mdb_stat(MDB_txn *txn, MDB_dbi dbi, MDB_stat *arg)
+{
+ if (!arg || !TXN_DBI_EXIST(txn, dbi, DB_VALID))
+ return EINVAL;
+
+ if (txn->mt_flags & MDB_TXN_BLOCKED)
+ return MDB_BAD_TXN;
+
+ if (txn->mt_dbflags[dbi] & DB_STALE) {
+ MDB_cursor mc;
+ MDB_xcursor mx;
+ /* Stale, must read the DB's root. cursor_init does it for us. */
+ mdb_cursor_init(&mc, txn, dbi, &mx);
+ }
+ return mdb_stat0(txn->mt_env, &txn->mt_dbs[dbi], arg);
+}
+
+void mdb_dbi_close(MDB_env *env, MDB_dbi dbi)
+{
+ char *ptr;
+ if (dbi < CORE_DBS || dbi >= env->me_maxdbs)
+ return;
+ ptr = env->me_dbxs[dbi].md_name.mv_data;
+ /* If there was no name, this was already closed */
+ if (ptr) {
+ env->me_dbxs[dbi].md_name.mv_data = NULL;
+ env->me_dbxs[dbi].md_name.mv_size = 0;
+ env->me_dbflags[dbi] = 0;
+ env->me_dbiseqs[dbi]++;
+ free(ptr);
+ }
+}
+
+int mdb_dbi_flags(MDB_txn *txn, MDB_dbi dbi, unsigned int *flags)
+{
+ /* We could return the flags for the FREE_DBI too but what's the point? */
+ if (!TXN_DBI_EXIST(txn, dbi, DB_USRVALID))
+ return EINVAL;
+ *flags = txn->mt_dbs[dbi].md_flags & PERSISTENT_FLAGS;
+ return MDB_SUCCESS;
+}
+
+/** Add all the DB's pages to the free list.
+ * @param[in] mc Cursor on the DB to free.
+ * @param[in] subs non-Zero to check for sub-DBs in this DB.
+ * @return 0 on success, non-zero on failure.
+ */
+static int
+mdb_drop0(MDB_cursor *mc, int subs)
+{
+ int rc;
+
+ rc = mdb_page_search(mc, NULL, MDB_PS_FIRST);
+ if (rc == MDB_SUCCESS) {
+ MDB_txn *txn = mc->mc_txn;
+ MDB_node *ni;
+ MDB_cursor mx;
+ unsigned int i;
+
+ /* DUPSORT sub-DBs have no ovpages/DBs. Omit scanning leaves.
+ * This also avoids any P_LEAF2 pages, which have no nodes.
+ * Also if the DB doesn't have sub-DBs and has no overflow
+ * pages, omit scanning leaves.
+ */
+ if ((mc->mc_flags & C_SUB) ||
+ (!subs && !mc->mc_db->md_overflow_pages))
+ mdb_cursor_pop(mc);
+
+ mdb_cursor_copy(mc, &mx);
+ while (mc->mc_snum > 0) {
+ MDB_page *mp = mc->mc_pg[mc->mc_top];
+ unsigned n = NUMKEYS(mp);
+ if (IS_LEAF(mp)) {
+ for (i=0; i<n; i++) {
+ ni = NODEPTR(mp, i);
+ if (ni->mn_flags & F_BIGDATA) {
+ MDB_page *omp;
+ pgno_t pg;
+ memcpy(&pg, NODEDATA(ni), sizeof(pg));
+ rc = mdb_page_get(mc, pg, &omp, NULL);
+ if (rc != 0)
+ goto done;
+ mdb_cassert(mc, IS_OVERFLOW(omp));
+ rc = mdb_midl_append_range(&txn->mt_free_pgs,
+ pg, omp->mp_pages);
+ if (rc)
+ goto done;
+ mc->mc_db->md_overflow_pages -= omp->mp_pages;
+ if (!mc->mc_db->md_overflow_pages && !subs)
+ break;
+ } else if (subs && (ni->mn_flags & F_SUBDATA)) {
+ mdb_xcursor_init1(mc, ni);
+ rc = mdb_drop0(&mc->mc_xcursor->mx_cursor, 0);
+ if (rc)
+ goto done;
+ }
+ }
+ if (!subs && !mc->mc_db->md_overflow_pages)
+ goto pop;
+ } else {
+ if ((rc = mdb_midl_need(&txn->mt_free_pgs, n)) != 0)
+ goto done;
+ for (i=0; i<n; i++) {
+ pgno_t pg;
+ ni = NODEPTR(mp, i);
+ pg = NODEPGNO(ni);
+ /* free it */
+ mdb_midl_xappend(txn->mt_free_pgs, pg);
+ }
+ }
+ if (!mc->mc_top)
+ break;
+ mc->mc_ki[mc->mc_top] = i;
+ rc = mdb_cursor_sibling(mc, 1);
+ if (rc) {
+ if (rc != MDB_NOTFOUND)
+ goto done;
+ /* no more siblings, go back to beginning
+ * of previous level.
+ */
+pop:
+ mdb_cursor_pop(mc);
+ mc->mc_ki[0] = 0;
+ for (i=1; i<mc->mc_snum; i++) {
+ mc->mc_ki[i] = 0;
+ mc->mc_pg[i] = mx.mc_pg[i];
+ }
+ }
+ }
+ /* free it */
+ rc = mdb_midl_append(&txn->mt_free_pgs, mc->mc_db->md_root);
+done:
+ if (rc)
+ txn->mt_flags |= MDB_TXN_ERROR;
+ } else if (rc == MDB_NOTFOUND) {
+ rc = MDB_SUCCESS;
+ }
+ mc->mc_flags &= ~C_INITIALIZED;
+ return rc;
+}
+
+int mdb_drop(MDB_txn *txn, MDB_dbi dbi, int del)
+{
+ MDB_cursor *mc, *m2;
+ int rc;
+
+ if ((unsigned)del > 1 || !TXN_DBI_EXIST(txn, dbi, DB_USRVALID))
+ return EINVAL;
+
+ if (F_ISSET(txn->mt_flags, MDB_TXN_RDONLY))
+ return EACCES;
+
+ if (TXN_DBI_CHANGED(txn, dbi))
+ return MDB_BAD_DBI;
+
+ rc = mdb_cursor_open(txn, dbi, &mc);
+ if (rc)
+ return rc;
+
+ rc = mdb_drop0(mc, mc->mc_db->md_flags & MDB_DUPSORT);
+ /* Invalidate the dropped DB's cursors */
+ for (m2 = txn->mt_cursors[dbi]; m2; m2 = m2->mc_next)
+ m2->mc_flags &= ~(C_INITIALIZED|C_EOF);
+ if (rc)
+ goto leave;
+
+ /* Can't delete the main DB */
+ if (del && dbi >= CORE_DBS) {
+ rc = mdb_del0(txn, MAIN_DBI, &mc->mc_dbx->md_name, NULL, F_SUBDATA);
+ if (!rc) {
+ txn->mt_dbflags[dbi] = DB_STALE;
+ mdb_dbi_close(txn->mt_env, dbi);
+ } else {
+ txn->mt_flags |= MDB_TXN_ERROR;
+ }
+ } else {
+ /* reset the DB record, mark it dirty */
+ txn->mt_dbflags[dbi] |= DB_DIRTY;
+ txn->mt_dbs[dbi].md_depth = 0;
+ txn->mt_dbs[dbi].md_branch_pages = 0;
+ txn->mt_dbs[dbi].md_leaf_pages = 0;
+ txn->mt_dbs[dbi].md_overflow_pages = 0;
+ txn->mt_dbs[dbi].md_entries = 0;
+ txn->mt_dbs[dbi].md_root = P_INVALID;
+
+ txn->mt_flags |= MDB_TXN_DIRTY;
+ }
+leave:
+ mdb_cursor_close(mc);
+ return rc;
+}
+
+int mdb_set_compare(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp)
+{
+ if (!TXN_DBI_EXIST(txn, dbi, DB_USRVALID))
+ return EINVAL;
+
+ txn->mt_dbxs[dbi].md_cmp = cmp;
+ return MDB_SUCCESS;
+}
+
+int mdb_set_dupsort(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp)
+{
+ if (!TXN_DBI_EXIST(txn, dbi, DB_USRVALID))
+ return EINVAL;
+
+ txn->mt_dbxs[dbi].md_dcmp = cmp;
+ return MDB_SUCCESS;
+}
+
+int mdb_set_relfunc(MDB_txn *txn, MDB_dbi dbi, MDB_rel_func *rel)
+{
+ if (!TXN_DBI_EXIST(txn, dbi, DB_USRVALID))
+ return EINVAL;
+
+ txn->mt_dbxs[dbi].md_rel = rel;
+ return MDB_SUCCESS;
+}
+
+int mdb_set_relctx(MDB_txn *txn, MDB_dbi dbi, void *ctx)
+{
+ if (!TXN_DBI_EXIST(txn, dbi, DB_USRVALID))
+ return EINVAL;
+
+ txn->mt_dbxs[dbi].md_relctx = ctx;
+ return MDB_SUCCESS;
+}
+
+int ESECT
+mdb_env_get_maxkeysize(MDB_env *env)
+{
+ return ENV_MAXKEY(env);
+}
+
+int ESECT
+mdb_reader_list(MDB_env *env, MDB_msg_func *func, void *ctx)
+{
+ unsigned int i, rdrs;
+ MDB_reader *mr;
+ char buf[64];
+ int rc = 0, first = 1;
+
+ if (!env || !func)
+ return -1;
+ if (!env->me_txns) {
+ return func("(no reader locks)\n", ctx);
+ }
+ rdrs = env->me_txns->mti_numreaders;
+ mr = env->me_txns->mti_readers;
+ for (i=0; i<rdrs; i++) {
+ if (mr[i].mr_pid) {
+ txnid_t txnid = mr[i].mr_txnid;
+ sprintf(buf, txnid == (txnid_t)-1 ?
+ "%10d %"Z"x -\n" : "%10d %"Z"x %"Z"u\n",
+ (int)mr[i].mr_pid, (size_t)mr[i].mr_tid, txnid);
+ if (first) {
+ first = 0;
+ rc = func(" pid thread txnid\n", ctx);
+ if (rc < 0)
+ break;
+ }
+ rc = func(buf, ctx);
+ if (rc < 0)
+ break;
+ }
+ }
+ if (first) {
+ rc = func("(no active readers)\n", ctx);
+ }
+ return rc;
+}
+
+/** Insert pid into list if not already present.
+ * return -1 if already present.
+ */
+static int ESECT
+mdb_pid_insert(MDB_PID_T *ids, MDB_PID_T pid)
+{
+ /* binary search of pid in list */
+ unsigned base = 0;
+ unsigned cursor = 1;
+ int val = 0;
+ unsigned n = ids[0];
+
+ while( 0 < n ) {
+ unsigned pivot = n >> 1;
+ cursor = base + pivot + 1;
+ val = pid - ids[cursor];
+
+ if( val < 0 ) {
+ n = pivot;
+
+ } else if ( val > 0 ) {
+ base = cursor;
+ n -= pivot + 1;
+
+ } else {
+ /* found, so it's a duplicate */
+ return -1;
+ }
+ }
+
+ if( val > 0 ) {
+ ++cursor;
+ }
+ ids[0]++;
+ for (n = ids[0]; n > cursor; n--)
+ ids[n] = ids[n-1];
+ ids[n] = pid;
+ return 0;
+}
+
+int ESECT
+mdb_reader_check(MDB_env *env, int *dead)
+{
+ if (!env)
+ return EINVAL;
+ if (dead)
+ *dead = 0;
+ return env->me_txns ? mdb_reader_check0(env, 0, dead) : MDB_SUCCESS;
+}
+
+/** As #mdb_reader_check(). \b rlocked is set if caller locked #me_rmutex. */
+static int ESECT
+mdb_reader_check0(MDB_env *env, int rlocked, int *dead)
+{
+ mdb_mutexref_t rmutex = rlocked ? NULL : env->me_rmutex;
+ unsigned int i, j, rdrs;
+ MDB_reader *mr;
+ MDB_PID_T *pids, pid;
+ int rc = MDB_SUCCESS, count = 0;
+
+ rdrs = env->me_txns->mti_numreaders;
+ pids = malloc((rdrs+1) * sizeof(MDB_PID_T));
+ if (!pids)
+ return ENOMEM;
+ pids[0] = 0;
+ mr = env->me_txns->mti_readers;
+ for (i=0; i<rdrs; i++) {
+ pid = mr[i].mr_pid;
+ if (pid && pid != env->me_pid) {
+ if (mdb_pid_insert(pids, pid) == 0) {
+ if (!mdb_reader_pid(env, Pidcheck, pid)) {
+ /* Stale reader found */
+ j = i;
+ if (rmutex) {
+ if ((rc = LOCK_MUTEX0(rmutex)) != 0) {
+ if ((rc = mdb_mutex_failed(env, rmutex, rc)))
+ break;
+ rdrs = 0; /* the above checked all readers */
+ } else {
+ /* Recheck, a new process may have reused pid */
+ if (mdb_reader_pid(env, Pidcheck, pid))
+ j = rdrs;
+ }
+ }
+ for (; j<rdrs; j++)
+ if (mr[j].mr_pid == pid) {
+ DPRINTF(("clear stale reader pid %u txn %"Z"d",
+ (unsigned) pid, mr[j].mr_txnid));
+ mr[j].mr_pid = 0;
+ count++;
+ }
+ if (rmutex)
+ UNLOCK_MUTEX(rmutex);
+ }
+ }
+ }
+ }
+ free(pids);
+ if (dead)
+ *dead = count;
+ return rc;
+}
+
+#ifdef MDB_ROBUST_SUPPORTED
+/** Handle #LOCK_MUTEX0() failure.
+ * Try to repair the lock file if the mutex owner died.
+ * @param[in] env the environment handle
+ * @param[in] mutex LOCK_MUTEX0() mutex
+ * @param[in] rc LOCK_MUTEX0() error (nonzero)
+ * @return 0 on success with the mutex locked, or an error code on failure.
+ */
+static int ESECT
+mdb_mutex_failed(MDB_env *env, mdb_mutexref_t mutex, int rc)
+{
+ int rlocked, rc2;
+ MDB_meta *meta;
+
+ if (rc == MDB_OWNERDEAD) {
+ /* We own the mutex. Clean up after dead previous owner. */
+ rc = MDB_SUCCESS;
+ rlocked = (mutex == env->me_rmutex);
+ if (!rlocked) {
+ /* Keep mti_txnid updated, otherwise next writer can
+ * overwrite data which latest meta page refers to.
+ */
+ meta = mdb_env_pick_meta(env);
+ env->me_txns->mti_txnid = meta->mm_txnid;
+ /* env is hosed if the dead thread was ours */
+ if (env->me_txn) {
+ env->me_flags |= MDB_FATAL_ERROR;
+ env->me_txn = NULL;
+ rc = MDB_PANIC;
+ }
+ }
+ DPRINTF(("%cmutex owner died, %s", (rlocked ? 'r' : 'w'),
+ (rc ? "this process' env is hosed" : "recovering")));
+ rc2 = mdb_reader_check0(env, rlocked, NULL);
+ if (rc2 == 0)
+ rc2 = mdb_mutex_consistent(mutex);
+ if (rc || (rc = rc2)) {
+ DPRINTF(("LOCK_MUTEX recovery failed, %s", mdb_strerror(rc)));
+ UNLOCK_MUTEX(mutex);
+ }
+ } else {
+#ifdef _WIN32
+ rc = ErrCode();
+#endif
+ DPRINTF(("LOCK_MUTEX failed, %s", mdb_strerror(rc)));
+ }
+
+ return rc;
+}
+#endif /* MDB_ROBUST_SUPPORTED */
+
+#if defined(_WIN32)
+/** Convert \b src to new wchar_t[] string with room for \b xtra extra chars */
+static int ESECT
+utf8_to_utf16(const char *src, MDB_name *dst, int xtra)
+{
+ int rc, need = 0;
+ wchar_t *result = NULL;
+ for (;;) { /* malloc result, then fill it in */
+ need = MultiByteToWideChar(CP_UTF8, 0, src, -1, result, need);
+ if (!need) {
+ rc = ErrCode();
+ free(result);
+ return rc;
+ }
+ if (!result) {
+ result = malloc(sizeof(wchar_t) * (need + xtra));
+ if (!result)
+ return ENOMEM;
+ continue;
+ }
+ dst->mn_alloced = 1;
+ dst->mn_len = need - 1;
+ dst->mn_val = result;
+ return MDB_SUCCESS;
+ }
+}
+#endif /* defined(_WIN32) */
+/** @} */
diff --git a/src/contrib/lmdb/midl.c b/src/contrib/lmdb/midl.c
new file mode 100644
index 0000000..7b2b77e
--- /dev/null
+++ b/src/contrib/lmdb/midl.c
@@ -0,0 +1,359 @@
+/** @file midl.c
+ * @brief ldap bdb back-end ID List functions */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2000-2018 The OpenLDAP Foundation.
+ * Portions Copyright 2001-2018 Howard Chu, Symas Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include "midl.h"
+
+/** @defgroup internal LMDB Internals
+ * @{
+ */
+/** @defgroup idls ID List Management
+ * @{
+ */
+#define CMP(x,y) ( (x) < (y) ? -1 : (x) > (y) )
+
+unsigned mdb_midl_search( MDB_IDL ids, MDB_ID id )
+{
+ /*
+ * binary search of id in ids
+ * if found, returns position of id
+ * if not found, returns first position greater than id
+ */
+ unsigned base = 0;
+ unsigned cursor = 1;
+ int val = 0;
+ unsigned n = ids[0];
+
+ while( 0 < n ) {
+ unsigned pivot = n >> 1;
+ cursor = base + pivot + 1;
+ val = CMP( ids[cursor], id );
+
+ if( val < 0 ) {
+ n = pivot;
+
+ } else if ( val > 0 ) {
+ base = cursor;
+ n -= pivot + 1;
+
+ } else {
+ return cursor;
+ }
+ }
+
+ if( val > 0 ) {
+ ++cursor;
+ }
+ return cursor;
+}
+
+#if 0 /* superseded by append/sort */
+int mdb_midl_insert( MDB_IDL ids, MDB_ID id )
+{
+ unsigned x, i;
+
+ x = mdb_midl_search( ids, id );
+ assert( x > 0 );
+
+ if( x < 1 ) {
+ /* internal error */
+ return -2;
+ }
+
+ if ( x <= ids[0] && ids[x] == id ) {
+ /* duplicate */
+ assert(0);
+ return -1;
+ }
+
+ if ( ++ids[0] >= MDB_IDL_DB_MAX ) {
+ /* no room */
+ --ids[0];
+ return -2;
+
+ } else {
+ /* insert id */
+ for (i=ids[0]; i>x; i--)
+ ids[i] = ids[i-1];
+ ids[x] = id;
+ }
+
+ return 0;
+}
+#endif
+
+MDB_IDL mdb_midl_alloc(int num)
+{
+ MDB_IDL ids = malloc((num+2) * sizeof(MDB_ID));
+ if (ids) {
+ *ids++ = num;
+ *ids = 0;
+ }
+ return ids;
+}
+
+void mdb_midl_free(MDB_IDL ids)
+{
+ if (ids)
+ free(ids-1);
+}
+
+void mdb_midl_shrink( MDB_IDL *idp )
+{
+ MDB_IDL ids = *idp;
+ if (*(--ids) > MDB_IDL_UM_MAX &&
+ (ids = realloc(ids, (MDB_IDL_UM_MAX+2) * sizeof(MDB_ID))))
+ {
+ *ids++ = MDB_IDL_UM_MAX;
+ *idp = ids;
+ }
+}
+
+static int mdb_midl_grow( MDB_IDL *idp, int num )
+{
+ MDB_IDL idn = *idp-1;
+ /* grow it */
+ idn = realloc(idn, (*idn + num + 2) * sizeof(MDB_ID));
+ if (!idn)
+ return ENOMEM;
+ *idn++ += num;
+ *idp = idn;
+ return 0;
+}
+
+int mdb_midl_need( MDB_IDL *idp, unsigned num )
+{
+ MDB_IDL ids = *idp;
+ num += ids[0];
+ if (num > ids[-1]) {
+ num = (num + num/4 + (256 + 2)) & -256;
+ if (!(ids = realloc(ids-1, num * sizeof(MDB_ID))))
+ return ENOMEM;
+ *ids++ = num - 2;
+ *idp = ids;
+ }
+ return 0;
+}
+
+int mdb_midl_append( MDB_IDL *idp, MDB_ID id )
+{
+ MDB_IDL ids = *idp;
+ /* Too big? */
+ if (ids[0] >= ids[-1]) {
+ if (mdb_midl_grow(idp, MDB_IDL_UM_MAX))
+ return ENOMEM;
+ ids = *idp;
+ }
+ ids[0]++;
+ ids[ids[0]] = id;
+ return 0;
+}
+
+int mdb_midl_append_list( MDB_IDL *idp, MDB_IDL app )
+{
+ MDB_IDL ids = *idp;
+ /* Too big? */
+ if (ids[0] + app[0] >= ids[-1]) {
+ if (mdb_midl_grow(idp, app[0]))
+ return ENOMEM;
+ ids = *idp;
+ }
+ memcpy(&ids[ids[0]+1], &app[1], app[0] * sizeof(MDB_ID));
+ ids[0] += app[0];
+ return 0;
+}
+
+int mdb_midl_append_range( MDB_IDL *idp, MDB_ID id, unsigned n )
+{
+ MDB_ID *ids = *idp, len = ids[0];
+ /* Too big? */
+ if (len + n > ids[-1]) {
+ if (mdb_midl_grow(idp, n | MDB_IDL_UM_MAX))
+ return ENOMEM;
+ ids = *idp;
+ }
+ ids[0] = len + n;
+ ids += len;
+ while (n)
+ ids[n--] = id++;
+ return 0;
+}
+
+void mdb_midl_xmerge( MDB_IDL idl, MDB_IDL merge )
+{
+ MDB_ID old_id, merge_id, i = merge[0], j = idl[0], k = i+j, total = k;
+ idl[0] = (MDB_ID)-1; /* delimiter for idl scan below */
+ old_id = idl[j];
+ while (i) {
+ merge_id = merge[i--];
+ for (; old_id < merge_id; old_id = idl[--j])
+ idl[k--] = old_id;
+ idl[k--] = merge_id;
+ }
+ idl[0] = total;
+}
+
+/* Quicksort + Insertion sort for small arrays */
+
+#define SMALL 8
+#define MIDL_SWAP(a,b) { itmp=(a); (a)=(b); (b)=itmp; }
+
+void
+mdb_midl_sort( MDB_IDL ids )
+{
+ /* Max possible depth of int-indexed tree * 2 items/level */
+ int istack[sizeof(int)*CHAR_BIT * 2];
+ int i,j,k,l,ir,jstack;
+ MDB_ID a, itmp;
+
+ ir = (int)ids[0];
+ l = 1;
+ jstack = 0;
+ for(;;) {
+ if (ir - l < SMALL) { /* Insertion sort */
+ for (j=l+1;j<=ir;j++) {
+ a = ids[j];
+ for (i=j-1;i>=1;i--) {
+ if (ids[i] >= a) break;
+ ids[i+1] = ids[i];
+ }
+ ids[i+1] = a;
+ }
+ if (jstack == 0) break;
+ ir = istack[jstack--];
+ l = istack[jstack--];
+ } else {
+ k = (l + ir) >> 1; /* Choose median of left, center, right */
+ MIDL_SWAP(ids[k], ids[l+1]);
+ if (ids[l] < ids[ir]) {
+ MIDL_SWAP(ids[l], ids[ir]);
+ }
+ if (ids[l+1] < ids[ir]) {
+ MIDL_SWAP(ids[l+1], ids[ir]);
+ }
+ if (ids[l] < ids[l+1]) {
+ MIDL_SWAP(ids[l], ids[l+1]);
+ }
+ i = l+1;
+ j = ir;
+ a = ids[l+1];
+ for(;;) {
+ do i++; while(ids[i] > a);
+ do j--; while(ids[j] < a);
+ if (j < i) break;
+ MIDL_SWAP(ids[i],ids[j]);
+ }
+ ids[l+1] = ids[j];
+ ids[j] = a;
+ jstack += 2;
+ if (ir-i+1 >= j-l) {
+ istack[jstack] = ir;
+ istack[jstack-1] = i;
+ ir = j-1;
+ } else {
+ istack[jstack] = j-1;
+ istack[jstack-1] = l;
+ l = i;
+ }
+ }
+ }
+}
+
+unsigned mdb_mid2l_search( MDB_ID2L ids, MDB_ID id )
+{
+ /*
+ * binary search of id in ids
+ * if found, returns position of id
+ * if not found, returns first position greater than id
+ */
+ unsigned base = 0;
+ unsigned cursor = 1;
+ int val = 0;
+ unsigned n = (unsigned)ids[0].mid;
+
+ while( 0 < n ) {
+ unsigned pivot = n >> 1;
+ cursor = base + pivot + 1;
+ val = CMP( id, ids[cursor].mid );
+
+ if( val < 0 ) {
+ n = pivot;
+
+ } else if ( val > 0 ) {
+ base = cursor;
+ n -= pivot + 1;
+
+ } else {
+ return cursor;
+ }
+ }
+
+ if( val > 0 ) {
+ ++cursor;
+ }
+ return cursor;
+}
+
+int mdb_mid2l_insert( MDB_ID2L ids, MDB_ID2 *id )
+{
+ unsigned x, i;
+
+ x = mdb_mid2l_search( ids, id->mid );
+
+ if( x < 1 ) {
+ /* internal error */
+ return -2;
+ }
+
+ if ( x <= ids[0].mid && ids[x].mid == id->mid ) {
+ /* duplicate */
+ return -1;
+ }
+
+ if ( ids[0].mid >= MDB_IDL_UM_MAX ) {
+ /* too big */
+ return -2;
+
+ } else {
+ /* insert id */
+ ids[0].mid++;
+ for (i=(unsigned)ids[0].mid; i>x; i--)
+ ids[i] = ids[i-1];
+ ids[x] = *id;
+ }
+
+ return 0;
+}
+
+int mdb_mid2l_append( MDB_ID2L ids, MDB_ID2 *id )
+{
+ /* Too big? */
+ if (ids[0].mid >= MDB_IDL_UM_MAX) {
+ return -2;
+ }
+ ids[0].mid++;
+ ids[ids[0].mid] = *id;
+ return 0;
+}
+
+/** @} */
+/** @} */
diff --git a/src/contrib/lmdb/midl.h b/src/contrib/lmdb/midl.h
new file mode 100644
index 0000000..1aa374c
--- /dev/null
+++ b/src/contrib/lmdb/midl.h
@@ -0,0 +1,186 @@
+/** @file midl.h
+ * @brief LMDB ID List header file.
+ *
+ * This file was originally part of back-bdb but has been
+ * modified for use in libmdb. Most of the macros defined
+ * in this file are unused, just left over from the original.
+ *
+ * This file is only used internally in libmdb and its definitions
+ * are not exposed publicly.
+ */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2000-2018 The OpenLDAP Foundation.
+ * Portions Copyright 2001-2018 Howard Chu, Symas Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+
+#ifndef _MDB_MIDL_H_
+#define _MDB_MIDL_H_
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @defgroup internal LMDB Internals
+ * @{
+ */
+
+/** @defgroup idls ID List Management
+ * @{
+ */
+ /** A generic unsigned ID number. These were entryIDs in back-bdb.
+ * Preferably it should have the same size as a pointer.
+ */
+typedef size_t MDB_ID;
+
+ /** An IDL is an ID List, a sorted array of IDs. The first
+ * element of the array is a counter for how many actual
+ * IDs are in the list. In the original back-bdb code, IDLs are
+ * sorted in ascending order. For libmdb IDLs are sorted in
+ * descending order.
+ */
+typedef MDB_ID *MDB_IDL;
+
+/* IDL sizes - likely should be even bigger
+ * limiting factors: sizeof(ID), thread stack size
+ */
+#define MDB_IDL_LOGN 16 /* DB_SIZE is 2^16, UM_SIZE is 2^17 */
+#define MDB_IDL_DB_SIZE (1<<MDB_IDL_LOGN)
+#define MDB_IDL_UM_SIZE (1<<(MDB_IDL_LOGN+1))
+
+#define MDB_IDL_DB_MAX (MDB_IDL_DB_SIZE-1)
+#define MDB_IDL_UM_MAX (MDB_IDL_UM_SIZE-1)
+
+#define MDB_IDL_SIZEOF(ids) (((ids)[0]+1) * sizeof(MDB_ID))
+#define MDB_IDL_IS_ZERO(ids) ( (ids)[0] == 0 )
+#define MDB_IDL_CPY( dst, src ) (memcpy( dst, src, MDB_IDL_SIZEOF( src ) ))
+#define MDB_IDL_FIRST( ids ) ( (ids)[1] )
+#define MDB_IDL_LAST( ids ) ( (ids)[(ids)[0]] )
+
+ /** Current max length of an #mdb_midl_alloc()ed IDL */
+#define MDB_IDL_ALLOCLEN( ids ) ( (ids)[-1] )
+
+ /** Append ID to IDL. The IDL must be big enough. */
+#define mdb_midl_xappend(idl, id) do { \
+ MDB_ID *xidl = (idl), xlen = ++(xidl[0]); \
+ xidl[xlen] = (id); \
+ } while (0)
+
+ /** Search for an ID in an IDL.
+ * @param[in] ids The IDL to search.
+ * @param[in] id The ID to search for.
+ * @return The index of the first ID greater than or equal to \b id.
+ */
+unsigned mdb_midl_search( MDB_IDL ids, MDB_ID id );
+
+ /** Allocate an IDL.
+ * Allocates memory for an IDL of the given size.
+ * @return IDL on success, NULL on failure.
+ */
+MDB_IDL mdb_midl_alloc(int num);
+
+ /** Free an IDL.
+ * @param[in] ids The IDL to free.
+ */
+void mdb_midl_free(MDB_IDL ids);
+
+ /** Shrink an IDL.
+ * Return the IDL to the default size if it has grown larger.
+ * @param[in,out] idp Address of the IDL to shrink.
+ */
+void mdb_midl_shrink(MDB_IDL *idp);
+
+ /** Make room for num additional elements in an IDL.
+ * @param[in,out] idp Address of the IDL.
+ * @param[in] num Number of elements to make room for.
+ * @return 0 on success, ENOMEM on failure.
+ */
+int mdb_midl_need(MDB_IDL *idp, unsigned num);
+
+ /** Append an ID onto an IDL.
+ * @param[in,out] idp Address of the IDL to append to.
+ * @param[in] id The ID to append.
+ * @return 0 on success, ENOMEM if the IDL is too large.
+ */
+int mdb_midl_append( MDB_IDL *idp, MDB_ID id );
+
+ /** Append an IDL onto an IDL.
+ * @param[in,out] idp Address of the IDL to append to.
+ * @param[in] app The IDL to append.
+ * @return 0 on success, ENOMEM if the IDL is too large.
+ */
+int mdb_midl_append_list( MDB_IDL *idp, MDB_IDL app );
+
+ /** Append an ID range onto an IDL.
+ * @param[in,out] idp Address of the IDL to append to.
+ * @param[in] id The lowest ID to append.
+ * @param[in] n Number of IDs to append.
+ * @return 0 on success, ENOMEM if the IDL is too large.
+ */
+int mdb_midl_append_range( MDB_IDL *idp, MDB_ID id, unsigned n );
+
+ /** Merge an IDL onto an IDL. The destination IDL must be big enough.
+ * @param[in] idl The IDL to merge into.
+ * @param[in] merge The IDL to merge.
+ */
+void mdb_midl_xmerge( MDB_IDL idl, MDB_IDL merge );
+
+ /** Sort an IDL.
+ * @param[in,out] ids The IDL to sort.
+ */
+void mdb_midl_sort( MDB_IDL ids );
+
+ /** An ID2 is an ID/pointer pair.
+ */
+typedef struct MDB_ID2 {
+ MDB_ID mid; /**< The ID */
+ void *mptr; /**< The pointer */
+} MDB_ID2;
+
+ /** An ID2L is an ID2 List, a sorted array of ID2s.
+ * The first element's \b mid member is a count of how many actual
+ * elements are in the array. The \b mptr member of the first element is unused.
+ * The array is sorted in ascending order by \b mid.
+ */
+typedef MDB_ID2 *MDB_ID2L;
+
+ /** Search for an ID in an ID2L.
+ * @param[in] ids The ID2L to search.
+ * @param[in] id The ID to search for.
+ * @return The index of the first ID2 whose \b mid member is greater than or equal to \b id.
+ */
+unsigned mdb_mid2l_search( MDB_ID2L ids, MDB_ID id );
+
+
+ /** Insert an ID2 into a ID2L.
+ * @param[in,out] ids The ID2L to insert into.
+ * @param[in] id The ID2 to insert.
+ * @return 0 on success, -1 if the ID was already present in the ID2L.
+ */
+int mdb_mid2l_insert( MDB_ID2L ids, MDB_ID2 *id );
+
+ /** Append an ID2 into a ID2L.
+ * @param[in,out] ids The ID2L to append into.
+ * @param[in] id The ID2 to append.
+ * @return 0 on success, -2 if the ID2L is too big.
+ */
+int mdb_mid2l_append( MDB_ID2L ids, MDB_ID2 *id );
+
+/** @} */
+/** @} */
+#ifdef __cplusplus
+}
+#endif
+#endif /* _MDB_MIDL_H_ */
diff --git a/src/contrib/macros.h b/src/contrib/macros.h
new file mode 100644
index 0000000..1db2241
--- /dev/null
+++ b/src/contrib/macros.h
@@ -0,0 +1,43 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \brief Common macros.
+ */
+
+#pragma once
+
+/*! \brief Eliminate compiler warning with unused parameters. */
+#define UNUSED(param) (void)(param)
+
+#ifndef MIN
+/*! \brief Type-safe minimum macro. */
+#define MIN(a, b) \
+ ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a < _b ? _a : _b; })
+
+/*! \brief Type-safe maximum macro. */
+#define MAX(a, b) \
+ ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a > _b ? _a : _b; })
+#endif
+
+#ifndef likely
+/*! \brief Optimize for x to be true value. */
+#define likely(x) __builtin_expect((x), 1)
+#endif
+
+#ifndef unlikely
+/*! \brief Optimize for x to be false value. */
+#define unlikely(x) __builtin_expect((x), 0)
+#endif
diff --git a/src/contrib/mempattern.c b/src/contrib/mempattern.c
new file mode 100644
index 0000000..74add91
--- /dev/null
+++ b/src/contrib/mempattern.c
@@ -0,0 +1,122 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+
+#include "contrib/mempattern.h"
+#include "contrib/string.h"
+#include "contrib/ucw/mempool.h"
+
+static void mm_nofree(void *p)
+{
+ /* nop */
+}
+
+static void *mm_malloc(void *ctx, size_t n)
+{
+ (void)ctx;
+ return malloc(n);
+}
+
+void *mm_alloc(knot_mm_t *mm, size_t size)
+{
+ if (mm) {
+ return mm->alloc(mm->ctx, size);
+ } else {
+ return malloc(size);
+ }
+}
+
+void *mm_calloc(knot_mm_t *mm, size_t nmemb, size_t size)
+{
+ if (nmemb == 0 || size == 0) {
+ return NULL;
+ }
+ if (mm) {
+ size_t total_size = nmemb * size;
+ if (total_size / nmemb != size) { // Overflow check
+ return NULL;
+ }
+ void *mem = mm_alloc(mm, total_size);
+ if (mem == NULL) {
+ return NULL;
+ }
+ return memzero(mem, total_size);
+ } else {
+ return calloc(nmemb, size);
+ }
+}
+
+void *mm_realloc(knot_mm_t *mm, void *what, size_t size, size_t prev_size)
+{
+ if (mm) {
+ void *p = mm->alloc(mm->ctx, size);
+ if (p == NULL) {
+ return NULL;
+ } else {
+ if (what) {
+ memcpy(p, what,
+ prev_size < size ? prev_size : size);
+ }
+ mm_free(mm, what);
+ return p;
+ }
+ } else {
+ return realloc(what, size);
+ }
+}
+
+char *mm_strdup(knot_mm_t *mm, const char *s)
+{
+ if (s == NULL) {
+ return NULL;
+ }
+ if (mm) {
+ size_t len = strlen(s) + 1;
+ void *mem = mm_alloc(mm, len);
+ if (mem == NULL) {
+ return NULL;
+ }
+ return memcpy(mem, s, len);
+ } else {
+ return strdup(s);
+ }
+}
+
+void mm_free(knot_mm_t *mm, void *what)
+{
+ if (mm) {
+ if (mm->free) {
+ mm->free(what);
+ }
+ } else {
+ free(what);
+ }
+}
+
+void mm_ctx_init(knot_mm_t *mm)
+{
+ mm->ctx = NULL;
+ mm->alloc = mm_malloc;
+ mm->free = free;
+}
+
+void mm_ctx_mempool(knot_mm_t *mm, size_t chunk_size)
+{
+ mm->ctx = mp_new(chunk_size);
+ mm->alloc = (knot_mm_alloc_t)mp_alloc;
+ mm->free = mm_nofree;
+}
diff --git a/src/contrib/mempattern.h b/src/contrib/mempattern.h
new file mode 100644
index 0000000..1c5d9a2
--- /dev/null
+++ b/src/contrib/mempattern.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \brief Memory allocation related functions.
+ */
+
+#pragma once
+
+#include "libknot/mm_ctx.h"
+
+/*! \brief Default memory block size. */
+#define MM_DEFAULT_BLKSIZE 4096
+
+/*! \brief Allocs using 'mm' if any, uses system malloc() otherwise. */
+void *mm_alloc(knot_mm_t *mm, size_t size);
+
+/*! \brief Callocs using 'mm' if any, uses system calloc() otherwise. */
+void *mm_calloc(knot_mm_t *mm, size_t nmemb, size_t size);
+
+/*! \brief Reallocs using 'mm' if any, uses system realloc() otherwise. */
+void *mm_realloc(knot_mm_t *mm, void *what, size_t size, size_t prev_size);
+
+/*! \brief Strdups using 'mm' if any, uses system strdup() otherwise. */
+char *mm_strdup(knot_mm_t *mm, const char *s);
+
+/*! \brief Free using 'mm' if any, uses system free() otherwise. */
+void mm_free(knot_mm_t *mm, void *what);
+
+/*! \brief Initialize default memory allocation context. */
+void mm_ctx_init(knot_mm_t *mm);
+
+/*! \brief Memory pool context. */
+void mm_ctx_mempool(knot_mm_t *mm, size_t chunk_size);
diff --git a/src/contrib/net.c b/src/contrib/net.c
new file mode 100644
index 0000000..81fc8ef
--- /dev/null
+++ b/src/contrib/net.c
@@ -0,0 +1,598 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <poll.h>
+#include <stdbool.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+#include "libknot/errcode.h"
+#include "contrib/net.h"
+#include "contrib/sockaddr.h"
+
+/*
+ * OS X doesn't support MSG_NOSIGNAL. Use SO_NOSIGPIPE socket option instead.
+ */
+#if defined(__APPLE__) && !defined(MSG_NOSIGNAL)
+# define MSG_NOSIGNAL 0
+# define osx_block_sigpipe(sock) sockopt_enable(sock, SOL_SOCKET, SO_NOSIGPIPE)
+#else
+# define osx_block_sigpipe(sock) KNOT_EOK
+#endif
+
+/*!
+ * \brief Enable socket option.
+ */
+static int sockopt_enable(int sock, int level, int optname)
+{
+ const int enable = 1;
+ if (setsockopt(sock, level, optname, &enable, sizeof(enable)) != 0) {
+ return knot_map_errno();
+ }
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Create a non-blocking socket.
+ *
+ * Prefer SOCK_NONBLOCK if available to save one fcntl() syscall.
+ *
+ */
+static int socket_create(int family, int type, int proto)
+{
+#ifdef SOCK_NONBLOCK
+ type |= SOCK_NONBLOCK;
+#endif
+ int sock = socket(family, type, proto);
+ if (sock < 0) {
+ return knot_map_errno();
+ }
+
+#ifndef SOCK_NONBLOCK
+ if (fcntl(sock, F_SETFL, O_NONBLOCK) != 0) {
+ int ret = knot_map_errno();
+ close(sock);
+ return ret;
+ }
+#endif
+
+ int ret = osx_block_sigpipe(sock);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ return sock;
+}
+
+int net_unbound_socket(int type, const struct sockaddr *sa)
+{
+ if (sa == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ /* Create socket. */
+ return socket_create(sa->sa_family, type, 0);
+}
+
+struct option {
+ int level;
+ int name;
+};
+
+/*!
+ * \brief Get setsock option for binding non-local address.
+ */
+static const struct option *nonlocal_option(int family)
+{
+ static const struct option ipv4 = {
+ #if defined(IP_FREEBIND)
+ IPPROTO_IP, IP_FREEBIND
+ #elif defined(IP_BINDANY)
+ IPPROTO_IP, IP_BINDANY
+ #else
+ 0, 0
+ #endif
+ };
+
+ static const struct option ipv6 = {
+ #if defined(IP_FREEBIND)
+ IPPROTO_IP, IP_FREEBIND
+ #elif defined(IPV6_BINDANY)
+ IPPROTO_IPV6, IPV6_BINDANY
+ #else
+ 0, 0
+ #endif
+
+ };
+
+ switch (family) {
+ case AF_INET: return &ipv4;
+ case AF_INET6: return &ipv6;
+ default:
+ return NULL;
+ }
+}
+
+static int enable_nonlocal(int sock, int family)
+{
+ const struct option *opt = nonlocal_option(family);
+ if (opt == NULL || opt->name == 0) {
+ return KNOT_ENOTSUP;
+ }
+
+ return sockopt_enable(sock, opt->level, opt->name);
+}
+
+static int enable_reuseport(int sock)
+{
+#ifdef ENABLE_REUSEPORT
+ return sockopt_enable(sock, SOL_SOCKET, SO_REUSEPORT);
+#else
+ return KNOT_ENOTSUP;
+#endif
+}
+
+static void unlink_unix_socket(const struct sockaddr *addr)
+{
+ char path[SOCKADDR_STRLEN] = { 0 };
+ sockaddr_tostr(path, sizeof(path), addr);
+ unlink(path);
+}
+
+int net_bound_socket(int type, const struct sockaddr *sa, enum net_flags flags)
+{
+ /* Create socket. */
+ int sock = net_unbound_socket(type, sa);
+ if (sock < 0) {
+ return sock;
+ }
+
+ /* Unlink UNIX sock if exists. */
+ if (sa->sa_family == AF_UNIX) {
+ unlink_unix_socket(sa);
+ }
+
+ /* Reuse old address if taken. */
+ int ret = sockopt_enable(sock, SOL_SOCKET, SO_REUSEADDR);
+ if (ret != KNOT_EOK) {
+ close(sock);
+ return ret;
+ }
+
+ /* Don't bind IPv4 for IPv6 any address. */
+ if (sa->sa_family == AF_INET6) {
+ ret = sockopt_enable(sock, IPPROTO_IPV6, IPV6_V6ONLY);
+ if (ret != KNOT_EOK) {
+ close(sock);
+ return ret;
+ }
+ }
+
+ /* Allow bind to non-local address. */
+ if (flags & NET_BIND_NONLOCAL) {
+ ret = enable_nonlocal(sock, sa->sa_family);
+ if (ret != KNOT_EOK) {
+ close(sock);
+ return ret;
+ }
+ }
+
+ /* Allow to bind the same address by multiple threads. */
+ if (flags & NET_BIND_MULTIPLE) {
+ ret = enable_reuseport(sock);
+ if (ret != KNOT_EOK) {
+ close(sock);
+ return ret;
+ }
+ }
+
+ /* Bind to specified address. */
+ ret = bind(sock, sa, sockaddr_len(sa));
+ if (ret < 0) {
+ ret = knot_map_errno();
+ close(sock);
+ return ret;
+ }
+
+ return sock;
+}
+
+int net_connected_socket(int type, const struct sockaddr *dst_addr,
+ const struct sockaddr *src_addr)
+{
+ if (dst_addr == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ /* Check port. */
+ if (sockaddr_port(dst_addr) == 0) {
+ return KNOT_NET_EADDR;
+ }
+
+ /* Bind to specific source address - if set. */
+ int sock = -1;
+ if (src_addr && src_addr->sa_family != AF_UNSPEC) {
+ sock = net_bound_socket(type, src_addr, 0);
+ } else {
+ sock = net_unbound_socket(type, dst_addr);
+ }
+ if (sock < 0) {
+ return sock;
+ }
+
+ /* Connect to destination. */
+ const struct sockaddr *sa = (const struct sockaddr *)dst_addr;
+ int ret = connect(sock, sa, sockaddr_len(sa));
+ if (ret != 0 && errno != EINPROGRESS) {
+ ret = knot_map_errno();
+ close(sock);
+ return ret;
+ }
+
+ return sock;
+}
+
+bool net_is_connected(int sock)
+{
+ struct sockaddr_storage ss;
+ socklen_t len = sizeof(ss);
+ return (getpeername(sock, (struct sockaddr *)&ss, &len) == 0);
+}
+
+int net_socktype(int sock)
+{
+ int type;
+ socklen_t size = sizeof(type);
+
+ if (getsockopt(sock, SOL_SOCKET, SO_TYPE, &type, &size) == 0) {
+ return type;
+ } else {
+ return AF_UNSPEC;
+ }
+}
+
+bool net_is_stream(int sock)
+{
+ return net_socktype(sock) == SOCK_STREAM;
+}
+
+int net_accept(int sock, struct sockaddr_storage *addr)
+{
+ socklen_t sa_len = sizeof(*addr);
+
+ int remote = -1;
+
+#if defined(HAVE_ACCEPT4) && defined(SOCK_NONBLOCK)
+ remote = accept4(sock, (struct sockaddr *)addr, &sa_len, SOCK_NONBLOCK);
+ if (remote < 0) {
+ return knot_map_errno();
+ }
+#else
+ remote = accept(sock, (struct sockaddr *)addr, &sa_len);
+ if (fcntl(remote, F_SETFL, O_NONBLOCK) != 0) {
+ int error = knot_map_errno();
+ close(remote);
+ return error;
+ }
+#endif
+
+ return remote;
+}
+
+/* -- I/O interface handling partial -------------------------------------- */
+
+/*!
+ * \brief Perform \a poll() on one socket.
+ */
+static int poll_one(int fd, int events, int timeout_ms)
+{
+ struct pollfd pfd = {
+ .fd = fd,
+ .events = events
+ };
+
+ return poll(&pfd, 1, timeout_ms);
+}
+
+/*!
+ * \brief Check if we should wait for I/O readiness.
+ *
+ * \param error \a errno set by the failed I/O operation.
+ */
+static bool io_should_wait(int error)
+{
+ /* socket data not ready */
+ if (error == EAGAIN || error == EWOULDBLOCK) {
+ return true;
+ }
+
+#ifndef __linux__
+ /* FreeBSD: connection in progress */
+ if (error == ENOTCONN) {
+ return true;
+ }
+#endif
+
+ return false;
+}
+
+/*!
+ * \brief I/O operation callbacks.
+ */
+struct io {
+ ssize_t (*process)(int sockfd, struct msghdr *msg);
+ int (*wait)(int sockfd, int timeout_ms);
+};
+
+/*!
+ * \brief Get total size of I/O vector in a message.
+ */
+static size_t msg_iov_len(const struct msghdr *msg)
+{
+ size_t total = 0;
+
+ for (int i = 0; i < msg->msg_iovlen; i++) {
+ total += msg->msg_iov[i].iov_len;
+ }
+
+ return total;
+}
+
+/*!
+ * \brief Shift processed data out of message IO vectors.
+ */
+static void msg_iov_shift(struct msghdr *msg, size_t done)
+{
+ struct iovec *iov = msg->msg_iov;
+ int iovlen = msg->msg_iovlen;
+
+ for (int i = 0; i < iovlen && done > 0; i++) {
+ if (iov[i].iov_len > done) {
+ iov[i].iov_base += done;
+ iov[i].iov_len -= done;
+ done = 0;
+ } else {
+ done -= iov[i].iov_len;
+ msg->msg_iov += 1;
+ msg->msg_iovlen -= 1;
+ }
+ }
+
+ assert(done == 0);
+}
+
+/*!
+ * \brief Perform an I/O operation with a socket with waiting.
+ *
+ * \param oneshot If set, doesn't wait until the buffer is fully processed.
+ *
+ */
+static ssize_t io_exec(const struct io *io, int fd, struct msghdr *msg,
+ bool oneshot, int timeout_ms)
+{
+ size_t done = 0;
+ size_t total = msg_iov_len(msg);
+
+ for (;;) {
+ /* Perform I/O. */
+ ssize_t ret = io->process(fd, msg);
+ if (ret == -1 && errno == EINTR) {
+ continue;
+ }
+ if (ret > 0) {
+ done += ret;
+ if (oneshot || done == total) {
+ break;
+ }
+ msg_iov_shift(msg, ret);
+ }
+
+ /* Wait for data readiness. */
+ if (ret > 0 || (ret == -1 && io_should_wait(errno))) {
+ do {
+ ret = io->wait(fd, timeout_ms);
+ } while (ret == -1 && errno == EINTR);
+ if (ret == 1) {
+ continue;
+ } else if (ret == 0) {
+ return KNOT_ETIMEOUT;
+ }
+ }
+
+ /* Disconnected or error. */
+ return KNOT_ECONN;
+ }
+
+ return done;
+}
+
+static ssize_t recv_process(int fd, struct msghdr *msg)
+{
+ return recvmsg(fd, msg, MSG_DONTWAIT | MSG_NOSIGNAL);
+}
+
+static int recv_wait(int fd, int timeout_ms)
+{
+ return poll_one(fd, POLLIN, timeout_ms);
+}
+
+static ssize_t recv_data(int sock, struct msghdr *msg, bool oneshot, int timeout_ms)
+{
+ static const struct io RECV_IO = {
+ .process = recv_process,
+ .wait = recv_wait
+ };
+
+ return io_exec(&RECV_IO, sock, msg, oneshot, timeout_ms);
+}
+
+static ssize_t send_process(int fd, struct msghdr *msg)
+{
+ return sendmsg(fd, msg, MSG_NOSIGNAL);
+}
+
+static int send_wait(int fd, int timeout_ms)
+{
+ return poll_one(fd, POLLOUT, timeout_ms);
+}
+
+static ssize_t send_data(int sock, struct msghdr *msg, int timeout_ms)
+{
+ static const struct io SEND_IO = {
+ .process = send_process,
+ .wait = send_wait
+ };
+
+ return io_exec(&SEND_IO, sock, msg, false, timeout_ms);
+}
+
+/* -- generic stream and datagram I/O -------------------------------------- */
+
+ssize_t net_send(int sock, const uint8_t *buffer, size_t size,
+ const struct sockaddr *addr, int timeout_ms)
+{
+ if (sock < 0 || buffer == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ struct iovec iov = { 0 };
+ iov.iov_base = (void *)buffer;
+ iov.iov_len = size;
+
+ struct msghdr msg = { 0 };
+ msg.msg_name = (void *)addr;
+ msg.msg_namelen = sockaddr_len(addr);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ int ret = send_data(sock, &msg, timeout_ms);
+ if (ret < 0) {
+ return ret;
+ } else if (ret != size) {
+ return KNOT_ECONN;
+ }
+
+ return ret;
+}
+
+ssize_t net_recv(int sock, uint8_t *buffer, size_t size,
+ struct sockaddr_storage *addr, int timeout_ms)
+{
+ if (sock < 0 || buffer == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ struct iovec iov = { 0 };
+ iov.iov_base = buffer;
+ iov.iov_len = size;
+
+ struct msghdr msg = { 0 };
+ msg.msg_name = (void *)addr;
+ msg.msg_namelen = addr ? sizeof(*addr) : 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ return recv_data(sock, &msg, true, timeout_ms);
+}
+
+ssize_t net_dgram_send(int sock, const uint8_t *buffer, size_t size,
+ const struct sockaddr *addr)
+{
+ return net_send(sock, buffer, size, addr, 0);
+}
+
+ssize_t net_dgram_recv(int sock, uint8_t *buffer, size_t size, int timeout_ms)
+{
+ return net_recv(sock, buffer, size, NULL, timeout_ms);
+}
+
+ssize_t net_stream_send(int sock, const uint8_t *buffer, size_t size, int timeout_ms)
+{
+ return net_send(sock, buffer, size, NULL, timeout_ms);
+}
+
+ssize_t net_stream_recv(int sock, uint8_t *buffer, size_t size, int timeout_ms)
+{
+ return net_recv(sock, buffer, size, NULL, timeout_ms);
+}
+
+/* -- DNS specific I/O ----------------------------------------------------- */
+
+ssize_t net_dns_tcp_send(int sock, const uint8_t *buffer, size_t size, int timeout_ms)
+{
+ if (sock < 0 || buffer == NULL || size > UINT16_MAX) {
+ return KNOT_EINVAL;
+ }
+
+ struct iovec iov[2];
+ uint16_t pktsize = htons(size);
+ iov[0].iov_base = &pktsize;
+ iov[0].iov_len = sizeof(uint16_t);
+ iov[1].iov_base = (void *)buffer;
+ iov[1].iov_len = size;
+
+ struct msghdr msg = { 0 };
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 2;
+
+ ssize_t ret = send_data(sock, &msg, timeout_ms);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return size; /* Do not count the size prefix. */
+}
+
+ssize_t net_dns_tcp_recv(int sock, uint8_t *buffer, size_t size, int timeout_ms)
+{
+ if (sock < 0 || buffer == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ struct iovec iov = { 0 };
+ struct msghdr msg = { 0 };
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ /* Receive size. */
+ uint16_t pktsize = 0;
+ iov.iov_base = &pktsize;
+ iov.iov_len = sizeof(pktsize);
+ int ret = recv_data(sock, &msg, false, timeout_ms);
+ if (ret != sizeof(pktsize)) {
+ return ret;
+ }
+
+ pktsize = ntohs(pktsize);
+
+ /* Check packet size */
+ if (size < pktsize) {
+ return KNOT_ESPACE;
+ }
+
+ /* Receive payload. */
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ iov.iov_base = buffer;
+ iov.iov_len = pktsize;
+ return recv_data(sock, &msg, false, timeout_ms);
+}
diff --git a/src/contrib/net.h b/src/contrib/net.h
new file mode 100644
index 0000000..1b6b527
--- /dev/null
+++ b/src/contrib/net.h
@@ -0,0 +1,185 @@
+/* Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/socket.h>
+
+/*!
+ * \brief Network interface flags.
+ */
+enum net_flags {
+ NET_BIND_NONLOCAL = (1 << 0), //!< Allow to bind unavailable address.
+ NET_BIND_MULTIPLE = (1 << 1), //!< Allow to bind address multiple times.
+};
+
+/*!
+ * \brief Create unbound socket of given family and type.
+ *
+ * \note The socket is set to non-blocking mode.
+ *
+ * \param type Socket transport type (SOCK_STREAM, SOCK_DGRAM).
+ * \param sa Socket address.
+ *
+ * \return socket or error code
+ */
+int net_unbound_socket(int type, const struct sockaddr *sa);
+
+/*!
+ * \brief Create socket bound to given address.
+ *
+ * The socket is set to non-blocking mode.
+ *
+ * \param type Socket transport type (SOCK_STREAM, SOCK_DGRAM).
+ * \param sa Socket address.
+ * \param flags Socket binding options.
+ *
+ * \return socket or error code
+ */
+int net_bound_socket(int type, const struct sockaddr *sa, enum net_flags flags);
+
+/*!
+ * \brief Create socket connected (asynchronously) to destination address.
+ *
+ * \note The socket is set to non-blocking mode.
+ *
+ * \param type Socket transport type (SOCK_STREAM, SOCK_DGRAM).
+ * \param dst_addr Destination address.
+ * \param src_addr Source address (can be NULL).
+ *
+ * \return socket or error code
+ */
+int net_connected_socket(int type, const struct sockaddr *dst_addr,
+ const struct sockaddr *src_addr);
+
+/*!
+ * \brief Return true if the socket is fully connected.
+ *
+ * \param sock Socket.
+ *
+ * \return true if connected
+ */
+bool net_is_connected(int sock);
+
+/*!
+ * \brief Get socket type (e.g. \a SOCK_STREAM).
+ *
+ * \param sock Socket.
+ */
+int net_socktype(int sock);
+
+/*!
+ * \brief Check if socket is a SOCK_STREAM socket.
+ */
+bool net_is_stream(int sock);
+
+/*!
+ * \brief Accept a connection on a listening socket.
+ *
+ * \brief The socket is set to non-blocking mode.
+ *
+ * \param sock Socket
+ * \param addr Remote address (can be NULL).
+ *
+ * \return socket or error code
+ */
+int net_accept(int sock, struct sockaddr_storage *addr);
+
+/*!
+ * \brief Send a message on a socket.
+ *
+ * The socket can be SOCK_STREAM or SOCK_DGRAM.
+ *
+ * The implementation handles partial-writes automatically.
+ *
+ * \param[in] sock Socket.
+ * \param[in] buffer Message buffer.
+ * \param[in] size Size of the message.
+ * \param[in] addr Remote address (ignored for SOCK_STREAM).
+ * \param[in] timeout_ms Write timeout in miliseconds (-1 for infinity,
+ * not valid for SOCK_DGRAM).
+ *
+ * \return Number of bytes sent or negative error code.
+ */
+ssize_t net_send(int sock, const uint8_t *buffer, size_t size,
+ const struct sockaddr *addr, int timeout_ms);
+
+/*!
+ * \brief Receive a message from a socket.
+ *
+ * \param[in] sock Socket.
+ * \param[out] buffer Receiving buffer.
+ * \param[in] size Capacity of the receiving buffer.
+ * \param[out] addr Remote address (can be NULL).
+ * \param[in] timeout_ms Read timeout in miliseconds (-1 for infinity).
+ *
+ * \return Number of bytes read or negative error code.
+ */
+ssize_t net_recv(int sock, uint8_t *buffer, size_t size,
+ struct sockaddr_storage *addr, int timeout_ms);
+
+/*!
+ * \brief Send a message on a SOCK_DGRAM socket.
+ *
+ * \see net_send
+ */
+ssize_t net_dgram_send(int sock, const uint8_t *buffer, size_t size,
+ const struct sockaddr *addr);
+
+/*!
+ * \brief Receive a message from a SOCK_DGRAM socket.
+ *
+ * \see net_recv
+ */
+ssize_t net_dgram_recv(int sock, uint8_t *buffer, size_t size, int timeout_ms);
+
+/*!
+ * \brief Send a message on a SOCK_STREAM socket.
+ *
+ * \see net_send
+ */
+ssize_t net_stream_send(int sock, const uint8_t *buffer, size_t size, int timeout_ms);
+
+/*!
+ * \brief Receive a message from a SOCK_STREAM socket.
+ *
+ * \see net_recv
+ */
+ssize_t net_stream_recv(int sock, uint8_t *buffer, size_t size, int timeout_ms);
+
+/*!
+ * \brief Send a DNS message on a TCP socket.
+ *
+ * The outgoing message is prefixed with a two-byte value carrying the DNS
+ * message size according to the specification. These two bytes are not
+ * reflected in the return value.
+ *
+ * \see net_send
+ */
+ssize_t net_dns_tcp_send(int sock, const uint8_t *buffer, size_t size, int timeout_ms);
+
+/*!
+ * \brief Receive a DNS message from a TCP socket.
+ *
+ * The first two bytes of the incoming message are interpreted as a DNS message
+ * size according to the specification. These two bytes are not included in
+ * the returned size. Only a complete DNS message is retrieved.
+ *
+ * \see net_recv
+ */
+ssize_t net_dns_tcp_recv(int sock, uint8_t *buffer, size_t size, int timeout_ms);
diff --git a/src/contrib/openbsd/LICENSE b/src/contrib/openbsd/LICENSE
new file mode 100644
index 0000000..e9a1aaa
--- /dev/null
+++ b/src/contrib/openbsd/LICENSE
@@ -0,0 +1,2 @@
+../licenses/0BSD
+../licenses/BSD-3-Clause \ No newline at end of file
diff --git a/src/contrib/openbsd/siphash.c b/src/contrib/openbsd/siphash.c
new file mode 100644
index 0000000..26b8cfc
--- /dev/null
+++ b/src/contrib/openbsd/siphash.c
@@ -0,0 +1,176 @@
+/* $OpenBSD: siphash.c,v 1.6 2017/04/12 17:41:49 deraadt Exp $ */
+
+/*-
+ * Copyright (c) 2013 Andre Oppermann <andre@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * SipHash is a family of PRFs SipHash-c-d where the integer parameters c and d
+ * are the number of compression rounds and the number of finalization rounds.
+ * A compression round is identical to a finalization round and this round
+ * function is called SipRound. Given a 128-bit key k and a (possibly empty)
+ * byte string m, SipHash-c-d returns a 64-bit value SipHash-c-d(k; m).
+ *
+ * Implemented from the paper "SipHash: a fast short-input PRF", 2012.09.18,
+ * by Jean-Philippe Aumasson and Daniel J. Bernstein,
+ * Permanent Document ID b9a943a805fbfc6fde808af9fc0ecdfa
+ * https://131002.net/siphash/siphash.pdf
+ * https://131002.net/siphash/
+ */
+
+#include <string.h>
+
+#include "libknot/endian.h"
+#include "contrib/string.h"
+#include "contrib/openbsd/siphash.h"
+
+static void SipHash_CRounds(SIPHASH_CTX *, int);
+static void SipHash_Rounds(SIPHASH_CTX *, int);
+
+void
+SipHash_Init(SIPHASH_CTX *ctx, const SIPHASH_KEY *key)
+{
+ uint64_t k0, k1;
+
+ k0 = le64toh(key->k0);
+ k1 = le64toh(key->k1);
+
+ ctx->v[0] = 0x736f6d6570736575ULL ^ k0;
+ ctx->v[1] = 0x646f72616e646f6dULL ^ k1;
+ ctx->v[2] = 0x6c7967656e657261ULL ^ k0;
+ ctx->v[3] = 0x7465646279746573ULL ^ k1;
+
+ memset(ctx->buf, 0, sizeof(ctx->buf));
+ ctx->bytes = 0;
+}
+
+void
+SipHash_Update(SIPHASH_CTX *ctx, int rc, int rf, const void *src, size_t len)
+{
+ const uint8_t *ptr = src;
+ size_t left, used;
+
+ if (len == 0)
+ return;
+
+ used = ctx->bytes % sizeof(ctx->buf);
+ ctx->bytes += len;
+
+ if (used > 0) {
+ left = sizeof(ctx->buf) - used;
+
+ if (len >= left) {
+ memcpy(&ctx->buf[used], ptr, left);
+ SipHash_CRounds(ctx, rc);
+ len -= left;
+ ptr += left;
+ } else {
+ memcpy(&ctx->buf[used], ptr, len);
+ return;
+ }
+ }
+
+ while (len >= sizeof(ctx->buf)) {
+ memcpy(ctx->buf, ptr, sizeof(ctx->buf));
+ SipHash_CRounds(ctx, rc);
+ len -= sizeof(ctx->buf);
+ ptr += sizeof(ctx->buf);
+ }
+
+ if (len > 0)
+ memcpy(&ctx->buf, ptr, len);
+}
+
+uint64_t
+SipHash_End(SIPHASH_CTX *ctx, int rc, int rf)
+{
+ uint64_t r;
+ size_t left, used;
+
+ used = ctx->bytes % sizeof(ctx->buf);
+ left = sizeof(ctx->buf) - used;
+ memset(&ctx->buf[used], 0, left - 1);
+ ctx->buf[7] = ctx->bytes;
+
+ SipHash_CRounds(ctx, rc);
+ ctx->v[2] ^= 0xff;
+ SipHash_Rounds(ctx, rf);
+
+ r = (ctx->v[0] ^ ctx->v[1]) ^ (ctx->v[2] ^ ctx->v[3]);
+ memzero(ctx, sizeof(*ctx));
+ return htole64(r);
+}
+
+uint64_t
+SipHash(const SIPHASH_KEY *key, int rc, int rf, const void *src, size_t len)
+{
+ SIPHASH_CTX ctx;
+
+ SipHash_Init(&ctx, key);
+ SipHash_Update(&ctx, rc, rf, src, len);
+ return (SipHash_End(&ctx, rc, rf));
+}
+
+#define SIP_ROTL(x, b) ((x) << (b)) | ( (x) >> (64 - (b)))
+
+static void
+SipHash_Rounds(SIPHASH_CTX *ctx, int rounds)
+{
+ while (rounds--) {
+ ctx->v[0] += ctx->v[1];
+ ctx->v[2] += ctx->v[3];
+ ctx->v[1] = SIP_ROTL(ctx->v[1], 13);
+ ctx->v[3] = SIP_ROTL(ctx->v[3], 16);
+
+ ctx->v[1] ^= ctx->v[0];
+ ctx->v[3] ^= ctx->v[2];
+ ctx->v[0] = SIP_ROTL(ctx->v[0], 32);
+
+ ctx->v[2] += ctx->v[1];
+ ctx->v[0] += ctx->v[3];
+ ctx->v[1] = SIP_ROTL(ctx->v[1], 17);
+ ctx->v[3] = SIP_ROTL(ctx->v[3], 21);
+
+ ctx->v[1] ^= ctx->v[2];
+ ctx->v[3] ^= ctx->v[0];
+ ctx->v[2] = SIP_ROTL(ctx->v[2], 32);
+ }
+}
+
+static void
+SipHash_CRounds(SIPHASH_CTX *ctx, int rounds)
+{
+ uint64_t tmp;
+
+ memcpy(&tmp, ctx->buf, sizeof(tmp));
+ uint64_t m = le64toh(tmp);
+
+ ctx->v[3] ^= m;
+ SipHash_Rounds(ctx, rounds);
+ ctx->v[0] ^= m;
+}
diff --git a/src/contrib/openbsd/siphash.h b/src/contrib/openbsd/siphash.h
new file mode 100644
index 0000000..d551fe8
--- /dev/null
+++ b/src/contrib/openbsd/siphash.h
@@ -0,0 +1,83 @@
+/*-
+ * Copyright (c) 2013 Andre Oppermann <andre@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $OpenBSD: siphash.h,v 1.3 2015/02/20 11:51:03 tedu Exp $
+ */
+
+/*
+ * SipHash is a family of pseudorandom functions (a.k.a. keyed hash functions)
+ * optimized for speed on short messages returning a 64bit hash/digest value.
+ *
+ * The number of rounds is defined during the initialization:
+ * SipHash24_Init() for the fast and resonable strong version
+ * SipHash48_Init() for the strong version (half as fast)
+ *
+ * struct SIPHASH_CTX ctx;
+ * SipHash24_Init(&ctx);
+ * SipHash_SetKey(&ctx, "16bytes long key");
+ * SipHash_Update(&ctx, pointer_to_string, length_of_string);
+ * SipHash_End(&ctx);
+ */
+
+#ifndef _SIPHASH_H_
+#define _SIPHASH_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#define SIPHASH_BLOCK_LENGTH 8
+#define SIPHASH_KEY_LENGTH 16
+#define SIPHASH_DIGEST_LENGTH 8
+
+typedef struct _SIPHASH_CTX {
+ uint64_t v[4];
+ uint8_t buf[SIPHASH_BLOCK_LENGTH];
+ uint32_t bytes;
+} SIPHASH_CTX;
+
+typedef struct {
+ uint64_t k0;
+ uint64_t k1;
+} SIPHASH_KEY;
+
+void SipHash_Init(SIPHASH_CTX *, const SIPHASH_KEY *);
+void SipHash_Update(SIPHASH_CTX *, int, int, const void *, size_t);
+uint64_t SipHash_End(SIPHASH_CTX *, int, int);
+uint64_t SipHash(const SIPHASH_KEY *, int, int, const void *, size_t);
+
+#define SipHash24_Init(_c, _k) SipHash_Init((_c), (_k))
+#define SipHash24_Update(_c, _p, _l) SipHash_Update((_c), 2, 4, (_p), (_l))
+#define SipHash24_End(_d) SipHash_End((_d), 2, 4)
+#define SipHash24(_k, _p, _l) SipHash((_k), 2, 4, (_p), (_l))
+
+#define SipHash48_Init(_c, _k) SipHash_Init((_c), (_k))
+#define SipHash48_Update(_c, _p, _l) SipHash_Update((_c), 4, 8, (_p), (_l))
+#define SipHash48_End(_d) SipHash_End((_d), 4, 8)
+#define SipHash48(_k, _p, _l) SipHash((_k), 4, 8, (_p), (_l))
+
+#endif /* _SIPHASH_H_ */
diff --git a/src/contrib/openbsd/strlcat.c b/src/contrib/openbsd/strlcat.c
new file mode 100644
index 0000000..1409062
--- /dev/null
+++ b/src/contrib/openbsd/strlcat.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <string.h>
+
+#include "contrib/openbsd/strlcat.h"
+
+size_t
+knot_strlcat(char *dst, const char *src, size_t siz)
+{
+ char *d = dst;
+ const char *s = src;
+ size_t n = siz;
+ size_t dlen;
+
+ /* Find the end of dst and adjust bytes left but don't go past end */
+ while (n-- != 0 && *d != '\0')
+ d++;
+ dlen = d - dst;
+ n = siz - dlen;
+
+ if (n == 0)
+ return(dlen + strlen(s));
+ while (*s != '\0') {
+ if (n != 1) {
+ *d++ = *s;
+ n--;
+ }
+ s++;
+ }
+ *d = '\0';
+
+ return(dlen + (s - src)); /* count does not include NUL */
+}
diff --git a/src/contrib/openbsd/strlcat.h b/src/contrib/openbsd/strlcat.h
new file mode 100644
index 0000000..7016069
--- /dev/null
+++ b/src/contrib/openbsd/strlcat.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#pragma once
+
+#ifndef HAVE_STRLCAT
+#define strlcat(dst, src, size) knot_strlcat(dst, src, size)
+#endif
+
+/*
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left). At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
+ * Returns strlen(src) + MIN(siz, strlen(initial dst)).
+ * If retval >= siz, truncation occurred.
+ */
+size_t
+knot_strlcat(char *dst, const char *src, size_t siz);
diff --git a/src/contrib/openbsd/strlcpy.c b/src/contrib/openbsd/strlcpy.c
new file mode 100644
index 0000000..eafc0e4
--- /dev/null
+++ b/src/contrib/openbsd/strlcpy.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <string.h>
+
+#include "contrib/openbsd/strlcpy.h"
+
+size_t
+knot_strlcpy(char *dst, const char *src, size_t siz)
+{
+ char *d = dst;
+ const char *s = src;
+ size_t n = siz;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0) {
+ while (--n != 0) {
+ if ((*d++ = *s++) == '\0')
+ break;
+ }
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0) {
+ if (siz != 0)
+ *d = '\0'; /* NUL-terminate dst */
+ while (*s++)
+ ;
+ }
+
+ return(s - src - 1); /* count does not include NUL */
+}
diff --git a/src/contrib/openbsd/strlcpy.h b/src/contrib/openbsd/strlcpy.h
new file mode 100644
index 0000000..6421068
--- /dev/null
+++ b/src/contrib/openbsd/strlcpy.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#pragma once
+
+#ifndef HAVE_STRLCPY
+#define strlcpy(dst, src, size) knot_strlcpy(dst, src, size)
+#endif
+
+/*
+ * Copy src to string dst of size siz. At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+knot_strlcpy(char *dst, const char *src, size_t siz);
diff --git a/src/contrib/qp-trie/trie.c b/src/contrib/qp-trie/trie.c
new file mode 100644
index 0000000..10f9919
--- /dev/null
+++ b/src/contrib/qp-trie/trie.c
@@ -0,0 +1,835 @@
+/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ The code originated from https://github.com/fanf2/qp/blob/master/qp.c
+ at revision 5f6d93753.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "contrib/qp-trie/trie.h"
+#include "contrib/macros.h"
+#include "contrib/mempattern.h"
+#include "libknot/errcode.h"
+
+#if defined(__i386) || defined(__x86_64) || defined(_M_IX86) \
+ || (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN) \
+ && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+
+ /*!
+ * \brief Use a pointer alignment hack to save memory.
+ *
+ * When on, isbranch() relies on the fact that in leaf_t the first pointer
+ * is aligned on multiple of 4 bytes and that the flags bitfield is
+ * overlaid over the lowest two bits of that pointer.
+ * Neither is really guaranteed by the C standards; the second part should
+ * be OK with x86_64 ABI and most likely any other little-endian platform.
+ * It would be possible to manipulate the right bits portably, but it would
+ * complicate the code nontrivially. C++ doesn't even guarantee type-punning.
+ * In debug mode we check this works OK when creating a new trie instance.
+ */
+ #define FLAGS_HACK 1
+#else
+ #define FLAGS_HACK 0
+#endif
+
+typedef unsigned char byte;
+typedef unsigned int uint;
+typedef uint bitmap_t; /*! Bit-maps, using the range of 1<<0 to 1<<16 (inclusive). */
+
+typedef struct {
+ uint32_t len; // 32 bits are enough for key lengths; probably even 16 bits would be.
+ char chars[];
+} tkey_t;
+
+/*! \brief Leaf of trie. */
+typedef struct {
+ #if !FLAGS_HACK
+ byte flags;
+ #endif
+ tkey_t *key; /*!< The pointer must be aligned to 4-byte multiples! */
+ trie_val_t val;
+} leaf_t;
+
+/*! \brief A trie node is either leaf_t or branch_t. */
+typedef union node node_t;
+
+/*!
+ * \brief Branch node of trie.
+ *
+ * - The flags distinguish whether the node is a leaf_t (0), or a branch
+ * testing the more-important nibble (1) or the less-important one (2).
+ * - It stores the index of the byte that the node tests. The combined
+ * value (index*4 + flags) increases in branch nodes as you go deeper
+ * into the trie. All the keys below a branch are identical up to the
+ * nibble identified by the branch. Indices have to be stored because
+ * we skip any branch nodes that would have a single child.
+ * (Consequently, the skipped parts of key have to be validated in a leaf.)
+ * - The bitmap indicates which subtries are present. The present child nodes
+ * are stored in the twigs array (with no holes between them).
+ * - To simplify storing keys that are prefixes of each other, the end-of-string
+ * position is treated as another nibble value, ordered before all others.
+ * That affects the bitmap and twigs fields.
+ *
+ * \note The branch nodes are never allocated individually, but they are
+ * always part of either the root node or the twigs array of the parent.
+ */
+typedef struct {
+ #if FLAGS_HACK
+ uint32_t flags : 2,
+ bitmap : 17; /*!< The first bitmap bit is for end-of-string child. */
+ #else
+ byte flags;
+ uint32_t bitmap;
+ #endif
+ uint32_t index;
+ node_t *twigs;
+} branch_t;
+
+union node {
+ leaf_t leaf;
+ branch_t branch;
+};
+
+struct trie {
+ node_t root; // undefined when weight == 0, see empty_root()
+ size_t weight;
+ knot_mm_t mm;
+};
+
+/*! \brief Make the root node empty (debug-only). */
+static inline void empty_root(node_t *root) {
+#ifndef NDEBUG
+ *root = (node_t){ .branch = {
+ .flags = 3, // invalid value that fits
+ .bitmap = 0,
+ .index = -1,
+ .twigs = NULL
+ } };
+#endif
+}
+
+/*! \brief Check that unportable code works OK (debug-only). */
+static void assert_portability(void) {
+#if FLAGS_HACK
+ assert(((union node){ .leaf = {
+ .key = ((void *)NULL) + 1,
+ .val = NULL
+ } }).branch.flags == 1);
+#endif
+}
+
+/*! \brief Propagate error codes. */
+#define ERR_RETURN(x) \
+ do { \
+ int err_code_ = x; \
+ if (unlikely(err_code_ != KNOT_EOK)) \
+ return err_code_; \
+ } while (false)
+
+/*!
+ * \brief Count the number of set bits.
+ *
+ * \TODO This implementation may be relatively slow on some HW.
+ */
+static uint bitmap_weight(bitmap_t w)
+{
+ assert((w & ~((1 << 17) - 1)) == 0); // using the least-important 17 bits
+ return __builtin_popcount(w);
+}
+
+/*! \brief Test flags to determine type of this node. */
+static bool isbranch(const node_t *t)
+{
+ uint f = t->branch.flags;
+ assert(f <= 2);
+ return f != 0;
+}
+
+/*! \brief Make a bitmask for testing a branch bitmap. */
+static bitmap_t nibbit(byte k, uint flags)
+{
+ uint shift = (2 - flags) << 2;
+ uint nibble = (k >> shift) & 0xf;
+ return 1 << (nibble + 1/*because of prefix keys*/);
+}
+
+/*! \brief Extract a nibble from a key and turn it into a bitmask. */
+static bitmap_t twigbit(node_t *t, const char *key, uint32_t len)
+{
+ assert(isbranch(t));
+ uint i = t->branch.index;
+
+ if (i >= len)
+ return 1 << 0; // leaf position
+
+ return nibbit((byte)key[i], t->branch.flags);
+}
+
+/*! \brief Test if a branch node has a child indicated by a bitmask. */
+static bool hastwig(node_t *t, bitmap_t bit)
+{
+ assert(isbranch(t));
+ return t->branch.bitmap & bit;
+}
+
+/*! \brief Compute offset of an existing child in a branch node. */
+static uint twigoff(node_t *t, bitmap_t b)
+{
+ assert(isbranch(t));
+ return bitmap_weight(t->branch.bitmap & (b - 1));
+}
+
+/*! \brief Get pointer to a particular child of a branch node. */
+static node_t* twig(node_t *t, uint i)
+{
+ assert(isbranch(t));
+ return &t->branch.twigs[i];
+}
+
+/*!
+ * \brief For a branch nod, compute offset of a child and child count.
+ *
+ * Having this separate might be meaningful for performance optimization.
+ */
+#define TWIGOFFMAX(off, max, t, b) do { \
+ off = twigoff(t, b); \
+ max = bitmap_weight(t->branch.bitmap); \
+ } while(0)
+
+/*! \brief Simple string comparator. */
+static int key_cmp(const char *k1, uint32_t k1_len, const char *k2, uint32_t k2_len)
+{
+ int ret = memcmp(k1, k2, MIN(k1_len, k2_len));
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* Key string is equal, compare lengths. */
+ if (k1_len == k2_len) {
+ return 0;
+ } else if (k1_len < k2_len) {
+ return -1;
+ } else {
+ return 1;
+ }
+}
+
+trie_t* trie_create(knot_mm_t *mm)
+{
+ assert_portability();
+ trie_t *trie = mm_alloc(mm, sizeof(trie_t));
+ if (trie != NULL) {
+ empty_root(&trie->root);
+ trie->weight = 0;
+ if (mm != NULL)
+ trie->mm = *mm;
+ else
+ mm_ctx_init(&trie->mm);
+ }
+ return trie;
+}
+
+/*! \brief Free anything under the trie node, except for the passed pointer itself. */
+static void clear_trie(node_t *trie, knot_mm_t *mm)
+{
+ if (!isbranch(trie)) {
+ mm_free(mm, trie->leaf.key);
+ } else {
+ branch_t *b = &trie->branch;
+ int len = bitmap_weight(b->bitmap);
+ for (int i = 0; i < len; ++i)
+ clear_trie(b->twigs + i, mm);
+ mm_free(mm, b->twigs);
+ }
+}
+
+void trie_free(trie_t *tbl)
+{
+ if (tbl == NULL)
+ return;
+ if (tbl->weight)
+ clear_trie(&tbl->root, &tbl->mm);
+ mm_free(&tbl->mm, tbl);
+}
+
+void trie_clear(trie_t *tbl)
+{
+ assert(tbl);
+ if (!tbl->weight)
+ return;
+ clear_trie(&tbl->root, &tbl->mm);
+ empty_root(&tbl->root);
+ tbl->weight = 0;
+}
+
+size_t trie_weight(const trie_t *tbl)
+{
+ assert(tbl);
+ return tbl->weight;
+}
+
+trie_val_t* trie_get_try(trie_t *tbl, const char *key, uint32_t len)
+{
+ assert(tbl);
+ if (!tbl->weight)
+ return NULL;
+ node_t *t = &tbl->root;
+ while (isbranch(t)) {
+ __builtin_prefetch(t->branch.twigs);
+ bitmap_t b = twigbit(t, key, len);
+ if (!hastwig(t, b))
+ return NULL;
+ t = twig(t, twigoff(t, b));
+ }
+ if (key_cmp(key, len, t->leaf.key->chars, t->leaf.key->len) != 0)
+ return NULL;
+ return &t->leaf.val;
+}
+
+int trie_del(trie_t *tbl, const char *key, uint32_t len, trie_val_t *val)
+{
+ assert(tbl);
+ if (!tbl->weight)
+ return KNOT_ENOENT;
+ node_t *t = &tbl->root; // current and parent node
+ branch_t *p = NULL;
+ bitmap_t b = 0;
+ while (isbranch(t)) {
+ __builtin_prefetch(t->branch.twigs);
+ b = twigbit(t, key, len);
+ if (!hastwig(t, b))
+ return KNOT_ENOENT;
+ p = &t->branch;
+ t = twig(t, twigoff(t, b));
+ }
+ if (key_cmp(key, len, t->leaf.key->chars, t->leaf.key->len) != 0)
+ return KNOT_ENOENT;
+ mm_free(&tbl->mm, t->leaf.key);
+ if (val != NULL)
+ *val = t->leaf.val; // we return trie_val_t directly when deleting
+ --tbl->weight;
+ if (unlikely(!p)) { // whole trie was a single leaf
+ assert(tbl->weight == 0);
+ empty_root(&tbl->root);
+ return KNOT_EOK;
+ }
+ // remove leaf t as child of p
+ int ci = t - p->twigs, // child index via pointer arithmetic
+ cc = bitmap_weight(p->bitmap); // child count
+ assert(ci >= 0 && ci < cc);
+
+ if (cc == 2) { // collapse binary node p: move the other child to this node
+ node_t *twigs = p->twigs;
+ (*(node_t *)p) = twigs[1 - ci]; // it might be a leaf or branch
+ mm_free(&tbl->mm, twigs);
+ return KNOT_EOK;
+ }
+ memmove(p->twigs + ci, p->twigs + ci + 1, sizeof(node_t) * (cc - ci - 1));
+ p->bitmap &= ~b;
+ node_t *twigs = mm_realloc(&tbl->mm, p->twigs, sizeof(node_t) * (cc - 1),
+ sizeof(node_t) * cc);
+ if (likely(twigs != NULL))
+ p->twigs = twigs;
+ /* We can ignore mm_realloc failure, only beware that next time
+ * the prev_size passed to it wouldn't be correct; TODO? */
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Stack of nodes, storing a path down a trie.
+ *
+ * The structure also serves directly as the public trie_it_t type,
+ * in which case it always points to the current leaf, unless we've finished
+ * (i.e. it->len == 0).
+ */
+typedef struct trie_it {
+ node_t* *stack; /*!< The stack; malloc is used directly instead of mm. */
+ uint32_t len; /*!< Current length of the stack. */
+ uint32_t alen; /*!< Allocated/available length of the stack. */
+ /*! \brief Initial storage for \a stack; it should fit in most use cases. */
+ node_t* stack_init[2000 / sizeof(node_t *)];
+} nstack_t;
+
+/*! \brief Create a node stack containing just the root (or empty). */
+static void ns_init(nstack_t *ns, trie_t *tbl)
+{
+ assert(tbl);
+ ns->stack = ns->stack_init;
+ ns->alen = sizeof(ns->stack_init) / sizeof(ns->stack_init[0]);
+ if (tbl->weight) {
+ ns->len = 1;
+ ns->stack[0] = &tbl->root;
+ } else {
+ ns->len = 0;
+ }
+}
+
+/*! \brief Free inside of the stack, i.e. not the passed pointer itself. */
+static void ns_cleanup(nstack_t *ns)
+{
+ assert(ns && ns->stack);
+ if (likely(ns->stack == ns->stack_init))
+ return;
+ free(ns->stack);
+ #ifndef NDEBUG
+ ns->stack = NULL;
+ ns->alen = 0;
+ #endif
+}
+
+/*! \brief Allocate more space for the stack. */
+static int ns_longer_alloc(nstack_t *ns)
+{
+ ns->alen *= 2;
+ size_t new_size = sizeof(nstack_t) + ns->alen * sizeof(node_t *);
+ node_t **st;
+ if (ns->stack == ns->stack_init) {
+ st = malloc(new_size);
+ if (st != NULL)
+ memcpy(st, ns->stack, ns->len * sizeof(node_t *));
+ } else {
+ st = realloc(ns->stack, new_size);
+ }
+ if (st == NULL)
+ return KNOT_ENOMEM;
+ ns->stack = st;
+ return KNOT_EOK;
+}
+
+/*! \brief Ensure the node stack can be extended by one. */
+static inline int ns_longer(nstack_t *ns)
+{
+ // get a longer stack if needed
+ if (likely(ns->len < ns->alen))
+ return KNOT_EOK;
+ return ns_longer_alloc(ns); // hand-split the part suitable for inlining
+}
+
+/*!
+ * \brief Find the "branching point" as if searching for a key.
+ *
+ * The whole path to the point is kept on the passed stack;
+ * always at least the root will remain on the top of it.
+ * Beware: the precise semantics of this function is rather tricky.
+ * The top of the stack will contain: the corresponding leaf if exact match is found;
+ * or the immediate node below a branching-point-on-edge or the branching-point itself.
+ *
+ * \param info Set position of the point of first mismatch (in index and flags).
+ * \param first Set the value of the first non-matching character (from trie),
+ * optionally; end-of-string character has value -256 (that's why it's int).
+ * Note: the character is converted to *unsigned* char (i.e. 0..255),
+ * as that's the ordering used in the trie.
+ *
+ * \return KNOT_EOK or KNOT_ENOMEM.
+ */
+static int ns_find_branch(nstack_t *ns, const char *key, uint32_t len,
+ branch_t *info, int *first)
+{
+ assert(ns && ns->len && info);
+ // First find some leaf with longest matching prefix.
+ while (isbranch(ns->stack[ns->len - 1])) {
+ ERR_RETURN(ns_longer(ns));
+ node_t *t = ns->stack[ns->len - 1];
+ __builtin_prefetch(t->branch.twigs);
+ bitmap_t b = twigbit(t, key, len);
+ // Even if our key is missing from this branch we need to
+ // keep iterating down to a leaf. It doesn't matter which
+ // twig we choose since the keys are all the same up to this
+ // index. Note that blindly using twigoff(t, b) can cause
+ // an out-of-bounds index if it equals twigmax(t).
+ uint i = hastwig(t, b) ? twigoff(t, b) : 0;
+ ns->stack[ns->len++] = twig(t, i);
+ }
+ tkey_t *lkey = ns->stack[ns->len-1]->leaf.key;
+ // Find index of the first char that differs.
+ uint32_t index = 0;
+ while (index < MIN(len,lkey->len)) {
+ if (key[index] != lkey->chars[index])
+ break;
+ else
+ ++index;
+ }
+ info->index = index;
+ if (first)
+ *first = lkey->len > index ? (unsigned char)lkey->chars[index] : -256;
+ // Find flags: which half-byte has matched.
+ uint flags;
+ if (index == len && len == lkey->len) { // found equivalent key
+ info->flags = flags = 0;
+ goto success;
+ }
+ if (likely(index < MIN(len,lkey->len))) {
+ byte k2 = (byte)lkey->chars[index];
+ byte k1 = (byte)key[index];
+ flags = ((k1 ^ k2) & 0xf0) ? 1 : 2;
+ } else { // one is prefix of another
+ flags = 1;
+ }
+ info->flags = flags;
+ // now go up the trie from the current leaf
+ branch_t *t;
+ do {
+ if (unlikely(ns->len == 1))
+ goto success; // only the root stays on the stack
+ t = (branch_t*)ns->stack[ns->len - 2];
+ if (t->index < index || (t->index == index && t->flags < flags))
+ goto success;
+ --ns->len;
+ } while (true);
+success:
+ #ifndef NDEBUG // invariants on successful return
+ assert(ns->len);
+ if (isbranch(ns->stack[ns->len - 1])) {
+ t = &ns->stack[ns->len - 1]->branch;
+ assert(t->index > index || (t->index == index && t->flags >= flags));
+ }
+ if (ns->len > 1) {
+ t = &ns->stack[ns->len - 2]->branch;
+ assert(t->index < index || (t->index == index
+ && (t->flags < flags || (t->flags == 1 && flags == 0))));
+ }
+ #endif
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Advance the node stack to the last leaf in the subtree.
+ *
+ * \return KNOT_EOK or KNOT_ENOMEM.
+ */
+static int ns_last_leaf(nstack_t *ns)
+{
+ assert(ns);
+ do {
+ ERR_RETURN(ns_longer(ns));
+ node_t *t = ns->stack[ns->len - 1];
+ if (!isbranch(t))
+ return KNOT_EOK;
+ int lasti = bitmap_weight(t->branch.bitmap) - 1;
+ assert(lasti >= 0);
+ ns->stack[ns->len++] = twig(t, lasti);
+ } while (true);
+}
+
+/*!
+ * \brief Advance the node stack to the first leaf in the subtree.
+ *
+ * \return KNOT_EOK or KNOT_ENOMEM.
+ */
+static int ns_first_leaf(nstack_t *ns)
+{
+ assert(ns && ns->len);
+ do {
+ ERR_RETURN(ns_longer(ns));
+ node_t *t = ns->stack[ns->len - 1];
+ if (!isbranch(t))
+ return KNOT_EOK;
+ ns->stack[ns->len++] = twig(t, 0);
+ } while (true);
+}
+
+/*!
+ * \brief Advance the node stack to the leaf that is previous to the current node.
+ *
+ * \note Prefix leaf under the current node DOES count (if present; perhaps questionable).
+ * \return KNOT_EOK on success, KNOT_ENOENT on not-found, or possibly KNOT_ENOMEM.
+ */
+static int ns_prev_leaf(nstack_t *ns)
+{
+ assert(ns && ns->len > 0);
+
+ node_t *t = ns->stack[ns->len - 1];
+ if (hastwig(t, 1 << 0)) { // the prefix leaf
+ t = twig(t, 0);
+ ERR_RETURN(ns_longer(ns));
+ ns->stack[ns->len++] = t;
+ return KNOT_EOK;
+ }
+
+ do {
+ if (ns->len < 2)
+ return KNOT_ENOENT; // root without empty key has no previous leaf
+ t = ns->stack[ns->len - 1];
+ node_t *p = ns->stack[ns->len - 2];
+ int pindex = t - p->branch.twigs; // index in parent via pointer arithmetic
+ assert(pindex >= 0 && pindex <= 16);
+ if (pindex > 0) { // t isn't the first child -> go down the previous one
+ ns->stack[ns->len - 1] = twig(p, pindex - 1);
+ return ns_last_leaf(ns);
+ }
+ // we've got to go up again
+ --ns->len;
+ } while (true);
+}
+
+/*!
+ * \brief Advance the node stack to the leaf that is successor to the current node.
+ *
+ * \note Prefix leaf or anything else under the current node DOES count.
+ * \return KNOT_EOK on success, KNOT_ENOENT on not-found, or possibly KNOT_ENOMEM.
+ */
+static int ns_next_leaf(nstack_t *ns)
+{
+ assert(ns && ns->len > 0);
+
+ node_t *t = ns->stack[ns->len - 1];
+ if (isbranch(t))
+ return ns_first_leaf(ns);
+ do {
+ if (ns->len < 2)
+ return KNOT_ENOENT; // not found, as no more parent is available
+ t = ns->stack[ns->len - 1];
+ node_t *p = ns->stack[ns->len - 2];
+ int pindex = t - p->branch.twigs; // index in parent via pointer arithmetic
+ assert(pindex >= 0 && pindex <= 16);
+ int pcount = bitmap_weight(p->branch.bitmap);
+ if (pindex + 1 < pcount) { // t isn't the last child -> go down the next one
+ ns->stack[ns->len - 1] = twig(p, pindex + 1);
+ return ns_first_leaf(ns);
+ }
+ // we've got to go up again
+ --ns->len;
+ } while (true);
+}
+
+int trie_get_leq(trie_t *tbl, const char *key, uint32_t len, trie_val_t **val)
+{
+ assert(tbl && val);
+ *val = NULL; // so on failure we can just return;
+ if (tbl->weight == 0)
+ return KNOT_ENOENT;
+ { // Intentionally un-indented; until end of function, to bound cleanup attr.
+ // First find a key with longest-matching prefix
+ __attribute__((cleanup(ns_cleanup)))
+ nstack_t ns_local;
+ ns_init(&ns_local, tbl);
+ nstack_t *ns = &ns_local;
+ branch_t bp;
+ int un_leaf; // first unmatched character in the leaf
+ ERR_RETURN(ns_find_branch(ns, key, len, &bp, &un_leaf));
+ int un_key = bp.index < len ? (unsigned char)key[bp.index] : -256;
+ node_t *t = ns->stack[ns->len - 1];
+ if (bp.flags == 0) { // found exact match
+ *val = &t->leaf.val;
+ return KNOT_EOK;
+ }
+ // Get t: the last node on matching path
+ if (isbranch(t) && t->branch.index == bp.index && t->branch.flags == bp.flags) {
+ // t is OK
+ } else {
+ // the top of the stack was the first unmatched node -> step up
+ if (ns->len == 1) {
+ // root was unmatched already
+ if (un_key < un_leaf)
+ return KNOT_ENOENT;
+ ERR_RETURN(ns_last_leaf(ns));
+ goto success;
+ }
+ --ns->len;
+ t = ns->stack[ns->len - 1];
+ }
+ // Now we re-do the first "non-matching" step in the trie
+ // but try the previous child if key was less (it may not exist)
+ bitmap_t b = twigbit(t, key, len);
+ int i = hastwig(t, b)
+ ? twigoff(t, b) - (un_key < un_leaf)
+ : twigoff(t, b) - 1 /*twigoff returns successor when !hastwig*/;
+ if (i >= 0) {
+ ERR_RETURN(ns_longer(ns));
+ ns->stack[ns->len++] = twig(t, i);
+ ERR_RETURN(ns_last_leaf(ns));
+ } else {
+ ERR_RETURN(ns_prev_leaf(ns));
+ }
+success:
+ assert(!isbranch(ns->stack[ns->len - 1]));
+ *val = &ns->stack[ns->len - 1]->leaf.val;
+ return 1;
+ }
+}
+
+/*! \brief Initialize a new leaf, copying the key, and returning failure code. */
+static int mk_leaf(node_t *leaf, const char *key, uint32_t len, knot_mm_t *mm)
+{
+ tkey_t *k = mm_alloc(mm, sizeof(tkey_t) + len);
+ #if FLAGS_HACK
+ assert(((uintptr_t)k) % 4 == 0); // we need an aligned pointer
+ #endif
+ if (unlikely(!k))
+ return KNOT_ENOMEM;
+ k->len = len;
+ memcpy(k->chars, key, len);
+ leaf->leaf = (leaf_t){
+ #if !FLAGS_HACK
+ .flags = 0,
+ #endif
+ .val = NULL,
+ .key = k
+ };
+ return KNOT_EOK;
+}
+
+trie_val_t* trie_get_ins(trie_t *tbl, const char *key, uint32_t len)
+{
+ assert(tbl);
+ // First leaf in an empty tbl?
+ if (unlikely(!tbl->weight)) {
+ if (unlikely(mk_leaf(&tbl->root, key, len, &tbl->mm)))
+ return NULL;
+ ++tbl->weight;
+ return &tbl->root.leaf.val;
+ }
+ { // Intentionally un-indented; until end of function, to bound cleanup attr.
+ // Find the branching-point
+ __attribute__((cleanup(ns_cleanup)))
+ nstack_t ns_local;
+ ns_init(&ns_local, tbl);
+ nstack_t *ns = &ns_local;
+ branch_t bp; // branch-point: index and flags signifying the longest common prefix
+ int k2; // the first unmatched character in the leaf
+ if (unlikely(ns_find_branch(ns, key, len, &bp, &k2)))
+ return NULL;
+ node_t *t = ns->stack[ns->len - 1];
+ if (bp.flags == 0) // the same key was already present
+ return &t->leaf.val;
+ node_t leaf;
+ if (unlikely(mk_leaf(&leaf, key, len, &tbl->mm)))
+ return NULL;
+
+ if (isbranch(t) && bp.index == t->branch.index && bp.flags == t->branch.flags) {
+ // The node t needs a new leaf child.
+ bitmap_t b1 = twigbit(t, key, len);
+ assert(!hastwig(t, b1));
+ uint s, m; TWIGOFFMAX(s, m, t, b1); // new child position and original child count
+ node_t *twigs = mm_realloc(&tbl->mm, t->branch.twigs,
+ sizeof(node_t) * (m + 1), sizeof(node_t) * m);
+ if (unlikely(!twigs))
+ goto err_leaf;
+ memmove(twigs + s + 1, twigs + s, sizeof(node_t) * (m - s));
+ twigs[s] = leaf;
+ t->branch.twigs = twigs;
+ t->branch.bitmap |= b1;
+ ++tbl->weight;
+ return &twigs[s].leaf.val;
+ } else {
+ // We need to insert a new binary branch with leaf at *t.
+ // Note: it works the same for the case where we insert above root t.
+ #ifndef NDEBUG
+ if (ns->len > 1) {
+ node_t *pt = ns->stack[ns->len - 2];
+ assert(hastwig(pt, twigbit(pt, key, len)));
+ }
+ #endif
+ node_t *twigs = mm_alloc(&tbl->mm, sizeof(node_t) * 2);
+ if (unlikely(!twigs))
+ goto err_leaf;
+ node_t t2 = *t; // Save before overwriting t.
+ t->branch.flags = bp.flags;
+ t->branch.index = bp.index;
+ t->branch.twigs = twigs;
+ bitmap_t b1 = twigbit(t, key, len);
+ bitmap_t b2 = unlikely(k2 == -256) ? (1 << 0) : nibbit(k2, bp.flags);
+ t->branch.bitmap = b1 | b2;
+ *twig(t, twigoff(t, b1)) = leaf;
+ *twig(t, twigoff(t, b2)) = t2;
+ ++tbl->weight;
+ return &twig(t, twigoff(t, b1))->leaf.val;
+ };
+err_leaf:
+ mm_free(&tbl->mm, leaf.leaf.key);
+ return NULL;
+ }
+}
+
+/*! \brief Apply a function to every trie_val_t*, in order; a recursive solution. */
+static int apply_trie(node_t *t, int (*f)(trie_val_t *, void *), void *d)
+{
+ assert(t);
+ if (!isbranch(t))
+ return f(&t->leaf.val, d);
+ int child_count = bitmap_weight(t->branch.bitmap);
+ for (int i = 0; i < child_count; ++i)
+ ERR_RETURN(apply_trie(twig(t, i), f, d));
+ return KNOT_EOK;
+}
+
+int trie_apply(trie_t *tbl, int (*f)(trie_val_t *, void *), void *d)
+{
+ assert(tbl && f);
+ if (!tbl->weight)
+ return KNOT_EOK;
+ return apply_trie(&tbl->root, f, d);
+}
+
+/* These are all thin wrappers around static Tns* functions. */
+trie_it_t* trie_it_begin(trie_t *tbl)
+{
+ assert(tbl);
+ trie_it_t *it = malloc(sizeof(nstack_t));
+ if (!it)
+ return NULL;
+ ns_init(it, tbl);
+ if (it->len == 0) // empty tbl
+ return it;
+ if (ns_first_leaf(it)) {
+ ns_cleanup(it);
+ free(it);
+ return NULL;
+ }
+ return it;
+}
+
+void trie_it_next(trie_it_t *it)
+{
+ assert(it && it->len);
+ if (ns_next_leaf(it) != KNOT_EOK)
+ it->len = 0;
+}
+
+bool trie_it_finished(trie_it_t *it)
+{
+ assert(it);
+ return it->len == 0;
+}
+
+void trie_it_free(trie_it_t *it)
+{
+ if (!it)
+ return;
+ ns_cleanup(it);
+ free(it);
+}
+
+const char* trie_it_key(trie_it_t *it, size_t *len)
+{
+ assert(it && it->len);
+ node_t *t = it->stack[it->len - 1];
+ assert(!isbranch(t));
+ tkey_t *key = t->leaf.key;
+ if (len)
+ *len = key->len;
+ return key->chars;
+}
+
+trie_val_t* trie_it_val(trie_it_t *it)
+{
+ assert(it && it->len);
+ node_t *t = it->stack[it->len - 1];
+ assert(!isbranch(t));
+ return &t->leaf.val;
+}
diff --git a/src/contrib/qp-trie/trie.h b/src/contrib/qp-trie/trie.h
new file mode 100644
index 0000000..28ea571
--- /dev/null
+++ b/src/contrib/qp-trie/trie.h
@@ -0,0 +1,112 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "libknot/mm_ctx.h"
+
+/*!
+ * \brief Native API of QP-tries:
+ *
+ * - keys are char strings, not necessarily zero-terminated,
+ * the structure copies the contents of the passed keys
+ * - values are void* pointers, typically you get an ephemeral pointer to it
+ * - key lengths are limited by 2^32-1 ATM
+ */
+
+/*! \brief Element value. */
+typedef void* trie_val_t;
+
+/*! \brief Opaque structure holding a QP-trie. */
+typedef struct trie trie_t;
+
+/*! \brief Opaque type for holding a QP-trie iterator. */
+typedef struct trie_it trie_it_t;
+
+/*! \brief Create a trie instance. */
+trie_t* trie_create(knot_mm_t *mm);
+
+/*! \brief Free a trie instance. */
+void trie_free(trie_t *tbl);
+
+/*! \brief Clear a trie instance (make it empty). */
+void trie_clear(trie_t *tbl);
+
+/*! \brief Return the number of keys in the trie. */
+size_t trie_weight(const trie_t *tbl);
+
+/*! \brief Search the trie, returning NULL on failure. */
+trie_val_t* trie_get_try(trie_t *tbl, const char *key, uint32_t len);
+
+/*! \brief Search the trie, inserting NULL trie_val_t on failure. */
+trie_val_t* trie_get_ins(trie_t *tbl, const char *key, uint32_t len);
+
+/*!
+ * \brief Search for less-or-equal element.
+ *
+ * \param tbl Trie.
+ * \param key Searched key.
+ * \param len Key length.
+ * \param val Must be valid; it will be set to NULL if not found or errored.
+ * \return KNOT_EOK for exact match, 1 for previous, KNOT_ENOENT for not-found,
+ * or KNOT_E*.
+ */
+int trie_get_leq(trie_t *tbl, const char *key, uint32_t len, trie_val_t **val);
+
+/*!
+ * \brief Apply a function to every trie_val_t, in order.
+ *
+ * \return KNOT_EOK if success or KNOT_E* if error.
+ */
+int trie_apply(trie_t *tbl, int (*f)(trie_val_t *, void *), void *d);
+
+/*!
+ * \brief Remove an item, returning KNOT_EOK if succeeded or KNOT_ENOENT if not found.
+ *
+ * If val!=NULL and deletion succeeded, the deleted value is set.
+ */
+int trie_del(trie_t *tbl, const char *key, uint32_t len, trie_val_t *val);
+
+/*! \brief Create a new iterator pointing to the first element (if any). */
+trie_it_t* trie_it_begin(trie_t *tbl);
+
+/*!
+ * \brief Advance the iterator to the next element.
+ *
+ * Iteration is in ascending lexicographical order.
+ * In particular, the empty string would be considered as the very first.
+ */
+void trie_it_next(trie_it_t *it);
+
+/*! \brief Test if the iterator has gone past the last element. */
+bool trie_it_finished(trie_it_t *it);
+
+/*! \brief Free any resources of the iterator. It's OK to call it on NULL. */
+void trie_it_free(trie_it_t *it);
+
+/*!
+ * \brief Return pointer to the key of the current element.
+ *
+ * \note The len is uint32_t internally but size_t is better for our usage
+ * as it is without an additional type conversion.
+ */
+const char* trie_it_key(trie_it_t *it, size_t *len);
+
+/*! \brief Return pointer to the value of the current element (writable). */
+trie_val_t* trie_it_val(trie_it_t *it);
diff --git a/src/contrib/sockaddr.c b/src/contrib/sockaddr.c
new file mode 100644
index 0000000..d569292
--- /dev/null
+++ b/src/contrib/sockaddr.c
@@ -0,0 +1,351 @@
+/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+
+#include "libknot/consts.h"
+#include "libknot/errcode.h"
+#include "contrib/sockaddr.h"
+#include "contrib/openbsd/strlcpy.h"
+#include "contrib/macros.h"
+
+int sockaddr_len(const struct sockaddr *sa)
+{
+ if (sa == NULL) {
+ return 0;
+ }
+
+ switch(sa->sa_family) {
+ case AF_INET:
+ return sizeof(struct sockaddr_in);
+ case AF_INET6:
+ return sizeof(struct sockaddr_in6);
+ case AF_UNIX:
+ return sizeof(struct sockaddr_un);
+ default:
+ return 0;
+ }
+}
+
+static int cmp_ipv4(const struct sockaddr_in *a, const struct sockaddr_in *b)
+{
+ if (a->sin_addr.s_addr < b->sin_addr.s_addr) {
+ return -1;
+ } else if (a->sin_addr.s_addr > b->sin_addr.s_addr) {
+ return 1;
+ } else {
+ return a->sin_port - b->sin_port;
+ }
+}
+
+static int cmp_ipv6(const struct sockaddr_in6 *a, const struct sockaddr_in6 *b)
+{
+ int ret = memcmp(&a->sin6_addr, &b->sin6_addr, sizeof(struct in6_addr));
+ if (ret == 0) {
+ ret = a->sin6_port - b->sin6_port;
+ }
+
+ return ret;
+}
+
+static int cmp_unix(const struct sockaddr_un *a, const struct sockaddr_un *b)
+{
+ int len_a = strnlen(a->sun_path, sizeof(a->sun_path));
+ int len_b = strnlen(b->sun_path, sizeof(b->sun_path));
+ int len_min = len_a <= len_b ? len_a : len_b;
+
+ int ret = strncmp(a->sun_path, b->sun_path, len_min);
+ if (ret == 0) {
+ ret = len_a - len_b;
+ }
+
+ return ret;
+}
+
+int sockaddr_cmp(const struct sockaddr *a, const struct sockaddr *b)
+{
+ if (a->sa_family != b->sa_family) {
+ return (int)a->sa_family - (int)b->sa_family;
+ }
+
+ switch (a->sa_family) {
+ case AF_UNSPEC:
+ return 0;
+ case AF_INET:
+ return cmp_ipv4((struct sockaddr_in *)a, (struct sockaddr_in *)b);
+ case AF_INET6:
+ return cmp_ipv6((struct sockaddr_in6 *)a, (struct sockaddr_in6 *)b);
+ case AF_UNIX:
+ return cmp_unix((struct sockaddr_un *)a, (struct sockaddr_un *)b);
+ default:
+ return 1;
+ }
+}
+
+int sockaddr_set(struct sockaddr_storage *ss, int family, const char *straddr, int port)
+{
+ if (ss == NULL || straddr == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ /* Set family and port. */
+ memset(ss, 0, sizeof(*ss));
+ ss->ss_family = family;
+ sockaddr_port_set((struct sockaddr *)ss, port);
+
+ /* Initialize address depending on address family. */
+ if (family == AF_INET6) {
+ struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)ss;
+ if (inet_pton(family, straddr, &ipv6->sin6_addr) < 1) {
+ return KNOT_ERROR;
+ }
+ return KNOT_EOK;
+ } else if (family == AF_INET) {
+ struct sockaddr_in *ipv4 = (struct sockaddr_in *)ss;
+ if (inet_pton(family, straddr, &ipv4->sin_addr) < 1) {
+ return KNOT_ERROR;
+ }
+ return KNOT_EOK;
+ } else if (family == AF_UNIX) {
+ struct sockaddr_un *un = (struct sockaddr_un *)ss;
+ size_t ret = strlcpy(un->sun_path, straddr, sizeof(un->sun_path));
+ if (ret >= sizeof(un->sun_path)) {
+ return KNOT_ESPACE;
+ }
+ return KNOT_EOK;
+ }
+
+ return KNOT_EINVAL;
+}
+
+void *sockaddr_raw(const struct sockaddr *sa, size_t *addr_size)
+{
+ if (sa == NULL || addr_size == NULL) {
+ return NULL;
+ }
+
+ if (sa->sa_family == AF_INET) {
+ struct sockaddr_in *ipv4 = (struct sockaddr_in *)sa;
+ *addr_size = sizeof(ipv4->sin_addr);
+ return &ipv4->sin_addr;
+ } else if (sa->sa_family == AF_INET6) {
+ struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)sa;
+ *addr_size = sizeof(ipv6->sin6_addr);
+ return &ipv6->sin6_addr;
+ } else {
+ return NULL;
+ }
+}
+
+int sockaddr_set_raw(struct sockaddr_storage *ss, int family,
+ const uint8_t *raw_addr, size_t raw_addr_size)
+{
+ if (ss == NULL || raw_addr == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ memset(ss, 0, sizeof(*ss));
+ ss->ss_family = family;
+
+ size_t sa_size = 0;
+ void *sa_data = sockaddr_raw((struct sockaddr *)ss, &sa_size);
+ if (sa_data == NULL || sa_size != raw_addr_size) {
+ return KNOT_EINVAL;
+ }
+
+ memcpy(sa_data, raw_addr, sa_size);
+
+ return KNOT_EOK;
+}
+
+int sockaddr_tostr(char *buf, size_t maxlen, const struct sockaddr *sa)
+{
+ if (sa == NULL || buf == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ const char *out = NULL;
+
+ /* Convert network address string. */
+ if (sa->sa_family == AF_INET6) {
+ const struct sockaddr_in6 *s = (const struct sockaddr_in6 *)sa;
+ out = inet_ntop(sa->sa_family, &s->sin6_addr, buf, maxlen);
+ } else if (sa->sa_family == AF_INET) {
+ const struct sockaddr_in *s = (const struct sockaddr_in *)sa;
+ out = inet_ntop(sa->sa_family, &s->sin_addr, buf, maxlen);
+ } else if (sa->sa_family == AF_UNIX) {
+ const struct sockaddr_un *s = (const struct sockaddr_un *)sa;
+ size_t ret = strlcpy(buf, s->sun_path, maxlen);
+ out = (ret < maxlen) ? buf : NULL;
+ } else {
+ return KNOT_EINVAL;
+ }
+
+ if (out == NULL) {
+ *buf = '\0';
+ return KNOT_ESPACE;
+ }
+
+ /* Write separator and port. */
+ int written = strlen(buf);
+ int port = sockaddr_port(sa);
+ if (port > 0) {
+ int ret = snprintf(&buf[written], maxlen - written, "@%d", port);
+ if (ret <= 0 || (size_t)ret >= maxlen - written) {
+ *buf = '\0';
+ return KNOT_ESPACE;
+ }
+
+ written += ret;
+ }
+
+ return written;
+}
+
+int sockaddr_port(const struct sockaddr *sa)
+{
+ if (sa == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ if (sa->sa_family == AF_INET6) {
+ return ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
+ } else if (sa->sa_family == AF_INET) {
+ return ntohs(((struct sockaddr_in *)sa)->sin_port);
+ } else {
+ return KNOT_EINVAL;
+ }
+}
+
+void sockaddr_port_set(struct sockaddr *sa, uint16_t port)
+{
+ if (sa == NULL) {
+ return;
+ }
+
+ if (sa->sa_family == AF_INET6) {
+ ((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
+ } else if (sa->sa_family == AF_INET) {
+ ((struct sockaddr_in *)sa)->sin_port = htons(port);
+ }
+}
+
+char *sockaddr_hostname(void)
+{
+ /* Fetch hostname. */
+ char host[KNOT_DNAME_MAXLEN + 1] = { '\0' };
+ if (gethostname(host, sizeof(host)) != 0) {
+ return NULL;
+ }
+ /* Just to be sure. */
+ host[sizeof(host) - 1] = '\0';
+
+ /* Fetch canonical name for this address/DNS. */
+ struct addrinfo hints, *info = NULL;
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = AI_CANONNAME;
+ if (getaddrinfo(host, "domain", &hints, &info) != 0) {
+ return NULL;
+ }
+
+ /* Fetch first valid hostname. */
+ char *hname = NULL;
+ struct addrinfo *p = NULL;
+ for (p = info; p != NULL; p = p->ai_next) {
+ if (p->ai_canonname) {
+ hname = strdup(p->ai_canonname);
+ break;
+ }
+ }
+
+ /* No valid hostname found, resort to gethostname() result */
+ if (hname == NULL) {
+ hname = strdup(host);
+ }
+
+ freeaddrinfo(info);
+ return hname;
+}
+
+bool sockaddr_is_any(const struct sockaddr *sa)
+{
+ if (sa == NULL) {
+ return false;
+ }
+
+ if (sa->sa_family == AF_INET) {
+ const struct sockaddr_in *ipv4 = (struct sockaddr_in *)sa;
+ return ipv4->sin_addr.s_addr == INADDR_ANY;
+ }
+
+ if (sa->sa_family == AF_INET6) {
+ const struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)sa;
+ return memcmp(&ipv6->sin6_addr, &in6addr_any, sizeof(ipv6->sin6_addr)) == 0;
+ }
+
+ return false;
+}
+
+bool sockaddr_net_match(const struct sockaddr *ss1,
+ const struct sockaddr *ss2,
+ unsigned prefix)
+{
+ if (ss1 == NULL || ss2 == NULL) {
+ return false;
+ }
+
+ if (ss1->sa_family != ss2->sa_family) {
+ return false;
+ }
+
+ size_t raw_len = 0;
+ const uint8_t *raw_1 = sockaddr_raw(ss1, &raw_len);
+ const uint8_t *raw_2 = sockaddr_raw(ss2, &raw_len);
+
+ prefix = MIN(prefix, raw_len * 8);
+ unsigned bytes = prefix / 8;
+ unsigned bits = prefix % 8;
+
+ /* Compare full bytes. */
+ if (memcmp(raw_1, raw_2, bytes) != 0) {
+ return false;
+ }
+
+ /* Compare last partial byte. */
+ return bits == 0 ||
+ (raw_1[bytes] >> (8 - bits) == raw_2[bytes] >> (8 - bits));
+}
+
+bool sockaddr_range_match(const struct sockaddr *sa,
+ const struct sockaddr *ss_min,
+ const struct sockaddr *ss_max)
+{
+ if (sa == NULL || ss_min == NULL || ss_max == NULL) {
+ return false;
+ }
+
+ if (ss_min->sa_family != ss_max->sa_family ||
+ ss_min->sa_family != sa->sa_family) {
+ return false;
+ }
+
+ return sockaddr_cmp(sa, ss_min) >= 0 && sockaddr_cmp(sa, ss_max) <= 0;
+}
diff --git a/src/contrib/sockaddr.h b/src/contrib/sockaddr.h
new file mode 100644
index 0000000..0fbf1ab
--- /dev/null
+++ b/src/contrib/sockaddr.h
@@ -0,0 +1,160 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+/* BSD IPv6 */
+#ifndef __POSIX_VISIBLE
+#define __POSIX_VISIBLE 200112
+#endif
+
+#include <stdbool.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdint.h>
+#include <unistd.h>
+
+/* Subnet maximum prefix length. */
+#define IPV4_PREFIXLEN 32
+#define IPV6_PREFIXLEN 128
+
+/* Address string "address[@port]" maximum length. */
+#define SOCKADDR_STRLEN_EXT (1 + 6) /* '@', 5 digits number, \0 */
+#define SOCKADDR_STRLEN (sizeof(struct sockaddr_un) + SOCKADDR_STRLEN_EXT)
+
+/*!
+ * \brief Calculate current structure length based on address family.
+ *
+ * \param sa Socket address.
+ *
+ * \return Number of bytes or error code.
+ */
+int sockaddr_len(const struct sockaddr *sa);
+
+/*!
+ * \brief Compare addresses.
+ *
+ * \return like memcmp(3)
+ */
+int sockaddr_cmp(const struct sockaddr *k1, const struct sockaddr *k2);
+
+/*!
+ * \brief Set address and port.
+ *
+ * \param ss Socket address.
+ * \param family Address family.
+ * \param straddr IP address in string format.
+ * \param port Port.
+ *
+ * \return KNOT_EOK on success or an error code.
+ */
+int sockaddr_set(struct sockaddr_storage *ss, int family, const char *straddr, int port);
+
+/*!
+ * \brief Return raw network address in network byte order.
+ *
+ * \param[in] sa Socket address.
+ * \param[out] addr_size Address length.
+ *
+ * \return Pointer to binary buffer of size addr_size.
+ */
+void *sockaddr_raw(const struct sockaddr *sa, size_t *addr_size);
+
+/*!
+ * \brief Set raw address.
+ *
+ * \param ss Socket address.
+ * \param family Address family.
+ * \param raw_addr IP address in binary format.
+ * \param raw_addr_size Size of the binary address.
+ *
+ * \return KNOT_EOK on success or an error code.
+ */
+int sockaddr_set_raw(struct sockaddr_storage *ss, int family,
+ const uint8_t *raw_addr, size_t raw_addr_size);
+
+/*!
+ * \brief Return string representation of socket address.
+ *
+ * \note String format: \<address>[@<port>], f.e. '127.0.0.1@53'
+ *
+ * \param buf Destination for string representation.
+ * \param maxlen Maximum number of written bytes.
+ * \param sa Socket address.
+ *
+ * \return Number of bytes written on success, error code on failure.
+ */
+int sockaddr_tostr(char *buf, size_t maxlen, const struct sockaddr *sa);
+
+/*!
+ * \brief Return port number from address.
+ *
+ * \param sa Socket address.
+ *
+ * \return Port number or error code.
+ */
+int sockaddr_port(const struct sockaddr *sa);
+
+/*!
+ * \brief Set port number.
+ *
+ * \param sa Socket address.
+ * \param port Port to set.
+ */
+void sockaddr_port_set(struct sockaddr *sa, uint16_t port);
+
+/*!
+ * \brief Get host FQDN address.
+ *
+ * \return Hostname string or NULL.
+ */
+char *sockaddr_hostname(void);
+
+/*!
+ * \brief Check if address is ANY address.
+ *
+ * \param sa Socket address.
+ */
+bool sockaddr_is_any(const struct sockaddr *sa);
+
+/*!
+ * \brief Check if two addresses match the given network prefix.
+ *
+ * \param sa1 First address.
+ * \param sa2 Second address.
+ * \param prefix Prefix length.
+ *
+ * \return True on match.
+ */
+bool sockaddr_net_match(const struct sockaddr *sa1,
+ const struct sockaddr *sa2,
+ unsigned prefix);
+
+/*!
+ * \brief Check if the address is within the given address range (inclusive).
+ *
+ * \param sa Address to check.
+ * \param sa_min Minimum address.
+ * \param sa_max Maximum address.
+ *
+ * \return True on match.
+ */
+bool sockaddr_range_match(const struct sockaddr *sa,
+ const struct sockaddr *sa_min,
+ const struct sockaddr *sa_max);
diff --git a/src/contrib/string.c b/src/contrib/string.c
new file mode 100644
index 0000000..6e0eea9
--- /dev/null
+++ b/src/contrib/string.c
@@ -0,0 +1,112 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "contrib/string.h"
+#include "contrib/ctype.h"
+
+uint8_t *memdup(const uint8_t *data, size_t data_size)
+{
+ uint8_t *result = (uint8_t *)malloc(data_size);
+ if (!result) {
+ return NULL;
+ }
+
+ return memcpy(result, data, data_size);
+}
+
+char *sprintf_alloc(const char *fmt, ...)
+{
+ char *strp = NULL;
+ va_list ap;
+
+ va_start(ap, fmt);
+ int ret = vasprintf(&strp, fmt, ap);
+ va_end(ap);
+
+ if (ret < 0) {
+ return NULL;
+ }
+ return strp;
+}
+
+char *strcdup(const char *s1, const char *s2)
+{
+ if (!s1 || !s2) {
+ return NULL;
+ }
+
+ size_t s1len = strlen(s1);
+ size_t s2len = strlen(s2);
+ size_t nlen = s1len + s2len + 1;
+
+ char* dst = malloc(nlen);
+ if (dst == NULL) {
+ return NULL;
+ }
+
+ memcpy(dst, s1, s1len);
+ memcpy(dst + s1len, s2, s2len + 1);
+ return dst;
+}
+
+char *strstrip(const char *str)
+{
+ // leading white-spaces
+ const char *scan = str;
+ while (is_space(scan[0])) {
+ scan += 1;
+ }
+
+ // trailing white-spaces
+ size_t len = strlen(scan);
+ while (len > 0 && is_space(scan[len - 1])) {
+ len -= 1;
+ }
+
+ char *trimmed = malloc(len + 1);
+ if (!trimmed) {
+ return NULL;
+ }
+
+ memcpy(trimmed, scan, len);
+ trimmed[len] = '\0';
+
+ return trimmed;
+}
+
+int const_time_memcmp(const void *s1, const void *s2, size_t n)
+{
+ volatile uint8_t equal = 0;
+
+ for (size_t i = 0; i < n; i++) {
+ equal |= ((uint8_t *)s1)[i] ^ ((uint8_t *)s2)[i];
+ }
+
+ return equal;
+}
+
+typedef void *(*memset_t)(void *, int, size_t);
+static volatile memset_t volatile_memset = memset;
+
+void *memzero(void *s, size_t n)
+{
+ return volatile_memset(s, 0, n);
+}
diff --git a/src/contrib/string.h b/src/contrib/string.h
new file mode 100644
index 0000000..19c74c7
--- /dev/null
+++ b/src/contrib/string.h
@@ -0,0 +1,82 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \brief String manipulations.
+ */
+
+#pragma once
+
+#include <stddef.h>
+#include <stdint.h>
+
+/*!
+ * \brief Create a copy of a binary buffer.
+ *
+ * Like \c strdup, but for binary data.
+ */
+uint8_t *memdup(const uint8_t *data, size_t data_size);
+
+/*!
+ * \brief Format string and take care of allocating memory.
+ *
+ * \note sprintf(3) manual page reference implementation.
+ *
+ * \param fmt Message format.
+ * \return formatted message or NULL.
+ */
+char *sprintf_alloc(const char *fmt, ...);
+
+/*!
+ * \brief Create new string from a concatenation of s1 and s2.
+ *
+ * \param s1 First string.
+ * \param s2 Second string.
+ *
+ * \retval Newly allocated string on success.
+ * \retval NULL on error.
+ */
+char *strcdup(const char *s1, const char *s2);
+
+/*!
+ * \brief Create a copy of a string skipping leading and trailing white spaces.
+ *
+ * \return Newly allocated string, NULL in case of error.
+ */
+char *strstrip(const char *str);
+
+/*!
+ * \brief Compare data in time based on string length.
+ * This function just checks for (in)equality not for relation
+ *
+ * \param s1 The first address to compare.
+ * \param s2 The second address to compare.
+ * \param n The size of memory to compare.
+ *
+ * \return Non zero on difference and zero if the buffers are identical.
+ */
+int const_time_memcmp(const void *s1, const void *s2, size_t n);
+
+/*!
+ * \brief Fill memory with zeroes.
+ *
+ * Inspired by OPENSSL_cleanse. Such a memset shouldn't be optimized out.
+ *
+ * \param s The address to fill.
+ * \param n The size of memory to fill.
+ *
+ * \return Pointer to the memory.
+ */
+void *memzero(void *s, size_t n);
diff --git a/src/contrib/strtonum.h b/src/contrib/strtonum.h
new file mode 100644
index 0000000..6cfe8bb
--- /dev/null
+++ b/src/contrib/strtonum.h
@@ -0,0 +1,120 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "libknot/errcode.h"
+#include "contrib/ctype.h"
+
+inline static int intmax_from_str(const char *src, intmax_t *dst,
+ intmax_t min, intmax_t max)
+{
+ if (!is_digit(*src) && *src != '-' && *src != '+') {
+ return KNOT_EINVAL;
+ }
+
+ errno = 0;
+ char *end = NULL;
+ intmax_t result = strtoimax(src, &end, 10);
+
+ if (errno == ERANGE) {
+ return KNOT_ERANGE;
+ }
+
+ if (src == end || *end != '\0') {
+ return KNOT_EINVAL;
+ }
+
+ if (result < min || result > max) {
+ return KNOT_ERANGE;
+ }
+
+ *dst = result;
+ return KNOT_EOK;
+}
+
+inline static int uintmax_from_str(const char *src, uintmax_t *dst,
+ uintmax_t min, uintmax_t max)
+{
+ if (!is_digit(*src) && *src != '+') {
+ return KNOT_EINVAL;
+ }
+
+ errno = 0;
+ char *end = NULL;
+ uintmax_t result = strtoumax(src, &end, 10);
+
+ if (errno == ERANGE) {
+ return KNOT_ERANGE;
+ }
+
+ if (src == end || *end != '\0') {
+ return KNOT_EINVAL;
+ }
+
+ if (result < min || result > max) {
+ return KNOT_ERANGE;
+ }
+
+ *dst = result;
+ return KNOT_EOK;
+}
+
+#define CONVERT(prefix, type, min, max, src, dst) \
+{ \
+ assert(src && dst); \
+ prefix##max_t value; \
+ int result = prefix##max_from_str(src, &value, min, max); \
+ if (result != KNOT_EOK) { \
+ return result; \
+ } \
+ *dst = (type)value; \
+ return KNOT_EOK; \
+}
+
+inline static int str_to_int(const char *src, int *dst, int min, int max)
+{
+ CONVERT(int, int, min, max, src, dst);
+}
+
+inline static int str_to_u8(const char *src, uint8_t *dst)
+{
+ CONVERT(uint, uint8_t, 0, UINT8_MAX, src, dst);
+}
+
+inline static int str_to_u16(const char *src, uint16_t *dst)
+{
+ CONVERT(uint, uint16_t, 0, UINT16_MAX, src, dst);
+}
+
+inline static int str_to_u32(const char *src, uint32_t *dst)
+{
+ CONVERT(uint, uint32_t, 0, UINT32_MAX, src, dst);
+}
+
+inline static int str_to_size(const char *src, size_t *dst, size_t min, size_t max)
+{
+ CONVERT(uint, size_t, min, max, src, dst);
+}
+
+#undef CONVERT
diff --git a/src/contrib/time.c b/src/contrib/time.c
new file mode 100644
index 0000000..8c32c2d
--- /dev/null
+++ b/src/contrib/time.c
@@ -0,0 +1,405 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "contrib/time.h"
+#include "contrib/ctype.h"
+#ifndef HAVE_CLOCK_GETTIME
+ #include <sys/time.h>
+#endif
+
+struct timespec time_now(void)
+{
+ struct timespec result = { 0 };
+
+#ifdef HAVE_CLOCK_GETTIME
+ clock_gettime(CLOCK_MONOTONIC, &result);
+#else // OS X < Sierra fallback.
+ struct timeval tmp = { 0 };
+ gettimeofday(&tmp, NULL);
+ result.tv_sec = tmp.tv_sec;
+ result.tv_nsec = 1000 * tmp.tv_usec;
+#endif
+
+ return result;
+}
+
+struct timespec time_diff(const struct timespec *begin, const struct timespec *end)
+{
+ struct timespec result = { 0 };
+
+ if (end->tv_nsec >= begin->tv_nsec) {
+ result.tv_sec = end->tv_sec - begin->tv_sec;
+ result.tv_nsec = end->tv_nsec - begin->tv_nsec;
+ } else {
+ result.tv_sec = end->tv_sec - begin->tv_sec - 1;
+ result.tv_nsec = 1000000000 - begin->tv_nsec + end->tv_nsec;
+ }
+
+ return result;
+}
+
+double time_diff_ms(const struct timespec *begin, const struct timespec *end)
+{
+ struct timespec result = time_diff(begin, end);
+
+ return (result.tv_sec * 1e3) + (result.tv_nsec / 1e6);
+}
+
+typedef struct {
+ const char *format;
+ const char *timespec;
+ const char *parsed;
+ knot_timediff_t offset;
+ char offset_sign;
+ char offset_unit;
+ struct tm calendar;
+ int error;
+} time_ctx_t;
+
+// After casting (struct tm) to (int []), we can use indexes...
+static int calendar_index(char ind)
+{
+ switch (ind) {
+ case 'Y': return 5;
+ case 'M': return 4;
+ case 'D': return 3;
+ case 'h': return 2;
+ case 'm': return 1;
+ case 's': return 0;
+ default: assert(0); return 6;
+ }
+}
+
+static size_t calendar_digits(int index)
+{
+ return index == 5 ? 4 : 2;
+}
+
+static size_t unit_value(char unit)
+{
+ size_t val = 1;
+ switch (unit) {
+ case 'M':
+ return 3600 * 24 * 30;
+ case 'Y':
+ val *= 365;
+ // FALLTHROUGH
+ case 'D':
+ val *= 24;
+ // FALLTHROUGH
+ case 'h':
+ val *= 60;
+ // FALLTHROUGH
+ case 'm':
+ val *= 60;
+ // FALLTHROUGH
+ case 's':
+ default:
+ return val;
+ }
+}
+
+static knot_time_t time_ctx_finalize(time_ctx_t *ctx)
+{
+ if (ctx->offset_sign) {
+ ctx->offset *= unit_value(ctx->offset_unit);
+ return knot_time_add(knot_time(), (ctx->offset_sign == '-' ? -1 : 1) * ctx->offset);
+ } else if (ctx->offset) {
+ return (knot_time_t)ctx->offset;
+ } else if (ctx->calendar.tm_year != 0) {
+ ctx->calendar.tm_isdst = -1;
+ ctx->calendar.tm_year -= 1900;
+ ctx->calendar.tm_mon -= 1;
+ // Set UTC timezone before using mktime
+ putenv("TZ=UTC");
+ tzset();
+ return (knot_time_t)mktime(&ctx->calendar);
+ } else {
+ return (knot_time_t)0;
+ }
+}
+
+static void time_ctx_reset(time_ctx_t *ctx)
+{
+ ctx->parsed = ctx->timespec;
+ ctx->offset = 0;
+ ctx->offset_sign = 0;
+ memset(&ctx->calendar, 0, sizeof(ctx->calendar));
+ ctx->error = 0;
+}
+
+static void parse_quote(time_ctx_t *ctx)
+{
+ while (*ctx->format != '|' && *ctx->format != '\0') {
+ if (*ctx->format == '\'') {
+ ctx->format++;
+ return;
+ }
+ if (*ctx->format++ != *ctx->parsed++) {
+ ctx->error = -1;
+ return;
+ }
+ }
+ ctx->error = -2;
+ return;
+}
+
+static void parse_offset(time_ctx_t *ctx)
+{
+ ctx->offset = 0;
+ ctx->error = -1;
+ while (is_digit(*ctx->parsed)) {
+ ctx->offset *= 10;
+ ctx->offset += *ctx->parsed++ - '0';
+ ctx->error = 0;
+ }
+}
+
+static void parse_calendar(time_ctx_t *ctx, int index)
+{
+ int *cal_arr = (int *)&ctx->calendar;
+ cal_arr[index] = 0;
+ for (size_t i = 0; i < calendar_digits(index); i++) {
+ if (!is_digit(*ctx->parsed)) {
+ ctx->error = -1;
+ return;
+ }
+ cal_arr[index] *= 10;
+ cal_arr[index] += *ctx->parsed++ - '0';
+ }
+}
+
+static void parse_sign(time_ctx_t *ctx)
+{
+ char sign1 = *(ctx->format - 1), sign2 = *ctx->format;
+
+ bool use_sign2 = (sign2 == '+' || sign2 == '-');
+
+ bool allow_plus = (sign1 == '+' || (sign1 == '-' && sign2 == '+'));
+ bool allow_minus = (sign1 == '-' || (sign1 == '+' && sign2 == '-'));
+ assert(sign1 == '+' || sign1 == '-');
+
+ if ((*ctx->parsed == '+' && allow_plus) || (*ctx->parsed == '-' && allow_minus)) {
+ ctx->offset_sign = *ctx->parsed++;
+ ctx->format += (use_sign2 ? 1 : 0);
+ } else {
+ ctx->error = -11;
+ }
+}
+
+static void parse_unit1(time_ctx_t *ctx)
+{
+ char u = *ctx->parsed++;
+ switch (u) {
+ case 'Y':
+ case 'M':
+ case 'D':
+ case 'h':
+ case 'm':
+ case 's':
+ ctx->offset_unit = u;
+ break;
+ default:
+ ctx->error = -1;
+ }
+}
+
+static void parse_unit2(time_ctx_t *ctx)
+{
+ char u = *ctx->parsed++;
+ switch (u) {
+ case 'y':
+ case 'd':
+ ctx->offset_unit = toupper((unsigned char)u);
+ break;
+ case 'h':
+ case 's':
+ ctx->offset_unit = u;
+ break;
+ case 'm':
+ switch (*ctx->parsed++) {
+ case 'o':
+ ctx->offset_unit = 'M';
+ break;
+ case 'i':
+ ctx->offset_unit = 'm';
+ break;
+ default:
+ ctx->error = -1;
+ }
+ break;
+ default:
+ ctx->error = -1;
+ }
+}
+
+int knot_time_parse(const char *format, const char *timespec, knot_time_t *time)
+{
+ if (format == NULL || timespec == NULL || time == NULL) {
+ return -1;
+ }
+
+ time_ctx_t ctx = {
+ .format = format,
+ .timespec = timespec,
+ .parsed = timespec,
+ .offset = 0,
+ .offset_sign = 0,
+ // we hope that .calendar is zeroed by default
+ .error = 0,
+ };
+
+ while (ctx.error == 0 && *ctx.format != '\0') {
+ switch (*ctx.format++) {
+ case '|':
+ if (*ctx.parsed == '\0') {
+ *time = time_ctx_finalize(&ctx);
+ return 0;
+ } else {
+ time_ctx_reset(&ctx);
+ }
+ break;
+ case '\'':
+ parse_quote(&ctx);
+ break;
+ case '#':
+ parse_offset(&ctx);
+ break;
+ case 'Y':
+ case 'M':
+ case 'D':
+ case 'h':
+ case 'm':
+ case 's':
+ parse_calendar(&ctx, calendar_index(*(ctx.format - 1)));
+ break;
+ case '+':
+ case '-':
+ parse_sign(&ctx);
+ break;
+ case 'U':
+ parse_unit1(&ctx);
+ break;
+ case 'u':
+ parse_unit2(&ctx);
+ break;
+ default:
+ return -1;
+ }
+
+ if (ctx.error < 0) {
+ while (*ctx.format != '|' && *ctx.format != '\0') {
+ ctx.format++;
+ }
+ time_ctx_reset(&ctx);
+ ctx.error = (*ctx.format == '\0' ? -1 : 0);
+ }
+ }
+
+ if (ctx.error == 0 && *ctx.parsed == '\0') {
+ *time = time_ctx_finalize(&ctx);
+ return 0;
+ }
+ return -1;
+}
+
+static char *unit_names_mixed[] = { "Y", "M", "D", "h", "m", "s" };
+static char *unit_names_lower[] = { "y", "mo", "d", "h", "mi", "s" };
+static size_t unit_sizes[] = { 3600*24*365, 3600*24*30, 3600*24, 3600, 60, 1 };
+static const size_t unit_count = 6;
+
+static int print_unit(char *dst, size_t dst_len, char *unit_names[unit_count],
+ size_t max_units, knot_time_t time)
+{
+ int ret;
+ if (time == 0) {
+ ret = snprintf(dst, dst_len, "0");
+ return (ret < 0 || ret >= dst_len ? -1 : 0);
+ }
+ knot_timediff_t diff = knot_time_diff(time, knot_time());
+ if (dst_len-- < 1) {
+ return -1;
+ }
+ *dst++ = (diff < 0 ? '-' : '+');
+ if (diff < 0) {
+ diff = -diff;
+ } else if (diff == 0) {
+ ret = snprintf(dst, dst_len, "0%s", unit_names[unit_count - 1]);
+ return (ret < 0 || ret >= dst_len ? -1 : 0);
+ }
+ size_t curr_unit = 0, used_units = 0;
+ while (curr_unit < unit_count && used_units < max_units) {
+ if (diff >= unit_sizes[curr_unit]) {
+ ret = snprintf(dst, dst_len, "%"KNOT_TIMEDIFF_PRINTF"%s",
+ diff / unit_sizes[curr_unit],
+ unit_names[curr_unit]);
+ if (ret < 0 || ret >= dst_len) {
+ return -1;
+ }
+ dst += ret;
+ dst_len -= ret;
+ used_units++;
+ diff %= unit_sizes[curr_unit];
+ }
+ curr_unit++;
+ }
+ return 0;
+}
+
+int knot_time_print(knot_time_print_t format, knot_time_t time, char *dst, size_t dst_len)
+{
+ if (dst == NULL) {
+ return -1;
+ }
+
+ int ret;
+ switch (format) {
+ case TIME_PRINT_UNIX:
+ ret = snprintf(dst, dst_len, "%"KNOT_TIME_PRINTF, time);
+ return ((ret >= 0 && ret < dst_len) ? 0 : -1);
+ case TIME_PRINT_ISO8601:
+ if (time > LONG_MAX) {
+ return -1;
+ }
+
+ // Set timezone to UTC before using timezone dependent functions
+ putenv("TZ=UTC");
+ tzset();
+
+ struct tm lt;
+ time_t tt = (time_t)time;
+ ret = (localtime_r(&tt, &lt) == NULL ? -1 :
+ strftime(dst, dst_len, "%Y-%m-%dT%H:%M:%SZ", &lt));
+ return (ret > 0 ? 0 : -1);
+ case TIME_PRINT_RELSEC:
+ ret = snprintf(dst, dst_len, "%+"KNOT_TIMEDIFF_PRINTF,
+ knot_time_diff(time, knot_time()));
+ return ((ret >= 0 && ret < dst_len) ? 0 : -1);
+ case TIME_PRINT_HUMAN_MIXED:
+ return print_unit(dst, dst_len, unit_names_mixed, unit_count, time);
+ case TIME_PRINT_HUMAN_LOWER:
+ return print_unit(dst, dst_len, unit_names_lower, unit_count, time);
+ default:
+ return -1;
+ }
+}
diff --git a/src/contrib/time.h b/src/contrib/time.h
new file mode 100644
index 0000000..55b8727
--- /dev/null
+++ b/src/contrib/time.h
@@ -0,0 +1,171 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <time.h>
+#include <inttypes.h>
+
+/*!
+ * \brief Specify output format for knot_time_print().
+ */
+typedef enum {
+ TIME_PRINT_UNIX, // numeric UNIX time
+ TIME_PRINT_ISO8601, // 2016-12-31T23:59:00
+ TIME_PRINT_RELSEC, // relative +6523
+ TIME_PRINT_HUMAN_MIXED, // relative with mixed-case units
+ TIME_PRINT_HUMAN_LOWER, // relative with lower-case units
+} knot_time_print_t;
+
+/*!
+ * \brief Get current time.
+ */
+struct timespec time_now(void);
+
+/*!
+ * \brief Get time elapsed between two events.
+ */
+struct timespec time_diff(const struct timespec *begin, const struct timespec *end);
+
+/*!
+ * \brief Get time elapsed between two events in miliseconds.
+ */
+double time_diff_ms(const struct timespec *begin, const struct timespec *end);
+
+/*!
+ * \brief Data type for keeping UNIX timestamps.
+ *
+ * This is because time_t can be 32-bit on some systems, which is bad.
+ * Zero value represents infinity.
+ */
+typedef uint64_t knot_time_t;
+
+/*!
+ * \brief Data type for keeping time differences.
+ */
+typedef int64_t knot_timediff_t;
+
+#define KNOT_TIMEDIFF_MIN INT64_MIN
+#define KNOT_TIMEDIFF_MAX INT64_MAX
+
+#define KNOT_TIME_PRINTF PRIu64
+#define KNOT_TIMEDIFF_PRINTF PRId64
+
+/*!
+ * \brief Returns current time sice epoch.
+ */
+inline static knot_time_t knot_time(void)
+{
+ return (knot_time_t)time(NULL);
+}
+
+/*!
+ * \brief Compare two timestamps.
+ *
+ * \return 0 if equal, -1 if the former is smaller (=earlier), 1 else.
+ */
+inline static int knot_time_cmp(knot_time_t a, knot_time_t b)
+{
+ return (a == b ? 0 : 1) * ((a && b) == 0 ? -1 : 1) * (a < b ? -1 : 1);
+}
+
+/*!
+ * \brief Return the smaller (=earlier) from given two timestamps.
+ */
+inline static knot_time_t knot_time_min(knot_time_t a, knot_time_t b)
+{
+ if ((a && b) == 0) {
+ return a + b;
+ } else {
+ return (a < b ? a : b);
+ }
+}
+
+/*!
+ * \brief Return the difference between two timestamps (to "minus" from).
+ *
+ * \note If both are zero (=infinity), KNOT_TIMEDIFF_MAX is returned.
+ */
+inline static knot_timediff_t knot_time_diff(knot_time_t to, knot_time_t from)
+{
+ if ((to && from) == 0) {
+ return (to > from ? KNOT_TIMEDIFF_MIN : KNOT_TIMEDIFF_MAX);
+ } else {
+ return (knot_timediff_t)to - (knot_timediff_t)from;
+ }
+}
+
+/*!
+ * \brief Add a time difference to timestamp.
+ */
+inline static knot_time_t knot_time_add(knot_time_t since, knot_timediff_t howlong)
+{
+ return (since != 0 ? since + howlong : since);
+}
+
+/*!
+ * \brief Convert uint32_t-encoded timestamp to knot_time_t.
+ *
+ * In RRSIG rdata, there are inception and expiration timestamps in uint32_t format.
+ * One shall use 'serial arithmetics' to decode them.
+ *
+ * \todo However it needs time(now) context which is slow to obtain, so we don't do it
+ * for now. Please fix this in next 100 years.
+ */
+inline static knot_time_t knot_time_from_u32(uint32_t u32time)
+{
+ return (knot_time_t)u32time;
+}
+
+/*!
+ * \brief Parse a text-formatted timestamp to knot_time_t using format specification.
+ *
+ * \param format The timestamp text format specification.
+ * \param timespec Text-formatted timestamp.
+ * \param time The parsed timestamp.
+ *
+ * The format specification basics:
+ * <format 1>|<format 2> - The pipe sign separates two time format specifications. Leftmost
+ * specification matching the timespec is used.
+ * '<a string>' - Matches exactly <a string> (not containing apostrophes) in timespec.
+ * # - Hashtag matches for a number in timespec, stands for either a UNIX timestamp,
+ * or, within a context of an unit, as a number of such units.
+ * Y, M, D, h, m, s - Matches a number, stands for a number of years, months, days, hours,
+ * minutes and seconds, respectively.
+ * +, - - The + and - signs declaring that following timespec is relative to "now".
+ * A single sign can be used to limit the timestamp being in future or in past,
+ * or both +- allow the timestamp to select any (just one) of them.
+ * U - Matches one of Y, M, D, h, m, s in the timespec standing for a time unit.
+ * u - Like U, but the unit in the timestamp is from: y, mo, d, h, mi, s.
+ *
+ * \retval -1 An error occurred, out_time has no sense.
+ * \return 0 OK, timestamp parsed successfully.
+ */
+int knot_time_parse(const char *format, const char *timespec, knot_time_t *time);
+
+/*!
+ * \brief Print the timestamp in specified format into a string buffer.
+ *
+ * \param format The timestamp text format specification.
+ * \param time The timestamp to be printed.
+ * \param dst The destination buffer pointer with text-formatted timestamp.
+ * \param dst_len The destination buffer length.
+ *
+ * \retval -1 An error occurred, the buffer may be filled with nonsense.
+ * \return 0 OK, timestamp printed successfully.
+ */
+int knot_time_print(knot_time_print_t format, knot_time_t time, char *dst, size_t dst_len);
diff --git a/src/contrib/tolower.h b/src/contrib/tolower.h
new file mode 100644
index 0000000..8f55182
--- /dev/null
+++ b/src/contrib/tolower.h
@@ -0,0 +1,51 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \brief Table for converting ASCII characters to lowercase.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+/*!
+ * \brief Converts binary character to lowercase.
+ *
+ * \param c Character code.
+ *
+ * \return \a c converted to lowercase (or \a c if not applicable).
+ */
+static inline uint8_t knot_tolower(uint8_t c) {
+ const uint8_t *tolower_table = (uint8_t *)
+ "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
+ "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
+ "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2A\x2B\x2C\x2D\x2E\x2F"
+ "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F"
+ "\x40\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6A\x6B\x6C\x6D\x6E\x6F"
+ "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7A\x5B\x5C\x5D\x5E\x5F"
+ "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6A\x6B\x6C\x6D\x6E\x6F"
+ "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7A\x7B\x7C\x7D\x7E\x7F"
+ "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F"
+ "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F"
+ "\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF"
+ "\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF"
+ "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF"
+ "\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF"
+ "\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF"
+ "\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF";
+
+ return tolower_table[c];
+}
diff --git a/src/contrib/trim.h b/src/contrib/trim.h
new file mode 100644
index 0000000..c1b83fa
--- /dev/null
+++ b/src/contrib/trim.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*!
+ * \brief Heap memory trimmer.
+ */
+
+#pragma once
+
+#ifdef HAVE_MALLOC_TRIM
+#include <malloc.h>
+#endif
+
+/*!
+ * \brief Trim excess heap memory.
+ */
+static inline void mem_trim(void)
+{
+#ifdef HAVE_MALLOC_TRIM
+ malloc_trim(0);
+#endif
+ return;
+}
diff --git a/src/contrib/ucw/LICENSE b/src/contrib/ucw/LICENSE
new file mode 100644
index 0000000..b463d57
--- /dev/null
+++ b/src/contrib/ucw/LICENSE
@@ -0,0 +1 @@
+../licenses/LGPL-2.0 \ No newline at end of file
diff --git a/src/contrib/ucw/array-sort.h b/src/contrib/ucw/array-sort.h
new file mode 100644
index 0000000..1ff1377
--- /dev/null
+++ b/src/contrib/ucw/array-sort.h
@@ -0,0 +1,195 @@
+/*
+ * UCW Library -- Universal Simple Array Sorter
+ *
+ * (c) 2003--2008 Martin Mares <mj@ucw.cz>
+ *
+ * This software may be freely distributed and used according to the terms
+ * of the GNU Lesser General Public License.
+ */
+
+#pragma once
+
+#include "contrib/macros.h"
+
+/*
+ * This is not a normal header file, it's a generator of sorting
+ * routines. Each time you include it with parameters set in the
+ * corresponding preprocessor macros, it generates an array sorter
+ * with the parameters given.
+ *
+ * You might wonder why the heck do we implement our own array sorter
+ * instead of using qsort(). The primary reason is that qsort handles
+ * only continuous arrays, but we need to sort array-like data structures
+ * where the only way to access elements is by using an indexing macro.
+ * Besides that, we are more than 2 times faster.
+ *
+ * So much for advocacy, there are the parameters (those marked with [*]
+ * are mandatory):
+ *
+ * ASORT_PREFIX(x) [*] add a name prefix (used on all global names
+ * defined by the sorter)
+ * ASORT_KEY_TYPE [*] data type of a single array entry key
+ * ASORT_ELT(i) returns the key of i-th element; if this macro is not
+ * defined, the function gets a pointer to an array to be sorted
+ * ASORT_LT(x,y) x < y for ASORT_KEY_TYPE (default: "x<y")
+ * ASORT_SWAP(i,j) swap i-th and j-th element (default: assume _ELT
+ * is an l-value and swap just the keys)
+ * ASORT_THRESHOLD threshold for switching between quicksort and insertsort
+ * ASORT_EXTRA_ARGS extra arguments for the sort function (they are always
+ * visible in all the macros supplied above), starts with comma
+ *
+ * After including this file, a function ASORT_PREFIX(sort)(unsigned array_size)
+ * or ASORT_PREFIX(sort)(ASORT_KEY_TYPE *array, unsigned array_size) [if ASORT_ELT
+ * is not defined] is declared and all parameter macros are automatically
+ * undef'd.
+ */
+
+#ifndef ASORT_LT
+#define ASORT_LT(x,y) ((x) < (y))
+#endif
+
+#ifndef ASORT_SWAP
+#define ASORT_SWAP(i,j) do { ASORT_KEY_TYPE tmp = ASORT_ELT(i); ASORT_ELT(i)=ASORT_ELT(j); ASORT_ELT(j)=tmp; } while (0)
+#endif
+
+#ifndef ASORT_THRESHOLD
+#define ASORT_THRESHOLD 8 /* Guesswork and experimentation */
+#endif
+
+#ifndef ASORT_EXTRA_ARGS
+#define ASORT_EXTRA_ARGS
+#endif
+
+#ifndef ASORT_ELT
+#define ASORT_ARRAY_ARG ASORT_KEY_TYPE *array,
+#define ASORT_ELT(i) array[i]
+#else
+#define ASORT_ARRAY_ARG
+#endif
+
+/**
+ * The generated sorting function. If `ASORT_ELT` macro is not provided, the
+ * @ASORT_ARRAY_ARG is equal to `ASORT_KEY_TYPE *array` and is the array to be
+ * sorted. If the macro is provided, this parameter is omitted. In that case,
+ * you can sort global variables or pass your structure by @ASORT_EXTRA_ARGS.
+ **/
+static void ASORT_PREFIX(sort)(ASORT_ARRAY_ARG unsigned array_size ASORT_EXTRA_ARGS)
+{
+ struct stk { int l, r; } stack[8*sizeof(unsigned)];
+ int l, r, left, right, m;
+ unsigned sp = 0;
+ ASORT_KEY_TYPE pivot;
+
+ if (array_size <= 1)
+ return;
+
+ /* QuickSort with optimizations a'la Sedgewick, but stop at ASORT_THRESHOLD */
+
+ left = 0;
+ right = array_size - 1;
+ for(;;)
+ {
+ l = left;
+ r = right;
+ m = (l+r)/2;
+ if (ASORT_LT(ASORT_ELT(m), ASORT_ELT(l)))
+ ASORT_SWAP(l,m);
+ if (ASORT_LT(ASORT_ELT(r), ASORT_ELT(m)))
+ {
+ ASORT_SWAP(m,r);
+ if (ASORT_LT(ASORT_ELT(m), ASORT_ELT(l)))
+ ASORT_SWAP(l,m);
+ }
+ pivot = ASORT_ELT(m);
+ do
+ {
+ while (ASORT_LT(ASORT_ELT(l), pivot))
+ l++;
+ while (ASORT_LT(pivot, ASORT_ELT(r)))
+ r--;
+ if (l < r)
+ {
+ ASORT_SWAP(l,r);
+ l++;
+ r--;
+ }
+ else if (l == r)
+ {
+ l++;
+ r--;
+ }
+ }
+ while (l <= r);
+ if ((r - left) >= ASORT_THRESHOLD && (right - l) >= ASORT_THRESHOLD)
+ {
+ /* Both partitions ok => push the larger one */
+ if ((r - left) > (right - l))
+ {
+ stack[sp].l = left;
+ stack[sp].r = r;
+ left = l;
+ }
+ else
+ {
+ stack[sp].l = l;
+ stack[sp].r = right;
+ right = r;
+ }
+ sp++;
+ }
+ else if ((r - left) >= ASORT_THRESHOLD)
+ {
+ /* Left partition OK, right undersize */
+ right = r;
+ }
+ else if ((right - l) >= ASORT_THRESHOLD)
+ {
+ /* Right partition OK, left undersize */
+ left = l;
+ }
+ else
+ {
+ /* Both partitions undersize => pop */
+ if (!sp)
+ break;
+ sp--;
+ left = stack[sp].l;
+ right = stack[sp].r;
+ }
+ }
+
+ /*
+ * We have a partially sorted array, finish by insertsort. Inspired
+ * by qsort() in GNU libc.
+ */
+
+ /* Find minimal element which will serve as a barrier */
+ r = MIN(array_size, ASORT_THRESHOLD);
+ m = 0;
+ for (l=1; l<r; l++)
+ if (ASORT_LT(ASORT_ELT(l),ASORT_ELT(m)))
+ m = l;
+ ASORT_SWAP(0,m);
+
+ /* Insertion sort */
+ for (m=1; m<(int)array_size; m++)
+ {
+ l=m;
+ while (ASORT_LT(ASORT_ELT(m),ASORT_ELT(l-1)))
+ l--;
+ while (l < m)
+ {
+ ASORT_SWAP(l,m);
+ l++;
+ }
+ }
+}
+
+#undef ASORT_PREFIX
+#undef ASORT_KEY_TYPE
+#undef ASORT_ELT
+#undef ASORT_LT
+#undef ASORT_SWAP
+#undef ASORT_THRESHOLD
+#undef ASORT_EXTRA_ARGS
+#undef ASORT_ARRAY_ARG
diff --git a/src/contrib/ucw/binsearch.h b/src/contrib/ucw/binsearch.h
new file mode 100644
index 0000000..b791d39
--- /dev/null
+++ b/src/contrib/ucw/binsearch.h
@@ -0,0 +1,50 @@
+/*
+ * UCW Library -- Generic Binary Search
+ *
+ * (c) 2005 Martin Mares <mj@ucw.cz>
+ *
+ * This software may be freely distributed and used according to the terms
+ * of the GNU Lesser General Public License.
+ */
+
+#pragma once
+
+/***
+ * [[defs]]
+ * Definitions
+ * -----------
+ ***/
+
+/**
+ * Find the first element not lower than \p x in the sorted array \p ary of \p N elements (non-decreasing order).
+ * Returns the index of the found element or \p N if no exists. Uses `ary_lt_x(ary,i,x)` to compare the i'th element with \p x.
+ * The time complexity is `O(log(N))`.
+ **/
+#define BIN_SEARCH_FIRST_GE_CMP(ary, N, ary_lt_x, x, ...) ({ \
+ unsigned l = 0, r = (N); \
+ while (l < r) \
+ { \
+ unsigned m = (l+r)/2; \
+ if (ary_lt_x(ary, m, x, __VA_ARGS__)) \
+ l = m+1; \
+ else \
+ r = m; \
+ } \
+ l; \
+})
+
+/**
+ * The default comparison macro for \ref BIN_SEARCH_FIRST_GE_CMP().
+ **/
+#define ARY_LT_NUM(ary,i,x) (ary)[i] < (x)
+
+/**
+ * Same as \ref BIN_SEARCH_FIRST_GE_CMP(), but uses the default `<` operator for comparisons.
+ **/
+#define BIN_SEARCH_FIRST_GE(ary,N,x) BIN_SEARCH_FIRST_GE_CMP(ary,N,ARY_LT_NUM,x)
+
+/**
+ * Search the sorted array \p ary of \p N elements (non-decreasing) for the first occurrence of \p x.
+ * Returns the index or -1 if no such element exists. Uses the `<` operator for comparisons.
+ **/
+#define BIN_SEARCH_EQ(ary,N,x) ({ int i = BIN_SEARCH_FIRST_GE(ary,N,x); if (i >= (N) || (ary)[i] != (x)) i=-1; i; })
diff --git a/src/contrib/ucw/heap.c b/src/contrib/ucw/heap.c
new file mode 100644
index 0000000..d7ed18e
--- /dev/null
+++ b/src/contrib/ucw/heap.c
@@ -0,0 +1,166 @@
+/*
+ * Binary heap
+ *
+ * (c) 2012 Ondrej Filip <feela@network.cz>
+ *
+ * This software may be freely distributed and used according to the terms
+ * of the GNU Lesser General Public License.
+ */
+
+/***
+ * Introduction
+ * ------------
+ *
+ * Binary heap is a simple data structure, which for example supports efficient insertions, deletions
+ * and access to the minimal inserted item. We define several macros for such operations.
+ * Note that because of simplicity of heaps, we have decided to define direct macros instead
+ * of a <<generic:,macro generator>> as for several other data structures in the Libucw.
+ *
+ * A heap is represented by a number of elements and by an array of values. Beware that we
+ * index this array from one, not from zero as do the standard C arrays.
+ *
+ * Most macros use these parameters:
+ *
+ * - @num - a variable (signed or unsigned integer) with the number of elements
+ * - @heap - a C array of type @type; the heap is stored in `heap[1] .. heap[num]`; `heap[0]` is unused
+ *
+ * A valid heap must follow these rules:
+ *
+ * - `num >= 0`
+ * - `heap[i] >= heap[i / 2]` for each `i` in `[2, num]`
+ *
+ * The first element `heap[1]` is always lower or equal to all other elements.
+ ***/
+
+#include <string.h>
+#include <stdlib.h>
+#include "contrib/ucw/heap.h"
+
+static inline void heap_swap(heap_val_t **e1, heap_val_t **e2)
+{
+ if (e1 == e2) return; /* Stack tmp should be faster than tmpelem. */
+ heap_val_t *tmp = *e1; /* Even faster than 2-XOR nowadays. */
+ *e1 = *e2;
+ *e2 = tmp;
+ int pos = (*e1)->pos;
+ (*e1)->pos = (*e2)->pos;
+ (*e2)->pos = pos;
+}
+
+int heap_init(struct heap *h, int (*cmp)(void *, void *), int init_size)
+{
+ int isize = init_size ? init_size : INITIAL_HEAP_SIZE;
+
+ h->num = 0;
+ h->max_size = isize;
+ h->cmp = cmp;
+ h->data = malloc((isize + 1) * sizeof(heap_val_t*)); /* Temp element unused. */
+
+ return h->data ? 1 : 0;
+}
+
+void heap_deinit(struct heap *h)
+{
+ free(h->data);
+ memset(h, 0, sizeof(*h));
+}
+
+static inline void _heap_bubble_down(struct heap *h, int e)
+{
+ int e1;
+ for (;;)
+ {
+ e1 = 2*e;
+ if(e1 > h->num) break;
+ if((h->cmp(*HELEMENT(h, e),*HELEMENT(h,e1)) < 0) && (e1 == h->num || (h->cmp(*HELEMENT(h, e),*HELEMENT(h,e1+1)) < 0))) break;
+ if((e1 != h->num) && (h->cmp(*HELEMENT(h, e1+1), *HELEMENT(h,e1)) < 0)) e1++;
+ heap_swap(HELEMENT(h,e),HELEMENT(h,e1));
+ e = e1;
+ }
+}
+
+static inline void _heap_bubble_up(struct heap *h, int e)
+{
+ int e1;
+ while (e > 1)
+ {
+ e1 = e/2;
+ if(h->cmp(*HELEMENT(h, e1),*HELEMENT(h,e)) < 0) break;
+ heap_swap(HELEMENT(h,e),HELEMENT(h,e1));
+ e = e1;
+ }
+
+}
+
+static void heap_increase(struct heap *h, int pos, heap_val_t *e)
+{
+ *HELEMENT(h, pos) = e;
+ e->pos = pos;
+ _heap_bubble_down(h, pos);
+}
+
+static void heap_decrease(struct heap *h, int pos, heap_val_t *e)
+{
+ *HELEMENT(h, pos) = e;
+ e->pos = pos;
+ _heap_bubble_up(h, pos);
+}
+
+void heap_replace(struct heap *h, int pos, heap_val_t *e)
+{
+ if (h->cmp(*HELEMENT(h, pos),e) < 0) {
+ heap_increase(h, pos, e);
+ } else {
+ heap_decrease(h, pos, e);
+ }
+}
+
+void heap_delmin(struct heap *h)
+{
+ if(h->num == 0) return;
+ if(h->num > 1)
+ {
+ heap_swap(HHEAD(h),HELEMENT(h,h->num));
+ }
+ (*HELEMENT(h, h->num))->pos = 0;
+ --h->num;
+ _heap_bubble_down(h, 1);
+}
+
+int heap_insert(struct heap *h, heap_val_t *e)
+{
+ if(h->num == h->max_size)
+ {
+ h->max_size = h->max_size * HEAP_INCREASE_STEP;
+ h->data = realloc(h->data, (h->max_size + 1) * sizeof(heap_val_t*));
+ if (!h->data) {
+ return 0;
+ }
+ }
+
+ h->num++;
+ *HELEMENT(h,h->num) = e;
+ e->pos = h->num;
+ _heap_bubble_up(h,h->num);
+ return 1;
+}
+
+int heap_find(struct heap *h, heap_val_t *elm)
+{
+ return ((struct heap_val *) elm)->pos;
+}
+
+void heap_delete(struct heap *h, int e)
+{
+ heap_swap(HELEMENT(h, e), HELEMENT(h, h->num));
+ (*HELEMENT(h, h->num))->pos = 0;
+ h->num--;
+ if(h->cmp(*HELEMENT(h, e), *HELEMENT(h, h->num + 1)) < 0) _heap_bubble_up(h, e);
+ else _heap_bubble_down(h, e);
+
+ if ((h->num > INITIAL_HEAP_SIZE) && (h->num < h->max_size / HEAP_DECREASE_THRESHOLD))
+ {
+ h->max_size = h->max_size / HEAP_INCREASE_STEP;
+ h->data = realloc(h->data, (h->max_size + 1) * sizeof(heap_val_t*));
+ }
+}
diff --git a/src/contrib/ucw/heap.h b/src/contrib/ucw/heap.h
new file mode 100644
index 0000000..7419b34
--- /dev/null
+++ b/src/contrib/ucw/heap.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+struct heap_val {
+ int pos;
+};
+
+typedef struct heap_val heap_val_t;
+
+struct heap {
+ int num; /* Number of elements */
+ int max_size; /* Size of allocated memory */
+ int (*cmp)(void *, void *);
+ heap_val_t **data;
+}; /* Array follows */
+
+#define INITIAL_HEAP_SIZE 512 /* initial heap size */
+#define HEAP_INCREASE_STEP 2 /* multiplier for each inflation, keep conservative */
+#define HEAP_DECREASE_THRESHOLD 2 /* threshold for deflation, keep conservative */
+#define HELEMENT(h,num) ((h)->data + (num))
+#define HHEAD(h) HELEMENT((h), 1)
+#define EMPTY_HEAP(h) ((h)->num == 0) /* h->num == 0 */
+
+int heap_init(struct heap *, int (*cmp)(void *, void *), int);
+void heap_deinit(struct heap *);
+
+void heap_delmin(struct heap *);
+int heap_insert(struct heap *, heap_val_t *);
+int heap_find(struct heap *, heap_val_t *);
+void heap_delete(struct heap *, int);
+void heap_replace(struct heap *h, int pos, heap_val_t *);
diff --git a/src/contrib/ucw/lists.c b/src/contrib/ucw/lists.c
new file mode 100644
index 0000000..8a9fa96
--- /dev/null
+++ b/src/contrib/ucw/lists.c
@@ -0,0 +1,235 @@
+/*
+ * BIRD Library -- Linked Lists
+ *
+ * (c) 1998 Martin Mares <mj@ucw.cz>
+ * (c) 2015, 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+/**
+ * DOC: Linked lists
+ *
+ * The BIRD library provides a set of functions for operating on linked
+ * lists. The lists are internally represented as standard doubly linked
+ * lists with synthetic head and tail which makes all the basic operations
+ * run in constant time and contain no extra end-of-list checks. Each list
+ * is described by a &list structure, nodes can have any format as long
+ * as they start with a &node structure. If you want your nodes to belong
+ * to multiple lists at once, you can embed multiple &node structures in them
+ * and use the SKIP_BACK() macro to calculate a pointer to the start of the
+ * structure from a &node pointer, but beware of obscurity.
+ *
+ * There also exist safe linked lists (&slist, &snode and all functions
+ * being prefixed with |s_|) which support asynchronous walking very
+ * similar to that used in the &fib structure.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "contrib/ucw/lists.h"
+#include "contrib/mempattern.h"
+
+/**
+ * add_tail - append a node to a list
+ * \p l: linked list
+ * \p n: list node
+ *
+ * add_tail() takes a node \p n and appends it at the end of the list \p l.
+ */
+void
+add_tail(list_t *l, node_t *n)
+{
+ node_t *z = l->tail;
+
+ n->next = (node_t *) &l->null;
+ n->prev = z;
+ z->next = n;
+ l->tail = n;
+}
+
+/**
+ * add_head - prepend a node to a list
+ * \p l: linked list
+ * \p n: list node
+ *
+ * add_head() takes a node \p n and prepends it at the start of the list \p l.
+ */
+void
+add_head(list_t *l, node_t *n)
+{
+ node_t *z = l->head;
+
+ n->next = z;
+ n->prev = (node_t *) &l->head;
+ z->prev = n;
+ l->head = n;
+}
+
+/**
+ * insert_node - insert a node to a list
+ * \p n: a new list node
+ * \p after: a node of a list
+ *
+ * Inserts a node \p n to a linked list after an already inserted
+ * node \p after.
+ */
+void
+insert_node(node_t *n, node_t *after)
+{
+ node_t *z = after->next;
+
+ n->next = z;
+ n->prev = after;
+ after->next = n;
+ z->prev = n;
+}
+
+/**
+ * rem_node - remove a node from a list
+ * \p n: node to be removed
+ *
+ * Removes a node \p n from the list it's linked in.
+ */
+void
+rem_node(node_t *n)
+{
+ node_t *z = n->prev;
+ node_t *x = n->next;
+
+ z->next = x;
+ x->prev = z;
+ n->prev = 0;
+ n->next = 0;
+}
+
+/**
+ * init_list - create an empty list
+ * \p l: list
+ *
+ * init_list() takes a &list structure and initializes its
+ * fields, so that it represents an empty list.
+ */
+void
+init_list(list_t *l)
+{
+ l->head = (node_t *) &l->null;
+ l->null = NULL;
+ l->tail = (node_t *) &l->head;
+}
+
+/**
+ * add_tail_list - concatenate two lists
+ * \p to: destination list
+ * \p l: source list
+ *
+ * This function appends all elements of the list \p l to
+ * the list \p to in constant time.
+ */
+void
+add_tail_list(list_t *to, list_t *l)
+{
+ node_t *p = to->tail;
+ node_t *q = l->head;
+
+ p->next = q;
+ q->prev = p;
+ q = l->tail;
+ q->next = (node_t *) &to->null;
+ to->tail = q;
+}
+
+/**
+ * list_dup - duplicate list
+ * \p to: destination list
+ * \p l: source list
+ *
+ * This function duplicates all elements of the list \p l to
+ * the list \p to in linear time.
+ *
+ * This function only works with a homogenous item size.
+ */
+void list_dup(list_t *dst, list_t *src, size_t itemsz)
+{
+ node_t *n = 0;
+ WALK_LIST(n, *src) {
+ node_t *i = malloc(itemsz);
+ memcpy(i, n, itemsz);
+ add_tail(dst, i);
+ }
+}
+
+/**
+ * list_size - gets number of nodes
+ * \p l: list
+ *
+ * This function counts nodes in list \p l and returns this number.
+ */
+size_t list_size(const list_t *l)
+{
+ size_t count = 0;
+
+ node_t *n = 0;
+ WALK_LIST(n, *l) {
+ count++;
+ }
+
+ return count;
+}
+
+/**
+ * ptrlist_add - add pointer to pointer list
+ * \p to: destination list
+ * \p val: added pointer
+ * \p mm: memory context
+ */
+ptrnode_t *ptrlist_add(list_t *to, void *val, knot_mm_t *mm)
+{
+ ptrnode_t *node = mm_alloc(mm , sizeof(ptrnode_t));
+ if (node == NULL) {
+ return NULL;
+ } else {
+ node->d = val;
+ }
+ add_tail(to, &node->n);
+ return node;
+}
+
+/**
+ * ptrlist_free - free all nodes in pointer list
+ * \p list: list nodes
+ * \p mm: memory context
+ */
+void ptrlist_free(list_t *list, knot_mm_t *mm)
+{
+ node_t *n = NULL, *nxt = NULL;
+ WALK_LIST_DELSAFE(n, nxt, *list) {
+ mm_free(mm, n);
+ }
+ init_list(list);
+}
+
+/**
+ * ptrlist_rem - remove pointer node
+ * \p val: pointer to remove
+ * \p mm: memory context
+ */
+void ptrlist_rem(ptrnode_t *node, knot_mm_t *mm)
+{
+ rem_node(&node->n);
+ mm_free(mm, node);
+}
+
+/**
+ * ptrlist_deep_free - free all nodes incl referenced data
+ * \p list: list nodes
+ * \p mm: memory context
+ */
+void ptrlist_deep_free(list_t *l, knot_mm_t *mm)
+{
+ ptrnode_t *n;
+ WALK_LIST(n, *l) {
+ mm_free(mm, n->d);
+ }
+ ptrlist_free(l, mm);
+}
diff --git a/src/contrib/ucw/lists.h b/src/contrib/ucw/lists.h
new file mode 100644
index 0000000..922e152
--- /dev/null
+++ b/src/contrib/ucw/lists.h
@@ -0,0 +1,84 @@
+/*
+ * BIRD Library -- Linked Lists
+ *
+ * (c) 1998 Martin Mares <mj@ucw.cz>
+ * (c) 2015, 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#pragma once
+
+/*
+ * I admit the list structure is very tricky and also somewhat awkward,
+ * but it's both efficient and easy to manipulate once one understands the
+ * basic trick: The list head always contains two synthetic nodes which are
+ * always present in the list: the head and the tail. But as the `next'
+ * entry of the tail and the `prev' entry of the head are both NULL, the
+ * nodes can overlap each other:
+ *
+ * head head_node.next
+ * null head_node.prev tail_node.next
+ * tail tail_node.prev
+ */
+
+#include <string.h>
+#include "libknot/mm_ctx.h"
+
+typedef struct node {
+ struct node *next, *prev;
+} node_t;
+
+typedef struct list { /* In fact two overlayed nodes */
+ struct node *head, *null, *tail;
+} list_t;
+
+#define NODE (node_t *)
+#define HEAD(list) ((void *)((list).head))
+#define TAIL(list) ((void *)((list).tail))
+#define WALK_LIST(n,list) for(n=HEAD(list);(NODE (n))->next; \
+ n=(void *)((NODE (n))->next))
+#define WALK_LIST_DELSAFE(n,nxt,list) \
+ for(n=HEAD(list); (nxt=(void *)((NODE (n))->next)); n=(void *) nxt)
+/* WALK_LIST_FIRST supposes that called code removes each processed node */
+#define WALK_LIST_FIRST(n,list) \
+ while(n=HEAD(list), (NODE (n))->next)
+#define WALK_LIST_BACKWARDS(n,list) for(n=TAIL(list);(NODE (n))->prev; \
+ n=(void *)((NODE (n))->prev))
+#define WALK_LIST_BACKWARDS_DELSAFE(n,prv,list) \
+ for(n=TAIL(list); prv=(void *)((NODE (n))->prev); n=(void *) prv)
+
+#define EMPTY_LIST(list) (!(list).head->next)
+
+/*! \brief Free every node in the list. */
+#define WALK_LIST_FREE(list) \
+ do { \
+ node_t *n=0,*nxt=0; \
+ WALK_LIST_DELSAFE(n,nxt,list) { \
+ free(n); \
+ } \
+ init_list(&list); \
+ } while(0)
+
+void add_tail(list_t *, node_t *);
+void add_head(list_t *, node_t *);
+void rem_node(node_t *);
+void add_tail_list(list_t *, list_t *);
+void init_list(list_t *);
+void insert_node(node_t *, node_t *);
+void list_dup(list_t *dst, list_t *src, size_t itemsz);
+size_t list_size(const list_t *);
+
+/*!
+ * \brief Generic pointer list implementation.
+ */
+typedef struct ptrnode {
+ node_t n;
+ void *d;
+} ptrnode_t;
+
+ptrnode_t *ptrlist_add(list_t *, void *, knot_mm_t *);
+void ptrlist_free(list_t *, knot_mm_t *);
+void ptrlist_rem(ptrnode_t *node, knot_mm_t *mm);
+void ptrlist_deep_free(list_t *, knot_mm_t *);
+
diff --git a/src/contrib/ucw/mempool.c b/src/contrib/ucw/mempool.c
new file mode 100644
index 0000000..bc41345
--- /dev/null
+++ b/src/contrib/ucw/mempool.c
@@ -0,0 +1,322 @@
+/*
+ * UCW Library -- Memory Pools (One-Time Allocation)
+ *
+ * (c) 1997--2001 Martin Mares <mj@ucw.cz>
+ * (c) 2007 Pavel Charvat <pchar@ucw.cz>
+ * (c) 2015, 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+ *
+ * This software may be freely distributed and used according to the terms
+ * of the GNU Lesser General Public License.
+ */
+
+#undef LOCAL_DEBUG
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include "contrib/asan.h"
+#include "contrib/macros.h"
+#include "contrib/ucw/mempool.h"
+
+/** \todo This shouldn't be precalculated, but computed on load. */
+#define CPU_PAGE_SIZE 4096
+
+/** Align an integer \p s to the nearest higher multiple of \p a (which should be a power of two) **/
+#define ALIGN_TO(s, a) (((s)+a-1)&~(a-1))
+#define MP_CHUNK_TAIL ALIGN_TO(sizeof(struct mempool_chunk), CPU_STRUCT_ALIGN)
+#define MP_SIZE_MAX (~0U - MP_CHUNK_TAIL - CPU_PAGE_SIZE)
+#define DBG(s, ...)
+
+/** \note Imported MMAP backend from bigalloc.c */
+#define CONFIG_UCW_POOL_IS_MMAP
+#ifdef CONFIG_UCW_POOL_IS_MMAP
+#include <sys/mman.h>
+static void *
+page_alloc(uint64_t len)
+{
+ if (!len) {
+ return NULL;
+ }
+ if (len > SIZE_MAX) {
+ return NULL;
+ }
+ assert(!(len & (CPU_PAGE_SIZE-1)));
+ uint8_t *p = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+ if (p == (uint8_t*) MAP_FAILED) {
+ return NULL;
+ }
+ return p;
+}
+
+static void
+page_free(void *start, uint64_t len)
+{
+ assert(!(len & (CPU_PAGE_SIZE-1)));
+ assert(!((uintptr_t) start & (CPU_PAGE_SIZE-1)));
+ munmap(start, len);
+}
+#endif
+
+struct mempool_chunk {
+ struct mempool_chunk *next;
+ unsigned size;
+};
+
+static unsigned
+mp_align_size(unsigned size)
+{
+#ifdef CONFIG_UCW_POOL_IS_MMAP
+ return ALIGN_TO(size + MP_CHUNK_TAIL, CPU_PAGE_SIZE) - MP_CHUNK_TAIL;
+#else
+ return ALIGN_TO(size, CPU_STRUCT_ALIGN);
+#endif
+}
+
+void
+mp_init(struct mempool *pool, unsigned chunk_size)
+{
+ chunk_size = mp_align_size(MAX(sizeof(struct mempool), chunk_size));
+ *pool = (struct mempool) {
+ .chunk_size = chunk_size,
+ .threshold = chunk_size >> 1,
+ .last_big = &pool->last_big
+ };
+}
+
+static void *
+mp_new_big_chunk(unsigned size)
+{
+ uint8_t *data = malloc(size + MP_CHUNK_TAIL);
+ if (!data) {
+ return NULL;
+ }
+ ASAN_POISON_MEMORY_REGION(data, size);
+ struct mempool_chunk *chunk = (struct mempool_chunk *)(data + size);
+ chunk->size = size;
+ return chunk;
+}
+
+static void
+mp_free_big_chunk(struct mempool_chunk *chunk)
+{
+ void *ptr = (uint8_t *)chunk - chunk->size;
+ ASAN_UNPOISON_MEMORY_REGION(ptr, chunk->size);
+ free(ptr);
+}
+
+static void *
+mp_new_chunk(unsigned size)
+{
+#ifdef CONFIG_UCW_POOL_IS_MMAP
+ uint8_t *data = page_alloc(size + MP_CHUNK_TAIL);
+ if (!data) {
+ return NULL;
+ }
+ ASAN_POISON_MEMORY_REGION(data, size);
+ struct mempool_chunk *chunk = (struct mempool_chunk *)(data + size);
+ chunk->size = size;
+ return chunk;
+#else
+ return mp_new_big_chunk(size);
+#endif
+}
+
+static void
+mp_free_chunk(struct mempool_chunk *chunk)
+{
+#ifdef CONFIG_UCW_POOL_IS_MMAP
+ uint8_t *data = (uint8_t *)chunk - chunk->size;
+ ASAN_UNPOISON_MEMORY_REGION(data, chunk->size);
+ page_free(data, chunk->size + MP_CHUNK_TAIL);
+#else
+ mp_free_big_chunk(chunk);
+#endif
+}
+
+struct mempool *
+mp_new(unsigned chunk_size)
+{
+ chunk_size = mp_align_size(MAX(sizeof(struct mempool), chunk_size));
+ struct mempool_chunk *chunk = mp_new_chunk(chunk_size);
+ struct mempool *pool = (void *)chunk - chunk_size;
+ ASAN_UNPOISON_MEMORY_REGION(pool, sizeof(*pool));
+ DBG("Creating mempool %p with %u bytes long chunks", pool, chunk_size);
+ chunk->next = NULL;
+ ASAN_POISON_MEMORY_REGION(chunk, sizeof(struct mempool_chunk));
+ *pool = (struct mempool) {
+ .state = { .free = { chunk_size - sizeof(*pool) }, .last = { chunk } },
+ .chunk_size = chunk_size,
+ .threshold = chunk_size >> 1,
+ .last_big = &pool->last_big
+ };
+ return pool;
+}
+
+static void
+mp_free_chain(struct mempool_chunk *chunk)
+{
+ while (chunk) {
+ ASAN_UNPOISON_MEMORY_REGION(chunk, sizeof(struct mempool_chunk));
+ struct mempool_chunk *next = chunk->next;
+ mp_free_chunk(chunk);
+ chunk = next;
+ }
+}
+
+static void
+mp_free_big_chain(struct mempool_chunk *chunk)
+{
+ while (chunk) {
+ ASAN_UNPOISON_MEMORY_REGION(chunk, sizeof(struct mempool_chunk));
+ struct mempool_chunk *next = chunk->next;
+ mp_free_big_chunk(chunk);
+ chunk = next;
+ }
+}
+
+void
+mp_delete(struct mempool *pool)
+{
+ if (pool == NULL) {
+ return;
+ }
+ DBG("Deleting mempool %p", pool);
+ mp_free_big_chain(pool->state.last[1]);
+ mp_free_chain(pool->unused);
+ mp_free_chain(pool->state.last[0]); // can contain the mempool structure
+}
+
+void
+mp_flush(struct mempool *pool)
+{
+ mp_free_big_chain(pool->state.last[1]);
+ struct mempool_chunk *chunk = pool->state.last[0], *next;
+ while (chunk) {
+ ASAN_UNPOISON_MEMORY_REGION(chunk, sizeof(struct mempool_chunk));
+ if ((uint8_t *)chunk - chunk->size == (uint8_t *)pool) {
+ break;
+ }
+ next = chunk->next;
+ chunk->next = pool->unused;
+ ASAN_POISON_MEMORY_REGION(chunk, sizeof(struct mempool_chunk));
+ pool->unused = chunk;
+ chunk = next;
+ }
+ pool->state.last[0] = chunk;
+ if (chunk) {
+ pool->state.free[0] = chunk->size - sizeof(*pool);
+ ASAN_POISON_MEMORY_REGION(chunk, sizeof(struct mempool_chunk));
+ } else {
+ pool->state.free[0] = 0;
+ }
+ pool->state.last[1] = NULL;
+ pool->state.free[1] = 0;
+ pool->last_big = &pool->last_big;
+}
+
+static void
+mp_stats_chain(struct mempool_chunk *chunk, struct mempool_stats *stats, unsigned idx)
+{
+ struct mempool_chunk *next;
+ while (chunk) {
+ ASAN_UNPOISON_MEMORY_REGION(chunk, sizeof(struct mempool_chunk));
+ stats->chain_size[idx] += chunk->size + sizeof(*chunk);
+ stats->chain_count[idx]++;
+ next = chunk->next;
+ ASAN_POISON_MEMORY_REGION(chunk, sizeof(struct mempool_chunk));
+ chunk = next;
+ }
+ stats->total_size += stats->chain_size[idx];
+}
+
+void
+mp_stats(struct mempool *pool, struct mempool_stats *stats)
+{
+ bzero(stats, sizeof(*stats));
+ mp_stats_chain(pool->state.last[0], stats, 0);
+ mp_stats_chain(pool->state.last[1], stats, 1);
+ mp_stats_chain(pool->unused, stats, 2);
+}
+
+uint64_t
+mp_total_size(struct mempool *pool)
+{
+ struct mempool_stats stats;
+ mp_stats(pool, &stats);
+ return stats.total_size;
+}
+
+static void *
+mp_alloc_internal(struct mempool *pool, unsigned size)
+{
+ struct mempool_chunk *chunk;
+ if (size <= pool->threshold) {
+ pool->idx = 0;
+ if (pool->unused) {
+ chunk = pool->unused;
+ ASAN_UNPOISON_MEMORY_REGION(chunk, sizeof(struct mempool_chunk));
+ pool->unused = chunk->next;
+ } else {
+ chunk = mp_new_chunk(pool->chunk_size);
+ }
+ chunk->next = pool->state.last[0];
+ ASAN_POISON_MEMORY_REGION(chunk, sizeof(struct mempool_chunk));
+ pool->state.last[0] = chunk;
+ pool->state.free[0] = pool->chunk_size - size;
+ return (uint8_t *)chunk - pool->chunk_size;
+ } else if (size <= MP_SIZE_MAX) {
+ pool->idx = 1;
+ unsigned aligned = ALIGN_TO(size, CPU_STRUCT_ALIGN);
+ chunk = mp_new_big_chunk(aligned);
+ if (!chunk) {
+ return NULL;
+ }
+ chunk->next = pool->state.last[1];
+ ASAN_POISON_MEMORY_REGION(chunk, sizeof(struct mempool_chunk));
+ pool->state.last[1] = chunk;
+ pool->state.free[1] = aligned - size;
+ return pool->last_big = (uint8_t *)chunk - aligned;
+ } else {
+ fprintf(stderr, "Cannot allocate %u bytes from a mempool", size);
+ assert(0);
+ return NULL;
+ }
+}
+
+void *
+mp_alloc(struct mempool *pool, unsigned size)
+{
+ unsigned avail = pool->state.free[0] & ~(CPU_STRUCT_ALIGN - 1);
+ void *ptr = NULL;
+ if (size <= avail) {
+ pool->state.free[0] = avail - size;
+ ptr = (uint8_t*)pool->state.last[0] - avail;
+ } else {
+ ptr = mp_alloc_internal(pool, size);
+ }
+ ASAN_UNPOISON_MEMORY_REGION(ptr, size);
+ return ptr;
+}
+
+void *
+mp_alloc_noalign(struct mempool *pool, unsigned size)
+{
+ void *ptr = NULL;
+ if (size <= pool->state.free[0]) {
+ ptr = (uint8_t*)pool->state.last[0] - pool->state.free[0];
+ pool->state.free[0] -= size;
+ } else {
+ ptr = mp_alloc_internal(pool, size);
+ }
+ ASAN_UNPOISON_MEMORY_REGION(ptr, size);
+ return ptr;
+}
+
+void *
+mp_alloc_zero(struct mempool *pool, unsigned size)
+{
+ void *ptr = mp_alloc(pool, size);
+ bzero(ptr, size);
+ return ptr;
+}
diff --git a/src/contrib/ucw/mempool.h b/src/contrib/ucw/mempool.h
new file mode 100644
index 0000000..c5a4fa8
--- /dev/null
+++ b/src/contrib/ucw/mempool.h
@@ -0,0 +1,124 @@
+/*
+ * UCW Library -- Memory Pools
+ *
+ * (c) 1997--2005 Martin Mares <mj@ucw.cz>
+ * (c) 2007 Pavel Charvat <pchar@ucw.cz>
+ * (c) 2015, 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+ *
+ * This software may be freely distributed and used according to the terms
+ * of the GNU Lesser General Public License.
+ */
+
+#pragma once
+
+#include <string.h>
+#include <stdint.h>
+
+#define CPU_STRUCT_ALIGN (sizeof(void*))
+
+/***
+ * [[defs]]
+ * Definitions
+ * -----------
+ ***/
+
+/**
+ * Memory pool state (see mp_push(), ...).
+ * You should use this one as an opaque handle only, the insides are internal.
+ **/
+struct mempool_state {
+ unsigned free[2];
+ void *last[2];
+};
+
+/**
+ * Memory pool.
+ * You should use this one as an opaque handle only, the insides are internal.
+ **/
+struct mempool {
+ struct mempool_state state;
+ void *unused, *last_big;
+ unsigned chunk_size, threshold, idx;
+};
+
+struct mempool_stats { /** Mempool statistics. See mp_stats(). **/
+ uint64_t total_size; /** Real allocated size in bytes. */
+ unsigned chain_count[3]; /** Number of allocated chunks in small/big/unused chains. */
+ unsigned chain_size[3]; /** Size of allocated chunks in small/big/unused chains. */
+};
+
+/***
+ * [[basic]]
+ * Basic manipulation
+ * ------------------
+ ***/
+
+/**
+ * Initialize a given mempool structure.
+ * \p chunk_size must be in the interval `[1, UINT_MAX / 2]`.
+ * It will allocate memory by this large chunks and take
+ * memory to satisfy requests from them.
+ *
+ * Memory pools can be treated as <<trans:respools,resources>>, see <<trans:res_mempool()>>.
+ **/
+void mp_init(struct mempool *pool, unsigned chunk_size);
+
+/**
+ * Allocate and initialize a new memory pool.
+ * See \ref mp_init() for \p chunk_size limitations.
+ *
+ * The new mempool structure is allocated on the new mempool.
+ *
+ * Memory pools can be treated as <<trans:respools,resources>>, see <<trans:res_mempool()>>.
+ **/
+struct mempool *mp_new(unsigned chunk_size);
+
+/**
+ * Cleanup mempool initialized by mp_init or mp_new.
+ * Frees all the memory allocated by this mempool and,
+ * if created by \ref mp_new(), the \p pool itself.
+ **/
+void mp_delete(struct mempool *pool);
+
+/**
+ * Frees all data on a memory pool, but leaves it working.
+ * It can keep some of the chunks allocated to serve
+ * further allocation requests. Leaves the \p pool alive,
+ * even if it was created with \ref mp_new().
+ **/
+void mp_flush(struct mempool *pool);
+
+/**
+ * Compute some statistics for debug purposes.
+ * See the definition of the <<struct_mempool_stats,mempool_stats structure>>.
+ **/
+void mp_stats(struct mempool *pool, struct mempool_stats *stats);
+uint64_t mp_total_size(struct mempool *pool); /** How many bytes were allocated by the pool. **/
+
+/***
+ * [[alloc]]
+ * Allocation routines
+ * -------------------
+ ***/
+
+/**
+ * The function allocates new \p size bytes on a given memory pool.
+ * If the \p size is zero, the resulting pointer is undefined,
+ * but it may be safely reallocated or used as the parameter
+ * to other functions below.
+ *
+ * The resulting pointer is always aligned to a multiple of
+ * `CPU_STRUCT_ALIGN` bytes and this condition remains true also
+ * after future reallocations.
+ **/
+void *mp_alloc(struct mempool *pool, unsigned size);
+
+/**
+ * The same as \ref mp_alloc(), but the result may be unaligned.
+ **/
+void *mp_alloc_noalign(struct mempool *pool, unsigned size);
+
+/**
+ * The same as \ref mp_alloc(), but fills the newly allocated memory with zeroes.
+ **/
+void *mp_alloc_zero(struct mempool *pool, unsigned size);
diff --git a/src/contrib/wire_ctx.h b/src/contrib/wire_ctx.h
new file mode 100644
index 0000000..25ff143
--- /dev/null
+++ b/src/contrib/wire_ctx.h
@@ -0,0 +1,361 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "libknot/endian.h"
+#include "libknot/errcode.h"
+
+/*!
+ * \brief Struct to keep the wire context.
+ */
+typedef struct wire_ctx {
+ size_t size;
+ uint8_t *wire;
+ uint8_t *position;
+ int error;
+ bool readonly;
+} wire_ctx_t;
+
+/*!
+ * \brief Initialize wire context.
+ */
+static inline wire_ctx_t wire_ctx_init(uint8_t *data, size_t size)
+{
+ assert(data);
+
+ wire_ctx_t result = {
+ .size = size,
+ .wire = data,
+ .position = data,
+ .error = KNOT_EOK,
+ .readonly = false
+ };
+
+ return result;
+}
+
+/*!
+ * \brief Initialize read only wire context.
+ *
+ * \note No write is performed, and error is set to KNOT_EACCES.
+ *
+ */
+static inline wire_ctx_t wire_ctx_init_const(const uint8_t *data, size_t size)
+{
+ assert(data);
+
+ wire_ctx_t result = wire_ctx_init((uint8_t *)data, size);
+ result.readonly = true;
+
+ return result;
+}
+
+/*!
+ * \brief Gets actual position.
+ *
+ * \return position from the begin.
+ */
+static inline size_t wire_ctx_offset(wire_ctx_t *ctx)
+{
+ assert(ctx);
+
+ return ctx->position - ctx->wire;
+}
+
+/*!
+ * \brief Set position offset from the begin.
+ *
+ * \param offset Wire offset (starts from 0).
+ *
+ * \note Noop if previous error.
+ */
+static inline void wire_ctx_set_offset(wire_ctx_t *ctx, size_t offset)
+{
+ assert(ctx);
+
+ if (ctx->error != KNOT_EOK) {
+ return;
+ }
+
+ if (offset > ctx->size) {
+ ctx->error = KNOT_ERANGE;
+ return;
+ }
+
+ ctx->position = ctx->wire + offset;
+}
+
+/*!
+ * \brief Gets available bytes.
+ *
+ * \return Number of bytes to end.
+ */
+static inline size_t wire_ctx_available(wire_ctx_t *ctx)
+{
+ assert(ctx);
+
+ return ctx->size - wire_ctx_offset(ctx);
+}
+
+/*!
+ * \brief Add offset to the current position.
+ *
+ * \note Noop if previous error.
+ */
+static inline void wire_ctx_skip(wire_ctx_t *ctx, ssize_t offset)
+{
+ assert(ctx);
+
+ if (ctx->error != KNOT_EOK) {
+ return;
+ }
+
+ // Check for out of scope skip.
+ if (offset >= 0) {
+ if (offset > wire_ctx_available(ctx)) {
+ ctx->error = KNOT_ERANGE;
+ return;
+ }
+ } else {
+ if (-offset > wire_ctx_offset(ctx)) {
+ ctx->error = KNOT_ERANGE;
+ return;
+ }
+ }
+
+ ctx->position += offset;
+}
+
+/*!
+ * \brief Check the context if reading is possible.
+ */
+static inline int wire_ctx_can_read(wire_ctx_t *ctx, size_t size)
+{
+ assert(ctx);
+
+ if (ctx->error != KNOT_EOK) {
+ return ctx->error;
+ }
+
+ if (wire_ctx_available(ctx) < size) {
+ return KNOT_EFEWDATA;
+ }
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Check the context if writing is possible.
+ */
+static inline int wire_ctx_can_write(wire_ctx_t *ctx, size_t size)
+{
+ assert(ctx);
+
+ if (ctx->error != KNOT_EOK) {
+ return ctx->error;
+ }
+
+ if (ctx->readonly) {
+ return KNOT_EACCES;
+ }
+
+ if (wire_ctx_available(ctx) < size) {
+ return KNOT_ESPACE;
+ }
+
+ return KNOT_EOK;
+}
+
+
+static inline void wire_ctx_read(wire_ctx_t *ctx, void *data, size_t size)
+{
+ assert(ctx);
+ assert(data);
+
+ if (ctx->error != KNOT_EOK) {
+ /* Avoid leaving data uninitialized. */
+ memset(data, 0, size);
+ return;
+ }
+
+ int ret = wire_ctx_can_read(ctx, size);
+ if (ret != KNOT_EOK) {
+ ctx->error = ret;
+ memset(data, 0, size);
+ return;
+ }
+
+ memcpy(data, ctx->position, size);
+ ctx->position += size;
+}
+
+static inline uint8_t wire_ctx_read_u8(wire_ctx_t *ctx)
+{
+ uint8_t result;
+ wire_ctx_read(ctx, &result, sizeof(result));
+
+ return result;
+}
+
+static inline uint16_t wire_ctx_read_u16(wire_ctx_t *ctx)
+{
+ uint16_t result;
+ wire_ctx_read(ctx, &result, sizeof(result));
+
+ return be16toh(result);
+}
+
+static inline uint32_t wire_ctx_read_u32(wire_ctx_t *ctx)
+{
+ uint32_t result;
+ wire_ctx_read(ctx, &result, sizeof(result));
+
+ return be32toh(result);
+}
+
+static inline uint64_t wire_ctx_read_u48(wire_ctx_t *ctx)
+{
+ /* This case is slightly tricky. */
+ uint64_t result = 0;
+ wire_ctx_read(ctx, (uint8_t *)&result + 1, 6);
+
+ return be64toh(result) >> 8;
+}
+
+static inline uint64_t wire_ctx_read_u64(wire_ctx_t *ctx)
+{
+ uint64_t result;
+ wire_ctx_read(ctx, &result, sizeof(result));
+
+ return be64toh(result);
+}
+
+
+static inline void wire_ctx_write(wire_ctx_t *ctx, const void *data, size_t size)
+{
+ assert(ctx);
+
+ if (ctx->error != KNOT_EOK) {
+ return;
+ }
+
+ if (size == 0) {
+ return;
+ }
+
+ assert(data);
+
+ int ret = wire_ctx_can_write(ctx, size);
+ if (ret != KNOT_EOK) {
+ ctx->error = ret;
+ return;
+ }
+
+ memcpy(ctx->position, data, size);
+ ctx->position += size;
+}
+
+static inline void wire_ctx_write_u8(wire_ctx_t *ctx, uint8_t value)
+{
+ wire_ctx_write(ctx, &value, sizeof(value));
+}
+
+static inline void wire_ctx_write_u16(wire_ctx_t *ctx, uint16_t value)
+{
+ uint16_t beval = htobe16(value);
+ wire_ctx_write(ctx, &beval, sizeof(beval));
+}
+
+static inline void wire_ctx_write_u32(wire_ctx_t *ctx, uint32_t value)
+{
+ uint32_t beval = htobe32(value);
+ wire_ctx_write(ctx, &beval, sizeof(beval));
+}
+
+static inline void wire_ctx_write_u48(wire_ctx_t *ctx, uint64_t value)
+{
+ /* This case is slightly tricky. */
+ uint64_t swapped = htobe64(value << 8);
+ wire_ctx_write(ctx, (uint8_t *)&swapped + 1, 6);
+}
+
+static inline void wire_ctx_write_u64(wire_ctx_t *ctx, uint64_t value)
+{
+ uint64_t beval = htobe64(value);
+ wire_ctx_write(ctx, &beval, sizeof(beval));
+}
+
+
+static inline void wire_ctx_memset(wire_ctx_t *dst, int value, size_t size)
+{
+ assert(dst);
+
+ if (dst->error != KNOT_EOK) {
+ return;
+ }
+
+ if (size == 0) {
+ return;
+ }
+
+ int ret = wire_ctx_can_write(dst, size);
+ if (ret != KNOT_EOK) {
+ dst->error = ret;
+ return;
+ }
+
+ memset(dst->position, value, size);
+ dst->position += size;
+}
+
+static inline void wire_ctx_clear(wire_ctx_t *ctx, size_t size)
+{
+ wire_ctx_memset(ctx, 0, size);
+}
+
+static inline void wire_ctx_copy(wire_ctx_t *dst, wire_ctx_t *src, size_t size)
+{
+ assert(dst);
+ assert(src);
+
+ if (size == 0 || dst->error != KNOT_EOK) {
+ return;
+ }
+
+ if (wire_ctx_can_read(src, size) != KNOT_EOK) {
+ dst->error = KNOT_EFEWDATA;
+ return;
+ }
+
+ int ret = wire_ctx_can_write(dst, size);
+ if (ret != KNOT_EOK) {
+ dst->error = ret;
+ return;
+ }
+
+ memcpy(dst->position, src->position, size);
+ dst->position += size;
+ src->position += size;
+}
+
diff --git a/src/knot/Makefile.inc b/src/knot/Makefile.inc
new file mode 100644
index 0000000..fc3700c
--- /dev/null
+++ b/src/knot/Makefile.inc
@@ -0,0 +1,196 @@
+libknotd_la_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAG_VISIBILITY) $(systemd_CFLAGS) \
+ $(liburcu_CFLAGS) -DKNOTD_MOD_STATIC
+libknotd_la_LDFLAGS = $(AM_LDFLAGS) -export-symbols-regex '^knotd_'
+libknotd_la_LIBADD = libcontrib.la libknot.la libzscanner.la $(systemd_LIBS) \
+ $(liburcu_LIBS) $(pthread_LIBS) $(dlopen_LIBS)
+
+include_libknotddir = $(includedir)/knot
+include_libknotd_HEADERS = \
+ knot/include/module.h
+
+libknotd_la_SOURCES = \
+ knot/conf/base.c \
+ knot/conf/base.h \
+ knot/conf/conf.c \
+ knot/conf/conf.h \
+ knot/conf/confdb.c \
+ knot/conf/confdb.h \
+ knot/conf/confio.c \
+ knot/conf/confio.h \
+ knot/conf/migration.c \
+ knot/conf/migration.h \
+ knot/conf/module.h \
+ knot/conf/module.c \
+ knot/conf/schema.c \
+ knot/conf/schema.h \
+ knot/conf/tools.c \
+ knot/conf/tools.h \
+ knot/ctl/commands.c \
+ knot/ctl/commands.h \
+ knot/ctl/process.c \
+ knot/ctl/process.h \
+ knot/dnssec/context.c \
+ knot/dnssec/context.h \
+ knot/dnssec/ds_query.c \
+ knot/dnssec/ds_query.h \
+ knot/dnssec/kasp/kasp_db.c \
+ knot/dnssec/kasp/kasp_db.h \
+ knot/dnssec/kasp/kasp_zone.c \
+ knot/dnssec/kasp/kasp_zone.h \
+ knot/dnssec/kasp/keystate.c \
+ knot/dnssec/kasp/keystate.h \
+ knot/dnssec/kasp/keystore.c \
+ knot/dnssec/kasp/keystore.h \
+ knot/dnssec/kasp/policy.h \
+ knot/dnssec/key-events.c \
+ knot/dnssec/key-events.h \
+ knot/dnssec/nsec-chain.c \
+ knot/dnssec/nsec-chain.h \
+ knot/dnssec/nsec3-chain.c \
+ knot/dnssec/nsec3-chain.h \
+ knot/dnssec/policy.c \
+ knot/dnssec/policy.h \
+ knot/dnssec/rrset-sign.c \
+ knot/dnssec/rrset-sign.h \
+ knot/dnssec/zone-events.c \
+ knot/dnssec/zone-events.h \
+ knot/dnssec/zone-keys.c \
+ knot/dnssec/zone-keys.h \
+ knot/dnssec/zone-nsec.c \
+ knot/dnssec/zone-nsec.h \
+ knot/dnssec/zone-sign.c \
+ knot/dnssec/zone-sign.h \
+ knot/events/events.c \
+ knot/events/events.h \
+ knot/events/handlers.h \
+ knot/events/handlers/dnssec.c \
+ knot/events/handlers/expire.c \
+ knot/events/handlers/flush.c \
+ knot/events/handlers/freeze_thaw.c \
+ knot/events/handlers/load.c \
+ knot/events/handlers/notify.c \
+ knot/events/handlers/nsec3resalt.c \
+ knot/events/handlers/refresh.c \
+ knot/events/handlers/update.c \
+ knot/events/handlers/parent_ds_query.c \
+ knot/events/replan.c \
+ knot/events/replan.h \
+ knot/nameserver/axfr.c \
+ knot/nameserver/axfr.h \
+ knot/nameserver/chaos.c \
+ knot/nameserver/chaos.h \
+ knot/nameserver/internet.c \
+ knot/nameserver/internet.h \
+ knot/nameserver/ixfr.c \
+ knot/nameserver/ixfr.h \
+ knot/nameserver/log.h \
+ knot/nameserver/notify.c \
+ knot/nameserver/notify.h \
+ knot/nameserver/nsec_proofs.c \
+ knot/nameserver/nsec_proofs.h \
+ knot/nameserver/process_query.c \
+ knot/nameserver/process_query.h \
+ knot/nameserver/query_module.c \
+ knot/nameserver/query_module.h \
+ knot/nameserver/tsig_ctx.c \
+ knot/nameserver/tsig_ctx.h \
+ knot/nameserver/update.c \
+ knot/nameserver/update.h \
+ knot/nameserver/xfr.c \
+ knot/nameserver/xfr.h \
+ knot/query/capture.c \
+ knot/query/capture.h \
+ knot/query/layer.h \
+ knot/query/query.c \
+ knot/query/query.h \
+ knot/query/requestor.c \
+ knot/query/requestor.h \
+ knot/common/evsched.c \
+ knot/common/evsched.h \
+ knot/common/fdset.c \
+ knot/common/fdset.h \
+ knot/common/log.c \
+ knot/common/log.h \
+ knot/common/process.c \
+ knot/common/process.h \
+ knot/common/ref.c \
+ knot/common/ref.h \
+ knot/common/stats.c \
+ knot/common/stats.h \
+ knot/server/dthreads.c \
+ knot/server/dthreads.h \
+ knot/journal/chgset_ctx.c \
+ knot/journal/chgset_ctx.h \
+ knot/journal/journal.c \
+ knot/journal/journal.h \
+ knot/journal/serialization.c \
+ knot/journal/serialization.h \
+ knot/server/server.c \
+ knot/server/server.h \
+ knot/server/tcp-handler.c \
+ knot/server/tcp-handler.h \
+ knot/server/udp-handler.c \
+ knot/server/udp-handler.h \
+ knot/updates/acl.c \
+ knot/updates/acl.h \
+ knot/updates/apply.c \
+ knot/updates/apply.h \
+ knot/updates/changesets.c \
+ knot/updates/changesets.h \
+ knot/updates/ddns.c \
+ knot/updates/ddns.h \
+ knot/updates/zone-update.c \
+ knot/updates/zone-update.h \
+ knot/worker/pool.c \
+ knot/worker/pool.h \
+ knot/worker/queue.c \
+ knot/worker/queue.h \
+ knot/zone/contents.c \
+ knot/zone/contents.h \
+ knot/zone/node.c \
+ knot/zone/node.h \
+ knot/zone/semantic-check.c \
+ knot/zone/semantic-check.h \
+ knot/zone/serial.c \
+ knot/zone/serial.h \
+ knot/zone/timers.c \
+ knot/zone/timers.h \
+ knot/zone/zone-diff.c \
+ knot/zone/zone-diff.h \
+ knot/zone/zone-dump.c \
+ knot/zone/zone-dump.h \
+ knot/zone/zone-load.c \
+ knot/zone/zone-load.h \
+ knot/zone/zone-tree.c \
+ knot/zone/zone-tree.h \
+ knot/zone/zone.c \
+ knot/zone/zone.h \
+ knot/zone/zonedb-load.c \
+ knot/zone/zonedb-load.h \
+ knot/zone/zonedb.c \
+ knot/zone/zonedb.h \
+ knot/zone/zonefile.c \
+ knot/zone/zonefile.h
+
+if HAVE_DAEMON
+noinst_LTLIBRARIES += libknotd.la
+pkgconfig_DATA += knotd.pc
+endif HAVE_DAEMON
+
+KNOTD_MOD_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAG_VISIBILITY)
+KNOTD_MOD_LDFLAGS = $(AM_LDFLAGS) -module -shared -avoid-version
+
+pkglibdir = $(module_instdir)
+pkglib_LTLIBRARIES =
+
+include $(srcdir)/knot/modules/cookies/Makefile.inc
+include $(srcdir)/knot/modules/dnsproxy/Makefile.inc
+include $(srcdir)/knot/modules/dnstap/Makefile.inc
+include $(srcdir)/knot/modules/geoip/Makefile.inc
+include $(srcdir)/knot/modules/noudp/Makefile.inc
+include $(srcdir)/knot/modules/onlinesign/Makefile.inc
+include $(srcdir)/knot/modules/queryacl/Makefile.inc
+include $(srcdir)/knot/modules/rrl/Makefile.inc
+include $(srcdir)/knot/modules/stats/Makefile.inc
+include $(srcdir)/knot/modules/synthrecord/Makefile.inc
+include $(srcdir)/knot/modules/whoami/Makefile.inc
diff --git a/src/knot/common/evsched.c b/src/knot/common/evsched.c
new file mode 100644
index 0000000..1c6f7b2
--- /dev/null
+++ b/src/knot/common/evsched.c
@@ -0,0 +1,267 @@
+/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/time.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "libknot/libknot.h"
+#include "knot/server/dthreads.h"
+#include "knot/common/evsched.h"
+
+/*! \brief Some implementations of timercmp >= are broken, this is for compat.*/
+static inline int timercmp_ge(struct timeval *a, struct timeval *b) {
+ return timercmp(a, b, >) || timercmp(a, b, ==);
+}
+
+static int compare_event_heap_nodes(void *e1, void *e2)
+{
+ if (timercmp(&((event_t *)e1)->tv, &((event_t *)e2)->tv, <)) return -1;
+ if (timercmp(&((event_t *)e1)->tv, &((event_t *)e2)->tv, >)) return 1;
+ return 0;
+}
+
+/*!
+ * \brief Get time T (now) + dt miliseconds.
+ */
+static struct timeval timeval_in(uint32_t dt)
+{
+ struct timeval tv = { 0 };
+ gettimeofday(&tv, NULL);
+
+ /* Add number of seconds. */
+ tv.tv_sec += dt / 1000;
+
+ /* Add the number of microseconds. */
+ tv.tv_usec += (dt % 1000) * 1000;
+
+ /* Check for overflow. */
+ while (tv.tv_usec > 999999) {
+ tv.tv_sec += 1;
+ tv.tv_usec -= 1 * 1000 * 1000;
+ }
+
+ return tv;
+}
+
+/*! \brief Event scheduler loop. */
+static int evsched_run(dthread_t *thread)
+{
+ evsched_t *sched = (evsched_t*)thread->data;
+ if (sched == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ /* Run event loop. */
+ pthread_mutex_lock(&sched->heap_lock);
+ while (!dt_is_cancelled(thread)) {
+ if (!!EMPTY_HEAP(&sched->heap) || sched->paused) {
+ pthread_cond_wait(&sched->notify, &sched->heap_lock);
+ continue;
+ }
+
+ /* Get current time. */
+ struct timeval dt;
+ gettimeofday(&dt, 0);
+
+ /* Get next event. */
+ event_t *ev = *((event_t**)HHEAD(&sched->heap));
+ assert(ev != NULL);
+
+ if (timercmp_ge(&dt, &ev->tv)) {
+ heap_delmin(&sched->heap);
+ ev->cb(ev);
+ } else {
+ /* Wait for next event or interrupt. Unlock calendar. */
+ struct timespec ts;
+ ts.tv_sec = ev->tv.tv_sec;
+ ts.tv_nsec = ev->tv.tv_usec * 1000L;
+ pthread_cond_timedwait(&sched->notify, &sched->heap_lock, &ts);
+ }
+ }
+ pthread_mutex_unlock(&sched->heap_lock);
+
+ return KNOT_EOK;
+}
+
+int evsched_init(evsched_t *sched, void *ctx)
+{
+ memset(sched, 0, sizeof(evsched_t));
+ sched->ctx = ctx;
+
+ /* Initialize event calendar. */
+ pthread_mutex_init(&sched->heap_lock, 0);
+ pthread_cond_init(&sched->notify, 0);
+ heap_init(&sched->heap, compare_event_heap_nodes, 0);
+
+ sched->thread = dt_create(1, evsched_run, NULL, sched);
+
+ if (sched->thread == NULL) {
+ evsched_deinit(sched);
+ return KNOT_ENOMEM;
+ }
+
+ return KNOT_EOK;
+}
+
+void evsched_deinit(evsched_t *sched)
+{
+ if (sched == NULL) {
+ return;
+ }
+
+ /* Deinitialize event calendar. */
+ pthread_mutex_destroy(&sched->heap_lock);
+ pthread_cond_destroy(&sched->notify);
+
+ while (!EMPTY_HEAP(&sched->heap)) {
+ event_t *e = (event_t *)*HHEAD(&sched->heap);
+ heap_delmin(&sched->heap);
+ evsched_event_free(e);
+ }
+
+ heap_deinit(&sched->heap);
+
+ if (sched->thread != NULL) {
+ dt_delete(&sched->thread);
+ }
+
+ /* Clear the structure. */
+ memset(sched, 0, sizeof(evsched_t));
+}
+
+event_t *evsched_event_create(evsched_t *sched, event_cb_t cb, void *data)
+{
+ /* Create event. */
+ if (sched == NULL) {
+ return NULL;
+ }
+
+ /* Allocate. */
+ event_t *e = malloc(sizeof(event_t));
+ if (e == NULL) {
+ return NULL;
+ }
+
+ /* Initialize. */
+ memset(e, 0, sizeof(event_t));
+ e->sched = sched;
+ e->cb = cb;
+ e->data = data;
+ e->hpos.pos=0;
+
+ return e;
+}
+
+void evsched_event_free(event_t *ev)
+{
+ if (ev == NULL) {
+ return;
+ }
+
+ free(ev);
+}
+
+int evsched_schedule(event_t *ev, uint32_t dt)
+{
+ if (ev == NULL || ev->sched == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ struct timeval new_time = timeval_in(dt);
+
+ evsched_t *sched = ev->sched;
+
+ /* Lock calendar. */
+ pthread_mutex_lock(&sched->heap_lock);
+
+ ev->tv = new_time;
+
+ /* Make sure it's not already enqueued. */
+ int found = heap_find(&sched->heap, (heap_val_t *)ev);
+ if (found > 0) {
+ heap_replace(&sched->heap, found, (heap_val_t *)ev);
+ } else {
+ heap_insert(&sched->heap, (heap_val_t *)ev);
+ }
+
+ /* Unlock calendar. */
+ pthread_cond_signal(&sched->notify);
+ pthread_mutex_unlock(&sched->heap_lock);
+
+ return KNOT_EOK;
+}
+
+int evsched_cancel(event_t *ev)
+{
+ if (ev == NULL || ev->sched == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ evsched_t *sched = ev->sched;
+
+ /* Lock calendar. */
+ pthread_mutex_lock(&sched->heap_lock);
+
+ int found = heap_find(&sched->heap, (heap_val_t *)ev);
+ if (found > 0) {
+ heap_delete(&sched->heap, found);
+ }
+
+ /* Unlock calendar. */
+ pthread_cond_signal(&sched->notify);
+ pthread_mutex_unlock(&sched->heap_lock);
+
+ /* Reset event timer. */
+ memset(&ev->tv, 0, sizeof(struct timeval));
+
+ return KNOT_EOK;
+}
+
+void evsched_start(evsched_t *sched)
+{
+ dt_start(sched->thread);
+}
+
+void evsched_stop(evsched_t *sched)
+{
+ pthread_mutex_lock(&sched->heap_lock);
+ dt_stop(sched->thread);
+ pthread_cond_signal(&sched->notify);
+ pthread_mutex_unlock(&sched->heap_lock);
+}
+
+void evsched_join(evsched_t *sched)
+{
+ dt_join(sched->thread);
+}
+
+void evsched_pause(evsched_t *sched)
+{
+ pthread_mutex_lock(&sched->heap_lock);
+ sched->paused = true;
+ pthread_mutex_unlock(&sched->heap_lock);
+}
+
+void evsched_resume(evsched_t *sched)
+{
+ pthread_mutex_lock(&sched->heap_lock);
+ sched->paused = false;
+ pthread_cond_signal(&sched->notify);
+ pthread_mutex_unlock(&sched->heap_lock);
+}
diff --git a/src/knot/common/evsched.h b/src/knot/common/evsched.h
new file mode 100644
index 0000000..13a236f
--- /dev/null
+++ b/src/knot/common/evsched.h
@@ -0,0 +1,153 @@
+/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \brief Event scheduler.
+ */
+
+#pragma once
+
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/time.h>
+
+#include "knot/server/dthreads.h"
+#include "contrib/ucw/heap.h"
+
+/* Forward decls. */
+struct evsched;
+struct event;
+
+/*!
+ * \brief Event callback.
+ *
+ * Pointer to whole event structure is passed to the callback.
+ * Callback should return 0 on success and negative integer on error.
+ *
+ * Example callback:
+ * \code
+ * void print_callback(event_t *t) {
+ * printf("Callback: %s\n", t->data);
+ * }
+ * \endcode
+ */
+typedef void (*event_cb_t)(struct event *);
+
+/*!
+ * \brief Event structure.
+ */
+typedef struct event {
+ struct heap_val hpos;
+ struct timeval tv; /*!< Event scheduled time. */
+ void *data; /*!< Usable data ptr. */
+ event_cb_t cb; /*!< Event callback. */
+ struct evsched *sched; /*!< Scheduler for this event. */
+} event_t;
+
+/*!
+ * \brief Event scheduler structure.
+ */
+typedef struct evsched {
+ volatile bool paused; /*!< Temporarily stop processing events. */
+ pthread_mutex_t heap_lock; /*!< Event heap locking. */
+ pthread_cond_t notify; /*!< Event heap notification. */
+ struct heap heap; /*!< Event heap. */
+ void *ctx; /*!< Scheduler context. */
+ dt_unit_t *thread;
+} evsched_t;
+
+/*!
+ * \brief Initialize event scheduler instance.
+ *
+ * \retval New instance on success.
+ * \retval NULL on error.
+ */
+int evsched_init(evsched_t *sched, void *ctx);
+
+/*!
+ * \brief Deinitialize and free event scheduler instance.
+ *
+ * \param sched Pointer to event scheduler instance.
+ */
+void evsched_deinit(evsched_t *sched);
+
+/*!
+ * \brief Create a callback event.
+ *
+ * \note Scheduler takes ownership of scheduled events. Created, but unscheduled
+ * events are in the ownership of the caller.
+ *
+ * \param sched Pointer to event scheduler instance.
+ * \param cb Callback handler.
+ * \param data Data for callback.
+ *
+ * \retval New instance on success.
+ * \retval NULL on error.
+ */
+event_t *evsched_event_create(evsched_t *sched, event_cb_t cb, void *data);
+
+/*!
+ * \brief Dispose event instance.
+ *
+ * \param ev Event instance.
+ */
+void evsched_event_free(event_t *ev);
+
+/*!
+ * \brief Schedule an event.
+ *
+ * \note This function checks if the event was already scheduled, if it was
+ * then it replaces this timer with the newer value.
+ * Running events are not canceled or waited for.
+ *
+ * \param ev Prepared event.
+ * \param dt Time difference in milliseconds from now (dt is relative).
+ *
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_EINVAL
+ */
+int evsched_schedule(event_t *ev, uint32_t dt);
+
+/*!
+ * \brief Cancel a scheduled event.
+ *
+ * \warning May block until current running event is finished (as it cannot
+ * interrupt running event).
+ *
+ * \warning Never cancel event in it's callback. As it never finishes,
+ * it deadlocks.
+ *
+ * \param ev Scheduled event.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EINVAL
+ */
+int evsched_cancel(event_t *ev);
+
+/*! \brief Start event processing threads. */
+void evsched_start(evsched_t *sched);
+
+/*! \brief Stop event processing threads. */
+void evsched_stop(evsched_t *sched);
+
+/*! \brief Join event processing threads. */
+void evsched_join(evsched_t *sched);
+
+/*! \brief Temporarily stop processing events. */
+void evsched_pause(evsched_t *sched);
+
+/*! \brief Resume processing events. */
+void evsched_resume(evsched_t *sched);
diff --git a/src/knot/common/fdset.c b/src/knot/common/fdset.c
new file mode 100644
index 0000000..3d78fdf
--- /dev/null
+++ b/src/knot/common/fdset.c
@@ -0,0 +1,151 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include "knot/common/fdset.h"
+#include "contrib/time.h"
+#include "libknot/errcode.h"
+
+/* Realloc memory or return error (part of fdset_resize). */
+#define MEM_RESIZE(tmp, p, n) \
+ if ((tmp = realloc((p), (n) * sizeof(*p))) == NULL) \
+ return KNOT_ENOMEM; \
+ (p) = tmp;
+
+static int fdset_resize(fdset_t *set, unsigned size)
+{
+ void *tmp = NULL;
+ MEM_RESIZE(tmp, set->ctx, size);
+ MEM_RESIZE(tmp, set->pfd, size);
+ MEM_RESIZE(tmp, set->timeout, size);
+ set->size = size;
+ return KNOT_EOK;
+}
+
+int fdset_init(fdset_t *set, unsigned size)
+{
+ if (set == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ memset(set, 0, sizeof(fdset_t));
+ return fdset_resize(set, size);
+}
+
+int fdset_clear(fdset_t* set)
+{
+ if (set == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ free(set->ctx);
+ free(set->pfd);
+ free(set->timeout);
+ memset(set, 0, sizeof(fdset_t));
+ return KNOT_EOK;
+}
+
+int fdset_add(fdset_t *set, int fd, unsigned events, void *ctx)
+{
+ if (set == NULL || fd < 0) {
+ return KNOT_EINVAL;
+ }
+
+ /* Realloc needed. */
+ if (set->n == set->size && fdset_resize(set, set->size + FDSET_INIT_SIZE))
+ return KNOT_ENOMEM;
+
+ /* Initialize. */
+ int i = set->n++;
+ set->pfd[i].fd = fd;
+ set->pfd[i].events = events;
+ set->pfd[i].revents = 0;
+ set->ctx[i] = ctx;
+ set->timeout[i] = 0;
+
+ /* Return index to this descriptor. */
+ return i;
+}
+
+int fdset_remove(fdset_t *set, unsigned i)
+{
+ if (set == NULL || i >= set->n) {
+ return KNOT_EINVAL;
+ }
+
+ /* Decrement number of elms. */
+ --set->n;
+
+ /* Nothing else if it is the last one.
+ * Move last -> i if some remain. */
+ unsigned last = set->n; /* Already decremented */
+ if (i < last) {
+ set->pfd[i] = set->pfd[last];
+ set->timeout[i] = set->timeout[last];
+ set->ctx[i] = set->ctx[last];
+ }
+
+ return KNOT_EOK;
+}
+
+int fdset_set_watchdog(fdset_t* set, int i, int interval)
+{
+ if (set == NULL || i >= set->n) {
+ return KNOT_EINVAL;
+ }
+
+ /* Lift watchdog if interval is negative. */
+ if (interval < 0) {
+ set->timeout[i] = 0;
+ return KNOT_EOK;
+ }
+
+ /* Update clock. */
+ struct timespec now = time_now();
+
+ set->timeout[i] = now.tv_sec + interval; /* Only seconds precision. */
+ return KNOT_EOK;
+}
+
+int fdset_sweep(fdset_t* set, fdset_sweep_cb_t cb, void *data)
+{
+ if (set == NULL || cb == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ /* Get time threshold. */
+ struct timespec now = time_now();
+
+ unsigned i = 0;
+ while (i < set->n) {
+
+ /* Check sweep state, remove if requested. */
+ if (set->timeout[i] > 0 && set->timeout[i] <= now.tv_sec) {
+ if (cb(set, i, data) == FDSET_SWEEP) {
+ if (fdset_remove(set, i) == KNOT_EOK)
+ continue; /* Stay on the index. */
+ }
+ }
+
+ /* Next descriptor. */
+ ++i;
+ }
+
+ return KNOT_EOK;
+}
diff --git a/src/knot/common/fdset.h b/src/knot/common/fdset.h
new file mode 100644
index 0000000..2d5ce02
--- /dev/null
+++ b/src/knot/common/fdset.h
@@ -0,0 +1,112 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \brief I/O multiplexing with context and timeouts for each fd.
+ */
+
+#pragma once
+
+#include <stddef.h>
+#include <poll.h>
+#include <sys/time.h>
+#include <signal.h>
+
+#define FDSET_INIT_SIZE 256 /* Resize step. */
+
+/*! \brief Set of filedescriptors with associated context and timeouts. */
+typedef struct fdset {
+ unsigned n; /*!< Active fds. */
+ unsigned size; /*!< Array size (allocated). */
+ void* *ctx; /*!< Context for each fd. */
+ struct pollfd *pfd; /*!< poll state for each fd */
+ time_t *timeout; /*!< Timeout for each fd (seconds precision). */
+} fdset_t;
+
+/*! \brief Mark-and-sweep state. */
+enum fdset_sweep_state {
+ FDSET_KEEP,
+ FDSET_SWEEP
+};
+
+/*! \brief Sweep callback (set, index, data) */
+typedef enum fdset_sweep_state (*fdset_sweep_cb_t)(fdset_t*, int, void*);
+
+/*!
+ * \brief Initialize fdset to given size.
+ */
+int fdset_init(fdset_t *set, unsigned size);
+
+/*!
+ * \brief Destroy FDSET.
+ *
+ * \retval 0 if successful.
+ * \retval -1 on error.
+ */
+int fdset_clear(fdset_t* set);
+
+/*!
+ * \brief Add file descriptor to watched set.
+ *
+ * \param set Target set.
+ * \param fd Added file descriptor.
+ * \param events Mask of watched events.
+ * \param ctx Context (optional).
+ *
+ * \retval index of the added fd if successful.
+ * \retval -1 on errors.
+ */
+int fdset_add(fdset_t *set, int fd, unsigned events, void *ctx);
+
+/*!
+ * \brief Remove file descriptor from watched set.
+ *
+ * \param set Target set.
+ * \param i Index of the removed fd.
+ *
+ * \retval 0 if successful.
+ * \retval -1 on errors.
+ */
+int fdset_remove(fdset_t *set, unsigned i);
+
+/*!
+ * \brief Set file descriptor watchdog interval.
+ *
+ * Set time (interval from now) after which the associated file descriptor
+ * should be sweeped (see fdset_sweep). Good example is setting a grace period
+ * of N seconds between socket activity. If socket is not active within
+ * <now, now + interval>, it is sweeped and potentially closed.
+ *
+ * \param set Target set.
+ * \param i Index for the file descriptor.
+ * \param interval Allowed interval without activity (seconds).
+ * -1 disables watchdog timer
+ *
+ * \retval 0 if successful.
+ * \retval -1 on errors.
+ */
+int fdset_set_watchdog(fdset_t* set, int i, int interval);
+
+/*!
+ * \brief Sweep file descriptors with exceeding inactivity period.
+ *
+ * \param set Target set.
+ * \param cb Callback for sweeped descriptors.
+ * \param data Pointer to extra data.
+ *
+ * \retval number of sweeped descriptors.
+ * \retval -1 on errors.
+ */
+int fdset_sweep(fdset_t* set, fdset_sweep_cb_t cb, void *data);
diff --git a/src/knot/common/log.c b/src/knot/common/log.c
new file mode 100644
index 0000000..8a35f37
--- /dev/null
+++ b/src/knot/common/log.c
@@ -0,0 +1,491 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+#include <urcu.h>
+
+#ifdef ENABLE_SYSTEMD
+#define SD_JOURNAL_SUPPRESS_LOCATION 1
+#include <systemd/sd-journal.h>
+#include <systemd/sd-daemon.h>
+#endif
+
+#include "knot/common/log.h"
+#include "libknot/libknot.h"
+#include "contrib/ucw/lists.h"
+
+/*! Single log message buffer length (one line). */
+#define LOG_BUFLEN 512
+#define NULL_ZONE_STR "?"
+
+#ifdef ENABLE_SYSTEMD
+int use_journal = 0;
+#endif
+
+/*! Log context. */
+typedef struct {
+ size_t target_count; /*!< Log target count. */
+ int *target; /*!< Log targets. */
+ size_t file_count; /*!< Open files count. */
+ FILE **file; /*!< Open files. */
+ log_flag_t flags; /*!< Formatting flags. */
+} log_t;
+
+/*! Log singleton. */
+log_t *s_log = NULL;
+
+static bool log_isopen(void)
+{
+ return s_log != NULL;
+}
+
+static void sink_free(log_t *log)
+{
+ if (log == NULL) {
+ return;
+ }
+
+ // Close open log files.
+ for (int i = 0; i < log->file_count; ++i) {
+ fclose(log->file[i]);
+ }
+ free(log->target);
+ free(log->file);
+ free(log);
+}
+
+/*!
+ * \brief Create logging targets respecting their canonical order.
+ *
+ * Facilities ordering: Syslog, Stderr, Stdout, File0...
+ */
+static log_t *sink_setup(size_t file_count)
+{
+ log_t *log = malloc(sizeof(*log));
+ if (log == NULL) {
+ return NULL;
+ }
+ memset(log, 0, sizeof(*log));
+
+ // Reserve space for targets.
+ log->target_count = LOG_TARGET_FILE + file_count;
+ log->target = malloc(LOG_SOURCE_ANY * sizeof(int) * log->target_count);
+ if (!log->target) {
+ free(log);
+ return NULL;
+ }
+ memset(log->target, 0, LOG_SOURCE_ANY * sizeof(int) * log->target_count);
+
+ // Reserve space for log files.
+ if (file_count > 0) {
+ log->file = malloc(sizeof(FILE *) * file_count);
+ if (!log->file) {
+ free(log->target);
+ free(log);
+ return NULL;
+ }
+ memset(log->file, 0, sizeof(FILE *) * file_count);
+ }
+
+ return log;
+}
+
+static void sink_publish(log_t *log)
+{
+ log_t **current_log = &s_log;
+ log_t *old_log = rcu_xchg_pointer(current_log, log);
+ synchronize_rcu();
+ sink_free(old_log);
+}
+
+static int *src_levels(log_t *log, log_target_t target, log_source_t src)
+{
+ assert(src < LOG_SOURCE_ANY);
+ return &log->target[LOG_SOURCE_ANY * target + src];
+}
+
+static void sink_levels_set(log_t *log, log_target_t target, log_source_t src, int levels)
+{
+ // Assign levels to the specified source.
+ if (src != LOG_SOURCE_ANY) {
+ *src_levels(log, target, src) = levels;
+ } else {
+ // ANY ~ set levels to all sources.
+ for (int i = 0; i < LOG_SOURCE_ANY; ++i) {
+ *src_levels(log, target, i) = levels;
+ }
+ }
+}
+
+static void sink_levels_add(log_t *log, log_target_t target, log_source_t src, int levels)
+{
+ // Add levels to the specified source.
+ if (src != LOG_SOURCE_ANY) {
+ *src_levels(log, target, src) |= levels;
+ } else {
+ // ANY ~ add levels to all sources.
+ for (int i = 0; i < LOG_SOURCE_ANY; ++i) {
+ *src_levels(log, target, i) |= levels;
+ }
+ }
+}
+
+void log_init(void)
+{
+ // Setup initial state.
+ int emask = LOG_MASK(LOG_CRIT) | LOG_MASK(LOG_ERR) | LOG_MASK(LOG_WARNING);
+ int imask = LOG_MASK(LOG_NOTICE) | LOG_MASK(LOG_INFO);
+
+ // Publish base log sink.
+ log_t *log = sink_setup(0);
+ if (log == NULL) {
+ fprintf(stderr, "Failed to setup logging\n");
+ return;
+ }
+
+#ifdef ENABLE_SYSTEMD
+ // Should only use the journal if system was booted with systemd.
+ use_journal = sd_booted();
+#endif
+
+ sink_levels_set(log, LOG_TARGET_SYSLOG, LOG_SOURCE_ANY, emask);
+ sink_levels_set(log, LOG_TARGET_STDERR, LOG_SOURCE_ANY, emask);
+ sink_levels_set(log, LOG_TARGET_STDOUT, LOG_SOURCE_ANY, imask);
+ sink_publish(log);
+
+ setlogmask(LOG_UPTO(LOG_DEBUG));
+ openlog(PACKAGE_NAME, LOG_PID, LOG_DAEMON);
+}
+
+void log_close(void)
+{
+ sink_publish(NULL);
+
+ fflush(stdout);
+ fflush(stderr);
+
+ closelog();
+}
+
+void log_flag_set(log_flag_t flag)
+{
+ if (log_isopen()) {
+ s_log->flags |= flag;
+ }
+}
+
+void log_levels_set(log_target_t target, log_source_t src, int levels)
+{
+ if (log_isopen()) {
+ sink_levels_set(s_log, target, src, levels);
+ }
+}
+
+void log_levels_add(log_target_t target, log_source_t src, int levels)
+{
+ if (log_isopen()) {
+ sink_levels_add(s_log, target, src, levels);
+ }
+}
+
+static void emit_log_msg(int level, log_source_t src, const char *zone,
+ size_t zone_len, const char *msg, const char *param)
+{
+ log_t *log = s_log;
+
+ // Syslog target.
+ if (*src_levels(log, LOG_TARGET_SYSLOG, src) & LOG_MASK(level)) {
+#ifdef ENABLE_SYSTEMD
+ if (use_journal) {
+ char *zone_fmt = zone ? "ZONE=%.*s." : NULL;
+ sd_journal_send("PRIORITY=%d", level,
+ "MESSAGE=%s", msg,
+ zone_fmt, zone_len, zone,
+ param, NULL);
+ } else
+#endif
+ {
+ syslog(level, "%s", msg);
+ }
+ }
+
+ // Prefix date and time.
+ char tstr[LOG_BUFLEN] = { 0 };
+ if (!(s_log->flags & LOG_FLAG_NOTIMESTAMP)) {
+ struct tm lt;
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ time_t sec = tv.tv_sec;
+ if (localtime_r(&sec, &lt) != NULL) {
+ strftime(tstr, sizeof(tstr), KNOT_LOG_TIME_FORMAT " ", &lt);
+ }
+ }
+
+ // Other log targets.
+ for (int i = LOG_TARGET_STDERR; i < LOG_TARGET_FILE + log->file_count; ++i) {
+ if (*src_levels(log, i, src) & LOG_MASK(level)) {
+ FILE *stream;
+ switch (i) {
+ case LOG_TARGET_STDERR: stream = stderr; break;
+ case LOG_TARGET_STDOUT: stream = stdout; break;
+ default: stream = log->file[i - LOG_TARGET_FILE]; break;
+ }
+
+ // Print the message.
+ fprintf(stream, "%s%s\n", tstr, msg);
+ if (stream == stdout) {
+ fflush(stream);
+ }
+ }
+ }
+}
+
+static const char *level_prefix(int level)
+{
+ switch (level) {
+ case LOG_DEBUG: return "debug";
+ case LOG_INFO: return "info";
+ case LOG_NOTICE: return "notice";
+ case LOG_WARNING: return "warning";
+ case LOG_ERR: return "error";
+ case LOG_CRIT: return "critical";
+ default: return NULL;
+ };
+}
+
+static int log_msg_add(char **write, size_t *capacity, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ int written = vsnprintf(*write, *capacity, fmt, args);
+ va_end(args);
+
+ if (written < 0 || written >= *capacity) {
+ return KNOT_ESPACE;
+ }
+
+ *write += written;
+ *capacity -= written;
+
+ return KNOT_EOK;
+}
+
+static void log_msg_text(int level, log_source_t src, const char *zone,
+ const char *fmt, va_list args, const char *param)
+{
+ if (!log_isopen() || src == LOG_SOURCE_ANY) {
+ return;
+ }
+
+ // Buffer for log message.
+ char buff[LOG_BUFLEN];
+ char *write = buff;
+ size_t capacity = sizeof(buff);
+
+ rcu_read_lock();
+
+ // Prefix error level.
+ if (level != LOG_INFO || !(s_log->flags & LOG_FLAG_NOINFO)) {
+ const char *prefix = level_prefix(level);
+ int ret = log_msg_add(&write, &capacity, "%s: ", prefix);
+ if (ret != KNOT_EOK) {
+ rcu_read_unlock();
+ return;
+ }
+ }
+
+ // Prefix zone name.
+ size_t zone_len = 0;
+ if (zone != NULL) {
+ zone_len = strlen(zone);
+ if (zone_len > 0 && zone[zone_len - 1] == '.') {
+ zone_len--;
+ }
+
+ int ret = log_msg_add(&write, &capacity, "[%.*s.] ", (int)zone_len, zone);
+ if (ret != KNOT_EOK) {
+ rcu_read_unlock();
+ return;
+ }
+ }
+
+ // Compile log message.
+ int ret = vsnprintf(write, capacity, fmt, args);
+ if (ret >= 0) {
+ // Send to logging targets.
+ emit_log_msg(level, src, zone, zone_len, buff, param);
+ }
+
+ rcu_read_unlock();
+}
+
+void log_fmt(int priority, log_source_t src, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ log_msg_text(priority, src, NULL, fmt, args, NULL);
+ va_end(args);
+}
+
+void log_fmt_zone(int priority, log_source_t src, const knot_dname_t *zone,
+ const char *param, const char *fmt, ...)
+{
+ char buff[KNOT_DNAME_TXT_MAXLEN + 1];
+ char *zone_str = knot_dname_to_str(buff, zone, sizeof(buff));
+ if (zone_str == NULL) {
+ zone_str = NULL_ZONE_STR;
+ }
+
+ va_list args;
+ va_start(args, fmt);
+ log_msg_text(priority, src, zone_str, fmt, args, param);
+ va_end(args);
+}
+
+void log_fmt_zone_str(int priority, log_source_t src, const char *zone,
+ const char *fmt, ...)
+{
+ if (zone == NULL) {
+ zone = NULL_ZONE_STR;
+ }
+
+ va_list args;
+ va_start(args, fmt);
+ log_msg_text(priority, src, zone, fmt, args, NULL);
+ va_end(args);
+}
+
+int log_update_privileges(int uid, int gid)
+{
+ if (!log_isopen()) {
+ return KNOT_EOK;
+ }
+
+ for (int i = 0; i < s_log->file_count; ++i) {
+ if (fchown(fileno(s_log->file[i]), uid, gid) < 0) {
+ return knot_map_errno();
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+static log_target_t get_logtype(const char *logname)
+{
+ assert(logname);
+
+ if (strcasecmp(logname, "syslog") == 0) {
+ return LOG_TARGET_SYSLOG;
+ } else if (strcasecmp(logname, "stderr") == 0) {
+ return LOG_TARGET_STDERR;
+ } else if (strcasecmp(logname, "stdout") == 0) {
+ return LOG_TARGET_STDOUT;
+ } else {
+ return LOG_TARGET_FILE;
+ }
+}
+
+static int log_open_file(log_t *log, const char *filename)
+{
+ assert(LOG_TARGET_FILE + log->file_count < log->target_count);
+
+ // Open the file.
+ log->file[log->file_count] = fopen(filename, "a");
+ if (log->file[log->file_count] == NULL) {
+ return knot_map_errno();
+ }
+
+ // Disable buffering.
+ setvbuf(log->file[log->file_count], NULL, _IONBF, 0);
+
+ return LOG_TARGET_FILE + log->file_count++;
+}
+
+void log_reconfigure(conf_t *conf)
+{
+ // Use defaults if no 'log' section is configured.
+ if (conf_id_count(conf, C_LOG) == 0) {
+ log_close();
+ log_init();
+ return;
+ }
+
+ // Find maximum log target id.
+ unsigned files = 0;
+ for (conf_iter_t iter = conf_iter(conf, C_LOG); iter.code == KNOT_EOK;
+ conf_iter_next(conf, &iter)) {
+ conf_val_t id = conf_iter_id(conf, &iter);
+ if (get_logtype(conf_str(&id)) == LOG_TARGET_FILE) {
+ ++files;
+ }
+ }
+
+ // Initialize logsystem.
+ log_t *log = sink_setup(files);
+ if (log == NULL) {
+ fprintf(stderr, "Failed to setup logging\n");
+ return;
+ }
+
+ // Setup logs.
+ for (conf_iter_t iter = conf_iter(conf, C_LOG); iter.code == KNOT_EOK;
+ conf_iter_next(conf, &iter)) {
+ conf_val_t id = conf_iter_id(conf, &iter);
+ const char *logname = conf_str(&id);
+
+ // Get target.
+ int target = get_logtype(logname);
+ if (target == LOG_TARGET_FILE) {
+ target = log_open_file(log, logname);
+ if (target < 0) {
+ log_error("failed to open log, file '%s' (%s)",
+ logname, knot_strerror(target));
+ continue;
+ }
+ }
+
+ conf_val_t levels_val;
+ unsigned levels;
+
+ // Set SERVER logging.
+ levels_val = conf_id_get(conf, C_LOG, C_SERVER, &id);
+ levels = conf_opt(&levels_val);
+ sink_levels_add(log, target, LOG_SOURCE_SERVER, levels);
+
+ // Set CONTROL logging.
+ levels_val = conf_id_get(conf, C_LOG, C_CTL, &id);
+ levels = conf_opt(&levels_val);
+ sink_levels_add(log, target, LOG_SOURCE_CONTROL, levels);
+
+ // Set ZONE logging.
+ levels_val = conf_id_get(conf, C_LOG, C_ZONE, &id);
+ levels = conf_opt(&levels_val);
+ sink_levels_add(log, target, LOG_SOURCE_ZONE, levels);
+
+ // Set ANY logging.
+ levels_val = conf_id_get(conf, C_LOG, C_ANY, &id);
+ levels = conf_opt(&levels_val);
+ sink_levels_add(log, target, LOG_SOURCE_ANY, levels);
+ }
+
+ sink_publish(log);
+}
diff --git a/src/knot/common/log.h b/src/knot/common/log.h
new file mode 100644
index 0000000..94b6b39
--- /dev/null
+++ b/src/knot/common/log.h
@@ -0,0 +1,185 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \brief Logging facility.
+ *
+ * Supported log levels/priorities:
+ * LOG_CRIT, LOG_ERR, LOG_WARNING, LOG_NOTICE, LOG_INFO, and LOG_DEBUG.
+ *
+ * \see syslog.h
+ */
+
+#pragma once
+
+#include <assert.h>
+#include <syslog.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "libknot/dname.h"
+#include "knot/conf/conf.h"
+
+/*! \brief Format for timestamps in log files. */
+#define KNOT_LOG_TIME_FORMAT "%Y-%m-%dT%H:%M:%S"
+
+/*! \brief Logging targets. */
+typedef enum {
+ LOG_TARGET_SYSLOG = 0, /*!< System log. */
+ LOG_TARGET_STDERR = 1, /*!< Standard error stream. */
+ LOG_TARGET_STDOUT = 2, /*!< Standard output stream. */
+ LOG_TARGET_FILE = 3 /*!< Generic logging to a file (unbuffered). */
+} log_target_t;
+
+/*! \brief Logging sources. */
+typedef enum {
+ LOG_SOURCE_SERVER = 0, /*!< Server module. */
+ LOG_SOURCE_CONTROL = 1, /*!< Server control module. */
+ LOG_SOURCE_ZONE = 2, /*!< Zone manipulation module. */
+ LOG_SOURCE_ANY = 3 /*!< Any module. */
+} log_source_t;
+
+/*! \brief Logging format flags. */
+typedef enum {
+ LOG_FLAG_NOTIMESTAMP = 1 << 0, /*!< Don't print timestamp prefix. */
+ LOG_FLAG_NOINFO = 1 << 1 /*!< Don't print info level prefix. */
+} log_flag_t;
+
+/*!
+ * \brief Setup logging subsystem.
+ */
+void log_init(void);
+
+/*!
+ * \brief Close and deinitialize log.
+ */
+void log_close(void);
+
+/*!
+ * \brief Set logging format flag.
+ */
+void log_flag_set(log_flag_t flag);
+
+/*!
+ * \brief Set log levels for given target.
+ *
+ * \param target Logging target index (LOG_TARGET_SYSLOG...).
+ * \param src Logging source (LOG_SOURCE_SERVER...LOG_SOURCE_ANY).
+ * \param levels Bitmask of specified log levels.
+ */
+void log_levels_set(log_target_t target, log_source_t src, int levels);
+
+/*!
+ * \brief Add log levels to a given target.
+ *
+ * New levels are added on top of existing, the resulting levels set is
+ * "old_levels OR new_levels".
+ *
+ * \param target Logging target index (LOG_TARGET_SYSLOG...).
+ * \param src Logging source (LOG_SOURCE_SERVER...LOG_SOURCE_ANY).
+ * \param levels Bitmask of specified log levels.
+ */
+void log_levels_add(log_target_t target, log_source_t src, int levels);
+
+/*!
+ * \brief Log message into server category.
+ *
+ * Function follows printf() format.
+ *
+ * \note LOG_SOURCE_ANY is not a valid value for the src parameter.
+ *
+ * \param priority Message priority.
+ * \param src Message source (LOG_SOURCE_SERVER...LOG_SOURCE_ZONE).
+ * \param fmt Content of the logged message.
+ */
+void log_fmt(int priority, log_source_t src, const char *fmt, ...)
+__attribute__((format(printf, 3, 4)));
+
+/*!
+ * \brief Log message into zone category.
+ *
+ * \see log_fmt
+ *
+ * \param zone Zone name in wire format.
+ * \param priority Message priority.
+ * \param src Message source (LOG_SOURCE_SERVER...LOG_SOURCE_ZONE).
+ * \param fmt Content of the logged message.
+ */
+void log_fmt_zone(int priority, log_source_t src, const knot_dname_t *zone,
+ const char *param, const char *fmt, ...)
+__attribute__((format(printf, 5, 6)));
+
+/*!
+ * \brief Log message into zone category.
+ *
+ * \see log_fmt
+ *
+ * \param zone Zone name as an ASCII string.
+ * \param priority Message priority.
+ * \param src Message source (LOG_SOURCE_SERVER...LOG_SOURCE_ZONE).
+ * \param fmt Content of the logged message.
+ */
+void log_fmt_zone_str(int priority, log_source_t src, const char *zone, const char *fmt, ...)
+__attribute__((format(printf, 4, 5)));
+
+/*!
+ * \brief Convenient logging macros.
+ */
+#define log_fatal(msg, ...) log_fmt(LOG_CRIT, LOG_SOURCE_SERVER, msg, ##__VA_ARGS__)
+#define log_error(msg, ...) log_fmt(LOG_ERR, LOG_SOURCE_SERVER, msg, ##__VA_ARGS__)
+#define log_warning(msg, ...) log_fmt(LOG_WARNING, LOG_SOURCE_SERVER, msg, ##__VA_ARGS__)
+#define log_notice(msg, ...) log_fmt(LOG_NOTICE, LOG_SOURCE_SERVER, msg, ##__VA_ARGS__)
+#define log_info(msg, ...) log_fmt(LOG_INFO, LOG_SOURCE_SERVER, msg, ##__VA_ARGS__)
+#define log_debug(msg, ...) log_fmt(LOG_DEBUG, LOG_SOURCE_SERVER, msg, ##__VA_ARGS__)
+
+#define log_ctl_fatal(msg, ...) log_fmt(LOG_CRIT, LOG_SOURCE_CONTROL, msg, ##__VA_ARGS__)
+#define log_ctl_error(msg, ...) log_fmt(LOG_ERR, LOG_SOURCE_CONTROL, msg, ##__VA_ARGS__)
+#define log_ctl_warning(msg, ...) log_fmt(LOG_WARNING, LOG_SOURCE_CONTROL, msg, ##__VA_ARGS__)
+#define log_ctl_notice(msg, ...) log_fmt(LOG_NOTICE, LOG_SOURCE_CONTROL, msg, ##__VA_ARGS__)
+#define log_ctl_info(msg, ...) log_fmt(LOG_INFO, LOG_SOURCE_CONTROL, msg, ##__VA_ARGS__)
+#define log_ctl_debug(msg, ...) log_fmt(LOG_DEBUG, LOG_SOURCE_CONTROL, msg, ##__VA_ARGS__)
+
+#define log_ctl_zone_str_error(zone, msg, ...) log_fmt_zone_str(LOG_ERR, LOG_SOURCE_CONTROL, zone, msg, ##__VA_ARGS__)
+#define log_ctl_zone_str_info(zone, msg, ...) log_fmt_zone_str(LOG_INFO, LOG_SOURCE_CONTROL, zone, msg, ##__VA_ARGS__)
+#define log_ctl_zone_str_debug(zone, msg, ...) log_fmt_zone_str(LOG_DEBUG, LOG_SOURCE_CONTROL, zone, msg, ##__VA_ARGS__)
+
+#define log_zone_fatal(zone, msg, ...) log_fmt_zone(LOG_CRIT, LOG_SOURCE_ZONE, zone, NULL, msg, ##__VA_ARGS__)
+#define log_zone_error(zone, msg, ...) log_fmt_zone(LOG_ERR, LOG_SOURCE_ZONE, zone, NULL, msg, ##__VA_ARGS__)
+#define log_zone_warning(zone, msg, ...) log_fmt_zone(LOG_WARNING, LOG_SOURCE_ZONE, zone, NULL, msg, ##__VA_ARGS__)
+#define log_zone_notice(zone, msg, ...) log_fmt_zone(LOG_NOTICE, LOG_SOURCE_ZONE, zone, NULL, msg, ##__VA_ARGS__)
+#define log_zone_info(zone, msg, ...) log_fmt_zone(LOG_INFO, LOG_SOURCE_ZONE, zone, NULL, msg, ##__VA_ARGS__)
+#define log_zone_debug(zone, msg, ...) log_fmt_zone(LOG_DEBUG, LOG_SOURCE_ZONE, zone, NULL, msg, ##__VA_ARGS__)
+
+#define log_zone_str_fatal(zone, msg, ...) log_fmt_zone_str(LOG_CRIT, LOG_SOURCE_ZONE, zone, msg, ##__VA_ARGS__)
+#define log_zone_str_error(zone, msg, ...) log_fmt_zone_str(LOG_ERR, LOG_SOURCE_ZONE, zone, msg, ##__VA_ARGS__)
+#define log_zone_str_warning(zone, msg, ...) log_fmt_zone_str(LOG_WARNING, LOG_SOURCE_ZONE, zone, msg, ##__VA_ARGS__)
+#define log_zone_str_notice(zone, msg, ...) log_fmt_zone_str(LOG_NOTICE, LOG_SOURCE_ZONE, zone, msg, ##__VA_ARGS__)
+#define log_zone_str_info(zone, msg, ...) log_fmt_zone_str(LOG_INFO, LOG_SOURCE_ZONE, zone, msg, ##__VA_ARGS__)
+#define log_zone_str_debug(zone, msg, ...) log_fmt_zone_str(LOG_DEBUG, LOG_SOURCE_ZONE, zone, msg, ##__VA_ARGS__)
+
+/*!
+ * \brief Update open files ownership.
+ *
+ * \param uid New owner id.
+ * \param gid New group id.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int log_update_privileges(int uid, int gid);
+
+/*!
+ * \brief Setup logging facilities from config.
+ */
+void log_reconfigure(conf_t *conf);
diff --git a/src/knot/common/process.c b/src/knot/common/process.c
new file mode 100644
index 0000000..4a46613
--- /dev/null
+++ b/src/knot/common/process.c
@@ -0,0 +1,189 @@
+/* Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "knot/common/log.h"
+#include "knot/common/process.h"
+#include "knot/conf/conf.h"
+#include "libknot/errcode.h"
+
+static char* pid_filename(void)
+{
+ conf_val_t val = conf_get(conf(), C_SRV, C_RUNDIR);
+ char *rundir = conf_abs_path(&val, NULL);
+ val = conf_get(conf(), C_SRV, C_PIDFILE);
+ char *pidfile = conf_abs_path(&val, rundir);
+ free(rundir);
+
+ return pidfile;
+}
+
+static pid_t pid_read(const char *filename)
+{
+ if (filename == NULL) {
+ return 0;
+ }
+
+ size_t len = 0;
+ char buf[64] = { 0 };
+
+ FILE *fp = fopen(filename, "r");
+ if (fp == NULL) {
+ return 0;
+ }
+
+ /* Read the content of the file. */
+ len = fread(buf, 1, sizeof(buf) - 1, fp);
+ fclose(fp);
+ if (len < 1) {
+ return 0;
+ }
+
+ /* Convert pid. */
+ errno = 0;
+ char *end = 0;
+ unsigned long pid = strtoul(buf, &end, 10);
+ if (end == buf || *end != '\0'|| errno != 0) {
+ return 0;
+ }
+
+ return (pid_t)pid;
+}
+
+static int pid_write(const char *filename)
+{
+ if (filename == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ /* Convert. */
+ char buf[64];
+ int len = 0;
+ len = snprintf(buf, sizeof(buf), "%lu", (unsigned long)getpid());
+ if (len < 0 || len >= sizeof(buf)) {
+ return KNOT_ENOMEM;
+ }
+
+ /* Create file. */
+ int ret = KNOT_EOK;
+ int fd = open(filename, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP);
+ if (fd >= 0) {
+ if (write(fd, buf, len) != len) {
+ ret = knot_map_errno();
+ }
+ close(fd);
+ } else {
+ ret = knot_map_errno();
+ }
+
+ return ret;
+}
+
+char *pid_check_and_create(void)
+{
+ struct stat st;
+ char *pidfile = pid_filename();
+ pid_t pid = pid_read(pidfile);
+
+ /* Check PID for existence and liveness. */
+ if (pid > 0 && pid_running(pid)) {
+ log_error("server PID found, already running");
+ free(pidfile);
+ return NULL;
+ } else if (stat(pidfile, &st) == 0) {
+ log_warning("removing stale PID file '%s'", pidfile);
+ pid_cleanup();
+ }
+
+ /* Create a PID file. */
+ int ret = pid_write(pidfile);
+ if (ret != KNOT_EOK) {
+ log_error("failed to create a PID file '%s' (%s)", pidfile,
+ knot_strerror(ret));
+ free(pidfile);
+ return NULL;
+ }
+
+ return pidfile;
+}
+
+void pid_cleanup(void)
+{
+ char *pidfile = pid_filename();
+ if (pidfile != NULL) {
+ (void)unlink(pidfile);
+ free(pidfile);
+ }
+}
+
+bool pid_running(pid_t pid)
+{
+ return kill(pid, 0) == 0;
+}
+
+int proc_update_privileges(int uid, int gid)
+{
+#ifdef HAVE_SETGROUPS
+ /* Drop supplementary groups. */
+ if ((uid_t)uid != getuid() || (gid_t)gid != getgid()) {
+ if (setgroups(0, NULL) < 0) {
+ log_warning("failed to drop supplementary groups for "
+ "UID %d (%s)", getuid(), strerror(errno));
+ }
+# ifdef HAVE_INITGROUPS
+ struct passwd *pw;
+ if ((pw = getpwuid(uid)) == NULL) {
+ log_warning("failed to get passwd entry for UID %d (%s)",
+ uid, strerror(errno));
+ } else {
+ if (initgroups(pw->pw_name, gid) < 0) {
+ log_warning("failed to set supplementary groups "
+ "for UID %d (%s)", uid, strerror(errno));
+ }
+ }
+# endif /* HAVE_INITGROUPS */
+ }
+#endif /* HAVE_SETGROUPS */
+
+ /* Watch uid/gid. */
+ if ((gid_t)gid != getgid()) {
+ log_info("changing GID to %d", gid);
+ if (setregid(gid, gid) < 0) {
+ log_error("failed to change GID to %d", gid);
+ return KNOT_ERROR;
+ }
+ }
+ if ((uid_t)uid != getuid()) {
+ log_info("changing UID to %d", uid);
+ if (setreuid(uid, uid) < 0) {
+ log_error("failed to change UID to %d", uid);
+ return KNOT_ERROR;
+ }
+ }
+
+ return KNOT_EOK;
+}
diff --git a/src/knot/common/process.h b/src/knot/common/process.h
new file mode 100644
index 0000000..04fbc3a
--- /dev/null
+++ b/src/knot/common/process.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \brief Functions for POSIX process handling.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <unistd.h>
+
+/*!
+ * \brief Check if PID file exists and create it if possible.
+ *
+ * \retval NULL if failed.
+ * \retval Created PID file path.
+ */
+char *pid_check_and_create(void);
+
+/*!
+ * \brief Remove PID file.
+ *
+ * \warning PID file content won't be checked.
+ */
+void pid_cleanup(void);
+
+/*!
+ * \brief Return true if the PID is running.
+ *
+ * \param pid Process ID.
+ *
+ * \retval 1 if running.
+ * \retval 0 if not running (or error).
+ */
+bool pid_running(pid_t pid);
+
+/*!
+ * \brief Update process privileges to new UID/GID.
+ *
+ * \param uid New user ID.
+ * \param gid New group ID.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_EACCESS if storage is not writeable.
+ */
+int proc_update_privileges(int uid, int gid);
diff --git a/src/knot/common/ref.c b/src/knot/common/ref.c
new file mode 100644
index 0000000..5f188e4
--- /dev/null
+++ b/src/knot/common/ref.c
@@ -0,0 +1,44 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+
+#include "knot/common/ref.h"
+
+void ref_init(ref_t *p, ref_destructor_t dtor)
+{
+ if (p) {
+ p->count = 0;
+ p->dtor = dtor;
+ }
+}
+
+void ref_retain(ref_t *p)
+{
+ if (p) {
+ __sync_add_and_fetch(&p->count, 1);
+ }
+}
+
+void ref_release(ref_t *p)
+{
+ if (p) {
+ int rc = __sync_sub_and_fetch(&p->count, 1);
+ if (rc == 0 && p->dtor) {
+ p->dtor(p);
+ }
+ }
+}
diff --git a/src/knot/common/ref.h b/src/knot/common/ref.h
new file mode 100644
index 0000000..5f5ec97
--- /dev/null
+++ b/src/knot/common/ref.h
@@ -0,0 +1,78 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \brief Atomic reference counting structures.
+ *
+ * Reference counting allows implicit sharing of objects
+ * between threads with custom destructor functions.
+ */
+
+#pragma once
+
+#include <stddef.h>
+
+struct ref;
+
+/*! \brief Prototype for object destructor callback. */
+typedef void (*ref_destructor_t)(struct ref * p);
+
+/*!
+ * \brief Structure for reference counting.
+ *
+ * Size equals to two sizes of pointer size.
+ * Structure may be embedded to the structures which
+ * we want to use for reference counting.
+ *
+ * \code
+ * struct mystruct {
+ * ref_t ref;
+ * int mydata;
+ * char *mystr;
+ * }
+ * \endcode
+ */
+typedef struct ref {
+ size_t count; /*! \brief Reference counter. */
+ ref_destructor_t dtor; /*! \brief Object destructor function. */
+} ref_t;
+
+/*!
+ * \brief Initialize reference counter.
+ *
+ * Set reference counter to 0 and initialize destructor callback.
+ *
+ * \param p Reference-counted object.
+ * \param dtor Destructor function.
+ */
+void ref_init(ref_t *p, ref_destructor_t dtor);
+
+/*!
+ * \brief Mark object as used by the caller.
+ *
+ * Reference counter will be incremented.
+ *
+ * \param p Reference-counted object.
+ */
+void ref_retain(ref_t *p);
+
+/*!
+ * \brief Marks object as unused by the caller.
+ *
+ * Reference counter will be decremented.
+ *
+ * \param p Reference-counted object.
+ */
+void ref_release(ref_t *p);
diff --git a/src/knot/common/stats.c b/src/knot/common/stats.c
new file mode 100644
index 0000000..8f49bf9
--- /dev/null
+++ b/src/knot/common/stats.c
@@ -0,0 +1,295 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <inttypes.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+#include <urcu.h>
+
+#include "contrib/files.h"
+#include "knot/common/stats.h"
+#include "knot/common/log.h"
+#include "knot/nameserver/query_module.h"
+
+struct {
+ bool active_dumper;
+ pthread_t dumper;
+ uint32_t timer;
+ server_t *server;
+} stats = { 0 };
+
+typedef struct {
+ FILE *fd;
+ const list_t *query_modules;
+ const knot_dname_t *zone;
+ bool zone_emitted;
+} dump_ctx_t;
+
+#define DUMP_STR(fd, level, name, ...) do { \
+ fprintf(fd, "%-.*s"name": %s\n", level, " ", ##__VA_ARGS__); \
+ } while (0)
+#define DUMP_CTR(fd, level, name, ...) do { \
+ fprintf(fd, "%-.*s"name": %"PRIu64"\n", level, " ", ##__VA_ARGS__); \
+ } while (0)
+
+uint64_t server_zone_count(server_t *server)
+{
+ return knot_zonedb_size(server->zone_db);
+}
+
+const stats_item_t server_stats[] = {
+ { "zone-count", server_zone_count },
+ { 0 }
+};
+
+static void dump_counters(FILE *fd, int level, mod_ctr_t *ctr)
+{
+ for (uint32_t j = 0; j < ctr->count; j++) {
+ uint64_t counter = ATOMIC_GET(ctr->counters[j]);
+
+ // Skip empty counters.
+ if (counter == 0) {
+ continue;
+ }
+
+ if (ctr->idx_to_str != NULL) {
+ char *str = ctr->idx_to_str(j, ctr->count);
+ if (str != NULL) {
+ DUMP_CTR(fd, level, "%s", str, counter);
+ free(str);
+ }
+ } else {
+ DUMP_CTR(fd, level, "%u", j, counter);
+ }
+ }
+}
+
+static void dump_modules(dump_ctx_t *ctx)
+{
+ int level = 0;
+ knotd_mod_t *mod = NULL;
+ WALK_LIST(mod, *ctx->query_modules) {
+ // Skip modules without statistics.
+ if (mod->stats_count == 0) {
+ continue;
+ }
+
+ // Dump zone name.
+ if (ctx->zone != NULL) {
+ // Prevent from zone section override.
+ if (!ctx->zone_emitted) {
+ DUMP_STR(ctx->fd, 0, "zone", "");
+ ctx->zone_emitted = true;
+ }
+ level = 1;
+
+ char name[KNOT_DNAME_TXT_MAXLEN + 1];
+ if (knot_dname_to_str(name, ctx->zone, sizeof(name)) == NULL) {
+ return;
+ }
+ DUMP_STR(ctx->fd, level++, "\"%s\"", name, "");
+ } else {
+ level = 0;
+ }
+
+ // Dump module counters.
+ DUMP_STR(ctx->fd, level, "%s", mod->id->name + 1, "");
+ for (int i = 0; i < mod->stats_count; i++) {
+ mod_ctr_t *ctr = mod->stats + i;
+ if (ctr->name == NULL) {
+ // Empty counter.
+ continue;
+ }
+ if (ctr->count == 1) {
+ // Simple counter.
+ uint64_t counter = ATOMIC_GET(ctr->counter);
+ DUMP_CTR(ctx->fd, level + 1, "%s", ctr->name, counter);
+ } else {
+ // Array of counters.
+ DUMP_STR(ctx->fd, level + 1, "%s", ctr->name, "");
+ dump_counters(ctx->fd, level + 2, ctr);
+ }
+ }
+ }
+}
+
+static void zone_stats_dump(zone_t *zone, dump_ctx_t *ctx)
+{
+ if (EMPTY_LIST(zone->query_modules)) {
+ return;
+ }
+
+ ctx->query_modules = &zone->query_modules;
+ ctx->zone = zone->name;
+
+ dump_modules(ctx);
+}
+
+static void dump_to_file(FILE *fd, server_t *server)
+{
+ char date[64] = "";
+
+ // Get formatted current time string.
+ struct tm tm;
+ time_t now = time(NULL);
+ localtime_r(&now, &tm);
+ strftime(date, sizeof(date), "%Y-%m-%dT%H:%M:%S%z", &tm);
+
+ // Get the server identity.
+ conf_val_t val = conf_get(conf(), C_SRV, C_IDENT);
+ const char *ident = conf_str(&val);
+ if (ident == NULL || ident[0] == '\0') {
+ ident = conf()->hostname;
+ }
+
+ // Dump record header.
+ fprintf(fd,
+ "---\n"
+ "time: %s\n"
+ "identity: %s\n",
+ date, ident);
+
+ // Dump server statistics.
+ DUMP_STR(fd, 0, "server", "");
+ for (const stats_item_t *item = server_stats; item->name != NULL; item++) {
+ DUMP_CTR(fd, 1, "%s", item->name, item->val(server));
+ }
+
+ dump_ctx_t ctx = {
+ .fd = fd,
+ .query_modules = conf()->query_modules,
+ };
+
+ // Dump global statistics.
+ dump_modules(&ctx);
+
+ // Dump zone statistics.
+ knot_zonedb_foreach(server->zone_db, zone_stats_dump, &ctx);
+}
+
+static void dump_stats(server_t *server)
+{
+ conf_val_t val = conf_get(conf(), C_SRV, C_RUNDIR);
+ char *rundir = conf_abs_path(&val, NULL);
+ val = conf_get(conf(), C_STATS, C_FILE);
+ char *file_name = conf_abs_path(&val, rundir);
+ free(rundir);
+
+ val = conf_get(conf(), C_STATS, C_APPEND);
+ bool append = conf_bool(&val);
+
+ // Open or create output file.
+ FILE *fd = NULL;
+ char *tmp_name = NULL;
+ if (append) {
+ fd = fopen(file_name, "a");
+ if (fd == NULL) {
+ log_error("stats, failed to append file '%s' (%s)",
+ file_name, knot_strerror(knot_map_errno()));
+ free(file_name);
+ return;
+ }
+ } else {
+ int ret = open_tmp_file(file_name, &tmp_name, &fd,
+ S_IRUSR | S_IWUSR | S_IRGRP);
+ if (ret != KNOT_EOK) {
+ log_error("stats, failed to open file '%s' (%s)",
+ file_name, knot_strerror(ret));
+ free(file_name);
+ return;
+ }
+ }
+ assert(fd);
+
+ // Dump stats into the file.
+ dump_to_file(fd, server);
+
+ fflush(fd);
+ fclose(fd);
+
+ // Switch the file contents.
+ if (!append) {
+ int ret = rename(tmp_name, file_name);
+ if (ret != 0) {
+ log_error("stats, failed to access file '%s' (%s)",
+ file_name, knot_strerror(knot_map_errno()));
+ unlink(tmp_name);
+ }
+ free(tmp_name);
+ }
+
+ log_debug("stats, dumped into file '%s'", file_name);
+ free(file_name);
+}
+
+static void *dumper(void *data)
+{
+ while (true) {
+ assert(stats.timer > 0);
+ sleep(stats.timer);
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+ rcu_read_lock();
+ dump_stats(stats.server);
+ rcu_read_unlock();
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+ }
+
+ return NULL;
+}
+
+void stats_reconfigure(conf_t *conf, server_t *server)
+{
+ if (conf == NULL || server == NULL) {
+ return;
+ }
+
+ // Update server context.
+ stats.server = server;
+
+ conf_val_t val = conf_get(conf, C_STATS, C_TIMER);
+ stats.timer = conf_int(&val);
+ if (stats.timer > 0) {
+ // Check if dumping is already running.
+ if (stats.active_dumper) {
+ return;
+ }
+
+ int ret = pthread_create(&stats.dumper, NULL, dumper, NULL);
+ if (ret != 0) {
+ log_error("stats, failed to launch periodic dumping (%s)",
+ knot_strerror(knot_map_errno_code(ret)));
+ } else {
+ stats.active_dumper = true;
+ }
+ // Stop current dumping.
+ } else if (stats.active_dumper) {
+ pthread_cancel(stats.dumper);
+ pthread_join(stats.dumper, NULL);
+ stats.active_dumper = false;
+ }
+}
+
+void stats_deinit(void)
+{
+ if (stats.active_dumper) {
+ pthread_cancel(stats.dumper);
+ pthread_join(stats.dumper, NULL);
+ }
+
+ memset(&stats, 0, sizeof(stats));
+}
diff --git a/src/knot/common/stats.h b/src/knot/common/stats.h
new file mode 100644
index 0000000..3ce73c6
--- /dev/null
+++ b/src/knot/common/stats.h
@@ -0,0 +1,47 @@
+/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \brief Server statistics general API.
+ */
+
+#pragma once
+
+#include "knot/server/server.h"
+
+typedef uint64_t (*stats_val_f)(server_t *server);
+
+/*!
+ * \brief Statistics metrics item.
+ */
+typedef struct {
+ const char *name; /*!< Metrics name. */
+ stats_val_f val; /*!< Metrics value getter. */
+} stats_item_t;
+
+/*!
+ * \brief Basic server metrics.
+ */
+extern const stats_item_t server_stats[];
+
+/*!
+ * \brief Reconfigures the statistics facility.
+ */
+void stats_reconfigure(conf_t *conf, server_t *server);
+
+/*!
+ * \brief Deinitializes the statistics facility.
+ */
+void stats_deinit(void);
diff --git a/src/knot/conf/base.c b/src/knot/conf/base.c
new file mode 100644
index 0000000..7fd8ba9
--- /dev/null
+++ b/src/knot/conf/base.c
@@ -0,0 +1,924 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <string.h>
+#include <urcu.h>
+
+#include "knot/conf/base.h"
+#include "knot/conf/confdb.h"
+#include "knot/conf/module.h"
+#include "knot/conf/tools.h"
+#include "knot/common/log.h"
+#include "knot/nameserver/query_module.h"
+#include "libknot/libknot.h"
+#include "libknot/yparser/ypformat.h"
+#include "libknot/yparser/yptrafo.h"
+#include "contrib/files.h"
+#include "contrib/sockaddr.h"
+#include "contrib/string.h"
+
+// The active configuration.
+conf_t *s_conf;
+
+conf_t* conf(void) {
+ return s_conf;
+}
+
+static int init_and_check(
+ conf_t *conf,
+ conf_flag_t flags)
+{
+ if (conf == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ knot_db_txn_t txn;
+ unsigned txn_flags = (flags & CONF_FREADONLY) ? KNOT_DB_RDONLY : 0;
+ int ret = conf->api->txn_begin(conf->db, &txn, txn_flags);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Initialize the database.
+ if (!(flags & CONF_FREADONLY)) {
+ ret = conf_db_init(conf, &txn, false);
+ if (ret != KNOT_EOK) {
+ conf->api->txn_abort(&txn);
+ return ret;
+ }
+ }
+
+ // Check the database.
+ if (!(flags & CONF_FNOCHECK)) {
+ ret = conf_db_check(conf, &txn);
+ if (ret < KNOT_EOK) {
+ conf->api->txn_abort(&txn);
+ return ret;
+ }
+ }
+
+ if (flags & CONF_FREADONLY) {
+ conf->api->txn_abort(&txn);
+ return KNOT_EOK;
+ } else {
+ return conf->api->txn_commit(&txn);
+ }
+}
+
+int conf_refresh_txn(
+ conf_t *conf)
+{
+ if (conf == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ // Close previously opened transaction.
+ conf->api->txn_abort(&conf->read_txn);
+
+ return conf->api->txn_begin(conf->db, &conf->read_txn, KNOT_DB_RDONLY);
+}
+
+void conf_refresh_hostname(
+ conf_t *conf)
+{
+ if (conf == NULL) {
+ return;
+ }
+
+ free(conf->hostname);
+ conf->hostname = sockaddr_hostname();
+ if (conf->hostname == NULL) {
+ // Empty hostname fallback, NULL cannot be passed to strlen!
+ conf->hostname = strdup("");
+ }
+}
+
+static void init_cache(
+ conf_t *conf)
+{
+ conf_val_t val = conf_get(conf, C_SRV, C_MAX_IPV4_UDP_PAYLOAD);
+ if (val.code != KNOT_EOK) {
+ val = conf_get(conf, C_SRV, C_MAX_UDP_PAYLOAD);
+ }
+ conf->cache.srv_max_ipv4_udp_payload = conf_int(&val);
+
+ val = conf_get(conf, C_SRV, C_MAX_IPV6_UDP_PAYLOAD);
+ if (val.code != KNOT_EOK) {
+ val = conf_get(conf, C_SRV, C_MAX_UDP_PAYLOAD);
+ }
+ conf->cache.srv_max_ipv6_udp_payload = conf_int(&val);
+
+ val = conf_get(conf, C_SRV, C_TCP_HSHAKE_TIMEOUT);
+ conf->cache.srv_tcp_hshake_timeout = conf_int(&val);
+
+ val = conf_get(conf, C_SRV, C_TCP_IDLE_TIMEOUT);
+ conf->cache.srv_tcp_idle_timeout = conf_int(&val);
+
+ val = conf_get(conf, C_SRV, C_TCP_REPLY_TIMEOUT);
+ conf->cache.srv_tcp_reply_timeout = conf_int(&val);
+
+ val = conf_get(conf, C_SRV, C_MAX_TCP_CLIENTS);
+ conf->cache.srv_max_tcp_clients = conf_int(&val);
+
+ val = conf_get(conf, C_CTL, C_TIMEOUT);
+ conf->cache.ctl_timeout = conf_int(&val) * 1000;
+
+ conf->cache.srv_nsid = conf_get(conf, C_SRV, C_NSID);
+
+ val = conf_get(conf, C_SRV, C_ECS);
+ conf->cache.use_ecs = conf_bool(&val);
+
+ val = conf_get(conf, C_SRV, C_ANS_ROTATION);
+ conf->cache.srv_ans_rotate = conf_bool(&val);
+}
+
+int conf_new(
+ conf_t **conf,
+ const yp_item_t *schema,
+ const char *db_dir,
+ size_t max_conf_size,
+ conf_flag_t flags)
+{
+ if (conf == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ conf_t *out = malloc(sizeof(conf_t));
+ if (out == NULL) {
+ return KNOT_ENOMEM;
+ }
+ memset(out, 0, sizeof(conf_t));
+
+ // Initialize config schema.
+ int ret = yp_schema_copy(&out->schema, schema);
+ if (ret != KNOT_EOK) {
+ goto new_error;
+ }
+
+ // Initialize query modules list.
+ out->query_modules = malloc(sizeof(list_t));
+ if (out->query_modules == NULL) {
+ ret = KNOT_ENOMEM;
+ goto new_error;
+ }
+ init_list(out->query_modules);
+
+ // Set the DB api.
+ out->api = knot_db_lmdb_api();
+ struct knot_db_lmdb_opts lmdb_opts = KNOT_DB_LMDB_OPTS_INITIALIZER;
+ lmdb_opts.mapsize = max_conf_size;
+ lmdb_opts.maxreaders = CONF_MAX_DB_READERS;
+ lmdb_opts.flags.env = KNOT_DB_LMDB_NOTLS;
+
+ // Open the database.
+ if (db_dir == NULL) {
+ // Prepare a temporary database.
+ char tpl[] = "/tmp/knot-confdb.XXXXXX";
+ lmdb_opts.path = mkdtemp(tpl);
+ if (lmdb_opts.path == NULL) {
+ CONF_LOG(LOG_ERR, "failed to create temporary directory (%s)",
+ knot_strerror(knot_map_errno()));
+ ret = KNOT_ENOMEM;
+ goto new_error;
+ }
+
+ ret = out->api->init(&out->db, NULL, &lmdb_opts);
+
+ // Remove the database to ensure it is temporary.
+ if (!remove_path(lmdb_opts.path)) {
+ CONF_LOG(LOG_WARNING, "failed to purge temporary directory '%s'",
+ lmdb_opts.path);
+ }
+ } else {
+ // Set the specified database.
+ lmdb_opts.path = db_dir;
+
+ // Set the read-only mode.
+ if (flags & CONF_FREADONLY) {
+ lmdb_opts.flags.env |= KNOT_DB_LMDB_RDONLY;
+ }
+
+ ret = out->api->init(&out->db, NULL, &lmdb_opts);
+ }
+ if (ret != KNOT_EOK) {
+ goto new_error;
+ }
+
+ // Initialize and check the database.
+ ret = init_and_check(out, flags);
+ if (ret != KNOT_EOK) {
+ goto new_error;
+ }
+
+ // Open common read-only transaction.
+ ret = conf_refresh_txn(out);
+ if (ret != KNOT_EOK) {
+ goto new_error;
+ }
+
+ // Cache the current hostname.
+ if (!(flags & CONF_FNOHOSTNAME)) {
+ conf_refresh_hostname(out);
+ }
+
+ // Initialize cached values.
+ init_cache(out);
+
+ // Load module schemas.
+ if (flags & (CONF_FREQMODULES | CONF_FOPTMODULES)) {
+ ret = conf_mod_load_common(out);
+ if (ret != KNOT_EOK && (flags & CONF_FREQMODULES)) {
+ goto new_error;
+ }
+
+ for (conf_iter_t iter = conf_iter(out, C_MODULE);
+ iter.code == KNOT_EOK; conf_iter_next(out, &iter)) {
+ conf_val_t id = conf_iter_id(out, &iter);
+ conf_val_t file = conf_id_get(out, C_MODULE, C_FILE, &id);
+ ret = conf_mod_load_extra(out, conf_str(&id), conf_str(&file), false);
+ if (ret != KNOT_EOK && (flags & CONF_FREQMODULES)) {
+ conf_iter_finish(out, &iter);
+ goto new_error;
+ }
+ }
+
+ conf_mod_load_purge(out, false);
+ }
+
+ *conf = out;
+
+ return KNOT_EOK;
+new_error:
+ conf_free(out);
+
+ return ret;
+}
+
+int conf_clone(
+ conf_t **conf)
+{
+ if (conf == NULL || s_conf == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ conf_t *out = malloc(sizeof(conf_t));
+ if (out == NULL) {
+ return KNOT_ENOMEM;
+ }
+ memset(out, 0, sizeof(conf_t));
+
+ // Initialize config schema.
+ int ret = yp_schema_copy(&out->schema, s_conf->schema);
+ if (ret != KNOT_EOK) {
+ free(out);
+ return ret;
+ }
+
+ // Set shared items.
+ out->api = s_conf->api;
+ out->db = s_conf->db;
+
+ // Initialize query modules list.
+ out->query_modules = malloc(sizeof(list_t));
+ if (out->query_modules == NULL) {
+ yp_schema_free(out->schema);
+ free(out);
+ return KNOT_ENOMEM;
+ }
+ init_list(out->query_modules);
+
+ // Open common read-only transaction.
+ ret = conf_refresh_txn(out);
+ if (ret != KNOT_EOK) {
+ free(out->query_modules);
+ yp_schema_free(out->schema);
+ free(out);
+ return ret;
+ }
+
+ // Copy the filename.
+ if (s_conf->filename != NULL) {
+ out->filename = strdup(s_conf->filename);
+ }
+
+ // Copy the hostname.
+ if (s_conf->hostname != NULL) {
+ out->hostname = strdup(s_conf->hostname);
+ }
+
+ // Initialize cached values.
+ init_cache(out);
+
+ out->is_clone = true;
+
+ *conf = out;
+
+ return KNOT_EOK;
+}
+
+conf_t *conf_update(
+ conf_t *conf,
+ conf_update_flag_t flags)
+{
+ // Remove the clone flag for new master configuration.
+ if (conf != NULL) {
+ conf->is_clone = false;
+
+ if ((flags & CONF_UPD_FCONFIO) && s_conf != NULL) {
+ conf->io.flags = s_conf->io.flags;
+ conf->io.zones = s_conf->io.zones;
+ }
+ if ((flags & CONF_UPD_FMODULES) && s_conf != NULL) {
+ free(conf->query_modules);
+ conf->query_modules = s_conf->query_modules;
+ conf->query_plan = s_conf->query_plan;
+ }
+ }
+
+ conf_t **current_conf = &s_conf;
+ conf_t *old_conf = rcu_xchg_pointer(current_conf, conf);
+
+ synchronize_rcu();
+
+ if (old_conf != NULL) {
+ // Remove the clone flag if a single configuration.
+ old_conf->is_clone = (conf != NULL) ? true : false;
+
+ if (flags & CONF_UPD_FCONFIO) {
+ old_conf->io.zones = NULL;
+ }
+ if (flags & CONF_UPD_FMODULES) {
+ old_conf->query_modules = NULL;
+ old_conf->query_plan = NULL;
+ }
+ if (!(flags & CONF_UPD_FNOFREE)) {
+ conf_free(old_conf);
+ old_conf = NULL;
+ }
+ }
+
+ return old_conf;
+}
+
+void conf_free(
+ conf_t *conf)
+{
+ if (conf == NULL) {
+ return;
+ }
+
+ yp_schema_free(conf->schema);
+ free(conf->filename);
+ free(conf->hostname);
+ if (conf->api != NULL) {
+ conf->api->txn_abort(&conf->read_txn);
+ }
+
+ if (conf->io.txn != NULL && conf->api != NULL) {
+ conf->api->txn_abort(conf->io.txn_stack);
+ }
+ if (conf->io.zones != NULL) {
+ trie_free(conf->io.zones);
+ }
+
+ conf_mod_load_purge(conf, false);
+ conf_deactivate_modules(conf->query_modules, &conf->query_plan);
+ free(conf->query_modules);
+ conf_mod_unload_shared(conf);
+
+ if (!conf->is_clone) {
+ if (conf->api != NULL) {
+ conf->api->deinit(conf->db);
+ }
+ }
+
+ free(conf);
+}
+
+#define CONF_LOG_LINE(file, line, msg, ...) do { \
+ CONF_LOG(LOG_ERR, "%s%s%sline %zu, " msg, \
+ (file != NULL ? "file '" : ""), (file != NULL ? file : ""), \
+ (file != NULL ? "', " : ""), line, ##__VA_ARGS__); \
+ } while (0)
+
+static void log_parser_err(
+ yp_parser_t *parser,
+ int ret)
+{
+ CONF_LOG_LINE(parser->file.name, parser->line_count,
+ "item '%s'%s%s%s (%s)",
+ parser->key,
+ (parser->data_len > 0) ? ", value '" : "",
+ (parser->data_len > 0) ? parser->data : "",
+ (parser->data_len > 0) ? "'" : "",
+ knot_strerror(ret));
+}
+
+static void log_parser_schema_err(
+ yp_parser_t *parser,
+ int ret)
+{
+ // Emit better message for 'unknown module' error.
+ if (ret == KNOT_YP_EINVAL_ITEM && parser->event == YP_EKEY0 &&
+ strncmp(parser->key, KNOTD_MOD_NAME_PREFIX, strlen(KNOTD_MOD_NAME_PREFIX)) == 0) {
+ CONF_LOG_LINE(parser->file.name, parser->line_count,
+ "unknown module '%s'", parser->key);
+ } else {
+ log_parser_err(parser, ret);
+ }
+}
+
+static void log_call_err(
+ yp_parser_t *parser,
+ knotd_conf_check_args_t *args,
+ int ret)
+{
+ CONF_LOG_LINE(args->extra->file_name, args->extra->line,
+ "item '%s'%s%s%s (%s)", args->item->name + 1,
+ (parser->data_len > 0) ? ", value '" : "",
+ (parser->data_len > 0) ? parser->data : "",
+ (parser->data_len > 0) ? "'" : "",
+ (args->err_str != NULL) ? args->err_str : knot_strerror(ret));
+}
+
+static void log_prev_err(
+ knotd_conf_check_args_t *args,
+ int ret)
+{
+ char buff[512] = { 0 };
+ size_t len = sizeof(buff);
+
+ // Get the previous textual identifier.
+ if ((args->item->flags & YP_FMULTI) != 0) {
+ if (yp_item_to_txt(args->item->var.g.id, args->id, args->id_len,
+ buff, &len, YP_SNOQUOTE) != KNOT_EOK) {
+ buff[0] = '\0';
+ }
+ }
+
+ CONF_LOG_LINE(args->extra->file_name, args->extra->line,
+ "%s '%s' (%s)", args->item->name + 1, buff,
+ args->err_str != NULL ? args->err_str : knot_strerror(ret));
+}
+
+static int finalize_previous_section(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ yp_parser_t *parser,
+ yp_check_ctx_t *ctx)
+{
+ yp_node_t *node = &ctx->nodes[0];
+
+ // Return if no previous section or include or empty multi-section.
+ if (node->item == NULL || node->item->type != YP_TGRP ||
+ (node->id_len == 0 && (node->item->flags & YP_FMULTI) != 0)) {
+ return KNOT_EOK;
+ }
+
+ knotd_conf_check_extra_t extra = {
+ .conf = conf,
+ .txn = txn,
+ .file_name = parser->file.name,
+ .line = parser->line_count
+ };
+ knotd_conf_check_args_t args = {
+ .item = node->item,
+ .id = node->id,
+ .id_len = node->id_len,
+ .data = node->data,
+ .data_len = node->data_len,
+ .extra = &extra
+ };
+
+ int ret = conf_exec_callbacks(&args);
+ if (ret != KNOT_EOK) {
+ log_prev_err(&args, ret);
+ }
+
+ return ret;
+}
+
+static int finalize_item(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ yp_parser_t *parser,
+ yp_check_ctx_t *ctx)
+{
+ yp_node_t *node = &ctx->nodes[ctx->current];
+
+ // Section callbacks are executed before another section.
+ if (node->item->type == YP_TGRP && node->id_len == 0) {
+ return KNOT_EOK;
+ }
+
+ knotd_conf_check_extra_t extra = {
+ .conf = conf,
+ .txn = txn,
+ .file_name = parser->file.name,
+ .line = parser->line_count
+ };
+ knotd_conf_check_args_t args = {
+ .item = (parser->event == YP_EID) ? node->item->var.g.id : node->item,
+ .id = node->id,
+ .id_len = node->id_len,
+ .data = node->data,
+ .data_len = node->data_len,
+ .extra = &extra
+ };
+
+ int ret = conf_exec_callbacks(&args);
+ if (ret != KNOT_EOK) {
+ log_call_err(parser, &args, ret);
+ }
+
+ return ret;
+}
+
+int conf_parse(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const char *input,
+ bool is_file)
+{
+ if (conf == NULL || txn == NULL || input == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ yp_parser_t *parser = malloc(sizeof(yp_parser_t));
+ if (parser == NULL) {
+ return KNOT_ENOMEM;
+ }
+ yp_init(parser);
+
+ int ret;
+
+ // Set parser source.
+ if (is_file) {
+ ret = yp_set_input_file(parser, input);
+ } else {
+ ret = yp_set_input_string(parser, input, strlen(input));
+ }
+ if (ret != KNOT_EOK) {
+ CONF_LOG(LOG_ERR, "failed to load file '%s' (%s)",
+ input, knot_strerror(ret));
+ goto parse_error;
+ }
+
+ // Initialize parser check context.
+ yp_check_ctx_t *ctx = yp_schema_check_init(&conf->schema);
+ if (ctx == NULL) {
+ ret = KNOT_ENOMEM;
+ goto parse_error;
+ }
+
+ int check_ret = KNOT_EOK;
+
+ // Parse the configuration.
+ while ((ret = yp_parse(parser)) == KNOT_EOK) {
+ if (parser->event == YP_EKEY0 || parser->event == YP_EID) {
+ check_ret = finalize_previous_section(conf, txn, parser, ctx);
+ if (check_ret != KNOT_EOK) {
+ break;
+ }
+ }
+
+ check_ret = yp_schema_check_parser(ctx, parser);
+ if (check_ret != KNOT_EOK) {
+ log_parser_schema_err(parser, check_ret);
+ break;
+ }
+
+ yp_node_t *node = &ctx->nodes[ctx->current];
+ yp_node_t *parent = node->parent;
+
+ if (parent == NULL) {
+ check_ret = conf_db_set(conf, txn, node->item->name,
+ NULL, node->id, node->id_len,
+ node->data, node->data_len);
+ } else {
+ check_ret = conf_db_set(conf, txn, parent->item->name,
+ node->item->name, parent->id,
+ parent->id_len, node->data,
+ node->data_len);
+ }
+ if (check_ret != KNOT_EOK) {
+ log_parser_err(parser, check_ret);
+ break;
+ }
+
+ check_ret = finalize_item(conf, txn, parser, ctx);
+ if (check_ret != KNOT_EOK) {
+ break;
+ }
+ }
+
+ if (ret == KNOT_EOF) {
+ ret = finalize_previous_section(conf, txn, parser, ctx);
+ } else if (ret != KNOT_EOK) {
+ log_parser_err(parser, ret);
+ } else {
+ ret = check_ret;
+ }
+
+ yp_schema_check_deinit(ctx);
+parse_error:
+ yp_deinit(parser);
+ free(parser);
+
+ return ret;
+}
+
+int conf_import(
+ conf_t *conf,
+ const char *input,
+ bool is_file)
+{
+ if (conf == NULL || input == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int ret;
+
+ knot_db_txn_t txn;
+ ret = conf->api->txn_begin(conf->db, &txn, 0);
+ if (ret != KNOT_EOK) {
+ goto import_error;
+ }
+
+ // Initialize the DB.
+ ret = conf_db_init(conf, &txn, true);
+ if (ret != KNOT_EOK) {
+ conf->api->txn_abort(&txn);
+ goto import_error;
+ }
+
+ // Parse and import given file.
+ ret = conf_parse(conf, &txn, input, is_file);
+ if (ret != KNOT_EOK) {
+ conf->api->txn_abort(&txn);
+ goto import_error;
+ }
+ // Load purge must be here as conf_parse may be called recursively!
+ conf_mod_load_purge(conf, false);
+
+ // Commit new configuration.
+ ret = conf->api->txn_commit(&txn);
+ if (ret != KNOT_EOK) {
+ goto import_error;
+ }
+
+ // Update read-only transaction.
+ ret = conf_refresh_txn(conf);
+ if (ret != KNOT_EOK) {
+ goto import_error;
+ }
+
+ // Update cached values.
+ init_cache(conf);
+
+ // Reset the filename.
+ free(conf->filename);
+ conf->filename = NULL;
+ if (is_file) {
+ conf->filename = strdup(input);
+ }
+
+ ret = KNOT_EOK;
+import_error:
+
+ return ret;
+}
+
+static int export_group_name(
+ FILE *fp,
+ const yp_item_t *group,
+ char *out,
+ size_t out_len,
+ yp_style_t style)
+{
+ int ret = yp_format_key0(group, NULL, 0, out, out_len, style, true, true);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ fprintf(fp, "%s", out);
+
+ return KNOT_EOK;
+}
+
+static int export_group(
+ conf_t *conf,
+ FILE *fp,
+ const yp_item_t *group,
+ const uint8_t *id,
+ size_t id_len,
+ char *out,
+ size_t out_len,
+ yp_style_t style,
+ bool *exported)
+{
+ // Export the multi-group name.
+ if ((group->flags & YP_FMULTI) != 0 && !(*exported)) {
+ int ret = export_group_name(fp, group, out, out_len, style);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ *exported = true;
+ }
+
+ // Iterate through all possible group items.
+ for (yp_item_t *item = group->sub_items; item->name != NULL; item++) {
+ // Export the identifier.
+ if (group->var.g.id == item && (group->flags & YP_FMULTI) != 0) {
+ int ret = yp_format_id(group->var.g.id, id, id_len, out,
+ out_len, style);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ fprintf(fp, "%s", out);
+ continue;
+ }
+
+ conf_val_t bin;
+ conf_db_get(conf, &conf->read_txn, group->name, item->name,
+ id, id_len, &bin);
+ if (bin.code == KNOT_ENOENT) {
+ continue;
+ } else if (bin.code != KNOT_EOK) {
+ return bin.code;
+ }
+
+ // Export the single-group name if an item is set.
+ if ((group->flags & YP_FMULTI) == 0 && !(*exported)) {
+ int ret = export_group_name(fp, group, out, out_len, style);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ *exported = true;
+ }
+
+ // Format single/multiple-valued item.
+ size_t values = conf_val_count(&bin);
+ for (size_t i = 1; i <= values; i++) {
+ conf_val(&bin);
+ int ret = yp_format_key1(item, bin.data, bin.len, out,
+ out_len, style, i == 1,
+ i == values);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ fprintf(fp, "%s", out);
+
+ if (values > 1) {
+ conf_val_next(&bin);
+ }
+ }
+ }
+
+ if (*exported) {
+ fprintf(fp, "\n");
+ }
+
+ return KNOT_EOK;
+}
+
+static int export_item(
+ conf_t *conf,
+ FILE *fp,
+ const yp_item_t *item,
+ char *buff,
+ size_t buff_len,
+ yp_style_t style)
+{
+ bool exported = false;
+
+ // Skip non-group items (include).
+ if (item->type != YP_TGRP) {
+ return KNOT_EOK;
+ }
+
+ // Export simple group without identifiers.
+ if (!(item->flags & YP_FMULTI)) {
+ return export_group(conf, fp, item, NULL, 0, buff, buff_len,
+ style, &exported);
+ }
+
+ // Iterate over all identifiers.
+ conf_iter_t iter;
+ int ret = conf_db_iter_begin(conf, &conf->read_txn, item->name, &iter);
+ switch (ret) {
+ case KNOT_EOK:
+ break;
+ case KNOT_ENOENT:
+ return KNOT_EOK;
+ default:
+ return ret;
+ }
+
+ while (ret == KNOT_EOK) {
+ const uint8_t *id;
+ size_t id_len;
+ ret = conf_db_iter_id(conf, &iter, &id, &id_len);
+ if (ret != KNOT_EOK) {
+ conf_db_iter_finish(conf, &iter);
+ return ret;
+ }
+
+ // Export group with identifiers.
+ ret = export_group(conf, fp, item, id, id_len, buff, buff_len,
+ style, &exported);
+ if (ret != KNOT_EOK) {
+ conf_db_iter_finish(conf, &iter);
+ return ret;
+ }
+
+ ret = conf_db_iter_next(conf, &iter);
+ }
+ if (ret != KNOT_EOF) {
+ return ret;
+ }
+
+ return KNOT_EOK;
+}
+
+int conf_export(
+ conf_t *conf,
+ const char *file_name,
+ yp_style_t style)
+{
+ if (conf == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ // Prepare common buffer;
+ const size_t buff_len = 2 * CONF_MAX_DATA_LEN; // Rough limit.
+ char *buff = malloc(buff_len);
+ if (buff == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ FILE *fp = (file_name != NULL) ? fopen(file_name, "w") : stdout;
+ if (fp == NULL) {
+ free(buff);
+ return knot_map_errno();
+ }
+
+ fprintf(fp, "# Configuration export (Knot DNS %s)\n\n", PACKAGE_VERSION);
+
+ const char *mod_prefix = KNOTD_MOD_NAME_PREFIX;
+ const size_t mod_prefix_len = strlen(mod_prefix);
+
+ int ret;
+
+ // Iterate over the schema.
+ for (yp_item_t *item = conf->schema; item->name != NULL; item++) {
+ // Don't export module sections again.
+ if (strncmp(item->name + 1, mod_prefix, mod_prefix_len) == 0) {
+ break;
+ }
+
+ // Export module sections before the template section.
+ if (strcmp(item->name + 1, C_TPL + 1) == 0) {
+ for (yp_item_t *mod = item + 1; mod->name != NULL; mod++) {
+ // Skip non-module sections.
+ if (strncmp(mod->name + 1, mod_prefix, mod_prefix_len) != 0) {
+ continue;
+ }
+
+ // Export module section.
+ ret = export_item(conf, fp, mod, buff, buff_len, style);
+ if (ret != KNOT_EOK) {
+ goto export_error;
+ }
+ }
+ }
+
+ // Export non-module section.
+ ret = export_item(conf, fp, item, buff, buff_len, style);
+ if (ret != KNOT_EOK) {
+ goto export_error;
+ }
+ }
+
+ ret = KNOT_EOK;
+export_error:
+ if (file_name != NULL) {
+ fclose(fp);
+ }
+ free(buff);
+
+ return ret;
+}
diff --git a/src/knot/conf/base.h b/src/knot/conf/base.h
new file mode 100644
index 0000000..b7ef61c
--- /dev/null
+++ b/src/knot/conf/base.h
@@ -0,0 +1,279 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include "libknot/libknot.h"
+#include "libknot/yparser/ypschema.h"
+#include "contrib/qp-trie/trie.h"
+#include "contrib/ucw/lists.h"
+#include "contrib/dynarray.h"
+#include "knot/include/module.h"
+
+/*! Default template identifier. */
+#define CONF_DEFAULT_ID ((uint8_t *)"\x08""default\0")
+/*! Default configuration file. */
+#define CONF_DEFAULT_FILE (CONFIG_DIR "/knot.conf")
+/*! Default configuration database. */
+#define CONF_DEFAULT_DBDIR (STORAGE_DIR "/confdb")
+/*! Maximum depth of nested transactions. */
+#define CONF_MAX_TXN_DEPTH 5
+/*! Maximum number of concurrent DB readers. */
+#define CONF_MAX_DB_READERS 630
+
+/*! Configuration specific logging. */
+#define CONF_LOG(severity, msg, ...) do { \
+ log_fmt(severity, LOG_SOURCE_SERVER, "config, " msg, ##__VA_ARGS__); \
+ } while (0)
+
+#define CONF_LOG_ZONE(severity, zone, msg, ...) do { \
+ log_fmt_zone(severity, LOG_SOURCE_ZONE, zone, NULL, "config, " msg, ##__VA_ARGS__); \
+ } while (0)
+
+/*! Configuration getter output. */
+typedef struct {
+ /*! Item description. */
+ const yp_item_t *item;
+ /*! Whole data (can be array). */
+ const uint8_t *blob;
+ /*! Whole data length. */
+ size_t blob_len;
+ // Public items.
+ /*! Current single data. */
+ const uint8_t *data;
+ /*! Current single data length. */
+ size_t len;
+ /*! Value getter return code. */
+ int code;
+} conf_val_t;
+
+/*! Query module context. */
+typedef struct {
+ /*! Module interface. */
+ const knotd_mod_api_t *api;
+ /*! Shared library dlopen handler. */
+ void *lib_handle;
+ /*! Indication of a temporary module created during confio check. */
+ bool temporary;
+} module_t;
+
+dynarray_declare(mod, module_t *, DYNARRAY_VISIBILITY_PUBLIC, 16)
+dynarray_declare(old_schema, yp_item_t *, DYNARRAY_VISIBILITY_PUBLIC, 16)
+
+/*! Configuration context. */
+typedef struct {
+ /*! Cloned configuration indicator. */
+ bool is_clone;
+ /*! Currently used namedb api. */
+ const struct knot_db_api *api;
+ /*! Configuration schema. */
+ yp_item_t *schema;
+ /*! Configuration database. */
+ knot_db_t *db;
+
+ /*! Read-only transaction for config access. */
+ knot_db_txn_t read_txn;
+
+ struct {
+ /*! The current writing transaction. */
+ knot_db_txn_t *txn;
+ /*! Stack of nested writing transactions. */
+ knot_db_txn_t txn_stack[CONF_MAX_TXN_DEPTH];
+ /*! Master transaction flags. */
+ yp_flag_t flags;
+ /*! Changed zones. */
+ trie_t *zones;
+ } io;
+
+ /*! Current config file (for reload if started with config file). */
+ char *filename;
+
+ /*! Prearranged hostname string (for automatic NSID or CH ident value). */
+ char *hostname;
+
+ /*! Cached critical confdb items. */
+ struct {
+ int16_t srv_max_ipv4_udp_payload;
+ int16_t srv_max_ipv6_udp_payload;
+ int32_t srv_tcp_hshake_timeout;
+ int32_t srv_tcp_idle_timeout;
+ int32_t srv_tcp_reply_timeout;
+ int32_t srv_max_tcp_clients;
+ int32_t ctl_timeout;
+ conf_val_t srv_nsid;
+ bool use_ecs;
+ bool srv_ans_rotate;
+ } cache;
+
+ /*! List of dynamically loaded modules. */
+ mod_dynarray_t modules;
+ /*! List of old schemas (lazy freed). */
+ old_schema_dynarray_t old_schemas;
+ /*! List of active query modules. */
+ list_t *query_modules;
+ /*! Default query modules plan. */
+ struct query_plan *query_plan;
+} conf_t;
+
+/*!
+ * Configuration access flags.
+ */
+typedef enum {
+ CONF_FNONE = 0, /*!< Empty flag. */
+ CONF_FREADONLY = 1 << 0, /*!< Read only access. */
+ CONF_FNOCHECK = 1 << 1, /*!< Disabled confdb check. */
+ CONF_FNOHOSTNAME = 1 << 2, /*!< Don't set the hostname. */
+ CONF_FREQMODULES = 1 << 3, /*!< Load module schemas (must succeed). */
+ CONF_FOPTMODULES = 1 << 4, /*!< Load module schemas (may fail). */
+} conf_flag_t;
+
+/*!
+ * Configuration update flags.
+ */
+typedef enum {
+ CONF_UPD_FNONE = 0, /*!< Empty flag. */
+ CONF_UPD_FNOFREE = 1 << 0, /*!< Disable auto-free of previous config. */
+ CONF_UPD_FMODULES = 1 << 1, /*!< Reuse previous global modules. */
+ CONF_UPD_FCONFIO = 1 << 2, /*!< Reuse previous confio reload context. */
+} conf_update_flag_t;
+
+/*!
+ * Returns the active configuration.
+ */
+conf_t* conf(void);
+
+/*!
+ * Refreshes common read-only transaction.
+ *
+ * \param[in] conf Configuration.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int conf_refresh_txn(
+ conf_t *conf
+);
+
+/*!
+ * Refreshes cached hostname.
+ *
+ * \param[in] conf Configuration.
+ */
+void conf_refresh_hostname(
+ conf_t *conf
+);
+
+/*!
+ * Creates new or opens old configuration database.
+ *
+ * \param[out] conf Configuration.
+ * \param[in] schema Configuration schema.
+ * \param[in] db_dir Database path or NULL.
+ * \param[in] max_conf_size Maximum configuration DB size in bytes (LMDB mapsize).
+ * \param[in] flags Access flags.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int conf_new(
+ conf_t **conf,
+ const yp_item_t *schema,
+ const char *db_dir,
+ size_t max_conf_size,
+ conf_flag_t flags
+);
+
+/*!
+ * Creates a partial copy of the active configuration.
+ *
+ * Shared objects: api, mm, db, filename.
+ *
+ * \param[out] conf Configuration.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int conf_clone(
+ conf_t **conf
+);
+
+/*!
+ * Replaces the active configuration with the specified one.
+ *
+ * \param[in] conf New configuration.
+ * \param[in] flags Update flags.
+ *
+ * \return Previous config if CONF_UPD_FNOFREE, else NULL.
+ */
+conf_t *conf_update(
+ conf_t *conf,
+ conf_update_flag_t flags
+);
+
+/*!
+ * Removes the specified configuration.
+ *
+ * \param[in] conf Configuration.
+ */
+void conf_free(
+ conf_t *conf
+);
+
+/*!
+ * Parses textual configuration from the string or from the file.
+ *
+ * This function is not for direct using, just for includes processing!
+ *
+ * \param[in] conf Configuration.
+ * \param[in] txn Transaction.
+ * \param[in] input Configuration string or filename.
+ * \param[in] is_file Specifies if the input is string or input filename.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int conf_parse(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const char *input,
+ bool is_file
+);
+
+/*!
+ * Imports textual configuration.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] input Configuration string or input filename.
+ * \param[in] is_file Specifies if the input is string or filename.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int conf_import(
+ conf_t *conf,
+ const char *input,
+ bool is_file
+);
+
+/*!
+ * Exports configuration to textual file.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] file_name Output filename (stdout is used if NULL).
+ * \param[in] style Formatting style.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int conf_export(
+ conf_t *conf,
+ const char *file_name,
+ yp_style_t style
+);
diff --git a/src/knot/conf/conf.c b/src/knot/conf/conf.c
new file mode 100644
index 0000000..8bdac68
--- /dev/null
+++ b/src/knot/conf/conf.c
@@ -0,0 +1,1216 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+
+#include "knot/conf/base.h"
+#include "knot/conf/confdb.h"
+#include "knot/common/log.h"
+#include "knot/server/dthreads.h"
+#include "libknot/libknot.h"
+#include "libknot/yparser/yptrafo.h"
+#include "contrib/macros.h"
+#include "contrib/sockaddr.h"
+#include "contrib/string.h"
+#include "contrib/wire_ctx.h"
+#include "contrib/openbsd/strlcat.h"
+
+#define DBG_LOG(err) CONF_LOG(LOG_DEBUG, "%s (%s)", __func__, knot_strerror((err)));
+
+conf_val_t conf_get_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key0_name,
+ const yp_name_t *key1_name)
+{
+ conf_val_t val = { NULL };
+
+ if (key0_name == NULL || key1_name == NULL) {
+ val.code = KNOT_EINVAL;
+ DBG_LOG(val.code);
+ return val;
+ }
+
+ conf_db_get(conf, txn, key0_name, key1_name, NULL, 0, &val);
+ switch (val.code) {
+ default:
+ CONF_LOG(LOG_ERR, "failed to read '%s/%s' (%s)",
+ key0_name + 1, key1_name + 1, knot_strerror(val.code));
+ // FALLTHROUGH
+ case KNOT_EOK:
+ case KNOT_ENOENT:
+ return val;
+ }
+}
+
+conf_val_t conf_rawid_get_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key0_name,
+ const yp_name_t *key1_name,
+ const uint8_t *id,
+ size_t id_len)
+{
+ conf_val_t val = { NULL };
+
+ if (key0_name == NULL || key1_name == NULL || id == NULL) {
+ val.code = KNOT_EINVAL;
+ DBG_LOG(val.code);
+ return val;
+ }
+
+ conf_db_get(conf, txn, key0_name, key1_name, id, id_len, &val);
+ switch (val.code) {
+ default:
+ CONF_LOG(LOG_ERR, "failed to read '%s/%s' with identifier (%s)",
+ key0_name + 1, key1_name + 1, knot_strerror(val.code));
+ // FALLTHROUGH
+ case KNOT_EOK:
+ case KNOT_ENOENT:
+ case KNOT_YP_EINVAL_ID:
+ return val;
+ }
+}
+
+conf_val_t conf_id_get_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key0_name,
+ const yp_name_t *key1_name,
+ conf_val_t *id)
+{
+ conf_val_t val = { NULL };
+
+ if (key0_name == NULL || key1_name == NULL || id == NULL ||
+ id->code != KNOT_EOK) {
+ val.code = KNOT_EINVAL;
+ DBG_LOG(val.code);
+ return val;
+ }
+
+ conf_val(id);
+
+ conf_db_get(conf, txn, key0_name, key1_name, id->data, id->len, &val);
+ switch (val.code) {
+ default:
+ CONF_LOG(LOG_ERR, "failed to read '%s/%s' with identifier (%s)",
+ key0_name + 1, key1_name + 1, knot_strerror(val.code));
+ // FALLTHROUGH
+ case KNOT_EOK:
+ case KNOT_ENOENT:
+ case KNOT_YP_EINVAL_ID:
+ return val;
+ }
+}
+
+conf_val_t conf_mod_get_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key1_name,
+ const conf_mod_id_t *mod_id)
+{
+ conf_val_t val = { NULL };
+
+ if (key1_name == NULL || mod_id == NULL) {
+ val.code = KNOT_EINVAL;
+ DBG_LOG(val.code);
+ return val;
+ }
+
+ conf_db_get(conf, txn, mod_id->name, key1_name, mod_id->data, mod_id->len,
+ &val);
+ switch (val.code) {
+ default:
+ CONF_LOG(LOG_ERR, "failed to read '%s/%s' (%s)",
+ mod_id->name + 1, key1_name + 1, knot_strerror(val.code));
+ // FALLTHROUGH
+ case KNOT_EOK:
+ case KNOT_ENOENT:
+ case KNOT_YP_EINVAL_ID:
+ return val;
+ }
+}
+
+conf_val_t conf_zone_get_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key1_name,
+ const knot_dname_t *dname)
+{
+ conf_val_t val = { NULL };
+
+ if (key1_name == NULL || dname == NULL) {
+ val.code = KNOT_EINVAL;
+ DBG_LOG(val.code);
+ return val;
+ }
+
+ size_t dname_size = knot_dname_size(dname);
+
+ // Try to get explicit value.
+ conf_db_get(conf, txn, C_ZONE, key1_name, dname, dname_size, &val);
+ switch (val.code) {
+ case KNOT_EOK:
+ return val;
+ default:
+ CONF_LOG_ZONE(LOG_ERR, dname, "failed to read '%s/%s' (%s)",
+ C_ZONE + 1, key1_name + 1, knot_strerror(val.code));
+ // FALLTHROUGH
+ case KNOT_ENOENT:
+ break;
+ }
+
+ // Check if a template is available.
+ conf_db_get(conf, txn, C_ZONE, C_TPL, dname, dname_size, &val);
+ switch (val.code) {
+ case KNOT_EOK:
+ // Use the specified template.
+ conf_val(&val);
+ conf_db_get(conf, txn, C_TPL, key1_name, val.data, val.len, &val);
+ break;
+ default:
+ CONF_LOG_ZONE(LOG_ERR, dname, "failed to read '%s/%s' (%s)",
+ C_ZONE + 1, C_TPL + 1, knot_strerror(val.code));
+ // FALLTHROUGH
+ case KNOT_ENOENT:
+ case KNOT_YP_EINVAL_ID:
+ // Use the default template.
+ conf_db_get(conf, txn, C_TPL, key1_name, CONF_DEFAULT_ID + 1,
+ CONF_DEFAULT_ID[0], &val);
+ }
+
+ switch (val.code) {
+ default:
+ CONF_LOG_ZONE(LOG_ERR, dname, "failed to read '%s/%s' (%s)",
+ C_TPL + 1, key1_name + 1, knot_strerror(val.code));
+ // FALLTHROUGH
+ case KNOT_EOK:
+ case KNOT_ENOENT:
+ case KNOT_YP_EINVAL_ID:
+ break;
+ }
+
+ return val;
+}
+
+conf_val_t conf_default_get_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key1_name)
+{
+ conf_val_t val = { NULL };
+
+ if (key1_name == NULL) {
+ val.code = KNOT_EINVAL;
+ DBG_LOG(val.code);
+ return val;
+ }
+
+ conf_db_get(conf, txn, C_TPL, key1_name, CONF_DEFAULT_ID + 1,
+ CONF_DEFAULT_ID[0], &val);
+ switch (val.code) {
+ default:
+ CONF_LOG(LOG_ERR, "failed to read default '%s/%s' (%s)",
+ C_TPL + 1, key1_name + 1, knot_strerror(val.code));
+ // FALLTHROUGH
+ case KNOT_EOK:
+ case KNOT_ENOENT:
+ case KNOT_YP_EINVAL_ID:
+ break;
+ }
+
+ return val;
+}
+
+bool conf_rawid_exists_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key0_name,
+ const uint8_t *id,
+ size_t id_len)
+{
+ if (key0_name == NULL || id == NULL) {
+ DBG_LOG(KNOT_EINVAL);
+ return false;
+ }
+
+ int ret = conf_db_get(conf, txn, key0_name, NULL, id, id_len, NULL);
+ switch (ret) {
+ case KNOT_EOK:
+ return true;
+ default:
+ CONF_LOG(LOG_ERR, "failed to check '%s' for identifier (%s)",
+ key0_name + 1, knot_strerror(ret));
+ // FALLTHROUGH
+ case KNOT_ENOENT:
+ case KNOT_YP_EINVAL_ID:
+ return false;
+ }
+}
+
+bool conf_id_exists_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key0_name,
+ conf_val_t *id)
+{
+ if (key0_name == NULL || id == NULL || id->code != KNOT_EOK) {
+ DBG_LOG(KNOT_EINVAL);
+ return false;
+ }
+
+ conf_val(id);
+
+ int ret = conf_db_get(conf, txn, key0_name, NULL, id->data, id->len, NULL);
+ switch (ret) {
+ case KNOT_EOK:
+ return true;
+ default:
+ CONF_LOG(LOG_ERR, "failed to check '%s' for identifier (%s)",
+ key0_name + 1, knot_strerror(ret));
+ // FALLTHROUGH
+ case KNOT_ENOENT:
+ case KNOT_YP_EINVAL_ID:
+ return false;
+ }
+}
+
+size_t conf_id_count_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key0_name)
+{
+ size_t count = 0;
+
+ for (conf_iter_t iter = conf_iter_txn(conf, txn, key0_name);
+ iter.code == KNOT_EOK; conf_iter_next(conf, &iter)) {
+ count++;
+ }
+
+ return count;
+}
+
+conf_iter_t conf_iter_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key0_name)
+{
+ conf_iter_t iter = { NULL };
+
+ (void)conf_db_iter_begin(conf, txn, key0_name, &iter);
+ switch (iter.code) {
+ default:
+ CONF_LOG(LOG_ERR, "failed to iterate through '%s' (%s)",
+ key0_name + 1, knot_strerror(iter.code));
+ // FALLTHROUGH
+ case KNOT_EOK:
+ case KNOT_ENOENT:
+ return iter;
+ }
+}
+
+void conf_iter_next(
+ conf_t *conf,
+ conf_iter_t *iter)
+{
+ (void)conf_db_iter_next(conf, iter);
+ switch (iter->code) {
+ default:
+ CONF_LOG(LOG_ERR, "failed to read next item (%s)",
+ knot_strerror(iter->code));
+ // FALLTHROUGH
+ case KNOT_EOK:
+ case KNOT_EOF:
+ return;
+ }
+}
+
+conf_val_t conf_iter_id(
+ conf_t *conf,
+ conf_iter_t *iter)
+{
+ conf_val_t val = { NULL };
+
+ val.code = conf_db_iter_id(conf, iter, &val.blob, &val.blob_len);
+ switch (val.code) {
+ default:
+ CONF_LOG(LOG_ERR, "failed to read identifier (%s)",
+ knot_strerror(val.code));
+ // FALLTHROUGH
+ case KNOT_EOK:
+ val.item = iter->item;
+ return val;
+ }
+}
+
+void conf_iter_finish(
+ conf_t *conf,
+ conf_iter_t *iter)
+{
+ conf_db_iter_finish(conf, iter);
+}
+
+size_t conf_val_count(
+ conf_val_t *val)
+{
+ if (val == NULL || val->code != KNOT_EOK) {
+ return 0;
+ }
+
+ if (!(val->item->flags & YP_FMULTI)) {
+ return 1;
+ }
+
+ size_t count = 0;
+ conf_val(val);
+ while (val->code == KNOT_EOK) {
+ count++;
+ conf_val_next(val);
+ }
+ if (val->code != KNOT_EOF) {
+ return 0;
+ }
+
+ // Reset to the initial state.
+ conf_val(val);
+
+ return count;
+}
+
+void conf_val(
+ conf_val_t *val)
+{
+ assert(val != NULL);
+ assert(val->code == KNOT_EOK || val->code == KNOT_EOF);
+
+ if (val->item->flags & YP_FMULTI) {
+ // Check if already called and not at the end.
+ if (val->data != NULL && val->code != KNOT_EOF) {
+ return;
+ }
+
+ assert(val->blob != NULL);
+ wire_ctx_t ctx = wire_ctx_init_const(val->blob, val->blob_len);
+ uint16_t len = wire_ctx_read_u16(&ctx);
+ assert(ctx.error == KNOT_EOK);
+
+ val->data = ctx.position;
+ val->len = len;
+ val->code = KNOT_EOK;
+ } else {
+ // Check for empty data.
+ if (val->blob_len == 0) {
+ val->data = NULL;
+ val->len = 0;
+ val->code = KNOT_EOK;
+ return;
+ } else {
+ assert(val->blob != NULL);
+ val->data = val->blob;
+ val->len = val->blob_len;
+ val->code = KNOT_EOK;
+ }
+ }
+}
+
+void conf_val_next(
+ conf_val_t *val)
+{
+ assert(val != NULL);
+ assert(val->code == KNOT_EOK);
+ assert(val->item->flags & YP_FMULTI);
+
+ // Check for the 'zero' call.
+ if (val->data == NULL) {
+ conf_val(val);
+ return;
+ }
+
+ if (val->data + val->len < val->blob + val->blob_len) {
+ wire_ctx_t ctx = wire_ctx_init_const(val->blob, val->blob_len);
+ size_t offset = val->data + val->len - val->blob;
+ wire_ctx_skip(&ctx, offset);
+ uint16_t len = wire_ctx_read_u16(&ctx);
+ assert(ctx.error == KNOT_EOK);
+
+ val->data = ctx.position;
+ val->len = len;
+ val->code = KNOT_EOK;
+ } else {
+ val->data = NULL;
+ val->len = 0;
+ val->code = KNOT_EOF;
+ }
+}
+
+bool conf_val_equal(
+ conf_val_t *val1,
+ conf_val_t *val2)
+{
+ if (val1->blob_len == val2->blob_len &&
+ memcmp(val1->blob, val2->blob, val1->blob_len) == 0) {
+ return true;
+ }
+
+ return false;
+}
+
+int64_t conf_int(
+ conf_val_t *val)
+{
+ assert(val != NULL && val->item != NULL);
+ assert(val->item->type == YP_TINT ||
+ (val->item->type == YP_TREF &&
+ val->item->var.r.ref->var.g.id->type == YP_TINT));
+
+ if (val->code == KNOT_EOK) {
+ conf_val(val);
+ return yp_int(val->data);
+ } else {
+ return val->item->var.i.dflt;
+ }
+}
+
+bool conf_bool(
+ conf_val_t *val)
+{
+ assert(val != NULL && val->item != NULL);
+ assert(val->item->type == YP_TBOOL ||
+ (val->item->type == YP_TREF &&
+ val->item->var.r.ref->var.g.id->type == YP_TBOOL));
+
+ if (val->code == KNOT_EOK) {
+ conf_val(val);
+ return yp_bool(val->data);
+ } else {
+ return val->item->var.b.dflt;
+ }
+}
+
+unsigned conf_opt(
+ conf_val_t *val)
+{
+ assert(val != NULL && val->item != NULL);
+ assert(val->item->type == YP_TOPT ||
+ (val->item->type == YP_TREF &&
+ val->item->var.r.ref->var.g.id->type == YP_TOPT));
+
+ if (val->code == KNOT_EOK) {
+ conf_val(val);
+ return yp_opt(val->data);
+ } else {
+ return val->item->var.o.dflt;
+ }
+}
+
+const char* conf_str(
+ conf_val_t *val)
+{
+ assert(val != NULL && val->item != NULL);
+ assert(val->item->type == YP_TSTR ||
+ (val->item->type == YP_TREF &&
+ val->item->var.r.ref->var.g.id->type == YP_TSTR));
+
+ if (val->code == KNOT_EOK) {
+ conf_val(val);
+ return yp_str(val->data);
+ } else {
+ return val->item->var.s.dflt;
+ }
+}
+
+const knot_dname_t* conf_dname(
+ conf_val_t *val)
+{
+ assert(val != NULL && val->item != NULL);
+ assert(val->item->type == YP_TDNAME ||
+ (val->item->type == YP_TREF &&
+ val->item->var.r.ref->var.g.id->type == YP_TDNAME));
+
+ if (val->code == KNOT_EOK) {
+ conf_val(val);
+ return yp_dname(val->data);
+ } else {
+ return (const knot_dname_t *)val->item->var.d.dflt;
+ }
+}
+
+const uint8_t* conf_bin(
+ conf_val_t *val,
+ size_t *len)
+{
+ assert(val != NULL && val->item != NULL && len != NULL);
+ assert(val->item->type == YP_THEX || val->item->type == YP_TB64 ||
+ (val->item->type == YP_TREF &&
+ (val->item->var.r.ref->var.g.id->type == YP_THEX ||
+ val->item->var.r.ref->var.g.id->type == YP_TB64)));
+
+ if (val->code == KNOT_EOK) {
+ conf_val(val);
+ *len = yp_bin_len(val->data);
+ return yp_bin(val->data);
+ } else {
+ *len = val->item->var.d.dflt_len;
+ return val->item->var.d.dflt;
+ }
+}
+
+const uint8_t* conf_data(
+ conf_val_t *val,
+ size_t *len)
+{
+ assert(val != NULL && val->item != NULL);
+ assert(val->item->type == YP_TDATA ||
+ (val->item->type == YP_TREF &&
+ val->item->var.r.ref->var.g.id->type == YP_TDATA));
+
+ if (val->code == KNOT_EOK) {
+ conf_val(val);
+ *len = val->len;
+ return val->data;
+ } else {
+ *len = val->item->var.d.dflt_len;
+ return val->item->var.d.dflt;
+ }
+}
+
+struct sockaddr_storage conf_addr(
+ conf_val_t *val,
+ const char *sock_base_dir)
+{
+ assert(val != NULL && val->item != NULL);
+ assert(val->item->type == YP_TADDR ||
+ (val->item->type == YP_TREF &&
+ val->item->var.r.ref->var.g.id->type == YP_TADDR));
+
+ struct sockaddr_storage out = { AF_UNSPEC };
+
+ if (val->code == KNOT_EOK) {
+ bool no_port;
+ conf_val(val);
+ out = yp_addr(val->data, &no_port);
+
+ if (out.ss_family == AF_UNIX) {
+ // val->data[0] is socket type identifier!
+ if (val->data[1] != '/' && sock_base_dir != NULL) {
+ char *tmp = sprintf_alloc("%s/%s", sock_base_dir,
+ val->data + 1);
+ val->code = sockaddr_set(&out, AF_UNIX, tmp, 0);
+ free(tmp);
+ }
+ } else if (no_port) {
+ sockaddr_port_set((struct sockaddr *)&out,
+ val->item->var.a.dflt_port);
+ }
+ } else {
+ const char *dflt_socket = val->item->var.a.dflt_socket;
+ if (dflt_socket != NULL) {
+ if (dflt_socket[0] == '/' || sock_base_dir == NULL) {
+ val->code = sockaddr_set(&out, AF_UNIX,
+ dflt_socket, 0);
+ } else {
+ char *tmp = sprintf_alloc("%s/%s", sock_base_dir,
+ dflt_socket);
+ val->code = sockaddr_set(&out, AF_UNIX, tmp, 0);
+ free(tmp);
+ }
+ }
+ }
+
+ return out;
+}
+
+struct sockaddr_storage conf_addr_range(
+ conf_val_t *val,
+ struct sockaddr_storage *max_ss,
+ int *prefix_len)
+{
+ assert(val != NULL && val->item != NULL && max_ss != NULL &&
+ prefix_len != NULL);
+ assert(val->item->type == YP_TNET ||
+ (val->item->type == YP_TREF &&
+ val->item->var.r.ref->var.g.id->type == YP_TNET));
+
+ struct sockaddr_storage out = { AF_UNSPEC };
+
+ if (val->code == KNOT_EOK) {
+ conf_val(val);
+ out = yp_addr_noport(val->data);
+ // addr_type, addr, format, formatted_data (port| addr| empty).
+ const uint8_t *format = val->data + sizeof(uint8_t) +
+ ((out.ss_family == AF_INET) ?
+ IPV4_PREFIXLEN / 8 : IPV6_PREFIXLEN / 8);
+ // See addr_range_to_bin.
+ switch (*format) {
+ case 1:
+ max_ss->ss_family = AF_UNSPEC;
+ *prefix_len = yp_int(format + sizeof(uint8_t));
+ break;
+ case 2:
+ *max_ss = yp_addr_noport(format + sizeof(uint8_t));
+ *prefix_len = -1;
+ break;
+ default:
+ max_ss->ss_family = AF_UNSPEC;
+ *prefix_len = -1;
+ break;
+ }
+ } else {
+ max_ss->ss_family = AF_UNSPEC;
+ *prefix_len = -1;
+ }
+
+ return out;
+}
+
+bool conf_addr_range_match(
+ conf_val_t *range,
+ const struct sockaddr_storage *addr)
+{
+ if (range == NULL || addr == NULL) {
+ return false;
+ }
+
+ while (range->code == KNOT_EOK) {
+ int mask;
+ struct sockaddr_storage min, max;
+
+ min = conf_addr_range(range, &max, &mask);
+ if (max.ss_family == AF_UNSPEC) {
+ if (sockaddr_net_match((struct sockaddr *)addr,
+ (struct sockaddr *)&min, mask)) {
+ return true;
+ }
+ } else {
+ if (sockaddr_range_match((struct sockaddr *)addr,
+ (struct sockaddr *)&min,
+ (struct sockaddr *)&max)) {
+ return true;
+ }
+ }
+
+ conf_val_next(range);
+ }
+
+ return false;
+}
+
+char* conf_abs_path(
+ conf_val_t *val,
+ const char *base_dir)
+{
+ const char *path = conf_str(val);
+ if (path == NULL) {
+ return NULL;
+ } else if (path[0] == '/') {
+ return strdup(path);
+ } else {
+ char *abs_path;
+ if (base_dir == NULL) {
+ char *cwd = realpath("./", NULL);
+ abs_path = sprintf_alloc("%s/%s", cwd, path);
+ free(cwd);
+ } else {
+ abs_path = sprintf_alloc("%s/%s", base_dir, path);
+ }
+ return abs_path;
+ }
+}
+
+conf_mod_id_t* conf_mod_id(
+ conf_val_t *val)
+{
+ assert(val != NULL && val->item != NULL);
+ assert(val->item->type == YP_TDATA ||
+ (val->item->type == YP_TREF &&
+ val->item->var.r.ref->var.g.id->type == YP_TDATA));
+
+ conf_mod_id_t *mod_id = NULL;
+
+ if (val->code == KNOT_EOK) {
+ conf_val(val);
+
+ mod_id = malloc(sizeof(conf_mod_id_t));
+ if (mod_id == NULL) {
+ return NULL;
+ }
+
+ // Set module name in yp_name_t format + add zero termination.
+ size_t name_len = 1 + val->data[0];
+ mod_id->name = malloc(name_len + 1);
+ if (mod_id->name == NULL) {
+ free(mod_id);
+ return NULL;
+ }
+ memcpy(mod_id->name, val->data, name_len);
+ mod_id->name[name_len] = '\0';
+
+ // Set module identifier.
+ mod_id->len = val->len - name_len;
+ mod_id->data = malloc(mod_id->len);
+ if (mod_id->data == NULL) {
+ free(mod_id->name);
+ free(mod_id);
+ return NULL;
+ }
+ memcpy(mod_id->data, val->data + name_len, mod_id->len);
+ }
+
+ return mod_id;
+}
+
+void conf_free_mod_id(
+ conf_mod_id_t *mod_id)
+{
+ free(mod_id->name);
+ free(mod_id->data);
+ free(mod_id);
+}
+
+static int get_index(
+ const char **start,
+ const char *end,
+ unsigned *index1,
+ unsigned *index2)
+{
+ char c, *p;
+ if (sscanf(*start, "[%u%c", index1, &c) != 2) {
+ return KNOT_EINVAL;
+ }
+ switch (c) {
+ case '-':
+ p = strchr(*start, '-') + 1;
+ if (end - p < 2 || index2 == NULL ||
+ sscanf(p, "%u%c", index2, &c) != 2 || c != ']') {
+ return KNOT_EINVAL;
+ }
+ break;
+ case ']':
+ if (index2 != NULL) {
+ *index2 = *index1;
+ }
+ break;
+ default:
+ return KNOT_EINVAL;
+ }
+
+ *start = strchr(*start, ']') + 1;
+ return ((*index1 < 256 && (index2 == NULL || *index2 < 256)
+ && end - *start >= 0 && (index2 == NULL || *index2 >= *index1))
+ ? KNOT_EOK : KNOT_EINVAL);
+}
+
+static void replace_slashes(
+ char *name,
+ bool remove_dot)
+{
+ // Replace possible slashes with underscores.
+ char *ch;
+ for (ch = name; *ch != '\0'; ch++) {
+ if (*ch == '/') {
+ *ch = '_';
+ }
+ }
+
+ // Remove trailing dot.
+ if (remove_dot && ch > name) {
+ assert(*(ch - 1) == '.');
+ *(ch - 1) = '\0';
+ }
+}
+
+static int str_char(
+ const knot_dname_t *zone,
+ char *buff,
+ size_t buff_len,
+ unsigned index1,
+ unsigned index2)
+{
+ if (knot_dname_to_str(buff, zone, buff_len) == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ size_t zone_len = strlen(buff);
+ assert(zone_len > 0);
+
+ // Get the block length.
+ size_t len = index2 - index1 + 1;
+
+ // Check for out of scope block.
+ if (index1 >= zone_len) {
+ buff[0] = '\0';
+ return KNOT_EOK;
+ }
+ // Check for partial block.
+ if (index2 >= zone_len) {
+ len = zone_len - index1;
+ }
+
+ // Copy the block.
+ memmove(buff, buff + index1, len);
+ buff[len] = '\0';
+
+ // Replace possible slashes with underscores.
+ replace_slashes(buff, false);
+
+ return KNOT_EOK;
+}
+
+static int str_zone(
+ const knot_dname_t *zone,
+ char *buff,
+ size_t buff_len)
+{
+ if (knot_dname_to_str(buff, zone, buff_len) == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ // Replace possible slashes with underscores.
+ replace_slashes(buff, true);
+
+ return KNOT_EOK;
+}
+
+static int str_label(
+ const knot_dname_t *zone,
+ char *buff,
+ size_t buff_len,
+ size_t right_index)
+{
+ size_t labels = knot_dname_labels(zone, NULL);
+
+ // Check for root label of the root zone.
+ if (labels == 0 && right_index == 0) {
+ return str_zone(zone, buff, buff_len);
+ // Check for labels error or for an exceeded index.
+ } else if (labels < 1 || labels <= right_index) {
+ buff[0] = '\0';
+ return KNOT_EOK;
+ }
+
+ // ~ Label length + label + root label.
+ knot_dname_t label[1 + KNOT_DNAME_MAXLABELLEN + 1];
+
+ // Compute the index from the left.
+ assert(labels > right_index);
+ size_t index = labels - right_index - 1;
+
+ // Create a dname from the single label.
+ size_t prefix_len = knot_dname_prefixlen(zone, index, NULL);
+ size_t label_len = *(zone + prefix_len);
+ memcpy(label, zone + prefix_len, 1 + label_len);
+ label[1 + label_len] = '\0';
+
+ return str_zone(label, buff, buff_len);
+}
+
+static char* get_filename(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const knot_dname_t *zone,
+ const char *name)
+{
+ assert(name);
+
+ const char *end = name + strlen(name);
+ char out[1024] = "";
+
+ do {
+ // Search for a formatter.
+ const char *pos = strchr(name, '%');
+
+ // If no formatter, copy the rest of the name.
+ if (pos == NULL) {
+ if (strlcat(out, name, sizeof(out)) >= sizeof(out)) {
+ CONF_LOG_ZONE(LOG_WARNING, zone, "too long zonefile name");
+ return NULL;
+ }
+ break;
+ }
+
+ // Copy constant block.
+ char *block = strndup(name, pos - name);
+ if (block == NULL ||
+ strlcat(out, block, sizeof(out)) >= sizeof(out)) {
+ CONF_LOG_ZONE(LOG_WARNING, zone, "too long zonefile name");
+ free(block);
+ return NULL;
+ }
+ free(block);
+
+ // Move name pointer behind the formatter.
+ name = pos + 2;
+
+ char buff[512] = "";
+ unsigned idx1, idx2;
+ bool failed = false;
+
+ const char type = *(pos + 1);
+ switch (type) {
+ case '%':
+ strlcat(buff, "%", sizeof(buff));
+ break;
+ case 'c':
+ if (get_index(&name, end, &idx1, &idx2) != KNOT_EOK ||
+ str_char(zone, buff, sizeof(buff), idx1, idx2) != KNOT_EOK) {
+ failed = true;
+ }
+ break;
+ case 'l':
+ if (get_index(&name, end, &idx1, NULL) != KNOT_EOK ||
+ str_label(zone, buff, sizeof(buff), idx1) != KNOT_EOK) {
+ failed = true;
+ }
+ break;
+ case 's':
+ if (str_zone(zone, buff, sizeof(buff)) != KNOT_EOK) {
+ failed = true;
+ }
+ break;
+ case '\0':
+ CONF_LOG_ZONE(LOG_WARNING, zone, "ignoring missing "
+ "trailing zonefile formatter");
+ continue;
+ default:
+ CONF_LOG_ZONE(LOG_WARNING, zone, "ignoring zonefile "
+ "formatter '%%%c'", type);
+ continue;
+ }
+
+ if (failed) {
+ CONF_LOG_ZONE(LOG_WARNING, zone, "failed to process "
+ "zonefile formatter '%%%c'", type);
+ return NULL;
+ }
+
+ if (strlcat(out, buff, sizeof(out)) >= sizeof(out)) {
+ CONF_LOG_ZONE(LOG_WARNING, zone, "too long zonefile name");
+ return NULL;
+ }
+ } while (name < end);
+
+ // Use storage prefix if not absolute path.
+ if (out[0] == '/') {
+ return strdup(out);
+ } else {
+ conf_val_t val = conf_zone_get_txn(conf, txn, C_STORAGE, zone);
+ char *storage = conf_abs_path(&val, NULL);
+ if (storage == NULL) {
+ return NULL;
+ }
+ char *abs = sprintf_alloc("%s/%s", storage, out);
+ free(storage);
+ return abs;
+ }
+}
+
+char* conf_zonefile_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const knot_dname_t *zone)
+{
+ if (zone == NULL) {
+ return NULL;
+ }
+
+ conf_val_t val = conf_zone_get_txn(conf, txn, C_FILE, zone);
+ const char *file = conf_str(&val);
+
+ // Use default zonefile name pattern if not specified.
+ if (file == NULL) {
+ file = "%s.zone";
+ }
+
+ return get_filename(conf, txn, zone, file);
+}
+
+char* conf_journalfile_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn)
+{
+ conf_val_t val = conf_default_get_txn(conf, txn, C_STORAGE);
+ char *storage = conf_abs_path(&val, NULL);
+ val = conf_default_get_txn(conf, txn, C_JOURNAL_DB);
+ char *journaldir = conf_abs_path(&val, storage);
+ free(storage);
+
+ return journaldir;
+}
+
+char* conf_kaspdir_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn)
+{
+ conf_val_t val = conf_default_get_txn(conf, txn, C_STORAGE);
+ char *storage = conf_abs_path(&val, NULL);
+ val = conf_default_get_txn(conf, txn, C_KASP_DB);
+ char *kaspdir = conf_abs_path(&val, storage);
+ free(storage);
+
+ return kaspdir;
+}
+
+size_t conf_udp_threads_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn)
+{
+ conf_val_t val = conf_get_txn(conf, txn, C_SRV, C_UDP_WORKERS);
+ int64_t workers = conf_int(&val);
+ if (workers == YP_NIL) {
+ return dt_optimal_size();
+ }
+
+ return workers;
+}
+
+size_t conf_tcp_threads_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn)
+{
+ conf_val_t val = conf_get_txn(conf, txn, C_SRV, C_TCP_WORKERS);
+ int64_t workers = conf_int(&val);
+ if (workers == YP_NIL) {
+ return MAX(conf_udp_threads_txn(conf, txn) * 2, CONF_XFERS);
+ }
+
+ return workers;
+}
+
+size_t conf_bg_threads_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn)
+{
+ conf_val_t val = conf_get_txn(conf, txn, C_SRV, C_BG_WORKERS);
+ int64_t workers = conf_int(&val);
+ if (workers == YP_NIL) {
+ return MIN(dt_optimal_size(), CONF_XFERS);
+ }
+
+ return workers;
+}
+
+int conf_user_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ int *uid,
+ int *gid)
+{
+ if (uid == NULL || gid == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ conf_val_t val = conf_get_txn(conf, txn, C_SRV, C_USER);
+ if (val.code == KNOT_EOK) {
+ char *user = strdup(conf_str(&val));
+
+ // Search for user:group separator.
+ char *sep_pos = strchr(user, ':');
+ if (sep_pos != NULL) {
+ // Process group name.
+ struct group *grp = getgrnam(sep_pos + 1);
+ if (grp != NULL) {
+ *gid = grp->gr_gid;
+ } else {
+ CONF_LOG(LOG_ERR, "invalid group name '%s'",
+ sep_pos + 1);
+ free(user);
+ return KNOT_EINVAL;
+ }
+
+ // Cut off group part.
+ *sep_pos = '\0';
+ } else {
+ *gid = getgid();
+ }
+
+ // Process user name.
+ struct passwd *pwd = getpwnam(user);
+ if (pwd != NULL) {
+ *uid = pwd->pw_uid;
+ } else {
+ CONF_LOG(LOG_ERR, "invalid user name '%s'", user);
+ free(user);
+ return KNOT_EINVAL;
+ }
+
+ free(user);
+ return KNOT_EOK;
+ } else if (val.code == KNOT_ENOENT) {
+ *uid = getuid();
+ *gid = getgid();
+ return KNOT_EOK;
+ } else {
+ return val.code;
+ }
+}
+
+conf_remote_t conf_remote_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ conf_val_t *id,
+ size_t index)
+{
+ assert(id != NULL && id->item != NULL);
+ assert(id->item->type == YP_TSTR ||
+ (id->item->type == YP_TREF &&
+ id->item->var.r.ref->var.g.id->type == YP_TSTR));
+
+ conf_remote_t out = { { AF_UNSPEC } };
+
+ conf_val_t rundir_val = conf_get_txn(conf, txn, C_SRV, C_RUNDIR);
+ char *rundir = conf_abs_path(&rundir_val, NULL);
+
+ // Get indexed remote address.
+ conf_val_t val = conf_id_get_txn(conf, txn, C_RMT, C_ADDR, id);
+ for (size_t i = 0; val.code == KNOT_EOK && i < index; i++) {
+ if (i == 0) {
+ conf_val(&val);
+ }
+ conf_val_next(&val);
+ }
+ // Index overflow causes empty socket.
+ out.addr = conf_addr(&val, rundir);
+
+ // Get outgoing address if family matches (optional).
+ val = conf_id_get_txn(conf, txn, C_RMT, C_VIA, id);
+ while (val.code == KNOT_EOK) {
+ struct sockaddr_storage via = conf_addr(&val, rundir);
+ if (via.ss_family == out.addr.ss_family) {
+ out.via = conf_addr(&val, rundir);
+ break;
+ }
+ conf_val_next(&val);
+ }
+
+ // Get TSIG key (optional).
+ conf_val_t key_id = conf_id_get_txn(conf, txn, C_RMT, C_KEY, id);
+ if (key_id.code == KNOT_EOK) {
+ out.key.name = (knot_dname_t *)conf_dname(&key_id);
+
+ val = conf_id_get_txn(conf, txn, C_KEY, C_ALG, &key_id);
+ out.key.algorithm = conf_opt(&val);
+
+ val = conf_id_get_txn(conf, txn, C_KEY, C_SECRET, &key_id);
+ out.key.secret.data = (uint8_t *)conf_bin(&val, &out.key.secret.size);
+ }
+
+ free(rundir);
+
+ return out;
+}
diff --git a/src/knot/conf/conf.h b/src/knot/conf/conf.h
new file mode 100644
index 0000000..bc3183e
--- /dev/null
+++ b/src/knot/conf/conf.h
@@ -0,0 +1,715 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <sys/socket.h>
+
+#include "knot/conf/base.h"
+#include "knot/conf/schema.h"
+
+#define CONF_XFERS 10
+
+/*! Configuration remote getter output. */
+typedef struct {
+ /*! Target socket address. */
+ struct sockaddr_storage addr;
+ /*! Local outgoing socket address. */
+ struct sockaddr_storage via;
+ /*! TSIG key. */
+ knot_tsig_key_t key;
+} conf_remote_t;
+
+/*! Configuration section iterator. */
+typedef struct {
+ /*! Item description. */
+ const yp_item_t *item;
+ /*! Namedb iterator. */
+ knot_db_iter_t *iter;
+ /*! Key0 database code. */
+ uint8_t key0_code;
+ // Public items.
+ /*! Iterator return code. */
+ int code;
+} conf_iter_t;
+
+/*! Configuration module getter output. */
+typedef struct {
+ /*! Module name. */
+ yp_name_t *name;
+ /*! Module id data. */
+ uint8_t *data;
+ /*! Module id data length. */
+ size_t len;
+} conf_mod_id_t;
+
+/*!
+ * Gets the configuration item value of the section without identifiers.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] txn Configuration DB transaction.
+ * \param[in] key0_name Section name.
+ * \param[in] key1_name Item name.
+ *
+ * \return Item value.
+ */
+conf_val_t conf_get_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key0_name,
+ const yp_name_t *key1_name
+);
+static inline conf_val_t conf_get(
+ conf_t *conf,
+ const yp_name_t *key0_name,
+ const yp_name_t *key1_name)
+{
+ return conf_get_txn(conf, &conf->read_txn, key0_name, key1_name);
+}
+
+/*!
+ * Gets the configuration item value of the section with identifiers (raw version).
+ *
+ * \param[in] conf Configuration.
+ * \param[in] txn Configuration DB transaction.
+ * \param[in] key0_name Section name.
+ * \param[in] key1_name Item name.
+ * \param[in] id Section identifier (raw value).
+ * \param[in] id_len Length of the section identifier.
+ *
+ * \return Item value.
+ */
+conf_val_t conf_rawid_get_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key0_name,
+ const yp_name_t *key1_name,
+ const uint8_t *id,
+ size_t id_len
+);
+static inline conf_val_t conf_rawid_get(
+ conf_t *conf,
+ const yp_name_t *key0_name,
+ const yp_name_t *key1_name,
+ const uint8_t *id,
+ size_t id_len)
+{
+ return conf_rawid_get_txn(conf, &conf->read_txn, key0_name, key1_name,
+ id, id_len);
+}
+
+/*!
+ * Gets the configuration item value of the section with identifiers.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] txn Configuration DB transaction.
+ * \param[in] key0_name Section name.
+ * \param[in] key1_name Item name.
+ * \param[in] id Section identifier (output of a config getter).
+ *
+ * \return Item value.
+ */
+conf_val_t conf_id_get_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key0_name,
+ const yp_name_t *key1_name,
+ conf_val_t *id
+);
+static inline conf_val_t conf_id_get(
+ conf_t *conf,
+ const yp_name_t *key0_name,
+ const yp_name_t *key1_name,
+ conf_val_t *id)
+{
+ return conf_id_get_txn(conf, &conf->read_txn, key0_name, key1_name, id);
+}
+
+/*!
+ * Gets the configuration item value of the module section.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] txn Configuration DB transaction.
+ * \param[in] key1_name Item name.
+ * \param[in] mod_id Module identifier.
+ *
+ * \return Item value.
+ */
+conf_val_t conf_mod_get_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key1_name,
+ const conf_mod_id_t *mod_id
+);
+static inline conf_val_t conf_mod_get(
+ conf_t *conf,
+ const yp_name_t *key1_name,
+ const conf_mod_id_t *mod_id)
+{
+ return conf_mod_get_txn(conf, &conf->read_txn, key1_name, mod_id);
+}
+
+/*!
+ * Gets the configuration item value of the zone section.
+ *
+ * \note A possibly associated template is taken into account.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] txn Configuration DB transaction.
+ * \param[in] key1_name Item name.
+ * \param[in] dname Zone name.
+ *
+ * \return Item value.
+ */
+conf_val_t conf_zone_get_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key1_name,
+ const knot_dname_t *dname
+);
+static inline conf_val_t conf_zone_get(
+ conf_t *conf,
+ const yp_name_t *key1_name,
+ const knot_dname_t *dname)
+{
+ return conf_zone_get_txn(conf, &conf->read_txn, key1_name, dname);
+}
+
+/*!
+ * Gets the configuration item value of the default template.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] txn Configuration DB transaction.
+ * \param[in] key1_name Item name.
+ *
+ * \return Item value.
+ */
+conf_val_t conf_default_get_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key1_name
+);
+static inline conf_val_t conf_default_get(
+ conf_t *conf,
+ const yp_name_t *key1_name)
+{
+ return conf_default_get_txn(conf, &conf->read_txn, key1_name);
+}
+
+/*!
+ * Checks the configuration section for the identifier (raw version).
+ *
+ * \param[in] conf Configuration.
+ * \param[in] txn Configuration DB transaction.
+ * \param[in] key0_name Section name.
+ * \param[in] id Section identifier (raw value).
+ * \param[in] id_len Length of the section identifier.
+ *
+ * \return True if exists.
+ */
+bool conf_rawid_exists_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key0_name,
+ const uint8_t *id,
+ size_t id_len
+);
+static inline bool conf_rawid_exists(
+ conf_t *conf,
+ const yp_name_t *key0_name,
+ const uint8_t *id,
+ size_t id_len)
+{
+ return conf_rawid_exists_txn(conf, &conf->read_txn, key0_name, id, id_len);
+}
+
+/*!
+ * Checks the configuration section for the identifier.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] txn Configuration DB transaction.
+ * \param[in] key0_name Section name.
+ * \param[in] id Section identifier (output of a config getter).
+ *
+ * \return True if exists.
+ */
+bool conf_id_exists_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key0_name,
+ conf_val_t *id
+);
+static inline bool conf_id_exists(
+ conf_t *conf,
+ const yp_name_t *key0_name,
+ conf_val_t *id)
+{
+ return conf_id_exists_txn(conf, &conf->read_txn, key0_name, id);
+}
+
+/*!
+ * Gets the number of section identifiers.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] txn Configuration DB transaction.
+ * \param[in] key0_name Section name.
+ *
+ * \return Number of identifiers.
+ */
+size_t conf_id_count_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key0_name
+);
+static inline size_t conf_id_count(
+ conf_t *conf,
+ const yp_name_t *key0_name)
+{
+ return conf_id_count_txn(conf, &conf->read_txn, key0_name);
+}
+
+/*!
+ * Gets a configuration section iterator.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] txn Configuration DB transaction.
+ * \param[in] key0_name Section name.
+ *
+ * \return Section iterator.
+ */
+conf_iter_t conf_iter_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key0_name
+);
+static inline conf_iter_t conf_iter(
+ conf_t *conf,
+ const yp_name_t *key0_name)
+{
+ return conf_iter_txn(conf, &conf->read_txn, key0_name);
+}
+
+/*!
+ * Moves the configuration section iterator to the next identifier.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] iter Configuration iterator.
+ */
+void conf_iter_next(
+ conf_t *conf,
+ conf_iter_t *iter
+);
+
+/*!
+ * Gets the current iterator value (identifier).
+ *
+ * \param[in] conf Configuration.
+ * \param[in] iter Configuration iterator.
+ *
+ * \return Section identifier.
+ */
+conf_val_t conf_iter_id(
+ conf_t *conf,
+ conf_iter_t *iter
+);
+
+/*!
+ * Deletes the section iterator.
+ *
+ * This function should be called when the iterating is early interrupted,
+ * otherwise this is done automaticaly at KNOT_EOF.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] iter Configuration iterator.
+ */
+void conf_iter_finish(
+ conf_t *conf,
+ conf_iter_t *iter
+);
+
+/*!
+ * Prepares the value for the direct access.
+ *
+ * The following access is through val->len and val->data.
+ *
+ * \param[in] val Item value.
+ */
+void conf_val(
+ conf_val_t *val
+);
+
+/*!
+ * Moves to the next item value.
+ *
+ * \param[in] val Item value.
+ */
+void conf_val_next(
+ conf_val_t *val
+);
+
+/*!
+ * Gets the number of values if multivalued item.
+ *
+ * \param[in] val Item value.
+ *
+ * \return Number of values.
+ */
+size_t conf_val_count(
+ conf_val_t *val
+);
+
+/*!
+ * Checks if two item values are equal.
+ *
+ * \param[in] val1 First item value.
+ * \param[in] val2 Second item value.
+ *
+ * \return true if equal, false if not.
+ */
+bool conf_val_equal(
+ conf_val_t *val1,
+ conf_val_t *val2
+);
+
+/*!
+ * Gets the numeric value of the item.
+ *
+ * \param[in] val Item value.
+ *
+ * \return Integer.
+ */
+int64_t conf_int(
+ conf_val_t *val
+);
+
+/*!
+ * Gets the boolean value of the item.
+ *
+ * \param[in] val Item value.
+ *
+ * \return Boolean.
+ */
+bool conf_bool(
+ conf_val_t *val
+);
+
+/*!
+ * Gets the option value of the item.
+ *
+ * \param[in] val Item value.
+ *
+ * \return Option id.
+ */
+unsigned conf_opt(
+ conf_val_t *val
+);
+
+/*!
+ * Gets the string value of the item.
+ *
+ * \param[in] val Item value.
+ *
+ * \return String pointer.
+ */
+const char* conf_str(
+ conf_val_t *val
+);
+
+/*!
+ * Gets the dname value of the item.
+ *
+ * \param[in] val Item value.
+ *
+ * \return Dname pointer.
+ */
+const knot_dname_t* conf_dname(
+ conf_val_t *val
+);
+
+/*!
+ * Gets the length-prefixed data value of the item.
+ *
+ * \param[in] val Item value.
+ * \param[out] len Output length.
+ *
+ * \return Data pointer.
+ */
+const uint8_t* conf_bin(
+ conf_val_t *val,
+ size_t *len
+);
+
+/*!
+ * Gets the generic data value of the item.
+ *
+ * \param[in] val Item value.
+ * \param[out] len Output length.
+ *
+ * \return Data pointer.
+ */
+const uint8_t* conf_data(
+ conf_val_t *val,
+ size_t *len
+);
+
+/*!
+ * Gets the socket address value of the item.
+ *
+ * \param[in] val Item value.
+ * \param[in] sock_base_dir Path prefix for a relative UNIX socket location.
+ *
+ * \return Socket address.
+ */
+struct sockaddr_storage conf_addr(
+ conf_val_t *val,
+ const char *sock_base_dir
+);
+
+/*!
+ * Gets the socket address range value of the item.
+ *
+ * \param[in] val Item value.
+ * \param[out] max_ss Upper address bound or AF_UNSPEC family if not specified.
+ * \param[out] prefix_len Network subnet prefix length or -1 if not specified.
+ *
+ * \return Socket address.
+ */
+struct sockaddr_storage conf_addr_range(
+ conf_val_t *val,
+ struct sockaddr_storage *max_ss,
+ int *prefix_len
+);
+
+/*!
+ * Checks the address if matches given address range/network block.
+ *
+ * \param[in] range Address range/network block.
+ * \param[in] addr Address to check.
+ *
+ * \return True if matches.
+ */
+bool conf_addr_range_match(
+ conf_val_t *range,
+ const struct sockaddr_storage *addr
+);
+
+/*!
+ * Gets the absolute string value of the item.
+ *
+ * \note The result must be explicitly deallocated.
+ *
+ * \param[in] val Item value.
+ * \param[in] base_dir Path prefix for a relative string.
+ *
+ * \return Absolute path string pointer.
+ */
+char* conf_abs_path(
+ conf_val_t *val,
+ const char *base_dir
+);
+
+/*!
+ * Ensures empty 'default' identifier value.
+ *
+ * \param[in] val Item value.
+ *
+ * \return Empty item value.
+ */
+static inline void conf_id_fix_default(conf_val_t *val)
+{
+ if (val->code != KNOT_EOK) {
+ conf_val_t empty = {
+ .item = val->item,
+ .code = KNOT_EOK
+ };
+
+ *val = empty;
+ }
+}
+
+/*!
+ * Gets the module identifier value of the item.
+ *
+ * \param[in] val Item value.
+ *
+ * \return Module identifier.
+ */
+conf_mod_id_t* conf_mod_id(
+ conf_val_t *val
+);
+
+/*!
+ * Destroys the module identifier.
+ *
+ * \param[in] mod_id Module identifier.
+ */
+void conf_free_mod_id(
+ conf_mod_id_t *mod_id
+);
+
+/*!
+ * Gets the absolute zone file path.
+ *
+ * \note The result must be explicitly deallocated.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] txn Configuration DB transaction.
+ * \param[in] zone Zone name.
+ *
+ * \return Absolute zonef ile path string pointer.
+ */
+char* conf_zonefile_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const knot_dname_t *zone
+);
+static inline char* conf_zonefile(
+ conf_t *conf,
+ const knot_dname_t *zone)
+{
+ return conf_zonefile_txn(conf, &conf->read_txn, zone);
+}
+
+/*!
+ * Gets the absolute journal file path.
+ *
+ * \note The result must be explicitly deallocated.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] txn Configuration DB transaction.
+ *
+ * \return Absolute journal file path string pointer.
+ */
+char* conf_journalfile_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn);
+static inline char* conf_journalfile(
+ conf_t *conf)
+{
+ return conf_journalfile_txn(conf, &conf->read_txn);
+}
+
+char* conf_kaspdir_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn);
+static inline char* conf_kaspdir(
+ conf_t *conf)
+{
+ return conf_kaspdir_txn(conf, &conf->read_txn);
+}
+
+/*!
+ * Gets the configured number of UDP threads.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] txn Configuration DB transaction.
+ *
+ * \return Number of threads.
+ */
+size_t conf_udp_threads_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn
+);
+static inline size_t conf_udp_threads(
+ conf_t *conf)
+{
+ return conf_udp_threads_txn(conf, &conf->read_txn);
+}
+
+/*!
+ * Gets the configured number of TCP threads.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] txn Configuration DB transaction.
+ *
+ * \return Number of threads.
+ */
+size_t conf_tcp_threads_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn
+);
+static inline size_t conf_tcp_threads(
+ conf_t *conf)
+{
+ return conf_tcp_threads_txn(conf, &conf->read_txn);
+}
+
+/*!
+ * Gets the configured number of worker threads.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] txn Configuration DB transaction.
+ *
+ * \return Number of threads.
+ */
+size_t conf_bg_threads_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn
+);
+static inline size_t conf_bg_threads(
+ conf_t *conf)
+{
+ return conf_bg_threads_txn(conf, &conf->read_txn);
+}
+
+/*!
+ * Gets the configured user and group identifiers.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] txn Configuration DB transaction.
+ * \param[out] uid User identifier.
+ * \param[out] gid Group identifier.
+ *
+ * \return Knot error code.
+ */
+int conf_user_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ int *uid,
+ int *gid
+);
+static inline int conf_user(
+ conf_t *conf,
+ int *uid,
+ int *gid)
+{
+ return conf_user_txn(conf, &conf->read_txn, uid, gid);
+}
+
+/*!
+ * Gets the remote parameters for the given identifier.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] txn Configuration DB transaction.
+ * \param[in] id Remote identifier.
+ * \param[in] index Remote index (counted from 0).
+ *
+ * \return Remote parameters.
+ */
+conf_remote_t conf_remote_txn(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ conf_val_t *id,
+ size_t index
+);
+static inline conf_remote_t conf_remote(
+ conf_t *conf,
+ conf_val_t *id,
+ size_t index)
+{
+ return conf_remote_txn(conf, &conf->read_txn, id, index);
+
+}
diff --git a/src/knot/conf/confdb.c b/src/knot/conf/confdb.c
new file mode 100644
index 0000000..364142a
--- /dev/null
+++ b/src/knot/conf/confdb.c
@@ -0,0 +1,951 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "knot/conf/confdb.h"
+#include "libknot/errcode.h"
+#include "libknot/yparser/yptrafo.h"
+#include "contrib/openbsd/strlcpy.h"
+#include "contrib/wire_ctx.h"
+
+/*
+ * A simple configuration:
+ *
+ * server.identity: "knot"
+ * server.version: "version"
+ * template[tpl1].storage: "directory1"
+ * template[tpl2].storage: "directory2"
+ * template[tpl2].master: [ "master1", "master2" ]
+ *
+ * And the corresponding configuration DB content:
+ *
+ * # DB structure version.
+ * [00][FF]: [02]
+ * # Sections codes.
+ * [00][00]server: [02]
+ * [00][00]template: [03]
+ * # Server section items codes.
+ * [02][00]identity: [02]
+ * [02][00]version: [03]
+ * # Server items values.
+ * [02][02]: knot\0
+ * [02][03]: version\0
+ * # Template section items codes.
+ * [03][00]master: [03]
+ * [03][00]storage: [02]
+ * # Template identificators.
+ * [03][01]tpl1\0
+ * [03][01]tpl2\0
+ * # Template items values.
+ * [03][02]tpl1\0: directory1\0
+ * [03][02]tpl2\0: directory2\0
+ * [03][03]tpl2\0: [00][08]master1\0 [00][08]master2\0
+ */
+
+typedef enum {
+ KEY0_ROOT = 0,
+ KEY1_ITEMS = 0,
+ KEY1_ID = 1,
+ KEY1_FIRST = 2,
+ KEY1_LAST = 200,
+ KEY1_VERSION = 255
+} db_code_t;
+
+typedef enum {
+ KEY0_POS = 0,
+ KEY1_POS = 1,
+ NAME_POS = 2
+} db_code_pos_t;
+
+typedef enum {
+ DB_GET,
+ DB_SET,
+ DB_DEL
+} db_action_t;
+
+static int db_check_version(
+ conf_t *conf,
+ knot_db_txn_t *txn)
+{
+ uint8_t k[2] = { KEY0_ROOT, KEY1_VERSION };
+ knot_db_val_t key = { k, sizeof(k) };
+ knot_db_val_t data;
+
+ // Get conf-DB version.
+ int ret = conf->api->find(txn, &key, &data, 0);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Check conf-DB version.
+ if (data.len != 1 || ((uint8_t *)data.data)[0] != CONF_DB_VERSION) {
+ return KNOT_CONF_EVERSION;
+ }
+
+ return KNOT_EOK;
+}
+
+int conf_db_init(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ bool purge)
+{
+ if (conf == NULL || txn == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ uint8_t k[2] = { KEY0_ROOT, KEY1_VERSION };
+ knot_db_val_t key = { k, sizeof(k) };
+
+ int ret = conf->api->count(txn);
+ if (ret == 0) { // Initialize empty DB with DB version.
+ uint8_t d[1] = { CONF_DB_VERSION };
+ knot_db_val_t data = { d, sizeof(d) };
+ return conf->api->insert(txn, &key, &data, 0);
+ } else if (ret > 0) { // Non-empty DB.
+ if (purge) {
+ // Purge the DB.
+ ret = conf->api->clear(txn);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ return conf_db_init(conf, txn, false);
+ }
+ return KNOT_EOK;
+ } else { // DB error.
+ return ret;
+ }
+}
+
+int conf_db_check(
+ conf_t *conf,
+ knot_db_txn_t *txn)
+{
+ int ret = conf->api->count(txn);
+ if (ret == 0) { // Not initialized DB.
+ return KNOT_CONF_ENOTINIT;
+ } else if (ret > 0) { // Check the DB.
+ int count = ret;
+
+ ret = db_check_version(conf, txn);
+ if (ret != KNOT_EOK) {
+ return ret;
+ } else if (count == 1) {
+ return KNOT_EOK; // Empty but initialized DB.
+ } else {
+ return count - 1; // Non-empty DB.
+ }
+ } else { // DB error.
+ return ret;
+ }
+}
+
+static int db_code(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ uint8_t section_code,
+ const yp_name_t *name,
+ db_action_t action,
+ uint8_t *code)
+{
+ if (name == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ knot_db_val_t key;
+ uint8_t k[CONF_MIN_KEY_LEN + YP_MAX_ITEM_NAME_LEN];
+ k[KEY0_POS] = section_code;
+ k[KEY1_POS] = KEY1_ITEMS;
+ memcpy(k + NAME_POS, name + 1, name[0]);
+ key.data = k;
+ key.len = CONF_MIN_KEY_LEN + name[0];
+
+ // Check if the item is already registered.
+ knot_db_val_t data;
+ int ret = conf->api->find(txn, &key, &data, 0);
+ switch (ret) {
+ case KNOT_EOK:
+ if (action == DB_DEL) {
+ return conf->api->del(txn, &key);
+ }
+ if (code != NULL) {
+ *code = ((uint8_t *)data.data)[0];
+ }
+ return KNOT_EOK;
+ case KNOT_ENOENT:
+ if (action != DB_SET) {
+ return KNOT_ENOENT;
+ }
+ break;
+ default:
+ return ret;
+ }
+
+ // Reduce the key to common prefix only.
+ key.len = CONF_MIN_KEY_LEN;
+
+ bool codes[KEY1_LAST + 1] = { false };
+
+ // Find all used item codes.
+ knot_db_iter_t *it = conf->api->iter_begin(txn, KNOT_DB_NOOP);
+ it = conf->api->iter_seek(it, &key, KNOT_DB_GEQ);
+ while (it != NULL) {
+ knot_db_val_t iter_key;
+ ret = conf->api->iter_key(it, &iter_key);
+ if (ret != KNOT_EOK) {
+ conf->api->iter_finish(it);
+ return ret;
+ }
+ uint8_t *key_data = (uint8_t *)iter_key.data;
+
+ // Check for database prefix end.
+ if (key_data[KEY0_POS] != k[KEY0_POS] ||
+ key_data[KEY1_POS] != k[KEY1_POS]) {
+ break;
+ }
+
+ knot_db_val_t iter_val;
+ ret = conf->api->iter_val(it, &iter_val);
+ if (ret != KNOT_EOK) {
+ conf->api->iter_finish(it);
+ return ret;
+ }
+ uint8_t code = ((uint8_t *)iter_val.data)[0];
+ codes[code] = true;
+
+ it = conf->api->iter_next(it);
+ }
+ conf->api->iter_finish(it);
+
+ // Find the smallest unused item code.
+ uint8_t new_code = KEY1_FIRST;
+ while (codes[new_code]) {
+ new_code++;
+ if (new_code > KEY1_LAST) {
+ return KNOT_ESPACE;
+ }
+ }
+
+ // Restore the full key.
+ key.len = CONF_MIN_KEY_LEN + name[0];
+
+ // Fill the data with a new code.
+ data.data = &new_code;
+ data.len = sizeof(new_code);
+
+ // Register new item code.
+ ret = conf->api->insert(txn, &key, &data, 0);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ if (code != NULL) {
+ *code = new_code;
+ }
+
+ return KNOT_EOK;
+}
+
+static uint8_t *find_data(
+ const knot_db_val_t *value,
+ const knot_db_val_t *current)
+{
+ wire_ctx_t ctx = wire_ctx_init_const(current->data, current->len);
+
+ // Loop over the data array. Each item has 2B length prefix.
+ while (wire_ctx_available(&ctx) > 0) {
+ uint16_t len = wire_ctx_read_u16(&ctx);
+ assert(ctx.error == KNOT_EOK);
+
+ // Check for the same data.
+ if (len == value->len &&
+ memcmp(ctx.position, value->data, value->len) == 0) {
+ wire_ctx_skip(&ctx, -sizeof(uint16_t));
+ assert(ctx.error == KNOT_EOK);
+ return ctx.position;
+ }
+ wire_ctx_skip(&ctx, len);
+ }
+
+ assert(ctx.error == KNOT_EOK && wire_ctx_available(&ctx) == 0);
+
+ return NULL;
+}
+
+static int db_set(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ knot_db_val_t *key,
+ knot_db_val_t *data,
+ bool multi)
+{
+ if (!multi) {
+ if (data->len > CONF_MAX_DATA_LEN) {
+ return KNOT_ERANGE;
+ }
+
+ // Insert new (overwrite old) data.
+ return conf->api->insert(txn, key, data, 0);
+ }
+
+ knot_db_val_t d;
+
+ if (data->len > UINT16_MAX) {
+ return KNOT_ERANGE;
+ }
+
+ int ret = conf->api->find(txn, key, &d, 0);
+ if (ret == KNOT_ENOENT) {
+ d.len = 0;
+ } else if (ret == KNOT_EOK) {
+ // Check for duplicate data.
+ if (find_data(data, &d) != NULL) {
+ return KNOT_EOK;
+ }
+ } else {
+ return ret;
+ }
+
+ // Prepare buffer for all data.
+ size_t new_len = d.len + sizeof(uint16_t) + data->len;
+ if (new_len > CONF_MAX_DATA_LEN) {
+ return KNOT_ESPACE;
+ }
+
+ uint8_t *new_data = malloc(new_len);
+ if (new_data == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ wire_ctx_t ctx = wire_ctx_init(new_data, new_len);
+
+ // Copy current data array.
+ wire_ctx_write(&ctx, d.data, d.len);
+ // Copy length prefix for the new data item.
+ wire_ctx_write_u16(&ctx, data->len);
+ // Copy the new data item.
+ wire_ctx_write(&ctx, data->data, data->len);
+
+ assert(ctx.error == KNOT_EOK && wire_ctx_available(&ctx) == 0);
+
+ d.data = new_data;
+ d.len = new_len;
+
+ // Insert new (or append) data.
+ ret = conf->api->insert(txn, key, &d, 0);
+
+ free(new_data);
+
+ return ret;
+}
+
+int conf_db_set(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key0,
+ const yp_name_t *key1,
+ const uint8_t *id,
+ size_t id_len,
+ const uint8_t *data,
+ size_t data_len)
+{
+ if (conf == NULL || txn == NULL || key0 == NULL ||
+ (id == NULL && id_len > 0) || (data == NULL && data_len > 0)) {
+ return KNOT_EINVAL;
+ }
+
+ // Check for valid keys.
+ const yp_item_t *item = yp_schema_find(key1 != NULL ? key1 : key0,
+ key1 != NULL ? key0 : NULL,
+ conf->schema);
+ if (item == NULL) {
+ return KNOT_YP_EINVAL_ITEM;
+ }
+
+ // Ignore alone key0 insertion.
+ if (key1 == NULL && id_len == 0) {
+ return KNOT_EOK;
+ }
+
+ // Ignore group id as a key1.
+ if (item->parent != NULL && (item->parent->flags & YP_FMULTI) != 0 &&
+ item->parent->var.g.id == item) {
+ key1 = NULL;
+ }
+
+ uint8_t k[CONF_MAX_KEY_LEN] = { 0 };
+ knot_db_val_t key = { k, CONF_MIN_KEY_LEN };
+
+ // Set key0 code.
+ int ret = db_code(conf, txn, KEY0_ROOT, key0, DB_SET, &k[KEY0_POS]);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Set id part.
+ if (id_len > 0) {
+ if (id_len > YP_MAX_ID_LEN) {
+ return KNOT_YP_EINVAL_ID;
+ }
+ memcpy(k + CONF_MIN_KEY_LEN, id, id_len);
+ key.len += id_len;
+
+ k[KEY1_POS] = KEY1_ID;
+ knot_db_val_t val = { NULL };
+
+ // Insert id.
+ if (key1 == NULL) {
+ ret = conf->api->find(txn, &key, &val, 0);
+ if (ret == KNOT_EOK) {
+ return KNOT_CONF_EREDEFINE;
+ }
+ ret = db_set(conf, txn, &key, &val, false);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ // Check for existing id.
+ } else {
+ ret = conf->api->find(txn, &key, &val, 0);
+ if (ret != KNOT_EOK) {
+ return KNOT_YP_EINVAL_ID;
+ }
+ }
+ }
+
+ // Insert key1 data.
+ if (key1 != NULL) {
+ // Set key1 code.
+ ret = db_code(conf, txn, k[KEY0_POS], key1, DB_SET, &k[KEY1_POS]);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ knot_db_val_t val = { (uint8_t *)data, data_len };
+ ret = db_set(conf, txn, &key, &val, item->flags & YP_FMULTI);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+static int db_unset(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ knot_db_val_t *key,
+ knot_db_val_t *data,
+ bool multi)
+{
+ // No item data can be zero length.
+ if (data->len == 0) {
+ return conf->api->del(txn, key);
+ }
+
+ knot_db_val_t d;
+
+ int ret = conf->api->find(txn, key, &d, 0);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Process singlevalued data.
+ if (!multi) {
+ if (d.len != data->len ||
+ memcmp((uint8_t *)d.data, data->data, d.len) != 0) {
+ return KNOT_ENOENT;
+ }
+ return conf->api->del(txn, key);
+ }
+
+ // Check if the data exists.
+ uint8_t *pos = find_data(data, &d);
+ if (pos == NULL) {
+ return KNOT_ENOENT;
+ }
+
+ // Prepare buffer for reduced data.
+ size_t total_len = d.len - sizeof(uint16_t) - data->len;
+ if (total_len == 0) {
+ return conf->api->del(txn, key);
+ }
+
+ uint8_t *new_data = malloc(total_len);
+ if (new_data == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ size_t new_len = 0;
+
+ // Copy leading data block.
+ assert(pos >= (uint8_t *)d.data);
+ size_t head_len = pos - (uint8_t *)d.data;
+ if (head_len > 0) {
+ memcpy(new_data, d.data, head_len);
+ new_len += head_len;
+ }
+
+ pos += sizeof(uint16_t) + data->len;
+
+ // Copy trailing data block.
+ assert(pos <= (uint8_t *)d.data + d.len);
+ size_t tail_len = (uint8_t *)d.data + d.len - pos;
+ if (tail_len > 0) {
+ memcpy(new_data + new_len, pos, tail_len);
+ new_len += tail_len;
+ }
+
+ d.data = new_data;
+ d.len = new_len;
+
+ // Insert reduced data.
+ ret = conf->api->insert(txn, key, &d, 0);
+
+ free(new_data);
+
+ return ret;
+}
+
+int conf_db_unset(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key0,
+ const yp_name_t *key1,
+ const uint8_t *id,
+ size_t id_len,
+ const uint8_t *data,
+ size_t data_len,
+ bool delete_key1)
+{
+ if (conf == NULL || txn == NULL || key0 == NULL ||
+ (id == NULL && id_len > 0) || (data == NULL && data_len > 0)) {
+ return KNOT_EINVAL;
+ }
+
+ // Check for valid keys.
+ const yp_item_t *item = yp_schema_find(key1 != NULL ? key1 : key0,
+ key1 != NULL ? key0 : NULL,
+ conf->schema);
+ if (item == NULL) {
+ return KNOT_YP_EINVAL_ITEM;
+ }
+
+ // Delete the key0.
+ if (key1 == NULL && id_len == 0) {
+ return db_code(conf, txn, KEY0_ROOT, key0, DB_DEL, NULL);
+ }
+
+ // Ignore group id as a key1.
+ if (item->parent != NULL && (item->parent->flags & YP_FMULTI) != 0 &&
+ item->parent->var.g.id == item) {
+ key1 = NULL;
+ }
+
+ uint8_t k[CONF_MAX_KEY_LEN] = { 0 };
+ knot_db_val_t key = { k, CONF_MIN_KEY_LEN };
+
+ // Set the key0 code.
+ int ret = db_code(conf, txn, KEY0_ROOT, key0, DB_GET, &k[KEY0_POS]);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Set the id part.
+ if (id_len > 0) {
+ if (id_len > YP_MAX_ID_LEN) {
+ return KNOT_YP_EINVAL_ID;
+ }
+ memcpy(k + CONF_MIN_KEY_LEN, id, id_len);
+ key.len += id_len;
+
+ k[KEY1_POS] = KEY1_ID;
+ knot_db_val_t val = { NULL };
+
+ // Delete the id.
+ if (key1 == NULL) {
+ return conf->api->del(txn, &key);
+ // Check for existing id.
+ } else {
+ ret = conf->api->find(txn, &key, &val, 0);
+ if (ret != KNOT_EOK) {
+ return KNOT_YP_EINVAL_ID;
+ }
+ }
+ }
+
+ if (key1 != NULL) {
+ // Set the key1 code.
+ ret = db_code(conf, txn, k[KEY0_POS], key1, DB_GET, &k[KEY1_POS]);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Delete the key1.
+ if (data_len == 0 && delete_key1) {
+ ret = db_code(conf, txn, k[KEY0_POS], key1, DB_DEL, NULL);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ // Delete the item data.
+ } else {
+ knot_db_val_t val = { (uint8_t *)data, data_len };
+ ret = db_unset(conf, txn, &key, &val, item->flags & YP_FMULTI);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+int conf_db_get(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key0,
+ const yp_name_t *key1,
+ const uint8_t *id,
+ size_t id_len,
+ conf_val_t *data)
+{
+ conf_val_t out = { NULL };
+
+ if (conf == NULL || txn == NULL || key0 == NULL ||
+ (id == NULL && id_len > 0)) {
+ out.code = KNOT_EINVAL;
+ goto get_error;
+ }
+
+ // Check for valid keys.
+ out.item = yp_schema_find(key1 != NULL ? key1 : key0,
+ key1 != NULL ? key0 : NULL,
+ conf->schema);
+ if (out.item == NULL) {
+ out.code = KNOT_YP_EINVAL_ITEM;
+ goto get_error;
+ }
+
+ // At least key1 or id must be specified.
+ if (key1 == NULL && id_len == 0) {
+ out.code = KNOT_EINVAL;
+ goto get_error;
+ }
+
+ // Ignore group id as a key1.
+ if (out.item->parent != NULL && (out.item->parent->flags & YP_FMULTI) != 0 &&
+ out.item->parent->var.g.id == out.item) {
+ key1 = NULL;
+ }
+
+ uint8_t k[CONF_MAX_KEY_LEN] = { 0 };
+ knot_db_val_t key = { k, CONF_MIN_KEY_LEN };
+ knot_db_val_t val = { NULL };
+
+ // Set the key0 code.
+ out.code = db_code(conf, txn, KEY0_ROOT, key0, DB_GET, &k[KEY0_POS]);
+ if (out.code != KNOT_EOK) {
+ if (id_len > 0) {
+ out.code = KNOT_YP_EINVAL_ID;
+ }
+ goto get_error;
+ }
+
+ // Set the id part.
+ if (id_len > 0) {
+ if (id_len > YP_MAX_ID_LEN) {
+ out.code = KNOT_YP_EINVAL_ID;
+ goto get_error;
+ }
+ memcpy(k + CONF_MIN_KEY_LEN, id, id_len);
+ key.len += id_len;
+
+ k[KEY1_POS] = KEY1_ID;
+
+ // Check for existing id.
+ out.code = conf->api->find(txn, &key, &val, 0);
+ if (out.code != KNOT_EOK) {
+ out.code = KNOT_YP_EINVAL_ID;
+ goto get_error;
+ }
+ }
+
+ // Set the key1 code.
+ if (key1 != NULL) {
+ out.code = db_code(conf, txn, k[KEY0_POS], key1, DB_GET, &k[KEY1_POS]);
+ if (out.code != KNOT_EOK) {
+ goto get_error;
+ }
+ }
+
+ // Get the data.
+ out.code = conf->api->find(txn, &key, &val, 0);
+ if (out.code == KNOT_EOK) {
+ out.blob = val.data;
+ out.blob_len = val.len;
+ }
+get_error:
+ // Set the output.
+ if (data != NULL) {
+ *data = out;
+ }
+
+ return out.code;
+}
+
+static int check_iter(
+ conf_t *conf,
+ conf_iter_t *iter)
+{
+ knot_db_val_t key;
+
+ // Get the current key.
+ int ret = conf->api->iter_key(iter->iter, &key);
+ if (ret != KNOT_EOK) {
+ return KNOT_ENOENT;
+ }
+ uint8_t *key_data = (uint8_t *)key.data;
+
+ // Check for key overflow.
+ if (key_data[KEY0_POS] != iter->key0_code || key_data[KEY1_POS] != KEY1_ID) {
+ return KNOT_EOF;
+ }
+
+ return KNOT_EOK;
+}
+
+int conf_db_iter_begin(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key0,
+ conf_iter_t *iter)
+{
+ conf_iter_t out = { NULL };
+
+ if (conf == NULL || txn == NULL || key0 == NULL || iter == NULL) {
+ out.code = KNOT_EINVAL;
+ goto iter_begin_error;
+ }
+
+ // Look-up group id item in the schema.
+ const yp_item_t *grp = yp_schema_find(key0, NULL, conf->schema);
+ if (grp == NULL) {
+ out.code = KNOT_YP_EINVAL_ITEM;
+ goto iter_begin_error;
+ }
+ if (grp->type != YP_TGRP || (grp->flags & YP_FMULTI) == 0) {
+ out.code = KNOT_ENOTSUP;
+ goto iter_begin_error;
+ }
+ out.item = grp->var.g.id;
+
+ // Get key0 code.
+ out.code = db_code(conf, txn, KEY0_ROOT, key0, DB_GET, &out.key0_code);
+ if (out.code != KNOT_EOK) {
+ goto iter_begin_error;
+ }
+
+ // Prepare key prefix.
+ uint8_t k[2] = { out.key0_code, KEY1_ID };
+ knot_db_val_t key = { k, sizeof(k) };
+
+ // Get the data.
+ out.iter = conf->api->iter_begin(txn, KNOT_DB_NOOP);
+ out.iter = conf->api->iter_seek(out.iter, &key, KNOT_DB_GEQ);
+
+ // Check for no section id.
+ out.code = check_iter(conf, &out);
+ if (out.code != KNOT_EOK) {
+ out.code = KNOT_ENOENT; // Treat all errors as no entry.
+ conf_db_iter_finish(conf, &out);
+ goto iter_begin_error;
+ }
+
+iter_begin_error:
+ // Set the output.
+ if (iter != NULL) {
+ *iter = out;
+ }
+
+ return out.code;
+}
+
+int conf_db_iter_next(
+ conf_t *conf,
+ conf_iter_t *iter)
+{
+ if (conf == NULL || iter == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ if (iter->code != KNOT_EOK) {
+ return iter->code;
+ }
+ assert(iter->iter != NULL);
+
+ // Move to the next key-value.
+ iter->iter = conf->api->iter_next(iter->iter);
+ if (iter->iter == NULL) {
+ conf_db_iter_finish(conf, iter);
+ iter->code = KNOT_EOF;
+ return iter->code;
+ }
+
+ // Check for key overflow.
+ iter->code = check_iter(conf, iter);
+ if (iter->code != KNOT_EOK) {
+ conf_db_iter_finish(conf, iter);
+ return iter->code;
+ }
+
+ return KNOT_EOK;
+}
+
+int conf_db_iter_id(
+ conf_t *conf,
+ conf_iter_t *iter,
+ const uint8_t **data,
+ size_t *data_len)
+{
+ if (conf == NULL || iter == NULL || iter->iter == NULL ||
+ data == NULL || data_len == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ knot_db_val_t key;
+ int ret = conf->api->iter_key(iter->iter, &key);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ *data = (uint8_t *)key.data + CONF_MIN_KEY_LEN;
+ *data_len = key.len - CONF_MIN_KEY_LEN;
+
+ return KNOT_EOK;
+}
+
+int conf_db_iter_del(
+ conf_t *conf,
+ conf_iter_t *iter)
+{
+ if (conf == NULL || iter == NULL || iter->iter == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ return knot_db_lmdb_iter_del(iter->iter);
+}
+
+void conf_db_iter_finish(
+ conf_t *conf,
+ conf_iter_t *iter)
+{
+ if (conf == NULL || iter == NULL) {
+ return;
+ }
+
+ if (iter->iter != NULL) {
+ conf->api->iter_finish(iter->iter);
+ iter->iter = NULL;
+ }
+}
+
+int conf_db_raw_dump(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const char *file_name)
+{
+ if (conf == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ // Use the current config read transaction if not specified.
+ if (txn == NULL) {
+ txn = &conf->read_txn;
+ }
+
+ FILE *fp = stdout;
+ if (file_name != NULL) {
+ fp = fopen(file_name, "w");
+ if (fp == NULL) {
+ return KNOT_ERROR;
+ }
+ }
+
+ int ret = KNOT_EOK;
+
+ knot_db_iter_t *it = conf->api->iter_begin(txn, KNOT_DB_FIRST);
+ while (it != NULL) {
+ knot_db_val_t key;
+ ret = conf->api->iter_key(it, &key);
+ if (ret != KNOT_EOK) {
+ break;
+ }
+
+ knot_db_val_t data;
+ ret = conf->api->iter_val(it, &data);
+ if (ret != KNOT_EOK) {
+ break;
+ }
+
+ uint8_t *k = (uint8_t *)key.data;
+ uint8_t *d = (uint8_t *)data.data;
+ if (k[1] == KEY1_ITEMS) {
+ fprintf(fp, "[%i][%i]%.*s", k[0], k[1],
+ (int)key.len - 2, k + 2);
+ fprintf(fp, ": %u\n", d[0]);
+ } else if (k[1] == KEY1_ID) {
+ fprintf(fp, "[%i][%i](%zu){", k[0], k[1], key.len - 2);
+ for (size_t i = 2; i < key.len; i++) {
+ fprintf(fp, "%02x", (uint8_t)k[i]);
+ }
+ fprintf(fp, "}\n");
+ } else {
+ fprintf(fp, "[%i][%i]", k[0], k[1]);
+ if (key.len > 2) {
+ fprintf(fp, "(%zu){", key.len - 2);
+ for (size_t i = 2; i < key.len; i++) {
+ fprintf(fp, "%02x", (uint8_t)k[i]);
+ }
+ fprintf(fp, "}");
+ }
+ fprintf(fp, ": (%zu)<", data.len);
+ for (size_t i = 0; i < data.len; i++) {
+ fprintf(fp, "%02x", (uint8_t)d[i]);
+ }
+ fprintf(fp, ">\n");
+ }
+
+ it = conf->api->iter_next(it);
+ }
+ conf->api->iter_finish(it);
+
+ if (file_name != NULL) {
+ fclose(fp);
+ } else {
+ fflush(fp);
+ }
+
+ return ret;
+}
diff --git a/src/knot/conf/confdb.h b/src/knot/conf/confdb.h
new file mode 100644
index 0000000..04e222d
--- /dev/null
+++ b/src/knot/conf/confdb.h
@@ -0,0 +1,230 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "knot/conf/conf.h"
+#include "libknot/libknot.h"
+#include "libknot/yparser/ypschema.h"
+
+/*! Current version of the configuration database structure. */
+#define CONF_DB_VERSION 2
+/*! Minimum length of a database key ([category_id, item_id]. */
+#define CONF_MIN_KEY_LEN (2 * sizeof(uint8_t))
+/*! Maximum length of a database key ([category_id, item_id, identifier]. */
+#define CONF_MAX_KEY_LEN (CONF_MIN_KEY_LEN + YP_MAX_ID_LEN)
+/*! Maximum size of database data. */
+#define CONF_MAX_DATA_LEN 65536
+
+/*!
+ * Initializes the configuration DB if empty.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] txn Configuration DB transaction.
+ * \param[in] purge Purge the DB indicator.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int conf_db_init(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ bool purge
+);
+
+/*!
+ * Checks the configuration DB and returns the number of items.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] txn Configuration DB transaction.
+ *
+ * \return Error code, KNOT_EOK if ok and empty, > 0 number of records.
+ */
+int conf_db_check(
+ conf_t *conf,
+ knot_db_txn_t *txn
+);
+
+/*!
+ * Sets the item with data in the configuration DB.
+ *
+ * Singlevalued data is rewritten, multivalued data is appended.
+ *
+ * \note Setting of key0 without key1 has no effect.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] txn Configuration DB transaction.
+ * \param[in] key0 Section name.
+ * \param[in] key1 Item name.
+ * \param[in] id Section identifier.
+ * \param[in] id_len Length of the section identifier.
+ * \param[in] data Item data.
+ * \param[in] data_len Length of the item data.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int conf_db_set(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key0,
+ const yp_name_t *key1,
+ const uint8_t *id,
+ size_t id_len,
+ const uint8_t *data,
+ size_t data_len
+);
+
+/*!
+ * Unsets the item data in the configuration DB.
+ *
+ * If no data is provided, the whole item is remove.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] txn Configuration DB transaction.
+ * \param[in] key0 Section name.
+ * \param[in] key1 Item name.
+ * \param[in] id Section identifier.
+ * \param[in] id_len Length of the section identifier.
+ * \param[in] data Item data.
+ * \param[in] data_len Length of the item data.
+ * \param[in] delete_key1 Set to unregister the item from the DB.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int conf_db_unset(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key0,
+ const yp_name_t *key1,
+ const uint8_t *id,
+ size_t id_len,
+ const uint8_t *data,
+ size_t data_len,
+ bool delete_key1
+);
+
+/*!
+ * Gets the item data from the configuration DB.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] txn Configuration DB transaction.
+ * \param[in] key0 Section name.
+ * \param[in] key1 Item name.
+ * \param[in] id Section identifier.
+ * \param[in] id_len Length of the section identifier.
+ * \param[out] data Item data.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int conf_db_get(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key0,
+ const yp_name_t *key1,
+ const uint8_t *id,
+ size_t id_len,
+ conf_val_t *data
+);
+
+/*!
+ * Gets a configuration DB section iterator.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] txn Configuration DB transaction.
+ * \param[in] key0 Section name.
+ * \param[out] iter Section iterator.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int conf_db_iter_begin(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const yp_name_t *key0,
+ conf_iter_t *iter
+);
+
+/*!
+ * Moves the section iterator to the next identifier.
+ *
+ * \param[in] conf Configuration.
+ * \param[in,out] iter Section iterator.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int conf_db_iter_next(
+ conf_t *conf,
+ conf_iter_t *iter
+);
+
+/*!
+ * Gets the current section iterator value (identifier).
+ *
+ * \param[in] conf Configuration.
+ * \param[in] iter Section iterator.
+ * \param[out] data Identifier.
+ * \param[out] data_len Length of the identifier.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int conf_db_iter_id(
+ conf_t *conf,
+ conf_iter_t *iter,
+ const uint8_t **data,
+ size_t *data_len
+);
+
+/*!
+ * Deletes the current section iterator value (identifier).
+ *
+ * \param[in] conf Configuration.
+ * \param[in,out] iter Section iterator.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int conf_db_iter_del(
+ conf_t *conf,
+ conf_iter_t *iter
+);
+
+/*!
+ * Deletes the section iterator.
+ *
+ * \param[in] conf Configuration.
+ * \param[in,out] iter Section iterator.
+ */
+void conf_db_iter_finish(
+ conf_t *conf,
+ conf_iter_t *iter
+);
+
+/*!
+ * Dumps the configuration DB in the textual form.
+ *
+ * \note This function is intended for debugging.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] txn Configuration DB transaction.
+ * \param[in] file_name File name to dump to (NULL to dump to stdout).
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int conf_db_raw_dump(
+ conf_t *conf,
+ knot_db_txn_t *txn,
+ const char *file_name
+);
diff --git a/src/knot/conf/confio.c b/src/knot/conf/confio.c
new file mode 100644
index 0000000..bd24800
--- /dev/null
+++ b/src/knot/conf/confio.c
@@ -0,0 +1,1514 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+
+#include "knot/common/log.h"
+#include "knot/conf/confdb.h"
+#include "knot/conf/confio.h"
+#include "knot/conf/module.h"
+#include "knot/conf/tools.h"
+
+#define FCN(io) (io->fcn != NULL) ? io->fcn(io) : KNOT_EOK;
+
+static void io_reset_val(
+ conf_io_t *io,
+ const yp_item_t *key0,
+ const yp_item_t *key1,
+ const uint8_t *id,
+ size_t id_len,
+ bool id_as_data,
+ conf_val_t *val)
+{
+ io->key0 = key0;
+ io->key1 = key1;
+ io->id = id;
+ io->id_len = id_len;
+ io->id_as_data = id_as_data;
+ io->data.val = val;
+ io->data.bin = NULL;
+}
+
+static void io_reset_bin(
+ conf_io_t *io,
+ const yp_item_t *key0,
+ const yp_item_t *key1,
+ const uint8_t *id,
+ size_t id_len,
+ const uint8_t *bin,
+ size_t bin_len)
+{
+ io_reset_val(io, key0, key1, id, id_len, false, NULL);
+ io->data.bin = bin;
+ io->data.bin_len = bin_len;
+}
+
+int conf_io_begin(
+ bool child)
+{
+ assert(conf() != NULL);
+
+ if (conf()->io.txn != NULL && !child) {
+ return KNOT_TXN_EEXISTS;
+ } else if (conf()->io.txn == NULL && child) {
+ return KNOT_TXN_ENOTEXISTS;
+ }
+
+ knot_db_txn_t *parent = conf()->io.txn;
+ knot_db_txn_t *txn = (parent == NULL) ? conf()->io.txn_stack : parent + 1;
+ if (txn >= conf()->io.txn_stack + CONF_MAX_TXN_DEPTH) {
+ return KNOT_TXN_EEXISTS;
+ }
+
+ // Start the writing transaction.
+ int ret = knot_db_lmdb_txn_begin(conf()->db, txn, parent, 0);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ conf()->io.txn = txn;
+
+ // Reset master transaction flags.
+ if (!child) {
+ conf()->io.flags = CONF_IO_FACTIVE;
+ if (conf()->io.zones != NULL) {
+ trie_clear(conf()->io.zones);
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+int conf_io_commit(
+ bool child)
+{
+ assert(conf() != NULL);
+
+ if (conf()->io.txn == NULL ||
+ (child && conf()->io.txn == conf()->io.txn_stack)) {
+ return KNOT_TXN_ENOTEXISTS;
+ }
+
+ knot_db_txn_t *txn = child ? conf()->io.txn : conf()->io.txn_stack;
+
+ // Commit the writing transaction.
+ int ret = conf()->api->txn_commit(txn);
+
+ conf()->io.txn = child ? txn - 1 : NULL;
+
+ return ret;
+}
+
+void conf_io_abort(
+ bool child)
+{
+ assert(conf() != NULL);
+
+ if (conf()->io.txn == NULL ||
+ (child && conf()->io.txn == conf()->io.txn_stack)) {
+ return;
+ }
+
+ knot_db_txn_t *txn = child ? conf()->io.txn : conf()->io.txn_stack;
+
+ // Abort the writing transaction.
+ conf()->api->txn_abort(txn);
+ conf()->io.txn = child ? txn - 1 : NULL;
+
+ // Reset master transaction flags.
+ if (!child) {
+ conf()->io.flags = YP_FNONE;
+ if (conf()->io.zones != NULL) {
+ trie_clear(conf()->io.zones);
+ }
+ }
+}
+
+static int list_section(
+ const yp_item_t *items,
+ const yp_item_t **item,
+ conf_io_t *io)
+{
+ for (*item = items; (*item)->name != NULL; (*item)++) {
+ int ret = FCN(io);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+int conf_io_list(
+ const char *key0,
+ conf_io_t *io)
+{
+ if (io == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ assert(conf() != NULL);
+
+ // List schema sections by default.
+ if (key0 == NULL) {
+ io_reset_val(io, NULL, NULL, NULL, 0, false, NULL);
+
+ return list_section(conf()->schema, &io->key0, io);
+ }
+
+ yp_check_ctx_t *ctx = yp_schema_check_init(&conf()->schema);
+ if (ctx == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ // Check the input.
+ int ret = yp_schema_check_str(ctx, key0, NULL, NULL, NULL);
+ if (ret != KNOT_EOK) {
+ goto list_error;
+ }
+
+ yp_node_t *node = &ctx->nodes[ctx->current];
+
+ // Check for non-group item.
+ if (node->item->type != YP_TGRP) {
+ ret = KNOT_ENOTSUP;
+ goto list_error;
+ }
+
+ io_reset_val(io, node->item, NULL, NULL, 0, false, NULL);
+
+ ret = list_section(node->item->sub_items, &io->key1, io);
+list_error:
+ yp_schema_check_deinit(ctx);
+
+ return ret;
+}
+
+static int diff_item(
+ conf_io_t *io)
+{
+ // Process an identifier item.
+ if ((io->key0->flags & YP_FMULTI) != 0 && io->key0->var.g.id == io->key1) {
+ bool old_id, new_id;
+
+ // Check if a removed identifier.
+ int ret = conf_db_get(conf(), &conf()->read_txn, io->key0->name,
+ NULL, io->id, io->id_len, NULL);
+ switch (ret) {
+ case KNOT_EOK:
+ old_id = true;
+ break;
+ case KNOT_ENOENT:
+ case KNOT_YP_EINVAL_ID:
+ old_id = false;
+ break;
+ default:
+ return ret;
+ }
+
+ // Check if an added identifier.
+ ret = conf_db_get(conf(), conf()->io.txn, io->key0->name, NULL,
+ io->id, io->id_len, NULL);
+ switch (ret) {
+ case KNOT_EOK:
+ new_id = true;
+ break;
+ case KNOT_ENOENT:
+ case KNOT_YP_EINVAL_ID:
+ new_id = false;
+ break;
+ default:
+ return ret;
+ }
+
+ // Check if valid identifier.
+ if (!old_id && !new_id) {
+ return KNOT_YP_EINVAL_ID;
+ }
+
+ if (old_id != new_id) {
+ io->id_as_data = true;
+ io->type = old_id ? OLD : NEW;
+
+ // Process the callback.
+ ret = FCN(io);
+
+ // Reset the modified parameters.
+ io->id_as_data = false;
+ io->type = NONE;
+
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+ }
+
+ conf_val_t old_val, new_val;
+
+ // Get the old item value.
+ conf_db_get(conf(), &conf()->read_txn, io->key0->name, io->key1->name,
+ io->id, io->id_len, &old_val);
+ switch (old_val.code) {
+ case KNOT_EOK:
+ break;
+ case KNOT_ENOENT:
+ case KNOT_YP_EINVAL_ID:
+ break;
+ default:
+ return old_val.code;
+ }
+
+ // Get the new item value.
+ conf_db_get(conf(), conf()->io.txn, io->key0->name, io->key1->name,
+ io->id, io->id_len, &new_val);
+ switch (new_val.code) {
+ case KNOT_EOK:
+ break;
+ case KNOT_ENOENT:
+ case KNOT_YP_EINVAL_ID:
+ if (old_val.code != KNOT_EOK) {
+ return KNOT_EOK;
+ }
+ break;
+ default:
+ return new_val.code;
+ }
+
+ // Process the value difference.
+ if (old_val.code != KNOT_EOK) {
+ io->data.val = &new_val;
+ io->type = NEW;
+ int ret = FCN(io);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ } else if (new_val.code != KNOT_EOK) {
+ io->data.val = &old_val;
+ io->type = OLD;
+ int ret = FCN(io);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ } else if (!conf_val_equal(&old_val, &new_val)) {
+ io->data.val = &old_val;
+ io->type = OLD;
+ int ret = FCN(io);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ io->data.val = &new_val;
+ io->type = NEW;
+ ret = FCN(io);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ // Reset the modified parameters.
+ io->data.val = NULL;
+ io->type = NONE;
+
+ return KNOT_EOK;
+}
+
+static int diff_section(
+ conf_io_t *io)
+{
+ // Get the value for the specified item.
+ if (io->key1 != NULL) {
+ return diff_item(io);
+ }
+
+ // Get the values for all items.
+ for (yp_item_t *i = io->key0->sub_items; i->name != NULL; i++) {
+ io->key1 = i;
+
+ int ret = diff_item(io);
+
+ // Reset the modified parameters.
+ io->key1 = NULL;
+
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+static int diff_iter_section(
+ conf_io_t *io)
+{
+ // First compare the section with the old and common identifiers.
+ conf_iter_t iter;
+ int ret = conf_db_iter_begin(conf(), &conf()->read_txn, io->key0->name,
+ &iter);
+ switch (ret) {
+ case KNOT_EOK:
+ break;
+ case KNOT_ENOENT:
+ // Continue to the second step.
+ ret = KNOT_EOF;
+ break;
+ default:
+ return ret;
+ }
+
+ while (ret == KNOT_EOK) {
+ ret = conf_db_iter_id(conf(), &iter, &io->id, &io->id_len);
+ if (ret != KNOT_EOK) {
+ conf_db_iter_finish(conf(), &iter);
+ return ret;
+ }
+
+ ret = diff_section(io);
+ if (ret != KNOT_EOK) {
+ conf_db_iter_finish(conf(), &iter);
+ return ret;
+ }
+
+ ret = conf_db_iter_next(conf(), &iter);
+ }
+ if (ret != KNOT_EOF) {
+ return ret;
+ }
+
+ // Second compare the section with the new identifiers.
+ ret = conf_db_iter_begin(conf(), conf()->io.txn, io->key0->name, &iter);
+ switch (ret) {
+ case KNOT_EOK:
+ break;
+ case KNOT_ENOENT:
+ return KNOT_EOK;
+ default:
+ return ret;
+ }
+
+ while (ret == KNOT_EOK) {
+ ret = conf_db_iter_id(conf(), &iter, &io->id, &io->id_len);
+ if (ret != KNOT_EOK) {
+ conf_db_iter_finish(conf(), &iter);
+ return ret;
+ }
+
+ // Ignore old and common identifiers.
+ ret = conf_db_get(conf(), &conf()->read_txn, io->key0->name,
+ NULL, io->id, io->id_len, NULL);
+ switch (ret) {
+ case KNOT_EOK:
+ ret = conf_db_iter_next(conf(), &iter);
+ continue;
+ case KNOT_ENOENT:
+ case KNOT_YP_EINVAL_ID:
+ break;
+ default:
+ conf_db_iter_finish(conf(), &iter);
+ return ret;
+ }
+
+ ret = diff_section(io);
+ if (ret != KNOT_EOK) {
+ conf_db_iter_finish(conf(), &iter);
+ return ret;
+ }
+
+ ret = conf_db_iter_next(conf(), &iter);
+ }
+ if (ret != KNOT_EOF) {
+ return ret;
+ }
+
+ return KNOT_EOK;
+}
+
+static int diff_zone_section(
+ conf_io_t *io)
+{
+ assert(io->key0->flags & CONF_IO_FZONE);
+
+ if (conf()->io.zones == NULL) {
+ return KNOT_EOK;
+ }
+
+ trie_it_t *it = trie_it_begin(conf()->io.zones);
+ for (; !trie_it_finished(it); trie_it_next(it)) {
+ io->id = (const uint8_t *)trie_it_key(it, &io->id_len);
+
+ // Get the difference for specific zone.
+ int ret = diff_section(io);
+ if (ret != KNOT_EOK) {
+ trie_it_free(it);
+ return ret;
+ }
+ }
+ trie_it_free(it);
+
+ return KNOT_EOK;
+}
+
+int conf_io_diff(
+ const char *key0,
+ const char *key1,
+ const char *id,
+ conf_io_t *io)
+{
+ if (io == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ assert(conf() != NULL);
+
+ if (conf()->io.txn == NULL) {
+ return KNOT_TXN_ENOTEXISTS;
+ }
+
+ // Compare all sections by default.
+ if (key0 == NULL) {
+ for (yp_item_t *i = conf()->schema; i->name != NULL; i++) {
+ // Skip non-group item.
+ if (i->type != YP_TGRP) {
+ continue;
+ }
+
+ int ret = conf_io_diff(i->name + 1, key1, NULL, io);
+
+ // Reset parameters after each section.
+ io_reset_val(io, NULL, NULL, NULL, 0, false, NULL);
+
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+ }
+
+ yp_check_ctx_t *ctx = yp_schema_check_init(&conf()->schema);
+ if (ctx == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ // Check the input.
+ int ret = yp_schema_check_str(ctx, key0, key1, id, NULL);
+ if (ret != KNOT_EOK) {
+ goto diff_error;
+ }
+
+ yp_node_t *node = &ctx->nodes[ctx->current];
+ yp_node_t *parent = node->parent;
+
+ // Key1 is not a group identifier.
+ if (parent != NULL) {
+ io_reset_val(io, parent->item, node->item, parent->id,
+ parent->id_len, false, NULL);
+ // Key1 is a group identifier.
+ } else if (key1 != NULL && strlen(key1) != 0) {
+ assert(node->item->type == YP_TGRP &&
+ (node->item->flags & YP_FMULTI) != 0);
+
+ io_reset_val(io, node->item, node->item->var.g.id, node->id,
+ node->id_len, true, NULL);
+ // No key1 specified.
+ } else {
+ io_reset_val(io, node->item, NULL, node->id, node->id_len,
+ false, NULL);
+ }
+
+ // Check for a non-group item.
+ if (io->key0->type != YP_TGRP) {
+ ret = KNOT_ENOTSUP;
+ goto diff_error;
+ }
+
+ // Compare the section with all identifiers by default.
+ if ((io->key0->flags & YP_FMULTI) != 0 && io->id_len == 0) {
+ // The zone section has an optimized diff.
+ if (io->key0->flags & CONF_IO_FZONE) {
+ // Full diff by default.
+ if (!(conf()->io.flags & CONF_IO_FACTIVE)) {
+ ret = diff_iter_section(io);
+ // Full diff if all zones changed.
+ } else if (conf()->io.flags & CONF_IO_FDIFF_ZONES) {
+ ret = diff_iter_section(io);
+ // Optimized diff for specific zones.
+ } else {
+ ret = diff_zone_section(io);
+ }
+ } else {
+ ret = diff_iter_section(io);
+ }
+
+ goto diff_error;
+ }
+
+ // Compare the section with a possible identifier.
+ ret = diff_section(io);
+diff_error:
+ yp_schema_check_deinit(ctx);
+
+ return ret;
+}
+
+static int get_section(
+ knot_db_txn_t *txn,
+ conf_io_t *io)
+{
+ conf_val_t data;
+
+ // Get the value for the specified item.
+ if (io->key1 != NULL) {
+ if (!io->id_as_data) {
+ // Get the item value.
+ conf_db_get(conf(), txn, io->key0->name, io->key1->name,
+ io->id, io->id_len, &data);
+ switch (data.code) {
+ case KNOT_EOK:
+ break;
+ case KNOT_ENOENT:
+ return KNOT_EOK;
+ default:
+ return data.code;
+ }
+
+ io->data.val = &data;
+ }
+
+ // Process the callback.
+ int ret = FCN(io);
+
+ // Reset the modified parameters.
+ io->data.val = NULL;
+
+ return ret;
+ }
+
+ // Get the values for all section items by default.
+ for (yp_item_t *i = io->key0->sub_items; i->name != NULL; i++) {
+ // Process the (first) identifier item.
+ if ((io->key0->flags & YP_FMULTI) != 0 && io->key0->var.g.id == i) {
+ // Check if existing identifier.
+ conf_db_get(conf(), txn, io->key0->name, NULL, io->id,
+ io->id_len, &data);
+ switch (data.code) {
+ case KNOT_EOK:
+ break;
+ case KNOT_ENOENT:
+ continue;
+ default:
+ return data.code;
+ }
+
+ io->key1 = i;
+ io->id_as_data = true;
+
+ // Process the callback.
+ int ret = FCN(io);
+
+ // Reset the modified parameters.
+ io->key1 = NULL;
+ io->id_as_data = false;
+
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ continue;
+ }
+
+ // Get the item value.
+ conf_db_get(conf(), txn, io->key0->name, i->name, io->id,
+ io->id_len, &data);
+ switch (data.code) {
+ case KNOT_EOK:
+ break;
+ case KNOT_ENOENT:
+ continue;
+ default:
+ return data.code;
+ }
+
+ io->key1 = i;
+ io->data.val = &data;
+
+ // Process the callback.
+ int ret = FCN(io);
+
+ // Reset the modified parameters.
+ io->key1 = NULL;
+ io->data.val = NULL;
+
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+int conf_io_get(
+ const char *key0,
+ const char *key1,
+ const char *id,
+ bool get_current,
+ conf_io_t *io)
+{
+ if (io == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ assert(conf() != NULL);
+
+ if (conf()->io.txn == NULL && !get_current) {
+ return KNOT_TXN_ENOTEXISTS;
+ }
+
+ // List all sections by default.
+ if (key0 == NULL) {
+ for (yp_item_t *i = conf()->schema; i->name != NULL; i++) {
+ // Skip non-group item.
+ if (i->type != YP_TGRP) {
+ continue;
+ }
+
+ int ret = conf_io_get(i->name + 1, key1, NULL,
+ get_current, io);
+ // Reset parameters after each section.
+ io_reset_val(io, NULL, NULL, NULL, 0, false, NULL);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+ }
+
+ yp_check_ctx_t *ctx = yp_schema_check_init(&conf()->schema);
+ if (ctx == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ // Check the input.
+ int ret = yp_schema_check_str(ctx, key0, key1, id, NULL);
+ if (ret != KNOT_EOK) {
+ goto get_error;
+ }
+
+ yp_node_t *node = &ctx->nodes[ctx->current];
+ yp_node_t *parent = node->parent;
+
+ // Key1 is not a group identifier.
+ if (parent != NULL) {
+ io_reset_val(io, parent->item, node->item, parent->id,
+ parent->id_len, false, NULL);
+ // Key1 is a group identifier.
+ } else if (key1 != NULL && strlen(key1) != 0) {
+ assert(node->item->type == YP_TGRP &&
+ (node->item->flags & YP_FMULTI) != 0);
+
+ io_reset_val(io, node->item, node->item->var.g.id, node->id,
+ node->id_len, true, NULL);
+ // No key1 specified.
+ } else {
+ io_reset_val(io, node->item, NULL, node->id, node->id_len, false,
+ NULL);
+ }
+
+ knot_db_txn_t *txn = get_current ? &conf()->read_txn : conf()->io.txn;
+
+ // Check for a non-group item.
+ if (io->key0->type != YP_TGRP) {
+ ret = KNOT_ENOTSUP;
+ goto get_error;
+ }
+
+ // List the section with all identifiers by default.
+ if ((io->key0->flags & YP_FMULTI) != 0 && io->id_len == 0) {
+ conf_iter_t iter;
+ ret = conf_db_iter_begin(conf(), txn, io->key0->name, &iter);
+ switch (ret) {
+ case KNOT_EOK:
+ break;
+ case KNOT_ENOENT:
+ ret = KNOT_EOK;
+ goto get_error;
+ default:
+ goto get_error;
+ }
+
+ while (ret == KNOT_EOK) {
+ // Set the section identifier.
+ ret = conf_db_iter_id(conf(), &iter, &io->id, &io->id_len);
+ if (ret != KNOT_EOK) {
+ conf_db_iter_finish(conf(), &iter);
+ goto get_error;
+ }
+
+ ret = get_section(txn, io);
+ if (ret != KNOT_EOK) {
+ conf_db_iter_finish(conf(), &iter);
+ goto get_error;
+ }
+
+ ret = conf_db_iter_next(conf(), &iter);
+ }
+
+ ret = KNOT_EOK;
+ goto get_error;
+ }
+
+ // List the section with a possible identifier.
+ ret = get_section(txn, io);
+get_error:
+ yp_schema_check_deinit(ctx);
+
+ return ret;
+}
+
+static void upd_changes(
+ const conf_io_t *io,
+ conf_io_type_t type,
+ yp_flag_t flags,
+ bool any_id)
+{
+ // Update common flags.
+ conf()->io.flags |= flags;
+
+ // Return if not important change.
+ if (type == CONF_IO_TNONE) {
+ return;
+ }
+
+ // Update reference item.
+ if (flags & CONF_IO_FREF) {
+ // Expected an identifier, which cannot be changed.
+ assert(type != CONF_IO_TCHANGE);
+
+ // Re-check and reload all zones if a reference has been removed.
+ if (type == CONF_IO_TUNSET) {
+ conf()->io.flags |= CONF_IO_FCHECK_ZONES | CONF_IO_FRLD_ZONES;
+ }
+ return;
+ // Return if no specific zone operation.
+ } else if (!(flags & CONF_IO_FZONE)) {
+ return;
+ }
+
+ // Don't process each zone individually, process all instead.
+ if (any_id) {
+ // Diff all zone changes.
+ conf()->io.flags |= CONF_IO_FCHECK_ZONES | CONF_IO_FDIFF_ZONES;
+
+ // Reload just with important changes.
+ if (flags & CONF_IO_FRLD_ZONE) {
+ conf()->io.flags |= CONF_IO_FRLD_ZONES;
+ }
+ return;
+ }
+
+ // Prepare zone changes storage if it doesn't exist.
+ trie_t *zones = conf()->io.zones;
+ if (zones == NULL) {
+ zones = trie_create(NULL);
+ if (zones == NULL) {
+ return;
+ }
+ conf()->io.zones = zones;
+ }
+
+ // Get zone status or create new.
+ trie_val_t *val = trie_get_ins(zones, (const char *)io->id, io->id_len);
+ conf_io_type_t *current = (conf_io_type_t *)val;
+
+ switch (type) {
+ case CONF_IO_TSET:
+ // Revert remove zone, but don't remove (probably changed).
+ if (*current & CONF_IO_TUNSET) {
+ *current &= ~CONF_IO_TUNSET;
+ } else {
+ // Must be a new zone.
+ assert(*current == CONF_IO_TNONE);
+ // Mark added zone.
+ *current = type;
+ }
+ break;
+ case CONF_IO_TUNSET:
+ if (*current & CONF_IO_TSET) {
+ // Remove inserted zone -> no change.
+ trie_del(zones, (const char *)io->id, io->id_len, NULL);
+ } else {
+ // Remove existing zone.
+ *current |= type;
+ }
+ break;
+ case CONF_IO_TCHANGE:
+ *current |= type;
+ // Mark zone to reload if required.
+ if (flags & CONF_IO_FRLD_ZONE) {
+ *current |= CONF_IO_TRELOAD;
+ }
+ break;
+ case CONF_IO_TRELOAD:
+ default:
+ assert(0);
+ }
+}
+
+static int set_item(
+ conf_io_t *io)
+{
+ int ret = conf_db_set(conf(), conf()->io.txn, io->key0->name,
+ (io->key1 != NULL) ? io->key1->name : NULL,
+ io->id, io->id_len, io->data.bin, io->data.bin_len);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Postpone group callbacks to config check.
+ if (io->key0->type == YP_TGRP && io->id_len == 0) {
+ return KNOT_EOK;
+ }
+
+ knotd_conf_check_extra_t extra = {
+ .conf = conf(),
+ .txn = conf()->io.txn
+ };
+ knotd_conf_check_args_t args = {
+ .item = (io->key1 != NULL) ? io->key1 :
+ ((io->id_len == 0) ? io->key0 : io->key0->var.g.id),
+ .id = io->id,
+ .id_len = io->id_len,
+ .data = io->data.bin,
+ .data_len = io->data.bin_len,
+ .extra = &extra
+ };
+
+ // Call the item callbacks (include, item check, mod-id check).
+ ret = conf_exec_callbacks(&args);
+ if (ret != KNOT_EOK) {
+ CONF_LOG(LOG_DEBUG, "item '%s' (%s)", args.item->name + 1,
+ args.err_str != NULL ? args.err_str : knot_strerror(ret));
+ }
+
+ return ret;
+}
+
+int conf_io_set(
+ const char *key0,
+ const char *key1,
+ const char *id,
+ const char *data)
+{
+ assert(conf() != NULL);
+
+ if (conf()->io.txn == NULL) {
+ return KNOT_TXN_ENOTEXISTS;
+ }
+
+ // At least key0 must be specified.
+ if (key0 == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ yp_check_ctx_t *ctx = yp_schema_check_init(&conf()->schema);
+ if (ctx == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ // Check the input.
+ int ret = yp_schema_check_str(ctx, key0, key1, id, data);
+ if (ret != KNOT_EOK) {
+ goto set_error;
+ }
+
+ yp_node_t *node = &ctx->nodes[ctx->current];
+ yp_node_t *parent = node->parent;
+
+ yp_flag_t upd_flags = node->item->flags;
+ conf_io_type_t upd_type = CONF_IO_TNONE;
+
+ conf_io_t io = { NULL };
+
+ // Key1 is not a group identifier.
+ if (parent != NULL) {
+ if (node->data_len == 0) {
+ ret = KNOT_YP_ENODATA;
+ goto set_error;
+ }
+ upd_type = CONF_IO_TCHANGE;
+ upd_flags |= parent->item->flags;
+ io_reset_bin(&io, parent->item, node->item, parent->id,
+ parent->id_len, node->data, node->data_len);
+ // A group identifier or whole group.
+ } else if (node->item->type == YP_TGRP) {
+ upd_type = CONF_IO_TSET;
+ if ((node->item->flags & YP_FMULTI) != 0) {
+ if (node->id_len == 0) {
+ ret = KNOT_YP_ENOID;
+ goto set_error;
+ }
+ upd_flags |= node->item->var.g.id->flags;
+ } else {
+ ret = KNOT_ENOTSUP;
+ goto set_error;
+ }
+ assert(node->data_len == 0);
+ io_reset_bin(&io, node->item, NULL, node->id, node->id_len,
+ NULL, 0);
+ // A non-group item with data (include).
+ } else if (node->data_len > 0) {
+ io_reset_bin(&io, node->item, NULL, NULL, 0, node->data,
+ node->data_len);
+ } else {
+ ret = KNOT_YP_ENODATA;
+ goto set_error;
+ }
+
+ // Set the item for all identifiers by default.
+ if (io.key0->type == YP_TGRP && io.key1 != NULL &&
+ (io.key0->flags & YP_FMULTI) != 0 && io.id_len == 0) {
+ conf_iter_t iter;
+ ret = conf_db_iter_begin(conf(), conf()->io.txn, io.key0->name,
+ &iter);
+ switch (ret) {
+ case KNOT_EOK:
+ break;
+ case KNOT_ENOENT:
+ ret = KNOT_EOK;
+ goto set_error;
+ default:
+ goto set_error;
+ }
+
+ uint8_t copied_id[YP_MAX_ID_LEN];
+ io.id = copied_id;
+ while (ret == KNOT_EOK) {
+ // Get the identifier and copy it because of next DB update.
+ const uint8_t *tmp_id;
+ ret = conf_db_iter_id(conf(), &iter, &tmp_id, &io.id_len);
+ if (ret != KNOT_EOK) {
+ conf_db_iter_finish(conf(), &iter);
+ goto set_error;
+ }
+ memcpy(copied_id, tmp_id, io.id_len);
+
+ // Set the data.
+ ret = set_item(&io);
+ if (ret != KNOT_EOK) {
+ conf_db_iter_finish(conf(), &iter);
+ goto set_error;
+ }
+
+ ret = conf_db_iter_next(conf(), &iter);
+ }
+ if (ret != KNOT_EOF) {
+ goto set_error;
+ }
+
+ upd_changes(&io, upd_type, upd_flags, true);
+
+ ret = KNOT_EOK;
+ goto set_error;
+ }
+
+ // Set the item with a possible identifier.
+ ret = set_item(&io);
+
+ if (ret == KNOT_EOK) {
+ upd_changes(&io, upd_type, upd_flags, false);
+ }
+set_error:
+ yp_schema_check_deinit(ctx);
+
+ return ret;
+}
+
+static int unset_section_data(
+ conf_io_t *io)
+{
+ // Unset the value for the specified item.
+ if (io->key1 != NULL) {
+ return conf_db_unset(conf(), conf()->io.txn, io->key0->name,
+ io->key1->name, io->id, io->id_len,
+ io->data.bin, io->data.bin_len, false);
+ }
+
+ // Unset the whole section by default.
+ for (yp_item_t *i = io->key0->sub_items; i->name != NULL; i++) {
+ // Skip the identifier item.
+ if ((io->key0->flags & YP_FMULTI) != 0 && io->key0->var.g.id == i) {
+ continue;
+ }
+
+ int ret = conf_db_unset(conf(), conf()->io.txn, io->key0->name,
+ i->name, io->id, io->id_len, io->data.bin,
+ io->data.bin_len, false);
+ switch (ret) {
+ case KNOT_EOK:
+ case KNOT_ENOENT:
+ continue;
+ default:
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+static int unset_section(
+ const yp_item_t *key0)
+{
+ // Unset the section items.
+ for (yp_item_t *i = key0->sub_items; i->name != NULL; i++) {
+ // Skip the identifier item.
+ if ((key0->flags & YP_FMULTI) != 0 && key0->var.g.id == i) {
+ continue;
+ }
+
+ int ret = conf_db_unset(conf(), conf()->io.txn, key0->name,
+ i->name, NULL, 0, NULL, 0, true);
+ switch (ret) {
+ case KNOT_EOK:
+ case KNOT_ENOENT:
+ continue;
+ default:
+ return ret;
+ }
+ }
+
+ // Unset the section.
+ int ret = conf_db_unset(conf(), conf()->io.txn, key0->name, NULL, NULL,
+ 0, NULL, 0, false);
+ switch (ret) {
+ case KNOT_EOK:
+ case KNOT_ENOENT:
+ return KNOT_EOK;
+ default:
+ return ret;
+ }
+}
+
+int conf_io_unset(
+ const char *key0,
+ const char *key1,
+ const char *id,
+ const char *data)
+{
+ assert(conf() != NULL);
+
+ if (conf()->io.txn == NULL) {
+ return KNOT_TXN_ENOTEXISTS;
+ }
+
+ // Unset all sections by default.
+ if (key0 == NULL) {
+ for (yp_item_t *i = conf()->schema; i->name != NULL; i++) {
+ // Skip non-group item.
+ if (i->type != YP_TGRP) {
+ continue;
+ }
+
+ int ret = conf_io_unset(i->name + 1, key1, NULL, NULL);
+ switch (ret) {
+ case KNOT_EOK:
+ case KNOT_ENOENT:
+ break;
+ default:
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+ }
+
+ yp_check_ctx_t *ctx = yp_schema_check_init(&conf()->schema);
+ if (ctx == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ // Check the input.
+ int ret = yp_schema_check_str(ctx, key0, key1, id, data);
+ if (ret != KNOT_EOK) {
+ goto unset_error;
+ }
+
+ yp_node_t *node = &ctx->nodes[ctx->current];
+ yp_node_t *parent = node->parent;
+
+ yp_flag_t upd_flags = node->item->flags;
+ conf_io_type_t upd_type = CONF_IO_TNONE;
+
+ conf_io_t io = { NULL };
+
+ // Key1 is not a group identifier.
+ if (parent != NULL) {
+ upd_type = CONF_IO_TCHANGE;
+ upd_flags |= parent->item->flags;
+ io_reset_bin(&io, parent->item, node->item, parent->id,
+ parent->id_len, node->data, node->data_len);
+ // A group identifier or whole group.
+ } else if (node->item->type == YP_TGRP) {
+ upd_type = CONF_IO_TUNSET;
+ if ((node->item->flags & YP_FMULTI) != 0) {
+ upd_flags |= node->item->var.g.id->flags;
+ }
+ assert(node->data_len == 0);
+ io_reset_bin(&io, node->item, NULL, node->id, node->id_len,
+ NULL, 0);
+ // A non-group item (include).
+ } else {
+ ret = KNOT_ENOTSUP;
+ goto unset_error;
+ }
+
+ // Unset the section with all identifiers by default.
+ if ((io.key0->flags & YP_FMULTI) != 0 && io.id_len == 0) {
+ conf_iter_t iter;
+ ret = conf_db_iter_begin(conf(), conf()->io.txn, io.key0->name,
+ &iter);
+ switch (ret) {
+ case KNOT_EOK:
+ break;
+ case KNOT_ENOENT:
+ ret = KNOT_EOK;
+ goto unset_error;
+ default:
+ goto unset_error;
+ }
+
+ uint8_t copied_id[YP_MAX_ID_LEN];
+ io.id = copied_id;
+ while (ret == KNOT_EOK) {
+ // Get the identifier and copy it because of next DB update.
+ const uint8_t *tmp_id;
+ ret = conf_db_iter_id(conf(), &iter, &tmp_id, &io.id_len);
+ if (ret != KNOT_EOK) {
+ conf_db_iter_finish(conf(), &iter);
+ goto unset_error;
+ }
+ memcpy(copied_id, tmp_id, io.id_len);
+
+ // Unset the section data.
+ ret = unset_section_data(&io);
+ switch (ret) {
+ case KNOT_EOK:
+ case KNOT_ENOENT:
+ break;
+ default:
+ conf_db_iter_finish(conf(), &iter);
+ goto unset_error;
+ }
+
+ ret = conf_db_iter_next(conf(), &iter);
+ }
+ if (ret != KNOT_EOF) {
+ goto unset_error;
+ }
+
+ if (io.key1 == NULL) {
+ // Unset all identifiers.
+ ret = conf_db_iter_begin(conf(), conf()->io.txn,
+ io.key0->name, &iter);
+ switch (ret) {
+ case KNOT_EOK:
+ break;
+ case KNOT_ENOENT:
+ ret = KNOT_EOK;
+ goto unset_error;
+ default:
+ goto unset_error;
+ }
+
+ while (ret == KNOT_EOK) {
+ ret = conf_db_iter_del(conf(), &iter);
+ if (ret != KNOT_EOK) {
+ conf_db_iter_finish(conf(), &iter);
+ goto unset_error;
+ }
+
+ ret = conf_db_iter_next(conf(), &iter);
+ }
+ if (ret != KNOT_EOF) {
+ goto unset_error;
+ }
+
+ // Unset the section.
+ ret = unset_section(io.key0);
+ if (ret != KNOT_EOK) {
+ goto unset_error;
+ }
+ }
+
+ upd_changes(&io, upd_type, upd_flags, true);
+
+ ret = KNOT_EOK;
+ goto unset_error;
+ }
+
+ // Unset the section data.
+ ret = unset_section_data(&io);
+ if (ret != KNOT_EOK) {
+ goto unset_error;
+ }
+
+ if (io.key1 == NULL) {
+ // Unset the identifier.
+ if (io.id_len != 0) {
+ ret = conf_db_unset(conf(), conf()->io.txn, io.key0->name,
+ NULL, io.id, io.id_len, NULL, 0, false);
+ if (ret != KNOT_EOK) {
+ goto unset_error;
+ }
+ // Unset the section.
+ } else {
+ ret = unset_section(io.key0);
+ if (ret != KNOT_EOK) {
+ goto unset_error;
+ }
+ }
+ }
+
+ if (ret == KNOT_EOK) {
+ upd_changes(&io, upd_type, upd_flags, false);
+ }
+unset_error:
+ yp_schema_check_deinit(ctx);
+
+ return ret;
+}
+
+static int check_section(
+ const yp_item_t *group,
+ const uint8_t *id,
+ size_t id_len,
+ conf_io_t *io)
+{
+ knotd_conf_check_extra_t extra = {
+ .conf = conf(),
+ .txn = conf()->io.txn,
+ .check = true
+ };
+ knotd_conf_check_args_t args = {
+ .id = id,
+ .id_len = id_len,
+ .extra = &extra
+ };
+
+ bool non_empty = false;
+
+ for (yp_item_t *item = group->sub_items; item->name != NULL; item++) {
+ args.item = item;
+
+ // Check the identifier.
+ if ((group->flags & YP_FMULTI) != 0 && group->var.g.id == item) {
+ io->error.code = conf_exec_callbacks(&args);
+ if (io->error.code != KNOT_EOK) {
+ io_reset_val(io, group, item, NULL, 0, false, NULL);
+ goto check_section_error;
+ }
+ continue;
+ }
+
+ // Get the item value.
+ conf_val_t bin;
+ conf_db_get(conf(), conf()->io.txn, group->name, item->name, id,
+ id_len, &bin);
+ if (bin.code == KNOT_ENOENT) {
+ continue;
+ } else if (bin.code != KNOT_EOK) {
+ return bin.code;
+ }
+
+ non_empty = true;
+
+ // Check the item value(s).
+ size_t values = conf_val_count(&bin);
+ for (size_t i = 1; i <= values; i++) {
+ conf_val(&bin);
+ args.data = bin.data;
+ args.data_len = bin.len;
+
+ io->error.code = conf_exec_callbacks(&args);
+ if (io->error.code != KNOT_EOK) {
+ io_reset_val(io, group, item, id, id_len, false,
+ &bin);
+ io->data.index = i;
+ goto check_section_error;
+ }
+
+ if (values > 1) {
+ conf_val_next(&bin);
+ }
+ }
+ }
+
+ // Check the whole section if not empty.
+ if (id != NULL || non_empty) {
+ args.item = group;
+ args.data = NULL;
+ args.data_len = 0;
+
+ io->error.code = conf_exec_callbacks(&args);
+ if (io->error.code != KNOT_EOK) {
+ io_reset_val(io, group, NULL, id, id_len, false, NULL);
+ goto check_section_error;
+ }
+ }
+
+ return KNOT_EOK;
+
+check_section_error:
+ io->error.str = args.err_str;
+ int ret = FCN(io);
+ if (ret == KNOT_EOK) {
+ return io->error.code;
+ }
+ return ret;
+}
+
+static int check_iter_section(
+ const yp_item_t *item,
+ conf_io_t *io)
+{
+ // Iterate over all identifiers.
+ conf_iter_t iter;
+ int ret = conf_db_iter_begin(conf(), conf()->io.txn, item->name, &iter);
+ switch (ret) {
+ case KNOT_EOK:
+ break;
+ case KNOT_ENOENT:
+ return KNOT_EOK;
+ default:
+ return ret;
+ }
+
+ while (ret == KNOT_EOK) {
+ size_t id_len;
+ const uint8_t *id;
+ ret = conf_db_iter_id(conf(), &iter, &id, &id_len);
+ if (ret != KNOT_EOK) {
+ conf_db_iter_finish(conf(), &iter);
+ return ret;
+ }
+
+ // Check specific section item.
+ ret = check_section(item, id, id_len, io);
+ if (ret != KNOT_EOK) {
+ conf_db_iter_finish(conf(), &iter);
+ return ret;
+ }
+
+ ret = conf_db_iter_next(conf(), &iter);
+ }
+ if (ret != KNOT_EOF) {
+ return ret;
+ }
+
+ return KNOT_EOK;
+}
+
+static int check_zone_section(
+ const yp_item_t *item,
+ conf_io_t *io)
+{
+ assert(item->flags & CONF_IO_FZONE);
+
+ if (conf()->io.zones == NULL) {
+ return KNOT_EOK;
+ }
+
+ trie_it_t *it = trie_it_begin(conf()->io.zones);
+ for (; !trie_it_finished(it); trie_it_next(it)) {
+ size_t id_len;
+ const uint8_t *id = (const uint8_t *)trie_it_key(it, &id_len);
+
+ conf_io_type_t type = (conf_io_type_t)(*trie_it_val(it));
+ if (type == CONF_IO_TUNSET) {
+ // Nothing to check.
+ continue;
+ }
+
+ // Check specific zone.
+ int ret = check_section(item, id, id_len, io);
+ if (ret != KNOT_EOK) {
+ trie_it_free(it);
+ return ret;
+ }
+ }
+ trie_it_free(it);
+
+ return KNOT_EOK;
+}
+
+int conf_io_check(
+ conf_io_t *io)
+{
+ if (io == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ assert(conf() != NULL);
+
+ if (conf()->io.txn == NULL) {
+ return KNOT_TXN_ENOTEXISTS;
+ }
+
+ int ret;
+
+ // Iterate over the schema.
+ for (yp_item_t *item = conf()->schema; item->name != NULL; item++) {
+ // Skip non-group items (include).
+ if (item->type != YP_TGRP) {
+ continue;
+ }
+
+ // Check simple group without identifiers.
+ if ((item->flags & YP_FMULTI) == 0) {
+ ret = check_section(item, NULL, 0, io);
+ if (ret != KNOT_EOK) {
+ goto check_error;
+ }
+ continue;
+ }
+
+ // The zone section has an optimized check.
+ if (item->flags & CONF_IO_FZONE) {
+ // Full check by default.
+ if (!(conf()->io.flags & CONF_IO_FACTIVE)) {
+ ret = check_iter_section(item, io);
+ // Full check if all zones changed.
+ } else if (conf()->io.flags & CONF_IO_FCHECK_ZONES) {
+ ret = check_iter_section(item, io);
+ // Optimized check for specific zones.
+ } else {
+ ret = check_zone_section(item, io);
+ }
+ } else {
+ ret = check_iter_section(item, io);
+ }
+ if (ret != KNOT_EOK) {
+ goto check_error;
+ }
+ }
+
+ ret = KNOT_EOK;
+check_error:
+ conf_mod_load_purge(conf(), true);
+
+ return ret;
+}
diff --git a/src/knot/conf/confio.h b/src/knot/conf/confio.h
new file mode 100644
index 0000000..460bfbd
--- /dev/null
+++ b/src/knot/conf/confio.h
@@ -0,0 +1,218 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include "knot/conf/conf.h"
+
+/*! Configuration schema additional flags for dynamic changes. */
+#define CONF_IO_FACTIVE YP_FUSR1 /*!< Active confio transaction indicator. */
+#define CONF_IO_FZONE YP_FUSR2 /*!< Zone section indicator. */
+#define CONF_IO_FREF YP_FUSR3 /*!< Possibly referenced id from a zone. */
+#define CONF_IO_FDIFF_ZONES YP_FUSR4 /*!< All zones config has changed. */
+#define CONF_IO_FCHECK_ZONES YP_FUSR5 /*!< All zones config needs to check. */
+#define CONF_IO_FRLD_SRV YP_FUSR6 /*!< Reload server. */
+#define CONF_IO_FRLD_LOG YP_FUSR7 /*!< Reload logging. */
+#define CONF_IO_FRLD_MOD YP_FUSR8 /*!< Reload global modules. */
+#define CONF_IO_FRLD_ZONE YP_FUSR9 /*!< Reload a specific zone. */
+#define CONF_IO_FRLD_ZONES YP_FUSR10 /*!< Reload all zones. */
+#define CONF_IO_FRLD_ALL (CONF_IO_FRLD_SRV | CONF_IO_FRLD_LOG | \
+ CONF_IO_FRLD_MOD | CONF_IO_FRLD_ZONES)
+
+/*! Zone configuration change type. */
+typedef enum {
+ CONF_IO_TNONE = 0, /*!< Unspecified. */
+ CONF_IO_TSET = 1 << 0, /*!< Zone added. */
+ CONF_IO_TUNSET = 1 << 1, /*!< Zone removed. */
+ CONF_IO_TCHANGE = 1 << 2, /*!< Zone has changed configuration. */
+ CONF_IO_TRELOAD = 1 << 3, /*!< Zone must be reloaded. */
+} conf_io_type_t;
+
+/*! Configuration interface output. */
+typedef struct conf_io conf_io_t;
+struct conf_io {
+ /*! Section. */
+ const yp_item_t *key0;
+ /*! Section item. */
+ const yp_item_t *key1;
+ /*! Section identifier. */
+ const uint8_t *id;
+ /*! Section identifier length. */
+ size_t id_len;
+ /*! Consider item identifier as item data. */
+ bool id_as_data;
+
+ enum {
+ /*! Default item state. */
+ NONE,
+ /*! New item indicator. */
+ NEW,
+ /*! Old item indicator. */
+ OLD
+ } type;
+
+ struct {
+ /*! Section item data (NULL if not used). */
+ conf_val_t *val;
+ /*! Index of data value to format (counted from 1, 0 means all). */
+ size_t index;
+ /*! Binary data value (NULL if not used). */
+ const uint8_t *bin;
+ /*! Length of the binary data value. */
+ size_t bin_len;
+ } data;
+
+ struct {
+ /*! Edit operation return code. */
+ int code;
+ /*! Edit operation return error message. */
+ const char *str;
+ } error;
+
+ /*! Optional processing callback. */
+ int (*fcn)(conf_io_t *);
+ /*! Miscellaneous data useful for the callback. */
+ void *misc;
+};
+
+/*!
+ * Starts new writing transaction.
+ *
+ * \param[in] child Nested transaction indicator.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int conf_io_begin(
+ bool child
+);
+
+/*!
+ * Commits the current writing transaction.
+ *
+ * \note Remember to call conf_refresh to publish the changes into the common
+ * configuration.
+ *
+ * \param[in] child Nested transaction indicator.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int conf_io_commit(
+ bool child
+);
+
+/*!
+ * Aborts the current writing transaction.
+ *
+ * \param[in] child Nested transaction indicator.
+ */
+void conf_io_abort(
+ bool child
+);
+
+/*!
+ * Gets the configuration sections list or section items list.
+ *
+ * \param[in] key0 Section name (NULL to get section list).
+ * \param[out] io Operation output.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int conf_io_list(
+ const char *key0,
+ conf_io_t *io
+);
+
+/*!
+ * Gets the configuration difference between the current configuration and
+ * the active transaction.
+ *
+ * \param[in] key0 Section name (NULL to diff all sections).
+ * \param[in] key1 Item name (NULL to diff all section items).
+ * \param[in] id Section identifier name (NULL to consider all section identifiers).
+ * \param[out] io Operation output.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int conf_io_diff(
+ const char *key0,
+ const char *key1,
+ const char *id,
+ conf_io_t *io
+);
+
+/*!
+ * Gets the configuration item(s) value(s).
+ *
+ * \param[in] key0 Section name (NULL to get all sections).
+ * \param[in] key1 Item name (NULL to get all section items).
+ * \param[in] id Section identifier name (NULL to consider all section identifiers).
+ * \param[in] get_current The current configuration or the active transaction switch.
+ * \param[out] io Operation output.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int conf_io_get(
+ const char *key0,
+ const char *key1,
+ const char *id,
+ bool get_current,
+ conf_io_t *io
+);
+
+/*!
+ * Sets the configuration item(s) value.
+ *
+ * \param[in] key0 Section name.
+ * \param[in] key1 Item name (NULL to add identifier only).
+ * \param[in] id Section identifier name (NULL to consider all section identifiers).
+ * \param[in] data Item data to set/add.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int conf_io_set(
+ const char *key0,
+ const char *key1,
+ const char *id,
+ const char *data
+);
+
+/*!
+ * Unsets the configuration item(s) value(s).
+ *
+ * \param[in] key0 Section name (NULL to unset all sections).
+ * \param[in] key1 Item name (NULL to unset the whole section).
+ * \param[in] id Section identifier name (NULL to consider all section identifiers).
+ * \param[in] data Item data (NULL to unset all data).
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int conf_io_unset(
+ const char *key0,
+ const char *key1,
+ const char *id,
+ const char *data
+);
+
+/*!
+ * Checks the configuration database semantics in the current writing transaction.
+ *
+ * \param[out] io Operation output.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int conf_io_check(
+ conf_io_t *io
+);
diff --git a/src/knot/conf/migration.c b/src/knot/conf/migration.c
new file mode 100644
index 0000000..a15edae
--- /dev/null
+++ b/src/knot/conf/migration.c
@@ -0,0 +1,81 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "knot/common/log.h"
+#include "knot/conf/migration.h"
+#include "knot/conf/confdb.h"
+
+/*
+static void try_unset(conf_t *conf, knot_db_txn_t *txn, yp_name_t *key0, yp_name_t *key1)
+{
+ int ret = conf_db_unset(conf, txn, key0, key1, NULL, 0, NULL, 0, true);
+ if (ret != KNOT_EOK && ret != KNOT_ENOENT) {
+ log_warning("conf, migration, failed to unset '%s%s%s' (%s)",
+ key0 + 1,
+ (key1 != NULL) ? "/" : "",
+ (key1 != NULL) ? key1 + 1 : "",
+ knot_strerror(ret));
+ }
+}
+
+#define check_set(conf, txn, key0, key1, id, id_len, data, data_len) \
+ ret = conf_db_set(conf, txn, key0, key1, id, id_len, data, data_len); \
+ if (ret != KNOT_EOK && ret != KNOT_CONF_EREDEFINE) { \
+ log_error("conf, migration, failed to set '%s%s%s' (%s)", \
+ key0 + 1, \
+ (key1 != NULL) ? "/" : "", \
+ (key1 != NULL) ? key1 + 1 : "", \
+ knot_strerror(ret)); \
+ return ret; \
+ }
+
+static int migrate_(
+ conf_t *conf,
+ knot_db_txn_t *txn)
+{
+ return KNOT_EOK;
+}
+*/
+
+int conf_migrate(
+ conf_t *conf)
+{
+ return KNOT_EOK;
+ /*
+ if (conf == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ knot_db_txn_t txn;
+ int ret = conf->api->txn_begin(conf->db, &txn, 0);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = migrate_(conf, &txn);
+ if (ret != KNOT_EOK) {
+ conf->api->txn_abort(&txn);
+ return ret;
+ }
+
+ ret = conf->api->txn_commit(&txn);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ return conf_refresh_txn(conf);
+ */
+}
diff --git a/src/knot/conf/migration.h b/src/knot/conf/migration.h
new file mode 100644
index 0000000..c885ff4
--- /dev/null
+++ b/src/knot/conf/migration.h
@@ -0,0 +1,30 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include "knot/conf/base.h"
+
+/*!
+ * Migrates from an old configuration schema.
+ *
+ * \param[in] conf Configuration.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int conf_migrate(
+ conf_t *conf
+);
diff --git a/src/knot/conf/module.c b/src/knot/conf/module.c
new file mode 100644
index 0000000..6bb013f
--- /dev/null
+++ b/src/knot/conf/module.c
@@ -0,0 +1,460 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <glob.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <urcu.h>
+
+#include "knot/conf/conf.h"
+#include "knot/conf/confio.h"
+#include "knot/conf/module.h"
+#include "knot/common/log.h"
+#include "knot/modules/static_modules.h"
+#include "knot/nameserver/query_module.h"
+#include "contrib/openbsd/strlcat.h"
+#include "contrib/string.h"
+
+#define LIB_EXTENSION ".so"
+
+dynarray_define(mod, module_t *, DYNARRAY_VISIBILITY_PUBLIC)
+dynarray_define(old_schema, yp_item_t *, DYNARRAY_VISIBILITY_PUBLIC)
+
+static module_t STATIC_MODULES[] = {
+ STATIC_MODULES_INIT
+ { NULL }
+};
+
+module_t *conf_mod_find(
+ conf_t *conf,
+ const char *name,
+ size_t len,
+ bool temporary)
+{
+ if (conf == NULL || name == NULL) {
+ return NULL;
+ }
+
+ // First, search in static modules.
+ for (module_t *mod = STATIC_MODULES; mod->api != NULL; mod++) {
+ if (strncmp(name, mod->api->name, len) == 0) {
+ return mod;
+ }
+ }
+
+ // Second, search in dynamic modules.
+ dynarray_foreach(mod, module_t *, module, conf->modules) {
+ if ((*module) != NULL && (*module)->temporary == temporary &&
+ strncmp(name, (*module)->api->name, len) == 0) {
+ return (*module);
+ }
+ }
+
+ return NULL;
+}
+
+static int mod_load(
+ conf_t *conf,
+ module_t *mod)
+{
+ static const yp_item_t module_common[] = {
+ { C_ID, YP_TSTR, YP_VNONE, CONF_IO_FREF },
+ { C_COMMENT, YP_TSTR, YP_VNONE },
+ { NULL }
+ };
+
+ yp_item_t *sub_items = NULL;
+
+ int ret;
+ if (mod->api->config != NULL) {
+ ret = yp_schema_merge(&sub_items, module_common, mod->api->config);
+ } else {
+ ret = yp_schema_copy(&sub_items, module_common);
+ }
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ /* Synthesise module config section name. */
+ const size_t name_len = strlen(mod->api->name);
+ if (name_len > YP_MAX_ITEM_NAME_LEN) {
+ return KNOT_YP_EINVAL_ITEM;
+ }
+ char name[1 + YP_MAX_ITEM_NAME_LEN + 1];
+ name[0] = name_len;
+ memcpy(name + 1, mod->api->name, name_len + 1);
+
+ const yp_item_t schema[] = {
+ { name, YP_TGRP, YP_VGRP = { sub_items },
+ YP_FALLOC | YP_FMULTI | CONF_IO_FRLD_MOD | CONF_IO_FRLD_ZONES,
+ { mod->api->config_check } },
+ { NULL }
+ };
+
+ yp_item_t *merged = NULL;
+ ret = yp_schema_merge(&merged, conf->schema, schema);
+ yp_schema_free(sub_items);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Update configuration schema (with lazy free).
+ yp_item_t **current_schema = &conf->schema;
+ yp_item_t *old_schema = rcu_xchg_pointer(current_schema, merged);
+ synchronize_rcu();
+ old_schema_dynarray_add(&conf->old_schemas, &old_schema);
+
+ return KNOT_EOK;
+}
+
+int conf_mod_load_common(
+ conf_t *conf)
+{
+ if (conf == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = KNOT_EOK;
+
+ // First, load static modules.
+ for (module_t *mod = STATIC_MODULES; mod->api != NULL; mod++) {
+ ret = mod_load(conf, mod);
+ if (ret != KNOT_EOK) {
+ break;
+ }
+
+ log_debug("module '%s', loaded static", mod->api->name);
+ }
+
+ // Second, try to load implicit shared modules if configured.
+ if (strlen(MODULE_DIR) > 0) {
+ struct stat path_stat;
+ glob_t glob_buf = { 0 };
+
+ char *path = sprintf_alloc("%s/*%s", MODULE_DIR, LIB_EXTENSION);
+ if (path == NULL) {
+ ret = KNOT_ENOMEM;
+ } else if (stat(MODULE_DIR, &path_stat) != 0 ||
+ !S_ISDIR(path_stat.st_mode)) {
+ if (errno == ENOENT) {
+ // Module directory doesn't exist.
+ ret = KNOT_EOK;
+ } else {
+ log_error("module, invalid directory '%s'",
+ MODULE_DIR);
+ ret = KNOT_EINVAL;
+ }
+ } else if (access(MODULE_DIR, F_OK | R_OK) != 0) {
+ log_error("module, failed to access directory '%s'",
+ MODULE_DIR);
+ ret = KNOT_EACCES;
+ } else {
+ ret = glob(path, 0, NULL, &glob_buf);
+ if (ret != 0 && ret != GLOB_NOMATCH) {
+ log_error("module, failed to read directory '%s'",
+ MODULE_DIR);
+ ret = KNOT_EACCES;
+ } else {
+ ret = KNOT_EOK;
+ }
+ }
+
+ // Process each module in the directory.
+ for (size_t i = 0; i < glob_buf.gl_pathc; i++) {
+ (void)conf_mod_load_extra(conf, NULL, glob_buf.gl_pathv[i],
+ false);
+ }
+
+ globfree(&glob_buf);
+ free(path);
+ }
+
+ conf_mod_load_purge(conf, false);
+
+ return ret;
+}
+
+int conf_mod_load_extra(
+ conf_t *conf,
+ const char *mod_name,
+ const char *file_name,
+ bool temporary)
+{
+ if (conf == NULL || (mod_name == NULL && file_name == NULL)) {
+ return KNOT_EINVAL;
+ }
+
+ // Synthesize module file name if not specified.
+ char *tmp_name = NULL;
+ if (file_name == NULL) {
+ tmp_name = sprintf_alloc("%s/%s%s", MODULE_INSTDIR,
+ mod_name + strlen(KNOTD_MOD_NAME_PREFIX),
+ LIB_EXTENSION);
+ if (tmp_name == NULL) {
+ return KNOT_ENOMEM;
+ }
+ file_name = tmp_name;
+ }
+
+ void *handle = dlopen(file_name, RTLD_NOW | RTLD_LOCAL);
+ if (handle == NULL) {
+ log_error("module, failed to open '%s' (%s)", file_name, dlerror());
+ free(tmp_name);
+ return KNOT_ENOENT;
+ }
+ (void)dlerror();
+
+ knotd_mod_api_t *api = dlsym(handle, "knotd_mod_api");
+ if (api == NULL) {
+ char *err = dlerror();
+ if (err == NULL) {
+ err = "empty symbol";
+ }
+ log_error("module, invalid library '%s' (%s)", file_name, err);
+ dlclose(handle);
+ free(tmp_name);
+ return KNOT_ENOENT;
+ }
+ free(tmp_name);
+
+ if (api->version != KNOTD_MOD_ABI_VERSION) {
+ log_error("module '%s', incompatible version", api->name);
+ dlclose(handle);
+ return KNOT_ENOTSUP;
+ }
+
+ if (api->name == NULL || (mod_name != NULL && strcmp(api->name, mod_name) != 0)) {
+ log_error("module '%s', module name mismatch", api->name);
+ dlclose(handle);
+ return KNOT_ENOTSUP;
+ }
+
+ // Check if the module is already loaded.
+ module_t *found = conf_mod_find(conf, api->name, strlen(api->name), temporary);
+ if (found != NULL) {
+ log_error("module '%s', duplicate module", api->name);
+ dlclose(handle);
+ return KNOT_EEXIST;
+ }
+
+ module_t *mod = calloc(1, sizeof(*mod));
+ if (mod == NULL) {
+ dlclose(handle);
+ return KNOT_ENOMEM;
+ }
+ mod->api = api;
+ mod->lib_handle = handle;
+ mod->temporary = temporary;
+
+ int ret = mod_load(conf, mod);
+ if (ret != KNOT_EOK) {
+ log_error("module '%s', failed to load (%s)", api->name,
+ knot_strerror(ret));
+ dlclose(handle);
+ free(mod);
+ return ret;
+ }
+
+ mod_dynarray_add(&conf->modules, &mod);
+
+ log_debug("module '%s', loaded shared", api->name);
+
+ return KNOT_EOK;
+}
+
+static void unload_shared(
+ module_t *mod)
+{
+ if (mod != NULL) {
+ assert(mod->lib_handle);
+ (void)dlclose(mod->lib_handle);
+ free(mod);
+ }
+}
+
+void conf_mod_load_purge(
+ conf_t *conf,
+ bool temporary)
+{
+ if (conf == NULL) {
+ return;
+ }
+
+ // Switch the current temporary schema with the initial one.
+ if (temporary && conf->old_schemas.size > 0) {
+ yp_item_t **current_schema = &conf->schema;
+ yp_item_t **initial = &(conf->old_schemas.arr(&conf->old_schemas))[0];
+
+ yp_item_t *old_schema = rcu_xchg_pointer(current_schema, *initial);
+ synchronize_rcu();
+ *initial = old_schema;
+ }
+
+ dynarray_foreach(old_schema, yp_item_t *, schema, conf->old_schemas) {
+ yp_schema_free(*schema);
+ }
+ old_schema_dynarray_free(&conf->old_schemas);
+
+ dynarray_foreach(mod, module_t *, module, conf->modules) {
+ if ((*module) != NULL && (*module)->temporary) {
+ unload_shared((*module));
+ *module = NULL; // Cannot remove from dynarray.
+ }
+ }
+}
+
+void conf_mod_unload_shared(
+ conf_t *conf)
+{
+ if (conf == NULL) {
+ return;
+ }
+
+ dynarray_foreach(mod, module_t *, module, conf->modules) {
+ unload_shared((*module));
+ }
+ mod_dynarray_free(&conf->modules);
+}
+
+#define LOG_ARGS(mod_id, msg) "module '%s%s%.*s', " msg, \
+ mod_id->name + 1, (mod_id->len > 0) ? "/" : "", (int)mod_id->len, \
+ mod_id->data
+
+#define MOD_ID_LOG(zone, level, mod_id, msg, ...) \
+ if (zone != NULL) \
+ log_zone_##level(zone, LOG_ARGS(mod_id, msg), ##__VA_ARGS__); \
+ else \
+ log_##level(LOG_ARGS(mod_id, msg), ##__VA_ARGS__);
+
+void conf_activate_modules(
+ conf_t *conf,
+ const knot_dname_t *zone_name,
+ list_t *query_modules,
+ struct query_plan **query_plan)
+{
+ int ret = KNOT_EOK;
+
+ if (conf == NULL || query_modules == NULL || query_plan == NULL) {
+ ret = KNOT_EINVAL;
+ goto activate_error;
+ }
+
+ conf_val_t val;
+
+ // Get list of associated modules.
+ if (zone_name != NULL) {
+ val = conf_zone_get(conf, C_MODULE, zone_name);
+ } else {
+ val = conf_default_get(conf, C_GLOBAL_MODULE);
+ }
+
+ switch (val.code) {
+ case KNOT_EOK:
+ break;
+ case KNOT_ENOENT: // Check if a module is configured at all.
+ case KNOT_YP_EINVAL_ID:
+ return;
+ default:
+ ret = val.code;
+ goto activate_error;
+ }
+
+ // Create query plan.
+ *query_plan = query_plan_create();
+ if (*query_plan == NULL) {
+ ret = KNOT_ENOMEM;
+ goto activate_error;
+ }
+
+ // Initialize query modules list.
+ init_list(query_modules);
+
+ // Open the modules.
+ while (val.code == KNOT_EOK) {
+ conf_mod_id_t *mod_id = conf_mod_id(&val);
+ if (mod_id == NULL) {
+ ret = KNOT_ENOMEM;
+ goto activate_error;
+ }
+
+ // Open the module.
+ knotd_mod_t *mod = query_module_open(conf, mod_id, *query_plan,
+ zone_name);
+ if (mod == NULL) {
+ MOD_ID_LOG(zone_name, error, mod_id, "failed to open");
+ conf_free_mod_id(mod_id);
+ goto skip_module;
+ }
+
+ // Check the module scope.
+ if ((zone_name == NULL && !(mod->api->flags & KNOTD_MOD_FLAG_SCOPE_GLOBAL)) ||
+ (zone_name != NULL && !(mod->api->flags & KNOTD_MOD_FLAG_SCOPE_ZONE))) {
+ MOD_ID_LOG(zone_name, error, mod_id, "out of scope");
+ query_module_close(mod);
+ goto skip_module;
+ }
+
+ // Check if the module is loadable.
+ if (mod->api->load == NULL) {
+ MOD_ID_LOG(zone_name, debug, mod_id, "empty module, not loaded");
+ query_module_close(mod);
+ goto skip_module;
+ }
+
+ // Load the module.
+ ret = mod->api->load(mod);
+ if (ret != KNOT_EOK) {
+ MOD_ID_LOG(zone_name, error, mod_id, "failed to load (%s)",
+ knot_strerror(ret));
+ query_module_close(mod);
+ goto skip_module;
+ }
+ mod->config = NULL; // Invalidate the current config.
+
+ add_tail(query_modules, &mod->node);
+skip_module:
+ conf_val_next(&val);
+ }
+
+ return;
+activate_error:
+ CONF_LOG(LOG_ERR, "failed to activate modules (%s)", knot_strerror(ret));
+}
+
+void conf_deactivate_modules(
+ list_t *query_modules,
+ struct query_plan **query_plan)
+{
+ if (query_modules == NULL || query_plan == NULL) {
+ return;
+ }
+
+ // Free query plan.
+ query_plan_free(*query_plan);
+ *query_plan = NULL;
+
+ // Free query modules list.
+ knotd_mod_t *mod = NULL, *next = NULL;
+ WALK_LIST_DELSAFE(mod, next, *query_modules) {
+ if (mod->api->unload != NULL) {
+ mod->api->unload(mod);
+ }
+ query_module_close(mod);
+ }
+ init_list(query_modules);
+}
diff --git a/src/knot/conf/module.h b/src/knot/conf/module.h
new file mode 100644
index 0000000..2dc353a
--- /dev/null
+++ b/src/knot/conf/module.h
@@ -0,0 +1,110 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include "knot/conf/base.h"
+
+/*!
+ * Finds specific module in static or dynamic modules.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] name Module name.
+ * \param[in] len Module name length.
+ * \param[in] temporary Find only a temporary module indication.
+ *
+ * \return Module, NULL if not found.
+ */
+module_t *conf_mod_find(
+ conf_t *conf,
+ const char *name,
+ size_t len,
+ bool temporary
+);
+
+/*!
+ * Loads common static and shared modules.
+ *
+ * \param[in] conf Configuration.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int conf_mod_load_common(
+ conf_t *conf
+);
+
+/*!
+ * Loads extra shared module.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] mod_name Module name.
+ * \param[in] file_name Shared library file name.
+ * \param[in] temporary Mark module as temporary.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int conf_mod_load_extra(
+ conf_t *conf,
+ const char *mod_name,
+ const char *file_name,
+ bool temporary
+);
+
+/*!
+ * Purges temporary schemas and modules after all modules loading.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] temporary Purge only temporary modules indication.
+ */
+void conf_mod_load_purge(
+ conf_t *conf,
+ bool temporary
+);
+
+/*!
+ * Unloads all shared modules.
+ *
+ * \param[in] conf Configuration.
+ */
+void conf_mod_unload_shared(
+ conf_t *conf
+);
+
+/*!
+ * Activates configured query modules for the specified zone or for all zones.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] zone_name Zone name, NULL for all zones.
+ * \param[in] query_modules Destination query modules list.
+ * \param[in] query_plan Destination query plan.
+ */
+void conf_activate_modules(
+ conf_t *conf,
+ const knot_dname_t *zone_name,
+ list_t *query_modules,
+ struct query_plan **query_plan
+);
+
+/*!
+ * Deactivates query modules list.
+ *
+ * \param[in] query_modules Destination query modules list.
+ * \param[in] query_plan Destination query plan.
+ */
+void conf_deactivate_modules(
+ list_t *query_modules,
+ struct query_plan **query_plan
+);
diff --git a/src/knot/conf/schema.c b/src/knot/conf/schema.c
new file mode 100644
index 0000000..560f005
--- /dev/null
+++ b/src/knot/conf/schema.c
@@ -0,0 +1,344 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <limits.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "knot/conf/schema.h"
+#include "knot/conf/confio.h"
+#include "knot/conf/tools.h"
+#include "knot/common/log.h"
+#include "knot/journal/journal.h"
+#include "knot/updates/acl.h"
+#include "libknot/rrtype/opt.h"
+#include "libdnssec/tsig.h"
+#include "libdnssec/key.h"
+
+#define HOURS(x) ((x) * 3600)
+#define DAYS(x) ((x) * HOURS(24))
+
+#define KILO(x) (1024LLU * (x))
+#define MEGA(x) (KILO(1024) * (x))
+#define GIGA(x) (MEGA(1024) * (x))
+#define TERA(x) (GIGA(1024) * (x))
+
+#define VIRT_MEM_TOP_32BIT GIGA(1)
+#define VIRT_MEM_LIMIT(x) (((sizeof(void *) < 8) && ((x) > VIRT_MEM_TOP_32BIT)) \
+ ? VIRT_MEM_TOP_32BIT : (x))
+
+static const knot_lookup_t keystore_backends[] = {
+ { KEYSTORE_BACKEND_PEM, "pem" },
+ { KEYSTORE_BACKEND_PKCS11, "pkcs11" },
+ { 0, NULL }
+};
+
+static const knot_lookup_t tsig_key_algs[] = {
+ { DNSSEC_TSIG_HMAC_MD5, "hmac-md5" },
+ { DNSSEC_TSIG_HMAC_SHA1, "hmac-sha1" },
+ { DNSSEC_TSIG_HMAC_SHA224, "hmac-sha224" },
+ { DNSSEC_TSIG_HMAC_SHA256, "hmac-sha256" },
+ { DNSSEC_TSIG_HMAC_SHA384, "hmac-sha384" },
+ { DNSSEC_TSIG_HMAC_SHA512, "hmac-sha512" },
+ { 0, NULL }
+};
+
+static const knot_lookup_t dnssec_key_algs[] = {
+ { DNSSEC_KEY_ALGORITHM_RSA_SHA1, "rsasha1" },
+ { DNSSEC_KEY_ALGORITHM_RSA_SHA1_NSEC3, "rsasha1-nsec3-sha1" },
+ { DNSSEC_KEY_ALGORITHM_RSA_SHA256, "rsasha256" },
+ { DNSSEC_KEY_ALGORITHM_RSA_SHA512, "rsasha512" },
+ { DNSSEC_KEY_ALGORITHM_ECDSA_P256_SHA256, "ecdsap256sha256" },
+ { DNSSEC_KEY_ALGORITHM_ECDSA_P384_SHA384, "ecdsap384sha384" },
+ { DNSSEC_KEY_ALGORITHM_ED25519, "ed25519" },
+ /* Obsolete items. */
+ { 3, "dsa" },
+ { 6, "dsa-nsec3-sha1" },
+ { 0, NULL }
+};
+
+const knot_lookup_t child_record[] = {
+ { CHILD_RECORDS_NONE, "none" },
+ { CHILD_RECORDS_EMPTY, "delete-dnssec" },
+ { CHILD_RECORDS_ROLLOVER, "rollover" },
+ { CHILD_RECORDS_ALWAYS, "always" },
+ { 0, NULL }
+};
+
+const knot_lookup_t acl_actions[] = {
+ { ACL_ACTION_NOTIFY, "notify" },
+ { ACL_ACTION_TRANSFER, "transfer" },
+ { ACL_ACTION_UPDATE, "update" },
+ { 0, NULL }
+};
+
+static const knot_lookup_t serial_policies[] = {
+ { SERIAL_POLICY_INCREMENT, "increment" },
+ { SERIAL_POLICY_UNIXTIME, "unixtime" },
+ { SERIAL_POLICY_DATESERIAL, "dateserial" },
+ { 0, NULL }
+};
+
+static const knot_lookup_t journal_content[] = {
+ { JOURNAL_CONTENT_NONE, "none" },
+ { JOURNAL_CONTENT_CHANGES, "changes" },
+ { JOURNAL_CONTENT_ALL, "all" },
+ { 0, NULL }
+};
+
+static const knot_lookup_t zonefile_load[] = {
+ { ZONEFILE_LOAD_NONE, "none" },
+ { ZONEFILE_LOAD_DIFF, "difference" },
+ { ZONEFILE_LOAD_DIFSE, "difference-no-serial" },
+ { ZONEFILE_LOAD_WHOLE, "whole" },
+ { 0, NULL }
+};
+
+static const knot_lookup_t log_severities[] = {
+ { LOG_UPTO(LOG_CRIT), "critical" },
+ { LOG_UPTO(LOG_ERR), "error" },
+ { LOG_UPTO(LOG_WARNING), "warning" },
+ { LOG_UPTO(LOG_NOTICE), "notice" },
+ { LOG_UPTO(LOG_INFO), "info" },
+ { LOG_UPTO(LOG_DEBUG), "debug" },
+ { 0, NULL }
+};
+
+static const knot_lookup_t journal_modes[] = {
+ { JOURNAL_MODE_ROBUST, "robust" },
+ { JOURNAL_MODE_ASYNC, "asynchronous" },
+ { 0, NULL }
+};
+
+static const yp_item_t desc_module[] = {
+ { C_ID, YP_TSTR, YP_VNONE, YP_FNONE, { check_module_id } },
+ { C_FILE, YP_TSTR, YP_VNONE },
+ { C_COMMENT, YP_TSTR, YP_VNONE },
+ { NULL }
+};
+
+static const yp_item_t desc_server[] = {
+ { C_IDENT, YP_TSTR, YP_VNONE },
+ { C_VERSION, YP_TSTR, YP_VNONE },
+ { C_NSID, YP_THEX, YP_VNONE },
+ { C_RUNDIR, YP_TSTR, YP_VSTR = { RUN_DIR } },
+ { C_USER, YP_TSTR, YP_VNONE },
+ { C_PIDFILE, YP_TSTR, YP_VSTR = { "knot.pid" } },
+ { C_UDP_WORKERS, YP_TINT, YP_VINT = { 1, 255, YP_NIL } },
+ { C_TCP_WORKERS, YP_TINT, YP_VINT = { 1, 255, YP_NIL } },
+ { C_BG_WORKERS, YP_TINT, YP_VINT = { 1, 255, YP_NIL } },
+ { C_ASYNC_START, YP_TBOOL, YP_VNONE },
+ { C_TCP_HSHAKE_TIMEOUT, YP_TINT, YP_VINT = { 0, INT32_MAX, 5, YP_STIME } },
+ { C_TCP_IDLE_TIMEOUT, YP_TINT, YP_VINT = { 0, INT32_MAX, 20, YP_STIME } },
+ { C_TCP_REPLY_TIMEOUT, YP_TINT, YP_VINT = { 0, INT32_MAX, 10, YP_STIME } },
+ { C_MAX_TCP_CLIENTS, YP_TINT, YP_VINT = { 0, INT32_MAX, 100 } },
+ { C_MAX_UDP_PAYLOAD, YP_TINT, YP_VINT = { KNOT_EDNS_MIN_DNSSEC_PAYLOAD,
+ KNOT_EDNS_MAX_UDP_PAYLOAD,
+ KNOT_EDNS_MAX_UDP_PAYLOAD, YP_SSIZE } },
+ { C_MAX_IPV4_UDP_PAYLOAD, YP_TINT, YP_VINT = { KNOT_EDNS_MIN_DNSSEC_PAYLOAD,
+ KNOT_EDNS_MAX_UDP_PAYLOAD,
+ KNOT_EDNS_MAX_UDP_PAYLOAD, YP_SSIZE } },
+ { C_MAX_IPV6_UDP_PAYLOAD, YP_TINT, YP_VINT = { KNOT_EDNS_MIN_DNSSEC_PAYLOAD,
+ KNOT_EDNS_MAX_UDP_PAYLOAD,
+ KNOT_EDNS_MAX_UDP_PAYLOAD, YP_SSIZE } },
+ { C_LISTEN, YP_TADDR, YP_VADDR = { 53 }, YP_FMULTI },
+ { C_COMMENT, YP_TSTR, YP_VNONE },
+ { C_ECS, YP_TBOOL, YP_VNONE },
+ { C_ANS_ROTATION, YP_TBOOL, YP_VNONE },
+ { NULL }
+};
+
+static const yp_item_t desc_control[] = {
+ { C_LISTEN, YP_TSTR, YP_VSTR = { "knot.sock" } },
+ { C_TIMEOUT, YP_TINT, YP_VINT = { 0, INT32_MAX / 1000, 5, YP_STIME } },
+ { C_COMMENT, YP_TSTR, YP_VNONE },
+ { NULL }
+};
+
+static const yp_item_t desc_log[] = {
+ { C_TARGET, YP_TSTR, YP_VNONE },
+ { C_SERVER, YP_TOPT, YP_VOPT = { log_severities, 0 } },
+ { C_CTL, YP_TOPT, YP_VOPT = { log_severities, 0 } },
+ { C_ZONE, YP_TOPT, YP_VOPT = { log_severities, 0 } },
+ { C_ANY, YP_TOPT, YP_VOPT = { log_severities, 0 } },
+ { C_COMMENT, YP_TSTR, YP_VNONE },
+ { NULL }
+};
+
+static const yp_item_t desc_stats[] = {
+ { C_TIMER, YP_TINT, YP_VINT = { 1, UINT32_MAX, 0, YP_STIME } },
+ { C_FILE, YP_TSTR, YP_VSTR = { "stats.yaml" } },
+ { C_APPEND, YP_TBOOL, YP_VNONE },
+ { NULL }
+};
+
+static const yp_item_t desc_keystore[] = {
+ { C_ID, YP_TSTR, YP_VNONE },
+ { C_BACKEND, YP_TOPT, YP_VOPT = { keystore_backends, KEYSTORE_BACKEND_PEM },
+ CONF_IO_FRLD_ZONES },
+ { C_CONFIG, YP_TSTR, YP_VSTR = { "keys" }, CONF_IO_FRLD_ZONES },
+ { C_COMMENT, YP_TSTR, YP_VNONE },
+ { NULL }
+};
+
+static const yp_item_t desc_key[] = {
+ { C_ID, YP_TDNAME, YP_VNONE },
+ { C_ALG, YP_TOPT, YP_VOPT = { tsig_key_algs, DNSSEC_TSIG_UNKNOWN } },
+ { C_SECRET, YP_TB64, YP_VNONE },
+ { C_COMMENT, YP_TSTR, YP_VNONE },
+ { NULL }
+};
+
+static const yp_item_t desc_acl[] = {
+ { C_ID, YP_TSTR, YP_VNONE, CONF_IO_FREF },
+ { C_ADDR, YP_TNET, YP_VNONE, YP_FMULTI },
+ { C_KEY, YP_TREF, YP_VREF = { C_KEY }, YP_FMULTI, { check_ref } },
+ { C_ACTION, YP_TOPT, YP_VOPT = { acl_actions, ACL_ACTION_NONE }, YP_FMULTI },
+ { C_DENY, YP_TBOOL, YP_VNONE },
+ { C_COMMENT, YP_TSTR, YP_VNONE },
+ { NULL }
+};
+
+static const yp_item_t desc_remote[] = {
+ { C_ID, YP_TSTR, YP_VNONE, CONF_IO_FREF },
+ { C_ADDR, YP_TADDR, YP_VADDR = { 53 }, YP_FMULTI },
+ { C_VIA, YP_TADDR, YP_VNONE, YP_FMULTI },
+ { C_KEY, YP_TREF, YP_VREF = { C_KEY }, YP_FNONE, { check_ref } },
+ { C_COMMENT, YP_TSTR, YP_VNONE },
+ { NULL }
+};
+
+static const yp_item_t desc_submission[] = {
+ { C_ID, YP_TSTR, YP_VNONE },
+ { C_PARENT, YP_TREF, YP_VREF = { C_RMT }, YP_FMULTI | CONF_IO_FRLD_ZONES,
+ { check_ref } },
+ { C_CHK_INTERVAL, YP_TINT, YP_VINT = { 1, UINT32_MAX, HOURS(1), YP_STIME },
+ CONF_IO_FRLD_ZONES },
+ { C_TIMEOUT, YP_TINT, YP_VINT = { 1, UINT32_MAX, 0, YP_STIME },
+ CONF_IO_FRLD_ZONES },
+ { NULL }
+};
+
+static const yp_item_t desc_policy[] = {
+ { C_ID, YP_TSTR, YP_VNONE, CONF_IO_FREF },
+ { C_KEYSTORE, YP_TREF, YP_VREF = { C_KEYSTORE }, CONF_IO_FRLD_ZONES,
+ { check_ref_dflt } },
+ { C_MANUAL, YP_TBOOL, YP_VNONE, CONF_IO_FRLD_ZONES },
+ { C_KSK_SHARED, YP_TBOOL, YP_VNONE, CONF_IO_FRLD_ZONES },
+ { C_SINGLE_TYPE_SIGNING, YP_TBOOL, YP_VNONE, CONF_IO_FRLD_ZONES },
+ { C_ALG, YP_TOPT, YP_VOPT = { dnssec_key_algs,
+ DNSSEC_KEY_ALGORITHM_ECDSA_P256_SHA256 },
+ CONF_IO_FRLD_ZONES },
+ { C_KSK_SIZE, YP_TINT, YP_VINT = { 0, UINT16_MAX, YP_NIL, YP_SSIZE },
+ CONF_IO_FRLD_ZONES },
+ { C_ZSK_SIZE, YP_TINT, YP_VINT = { 0, UINT16_MAX, YP_NIL, YP_SSIZE },
+ CONF_IO_FRLD_ZONES },
+ { C_DNSKEY_TTL, YP_TINT, YP_VINT = { 0, UINT32_MAX, YP_NIL, YP_STIME },
+ CONF_IO_FRLD_ZONES },
+ { C_ZSK_LIFETIME, YP_TINT, YP_VINT = { 0, UINT32_MAX, DAYS(30), YP_STIME },
+ CONF_IO_FRLD_ZONES },
+ { C_KSK_LIFETIME, YP_TINT, YP_VINT = { 0, UINT32_MAX, 0, YP_STIME },
+ CONF_IO_FRLD_ZONES },
+ { C_PROPAG_DELAY, YP_TINT, YP_VINT = { 0, UINT32_MAX, HOURS(1), YP_STIME },
+ CONF_IO_FRLD_ZONES },
+ { C_RRSIG_LIFETIME, YP_TINT, YP_VINT = { 1, UINT32_MAX, DAYS(14), YP_STIME },
+ CONF_IO_FRLD_ZONES },
+ { C_RRSIG_REFRESH, YP_TINT, YP_VINT = { 1, UINT32_MAX, DAYS(7), YP_STIME },
+ CONF_IO_FRLD_ZONES },
+ { C_NSEC3, YP_TBOOL, YP_VNONE, CONF_IO_FRLD_ZONES },
+ { C_NSEC3_ITER, YP_TINT, YP_VINT = { 0, UINT16_MAX, 10 }, CONF_IO_FRLD_ZONES },
+ { C_NSEC3_OPT_OUT, YP_TBOOL, YP_VNONE, CONF_IO_FRLD_ZONES },
+ { C_NSEC3_SALT_LEN, YP_TINT, YP_VINT = { 0, UINT8_MAX, 8 }, CONF_IO_FRLD_ZONES },
+ { C_NSEC3_SALT_LIFETIME, YP_TINT, YP_VINT = { 1, UINT32_MAX, DAYS(30), YP_STIME },
+ CONF_IO_FRLD_ZONES },
+ { C_KSK_SBM, YP_TREF, YP_VREF = { C_SBM }, CONF_IO_FRLD_ZONES,
+ { check_ref } },
+ { C_CHILD_RECORDS, YP_TOPT, YP_VOPT = { child_record, CHILD_RECORDS_ALWAYS } },
+ { C_COMMENT, YP_TSTR, YP_VNONE },
+ { NULL }
+};
+
+#define ZONE_ITEMS(FLAGS) \
+ { C_STORAGE, YP_TSTR, YP_VSTR = { STORAGE_DIR }, FLAGS }, \
+ { C_FILE, YP_TSTR, YP_VNONE, FLAGS }, \
+ { C_MASTER, YP_TREF, YP_VREF = { C_RMT }, YP_FMULTI, { check_ref } }, \
+ { C_DDNS_MASTER, YP_TREF, YP_VREF = { C_RMT }, YP_FNONE, { check_ref } }, \
+ { C_NOTIFY, YP_TREF, YP_VREF = { C_RMT }, YP_FMULTI, { check_ref } }, \
+ { C_ACL, YP_TREF, YP_VREF = { C_ACL }, YP_FMULTI, { check_ref } }, \
+ { C_SEM_CHECKS, YP_TBOOL, YP_VNONE, FLAGS }, \
+ { C_DISABLE_ANY, YP_TBOOL, YP_VNONE }, \
+ { C_ZONEFILE_SYNC, YP_TINT, YP_VINT = { -1, INT32_MAX, 0, YP_STIME } }, \
+ { C_JOURNAL_CONTENT, YP_TOPT, YP_VOPT = { journal_content, JOURNAL_CONTENT_CHANGES } }, \
+ { C_ZONEFILE_LOAD, YP_TOPT, YP_VOPT = { zonefile_load, ZONEFILE_LOAD_WHOLE } }, \
+ { C_MAX_ZONE_SIZE, YP_TINT, YP_VINT = { 0, SSIZE_MAX, SSIZE_MAX, YP_SSIZE }, FLAGS }, \
+ { C_MAX_JOURNAL_USAGE, YP_TINT, YP_VINT = { KILO(40), SSIZE_MAX, MEGA(100), YP_SSIZE } }, \
+ { C_MAX_JOURNAL_DEPTH, YP_TINT, YP_VINT = { 2, SSIZE_MAX, SSIZE_MAX } }, \
+ { C_DNSSEC_SIGNING, YP_TBOOL, YP_VNONE, FLAGS }, \
+ { C_DNSSEC_POLICY, YP_TREF, YP_VREF = { C_POLICY }, FLAGS, { check_ref_dflt } }, \
+ { C_SERIAL_POLICY, YP_TOPT, YP_VOPT = { serial_policies, SERIAL_POLICY_INCREMENT } }, \
+ { C_REQUEST_EDNS_OPTION, YP_TDATA, YP_VDATA = { 0, NULL, edns_opt_to_bin, edns_opt_to_txt } }, \
+ { C_MAX_REFRESH_INTERVAL,YP_TINT, YP_VINT = { 2, UINT32_MAX, UINT32_MAX, YP_STIME } }, \
+ { C_MIN_REFRESH_INTERVAL,YP_TINT, YP_VINT = { 2, UINT32_MAX, 2, YP_STIME } }, \
+ { C_MODULE, YP_TDATA, YP_VDATA = { 0, NULL, mod_id_to_bin, mod_id_to_txt }, \
+ YP_FMULTI | FLAGS, { check_modref } }, \
+ { C_COMMENT, YP_TSTR, YP_VNONE }, \
+
+static const yp_item_t desc_template[] = {
+ { C_ID, YP_TSTR, YP_VNONE, CONF_IO_FREF },
+ ZONE_ITEMS(CONF_IO_FRLD_ZONES)
+ { C_GLOBAL_MODULE, YP_TDATA, YP_VDATA = { 0, NULL, mod_id_to_bin, mod_id_to_txt },
+ YP_FMULTI | CONF_IO_FRLD_MOD, { check_modref } },
+ { C_TIMER_DB, YP_TSTR, YP_VSTR = { "timers" }, CONF_IO_FRLD_ZONES },
+ { C_MAX_TIMER_DB_SIZE, YP_TINT, YP_VINT = { MEGA(1), VIRT_MEM_LIMIT(GIGA(100)),
+ MEGA(100), YP_SSIZE }, CONF_IO_FRLD_ZONES },
+ { C_JOURNAL_DB, YP_TSTR, YP_VSTR = { "journal" }, CONF_IO_FRLD_SRV },
+ { C_JOURNAL_DB_MODE, YP_TOPT, YP_VOPT = { journal_modes, JOURNAL_MODE_ROBUST },
+ CONF_IO_FRLD_SRV },
+ { C_MAX_JOURNAL_DB_SIZE, YP_TINT, YP_VINT = { JOURNAL_MIN_FSLIMIT, VIRT_MEM_LIMIT(TERA(100)),
+ VIRT_MEM_LIMIT(GIGA(20)), YP_SSIZE },
+ CONF_IO_FRLD_SRV },
+ { C_KASP_DB, YP_TSTR, YP_VSTR = { "keys" }, CONF_IO_FRLD_SRV },
+ { C_MAX_KASP_DB_SIZE, YP_TINT, YP_VINT = { MEGA(5), VIRT_MEM_LIMIT(GIGA(100)),
+ MEGA(500), YP_SSIZE }, CONF_IO_FRLD_SRV },
+ { NULL }
+};
+
+static const yp_item_t desc_zone[] = {
+ { C_DOMAIN, YP_TDNAME, YP_VNONE, CONF_IO_FRLD_ZONE },
+ { C_TPL, YP_TREF, YP_VREF = { C_TPL }, CONF_IO_FRLD_ZONE, { check_ref } },
+ ZONE_ITEMS(CONF_IO_FRLD_ZONE)
+ { NULL }
+};
+
+const yp_item_t conf_schema[] = {
+ { C_MODULE, YP_TGRP, YP_VGRP = { desc_module }, YP_FMULTI | CONF_IO_FRLD_ALL |
+ CONF_IO_FCHECK_ZONES, { load_module } },
+ { C_SRV, YP_TGRP, YP_VGRP = { desc_server }, CONF_IO_FRLD_SRV, { check_server } },
+ { C_CTL, YP_TGRP, YP_VGRP = { desc_control } },
+ { C_LOG, YP_TGRP, YP_VGRP = { desc_log }, YP_FMULTI | CONF_IO_FRLD_LOG },
+ { C_STATS, YP_TGRP, YP_VGRP = { desc_stats }, CONF_IO_FRLD_SRV },
+ { C_KEYSTORE, YP_TGRP, YP_VGRP = { desc_keystore }, YP_FMULTI, { check_keystore } },
+ { C_KEY, YP_TGRP, YP_VGRP = { desc_key }, YP_FMULTI, { check_key } },
+ { C_ACL, YP_TGRP, YP_VGRP = { desc_acl }, YP_FMULTI, { check_acl } },
+ { C_RMT, YP_TGRP, YP_VGRP = { desc_remote }, YP_FMULTI, { check_remote } },
+ { C_SBM, YP_TGRP, YP_VGRP = { desc_submission }, YP_FMULTI },
+ { C_POLICY, YP_TGRP, YP_VGRP = { desc_policy }, YP_FMULTI, { check_policy } },
+ { C_TPL, YP_TGRP, YP_VGRP = { desc_template }, YP_FMULTI, { check_template } },
+ { C_ZONE, YP_TGRP, YP_VGRP = { desc_zone }, YP_FMULTI | CONF_IO_FZONE, { check_zone } },
+ { C_INCL, YP_TSTR, YP_VNONE, CONF_IO_FDIFF_ZONES | CONF_IO_FRLD_ALL, { include_file } },
+ { NULL }
+};
diff --git a/src/knot/conf/schema.h b/src/knot/conf/schema.h
new file mode 100644
index 0000000..8ba6941
--- /dev/null
+++ b/src/knot/conf/schema.h
@@ -0,0 +1,154 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include "libknot/lookup.h"
+#include "libknot/yparser/ypschema.h"
+
+#define C_ACL "\x03""acl"
+#define C_ACTION "\x06""action"
+#define C_ADDR "\x07""address"
+#define C_ALG "\x09""algorithm"
+#define C_ANS_ROTATION "\x0F""answer-rotation"
+#define C_ANY "\x03""any"
+#define C_APPEND "\x06""append"
+#define C_ASYNC_START "\x0B""async-start"
+#define C_BACKEND "\x07""backend"
+#define C_BG_WORKERS "\x12""background-workers"
+#define C_CHILD_RECORDS "\x13""cds-cdnskey-publish"
+#define C_CHK_INTERVAL "\x0E""check-interval"
+#define C_COMMENT "\x07""comment"
+#define C_CONFIG "\x06""config"
+#define C_CTL "\x07""control"
+#define C_DDNS_MASTER "\x0B""ddns-master"
+#define C_DENY "\x04""deny"
+#define C_DISABLE_ANY "\x0B""disable-any"
+#define C_DNSKEY_TTL "\x0A""dnskey-ttl"
+#define C_DNSSEC_POLICY "\x0D""dnssec-policy"
+#define C_DNSSEC_SIGNING "\x0E""dnssec-signing"
+#define C_DOMAIN "\x06""domain"
+#define C_ECS "\x12""edns-client-subnet"
+#define C_FILE "\x04""file"
+#define C_GLOBAL_MODULE "\x0D""global-module"
+#define C_ID "\x02""id"
+#define C_IDENT "\x08""identity"
+#define C_INCL "\x07""include"
+#define C_JOURNAL_CONTENT "\x0F""journal-content"
+#define C_JOURNAL_DB "\x0A""journal-db"
+#define C_JOURNAL_DB_MODE "\x0F""journal-db-mode"
+#define C_KASP_DB "\x07""kasp-db"
+#define C_KEY "\x03""key"
+#define C_KEYSTORE "\x08""keystore"
+#define C_KSK_LIFETIME "\x0C""ksk-lifetime"
+#define C_KSK_SBM "\x0E""ksk-submission"
+#define C_KSK_SHARED "\x0a""ksk-shared"
+#define C_KSK_SIZE "\x08""ksk-size"
+#define C_LISTEN "\x06""listen"
+#define C_LOG "\x03""log"
+#define C_MANUAL "\x06""manual"
+#define C_MASTER "\x06""master"
+#define C_MAX_IPV4_UDP_PAYLOAD "\x14""max-ipv4-udp-payload"
+#define C_MAX_IPV6_UDP_PAYLOAD "\x14""max-ipv6-udp-payload"
+#define C_MAX_JOURNAL_DB_SIZE "\x13""max-journal-db-size"
+#define C_MAX_JOURNAL_DEPTH "\x11""max-journal-depth"
+#define C_MAX_JOURNAL_USAGE "\x11""max-journal-usage"
+#define C_MAX_KASP_DB_SIZE "\x10""max-kasp-db-size"
+#define C_MAX_REFRESH_INTERVAL "\x14""max-refresh-interval"
+#define C_MAX_TCP_CLIENTS "\x0F""max-tcp-clients"
+#define C_MAX_TIMER_DB_SIZE "\x11""max-timer-db-size"
+#define C_MAX_UDP_PAYLOAD "\x0F""max-udp-payload"
+#define C_MAX_ZONE_SIZE "\x0D""max-zone-size"
+#define C_MIN_REFRESH_INTERVAL "\x14""min-refresh-interval"
+#define C_MODULE "\x06""module"
+#define C_NOTIFY "\x06""notify"
+#define C_NSEC3 "\x05""nsec3"
+#define C_NSEC3_ITER "\x10""nsec3-iterations"
+#define C_NSEC3_OPT_OUT "\x0D""nsec3-opt-out"
+#define C_NSEC3_SALT_LEN "\x11""nsec3-salt-length"
+#define C_NSEC3_SALT_LIFETIME "\x13""nsec3-salt-lifetime"
+#define C_NSID "\x04""nsid"
+#define C_PARENT "\x06""parent"
+#define C_PIDFILE "\x07""pidfile"
+#define C_POLICY "\x06""policy"
+#define C_PROPAG_DELAY "\x11""propagation-delay"
+#define C_REQUEST_EDNS_OPTION "\x13""request-edns-option"
+#define C_RMT "\x06""remote"
+#define C_RRSIG_LIFETIME "\x0E""rrsig-lifetime"
+#define C_RRSIG_REFRESH "\x0D""rrsig-refresh"
+#define C_RUNDIR "\x06""rundir"
+#define C_SBM "\x0A""submission"
+#define C_SECRET "\x06""secret"
+#define C_SEM_CHECKS "\x0F""semantic-checks"
+#define C_SERIAL_POLICY "\x0D""serial-policy"
+#define C_SERVER "\x06""server"
+#define C_SINGLE_TYPE_SIGNING "\x13""single-type-signing"
+#define C_SRV "\x06""server"
+#define C_STATS "\x0A""statistics"
+#define C_STORAGE "\x07""storage"
+#define C_TARGET "\x06""target"
+#define C_TCP_HSHAKE_TIMEOUT "\x15""tcp-handshake-timeout"
+#define C_TCP_IDLE_TIMEOUT "\x10""tcp-idle-timeout"
+#define C_TCP_REPLY_TIMEOUT "\x11""tcp-reply-timeout"
+#define C_TCP_WORKERS "\x0B""tcp-workers"
+#define C_TIMEOUT "\x07""timeout"
+#define C_TIMER "\x05""timer"
+#define C_TIMER_DB "\x08""timer-db"
+#define C_TPL "\x08""template"
+#define C_UDP_WORKERS "\x0B""udp-workers"
+#define C_USER "\x04""user"
+#define C_VERSION "\x07""version"
+#define C_VIA "\x03""via"
+#define C_ZONE "\x04""zone"
+#define C_ZONEFILE_LOAD "\x0D""zonefile-load"
+#define C_ZONEFILE_SYNC "\x0D""zonefile-sync"
+#define C_ZSK_LIFETIME "\x0C""zsk-lifetime"
+#define C_ZSK_SIZE "\x08""zsk-size"
+
+enum {
+ KEYSTORE_BACKEND_PEM = 1,
+ KEYSTORE_BACKEND_PKCS11 = 2,
+};
+
+enum {
+ CHILD_RECORDS_NONE = 0,
+ CHILD_RECORDS_EMPTY = 1,
+ CHILD_RECORDS_ROLLOVER = 2,
+ CHILD_RECORDS_ALWAYS = 3,
+};
+
+enum {
+ SERIAL_POLICY_INCREMENT = 1,
+ SERIAL_POLICY_UNIXTIME = 2,
+ SERIAL_POLICY_DATESERIAL = 3,
+};
+
+enum {
+ JOURNAL_CONTENT_NONE = 0,
+ JOURNAL_CONTENT_CHANGES = 1,
+ JOURNAL_CONTENT_ALL = 2,
+};
+
+enum {
+ ZONEFILE_LOAD_NONE = 0,
+ ZONEFILE_LOAD_DIFF = 1,
+ ZONEFILE_LOAD_WHOLE = 2,
+ ZONEFILE_LOAD_DIFSE = 3,
+};
+
+extern const knot_lookup_t acl_actions[];
+
+extern const yp_item_t conf_schema[];
diff --git a/src/knot/conf/tools.c b/src/knot/conf/tools.c
new file mode 100644
index 0000000..3ab365e
--- /dev/null
+++ b/src/knot/conf/tools.c
@@ -0,0 +1,551 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <glob.h>
+#include <inttypes.h>
+#include <libgen.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "libdnssec/key.h"
+#include "knot/conf/tools.h"
+#include "knot/conf/conf.h"
+#include "knot/conf/module.h"
+#include "knot/conf/schema.h"
+#include "knot/common/log.h"
+#include "libknot/errcode.h"
+#include "libknot/yparser/yptrafo.h"
+#include "contrib/string.h"
+#include "contrib/wire_ctx.h"
+
+#define MAX_INCLUDE_DEPTH 5
+
+static bool is_default_id(
+ const uint8_t *id,
+ size_t id_len)
+{
+ return id_len == CONF_DEFAULT_ID[0] &&
+ memcmp(id, CONF_DEFAULT_ID + 1, id_len) == 0;
+}
+
+int conf_exec_callbacks(
+ knotd_conf_check_args_t *args)
+{
+ if (args == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ for (size_t i = 0; i < YP_MAX_MISC_COUNT; i++) {
+ int (*fcn)(knotd_conf_check_args_t *) = args->item->misc[i];
+ if (fcn == NULL) {
+ break;
+ }
+
+ int ret = fcn(args);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+int mod_id_to_bin(
+ YP_TXT_BIN_PARAMS)
+{
+ YP_CHECK_PARAMS_BIN;
+
+ // Check for "mod_name/mod_id" format.
+ const uint8_t *pos = (uint8_t *)strchr((char *)in->position, '/');
+ if (pos == in->position) {
+ // Missing module name.
+ return KNOT_EINVAL;
+ } else if (pos >= stop - 1) {
+ // Missing module identifier after slash.
+ return KNOT_EINVAL;
+ }
+
+ // Write mod_name in the yp_name_t format.
+ uint8_t name_len = (pos != NULL) ? (pos - in->position) :
+ wire_ctx_available(in);
+ wire_ctx_write_u8(out, name_len);
+ wire_ctx_write(out, in->position, name_len);
+ wire_ctx_skip(in, name_len);
+
+ // Check for mod_id.
+ if (pos != NULL) {
+ // Skip the separator.
+ wire_ctx_skip(in, sizeof(uint8_t));
+
+ // Write mod_id as a zero terminated string.
+ int ret = yp_str_to_bin(in, out, stop);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ YP_CHECK_RET;
+}
+
+int mod_id_to_txt(
+ YP_BIN_TXT_PARAMS)
+{
+ YP_CHECK_PARAMS_TXT;
+
+ // Write mod_name.
+ uint8_t name_len = wire_ctx_read_u8(in);
+ wire_ctx_write(out, in->position, name_len);
+ wire_ctx_skip(in, name_len);
+
+ // Check for mod_id.
+ if (wire_ctx_available(in) > 0) {
+ // Write the separator.
+ wire_ctx_write_u8(out, '/');
+
+ // Write mod_id.
+ int ret = yp_str_to_txt(in, out);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ YP_CHECK_RET;
+}
+
+int edns_opt_to_bin(
+ YP_TXT_BIN_PARAMS)
+{
+ YP_CHECK_PARAMS_BIN;
+
+ // Check for "code:[value]" format.
+ const uint8_t *pos = (uint8_t *)strchr((char *)in->position, ':');
+ if (pos == NULL || pos >= stop) {
+ return KNOT_EINVAL;
+ }
+
+ // Write option code.
+ int ret = yp_int_to_bin(in, out, pos, 0, UINT16_MAX, YP_SNONE);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Skip the separator.
+ wire_ctx_skip(in, sizeof(uint8_t));
+
+ // Write option data.
+ ret = yp_hex_to_bin(in, out, stop);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ YP_CHECK_RET;
+}
+
+int edns_opt_to_txt(
+ YP_BIN_TXT_PARAMS)
+{
+ YP_CHECK_PARAMS_TXT;
+
+ // Write option code.
+ int ret = yp_int_to_txt(in, out, YP_SNONE);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Write the separator.
+ wire_ctx_write_u8(out, ':');
+
+ // Write option data.
+ ret = yp_hex_to_txt(in, out);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ YP_CHECK_RET;
+}
+
+int check_ref(
+ knotd_conf_check_args_t *args)
+{
+ const yp_item_t *ref = args->item->var.r.ref;
+
+ // Try to find a referenced block with the id.
+ if (!conf_rawid_exists_txn(args->extra->conf, args->extra->txn, ref->name,
+ args->data, args->data_len)) {
+ args->err_str = "invalid reference";
+ return KNOT_ENOENT;
+ }
+
+ return KNOT_EOK;
+}
+
+int check_ref_dflt(
+ knotd_conf_check_args_t *args)
+{
+ if (check_ref(args) != KNOT_EOK && !is_default_id(args->data, args->data_len)) {
+ args->err_str = "invalid reference";
+ return KNOT_ENOENT;
+ }
+
+ return KNOT_EOK;
+}
+
+int check_modref(
+ knotd_conf_check_args_t *args)
+{
+ const yp_name_t *mod_name = (const yp_name_t *)args->data;
+ const uint8_t *id = args->data + 1 + args->data[0];
+ size_t id_len = args->data_len - 1 - args->data[0];
+
+ // Check if the module is ever available.
+ const module_t *mod = conf_mod_find(args->extra->conf, mod_name + 1,
+ mod_name[0], args->extra->check);
+ if (mod == NULL) {
+ args->err_str = "unknown module";
+ return KNOT_EINVAL;
+ }
+
+ // Check if the module requires some configuration.
+ if (id_len == 0) {
+ if (mod->api->flags & KNOTD_MOD_FLAG_OPT_CONF) {
+ return KNOT_EOK;
+ } else {
+ args->err_str = "missing module configuration";
+ return KNOT_YP_ENOID;
+ }
+ }
+
+ // Try to find a module with the id.
+ if (!conf_rawid_exists_txn(args->extra->conf, args->extra->txn, mod_name,
+ id, id_len)) {
+ args->err_str = "invalid module reference";
+ return KNOT_ENOENT;
+ }
+
+ return KNOT_EOK;
+}
+
+int check_module_id(
+ knotd_conf_check_args_t *args)
+{
+ const size_t len = strlen(KNOTD_MOD_NAME_PREFIX);
+
+ if (strncmp((const char *)args->id, KNOTD_MOD_NAME_PREFIX, len) != 0) {
+ args->err_str = "required 'mod-' prefix";
+ return KNOT_EINVAL;
+ }
+
+ return KNOT_EOK;
+}
+
+int check_server(
+ knotd_conf_check_args_t *args)
+{
+ return KNOT_EOK;
+}
+
+int check_keystore(
+ knotd_conf_check_args_t *args)
+{
+ conf_val_t backend = conf_rawid_get_txn(args->extra->conf, args->extra->txn, C_KEYSTORE,
+ C_BACKEND, args->id, args->id_len);
+ conf_val_t config = conf_rawid_get_txn(args->extra->conf, args->extra->txn, C_KEYSTORE,
+ C_CONFIG, args->id, args->id_len);
+
+ if (conf_opt(&backend) == KEYSTORE_BACKEND_PKCS11 && conf_str(&config) == NULL) {
+ args->err_str = "no PKCS #11 configuration defined";
+ return KNOT_EINVAL;
+ }
+
+ return KNOT_EOK;
+}
+
+int check_policy(
+ knotd_conf_check_args_t *args)
+{
+ conf_val_t alg = conf_rawid_get_txn(args->extra->conf, args->extra->txn, C_POLICY,
+ C_ALG, args->id, args->id_len);
+ conf_val_t ksk = conf_rawid_get_txn(args->extra->conf, args->extra->txn, C_POLICY,
+ C_KSK_SIZE, args->id, args->id_len);
+ conf_val_t zsk = conf_rawid_get_txn(args->extra->conf, args->extra->txn, C_POLICY,
+ C_ZSK_SIZE, args->id, args->id_len);
+ conf_val_t lifetime = conf_rawid_get_txn(args->extra->conf, args->extra->txn, C_POLICY,
+ C_RRSIG_LIFETIME, args->id, args->id_len);
+ conf_val_t refresh = conf_rawid_get_txn(args->extra->conf, args->extra->txn, C_POLICY,
+ C_RRSIG_REFRESH, args->id, args->id_len);
+
+ conf_val_t prop_del = conf_rawid_get_txn(args->extra->conf, args->extra->txn, C_POLICY,
+ C_PROPAG_DELAY, args->id, args->id_len);
+ conf_val_t zsk_life = conf_rawid_get_txn(args->extra->conf, args->extra->txn, C_POLICY,
+ C_ZSK_LIFETIME, args->id, args->id_len);
+ conf_val_t ksk_life = conf_rawid_get_txn(args->extra->conf, args->extra->txn, C_POLICY,
+ C_KSK_LIFETIME, args->id, args->id_len);
+ conf_val_t dnskey_ttl = conf_rawid_get_txn(args->extra->conf, args->extra->txn, C_POLICY,
+ C_DNSKEY_TTL, args->id, args->id_len);
+
+ unsigned algorithm = conf_opt(&alg);
+ if (algorithm == 3 || algorithm == 6) {
+ args->err_str = "DSA algorithm no longer supported";
+ return KNOT_EINVAL;
+ }
+
+ int64_t ksk_size = conf_int(&ksk);
+ if (ksk_size != YP_NIL && !dnssec_algorithm_key_size_check(algorithm, ksk_size)) {
+ args->err_str = "KSK key size not compatible with the algorithm";
+ return KNOT_EINVAL;
+ }
+
+ int64_t zsk_size = conf_int(&zsk);
+ if (zsk_size != YP_NIL && !dnssec_algorithm_key_size_check(algorithm, zsk_size)) {
+ args->err_str = "ZSK key size not compatible with the algorithm";
+ return KNOT_EINVAL;
+ }
+
+ int64_t lifetime_val = conf_int(&lifetime);
+ int64_t refresh_val = conf_int(&refresh);
+ if (lifetime_val <= refresh_val) {
+ args->err_str = "RRSIG refresh has to be lower than RRSIG lifetime";
+ return KNOT_EINVAL;
+ }
+
+ int64_t prop_del_val = conf_int(&prop_del);
+ int64_t zsk_life_val = conf_int(&zsk_life);
+ int64_t ksk_life_val = conf_int(&ksk_life);
+ int64_t dnskey_ttl_val = conf_int(&dnskey_ttl);
+ if (dnskey_ttl_val == YP_NIL) {
+ dnskey_ttl_val = 0;
+ }
+
+ if (zsk_life_val != 0 && zsk_life_val < 2 * prop_del_val + dnskey_ttl_val) {
+ args->err_str = "ZSK lifetime too low according to propagation delay and DNSKEY TTL";
+ return KNOT_EINVAL;
+ }
+ if (ksk_life_val != 0 && ksk_life_val < 2 * prop_del_val + 2 * dnskey_ttl_val) {
+ args->err_str = "KSK lifetime too low according to propagation delay and DNSKEY TTL";
+ return KNOT_EINVAL;
+ }
+
+ return KNOT_EOK;
+}
+
+int check_key(
+ knotd_conf_check_args_t *args)
+{
+ conf_val_t alg = conf_rawid_get_txn(args->extra->conf, args->extra->txn, C_KEY,
+ C_ALG, args->id, args->id_len);
+ if (conf_val_count(&alg) == 0) {
+ args->err_str = "no key algorithm defined";
+ return KNOT_EINVAL;
+ }
+
+ conf_val_t secret = conf_rawid_get_txn(args->extra->conf, args->extra->txn, C_KEY,
+ C_SECRET, args->id, args->id_len);
+ if (conf_val_count(&secret) == 0) {
+ args->err_str = "no key secret defined";
+ return KNOT_EINVAL;
+ }
+
+ return KNOT_EOK;
+}
+
+int check_acl(
+ knotd_conf_check_args_t *args)
+{
+ conf_val_t action = conf_rawid_get_txn(args->extra->conf, args->extra->txn, C_ACL,
+ C_ACTION, args->id, args->id_len);
+ conf_val_t deny = conf_rawid_get_txn(args->extra->conf, args->extra->txn, C_ACL,
+ C_DENY, args->id, args->id_len);
+ if (conf_val_count(&action) == 0 && conf_val_count(&deny) == 0) {
+ args->err_str = "no ACL action defined";
+ return KNOT_EINVAL;
+ }
+
+ return KNOT_EOK;
+}
+
+int check_remote(
+ knotd_conf_check_args_t *args)
+{
+ conf_val_t addr = conf_rawid_get_txn(args->extra->conf, args->extra->txn, C_RMT,
+ C_ADDR, args->id, args->id_len);
+ if (conf_val_count(&addr) == 0) {
+ args->err_str = "no remote address defined";
+ return KNOT_EINVAL;
+ }
+
+ return KNOT_EOK;
+}
+
+int check_template(
+ knotd_conf_check_args_t *args)
+{
+ // Stop if the default template.
+ if (is_default_id(args->id, args->id_len)) {
+ return KNOT_EOK;
+ }
+
+ conf_val_t val;
+ #define CHECK_DFLT(item, name) \
+ val = conf_rawid_get_txn(args->extra->conf, args->extra->txn, C_TPL, \
+ item, args->id, args->id_len); \
+ if (val.code == KNOT_EOK) { \
+ args->err_str = name " in non-default template"; \
+ return KNOT_EINVAL; \
+ }
+
+ CHECK_DFLT(C_GLOBAL_MODULE, "global module");
+ CHECK_DFLT(C_TIMER_DB, "timer database path");
+ CHECK_DFLT(C_MAX_TIMER_DB_SIZE, "timer database maximum size");
+ CHECK_DFLT(C_JOURNAL_DB, "journal database path");
+ CHECK_DFLT(C_JOURNAL_DB_MODE, "journal database mode");
+ CHECK_DFLT(C_MAX_JOURNAL_DB_SIZE, "journal database maximum size");
+ CHECK_DFLT(C_KASP_DB, "KASP database path");
+ CHECK_DFLT(C_MAX_KASP_DB_SIZE, "KASP database maximum size");
+
+ return KNOT_EOK;
+}
+
+int check_zone(
+ knotd_conf_check_args_t *args)
+{
+ return KNOT_EOK;
+}
+
+static int glob_error(
+ const char *epath,
+ int eerrno)
+{
+ CONF_LOG(LOG_WARNING, "failed to access '%s' (%s)", epath,
+ knot_strerror(knot_map_errno_code(eerrno)));
+
+ return 0;
+}
+
+int include_file(
+ knotd_conf_check_args_t *args)
+{
+ if (args->data_len == 0) {
+ return KNOT_YP_ENODATA;
+ }
+
+ // This function should not be called in more threads.
+ static int depth = 0;
+ glob_t glob_buf = { 0 };
+ char *path = NULL;
+ int ret;
+
+ // Check for include loop.
+ if (depth++ > MAX_INCLUDE_DEPTH) {
+ CONF_LOG(LOG_ERR, "include loop detected");
+ ret = KNOT_EPARSEFAIL;
+ goto include_error;
+ }
+
+ // Prepare absolute include path.
+ if (args->data[0] == '/') {
+ path = sprintf_alloc("%.*s", (int)args->data_len, args->data);
+ } else {
+ const char *file_name = args->extra->file_name != NULL ?
+ args->extra->file_name : "./";
+ char *full_current_name = realpath(file_name, NULL);
+ if (full_current_name == NULL) {
+ ret = KNOT_ENOMEM;
+ goto include_error;
+ }
+
+ path = sprintf_alloc("%s/%.*s", dirname(full_current_name),
+ (int)args->data_len, args->data);
+ free(full_current_name);
+ }
+ if (path == NULL) {
+ ret = KNOT_ESPACE;
+ goto include_error;
+ }
+
+ // Evaluate include pattern (empty wildcard match is also valid).
+ ret = glob(path, 0, glob_error, &glob_buf);
+ if (ret != 0 && (ret != GLOB_NOMATCH || strchr(path, '*') == NULL)) {
+ ret = KNOT_EFILE;
+ goto include_error;
+ }
+
+ // Process glob result.
+ for (size_t i = 0; i < glob_buf.gl_pathc; i++) {
+ // Get file status.
+ struct stat file_stat;
+ if (stat(glob_buf.gl_pathv[i], &file_stat) != 0) {
+ CONF_LOG(LOG_WARNING, "failed to get file status for '%s'",
+ glob_buf.gl_pathv[i]);
+ continue;
+ }
+
+ // Ignore directory or non-regular file.
+ if (S_ISDIR(file_stat.st_mode)) {
+ continue;
+ } else if (!S_ISREG(file_stat.st_mode)) {
+ CONF_LOG(LOG_WARNING, "invalid include file '%s'",
+ glob_buf.gl_pathv[i]);
+ continue;
+ }
+
+ // Include regular file.
+ ret = conf_parse(args->extra->conf, args->extra->txn,
+ glob_buf.gl_pathv[i], true);
+ if (ret != KNOT_EOK) {
+ goto include_error;
+ }
+ }
+
+ ret = KNOT_EOK;
+include_error:
+ globfree(&glob_buf);
+ free(path);
+ depth--;
+
+ return ret;
+}
+
+int load_module(
+ knotd_conf_check_args_t *args)
+{
+ conf_val_t val = conf_rawid_get_txn(args->extra->conf, args->extra->txn,
+ C_MODULE, C_FILE, args->id, args->id_len);
+ const char *file_name = conf_str(&val);
+
+ char *mod_name = strndup((const char *)args->id, args->id_len);
+ if (mod_name == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ int ret = conf_mod_load_extra(args->extra->conf, mod_name, file_name,
+ args->extra->check);
+ free(mod_name);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Update currently iterating item.
+ const yp_item_t *section = yp_schema_find(C_MODULE, NULL, args->extra->conf->schema);
+ assert(section);
+ args->item = section->var.g.id;
+
+ return ret;
+}
diff --git a/src/knot/conf/tools.h b/src/knot/conf/tools.h
new file mode 100644
index 0000000..5283c0f
--- /dev/null
+++ b/src/knot/conf/tools.h
@@ -0,0 +1,107 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "knot/conf/conf.h"
+#include "libknot/yparser/ypschema.h"
+
+typedef struct knotd_conf_check_extra {
+ conf_t *conf;
+ knot_db_txn_t *txn;
+ const char *file_name;
+ size_t line;
+ bool check; /*!< Indication of the confio check mode. */
+} knotd_conf_check_extra_t;
+
+int conf_exec_callbacks(
+ knotd_conf_check_args_t *args
+);
+
+int mod_id_to_bin(
+ YP_TXT_BIN_PARAMS
+);
+
+int mod_id_to_txt(
+ YP_BIN_TXT_PARAMS
+);
+
+int edns_opt_to_bin(
+ YP_TXT_BIN_PARAMS
+);
+
+int edns_opt_to_txt(
+ YP_BIN_TXT_PARAMS
+);
+
+int check_ref(
+ knotd_conf_check_args_t *args
+);
+
+int check_ref_dflt(
+ knotd_conf_check_args_t *args
+);
+
+int check_modref(
+ knotd_conf_check_args_t *args
+);
+
+int check_module_id(
+ knotd_conf_check_args_t *args
+);
+
+int check_server(
+ knotd_conf_check_args_t *args
+);
+
+int check_keystore(
+ knotd_conf_check_args_t *args
+);
+
+int check_policy(
+ knotd_conf_check_args_t *args
+);
+
+int check_key(
+ knotd_conf_check_args_t *args
+);
+
+int check_acl(
+ knotd_conf_check_args_t *args
+);
+
+int check_remote(
+ knotd_conf_check_args_t *args
+);
+
+int check_template(
+ knotd_conf_check_args_t *args
+);
+
+int check_zone(
+ knotd_conf_check_args_t *args
+);
+
+int include_file(
+ knotd_conf_check_args_t *args
+);
+
+int load_module(
+ knotd_conf_check_args_t *args
+);
diff --git a/src/knot/ctl/commands.c b/src/knot/ctl/commands.c
new file mode 100644
index 0000000..7d5ad02
--- /dev/null
+++ b/src/knot/ctl/commands.c
@@ -0,0 +1,1841 @@
+/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#include "knot/common/log.h"
+#include "knot/common/stats.h"
+#include "knot/conf/confio.h"
+#include "knot/ctl/commands.h"
+#include "knot/dnssec/key-events.h"
+#include "knot/events/events.h"
+#include "knot/events/handlers.h"
+#include "knot/nameserver/query_module.h"
+#include "knot/updates/zone-update.h"
+#include "knot/zone/timers.h"
+#include "knot/zone/zonefile.h"
+#include "libknot/libknot.h"
+#include "libknot/yparser/yptrafo.h"
+#include "contrib/macros.h"
+#include "contrib/mempattern.h"
+#include "contrib/string.h"
+#include "contrib/ucw/lists.h"
+#include "libzscanner/scanner.h"
+#include "contrib/strtonum.h"
+
+#define MATCH_OR_FILTER(args, code) ((args)->data[KNOT_CTL_IDX_FILTER] == NULL || \
+ strchr((args)->data[KNOT_CTL_IDX_FILTER], (code)) != NULL)
+
+#define MATCH_AND_FILTER(args, code) ((args)->data[KNOT_CTL_IDX_FILTER] != NULL && \
+ strchr((args)->data[KNOT_CTL_IDX_FILTER], (code)) != NULL)
+
+void ctl_log_data(knot_ctl_data_t *data)
+{
+ if (data == NULL) {
+ return;
+ }
+
+ const char *zone = (*data)[KNOT_CTL_IDX_ZONE];
+ const char *section = (*data)[KNOT_CTL_IDX_SECTION];
+ const char *item = (*data)[KNOT_CTL_IDX_ITEM];
+ const char *id = (*data)[KNOT_CTL_IDX_ID];
+
+ if (section == NULL) {
+ return;
+ }
+
+ if (zone != NULL) {
+ log_ctl_zone_str_debug(zone,
+ "control, item '%s%s%s%s%s%s'", section,
+ (id != NULL ? "[" : ""),
+ (id != NULL ? id : ""),
+ (id != NULL ? "]" : ""),
+ (item != NULL ? "." : ""),
+ (item != NULL ? item : ""));
+ } else {
+ log_ctl_debug("control, item '%s%s%s%s%s%s'", section,
+ (id != NULL ? "[" : ""),
+ (id != NULL ? id : ""),
+ (id != NULL ? "]" : ""),
+ (item != NULL ? "." : ""),
+ (item != NULL ? item : ""));
+ }
+}
+
+static void send_error(ctl_args_t *args, const char *msg)
+{
+ knot_ctl_data_t data;
+ memcpy(&data, args->data, sizeof(data));
+
+ data[KNOT_CTL_IDX_ERROR] = msg;
+
+ int ret = knot_ctl_send(args->ctl, KNOT_CTL_TYPE_DATA, &data);
+ if (ret != KNOT_EOK) {
+ log_ctl_debug("control, failed to send error (%s)", knot_strerror(ret));
+ }
+}
+
+static int get_zone(ctl_args_t *args, zone_t **zone)
+{
+ const char *name = args->data[KNOT_CTL_IDX_ZONE];
+ assert(name != NULL);
+
+ uint8_t buff[KNOT_DNAME_MAXLEN];
+
+ knot_dname_t *dname = knot_dname_from_str(buff, name, sizeof(buff));
+ if (dname == NULL) {
+ return KNOT_EINVAL;
+ }
+ knot_dname_to_lower(dname);
+
+ *zone = knot_zonedb_find(args->server->zone_db, dname);
+ if (*zone == NULL) {
+ return KNOT_ENOZONE;
+ }
+
+ return KNOT_EOK;
+}
+
+static int zones_apply(ctl_args_t *args, int (*fcn)(zone_t *, ctl_args_t *))
+{
+ // Process all configured zones if none is specified.
+ if (args->data[KNOT_CTL_IDX_ZONE] == NULL) {
+ knot_zonedb_foreach(args->server->zone_db, fcn, args);
+ return KNOT_EOK;
+ }
+
+ int ret = KNOT_EOK;
+
+ while (true) {
+ zone_t *zone;
+ ret = get_zone(args, &zone);
+ if (ret == KNOT_EOK) {
+ ret = fcn(zone, args);
+ }
+ if (ret != KNOT_EOK) {
+ log_ctl_zone_str_error(args->data[KNOT_CTL_IDX_ZONE],
+ "control, error (%s)", knot_strerror(ret));
+ send_error(args, knot_strerror(ret));
+ }
+
+ // Get next zone name.
+ ret = knot_ctl_receive(args->ctl, &args->type, &args->data);
+ if (ret != KNOT_EOK || args->type != KNOT_CTL_TYPE_DATA) {
+ break;
+ }
+ ctl_log_data(&args->data);
+ }
+
+ return ret;
+}
+
+static int zone_status(zone_t *zone, ctl_args_t *args)
+{
+ char name[KNOT_DNAME_TXT_MAXLEN + 1];
+ if (knot_dname_to_str(name, zone->name, sizeof(name)) == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ knot_ctl_data_t data = {
+ [KNOT_CTL_IDX_ZONE] = name
+ };
+
+ int ret;
+ char buff[128];
+ knot_ctl_type_t type = KNOT_CTL_TYPE_DATA;
+
+ if (MATCH_OR_FILTER(args, CTL_FILTER_STATUS_ROLE)) {
+ data[KNOT_CTL_IDX_TYPE] = "role";
+
+ if (zone_is_slave(conf(), zone)) {
+ data[KNOT_CTL_IDX_DATA] = "slave";
+ } else {
+ data[KNOT_CTL_IDX_DATA] = "master";
+ }
+
+ ret = knot_ctl_send(args->ctl, type, &data);
+ if (ret != KNOT_EOK) {
+ return ret;
+ } else {
+ type = KNOT_CTL_TYPE_EXTRA;
+ }
+ }
+
+ if (MATCH_OR_FILTER(args, CTL_FILTER_STATUS_SERIAL)) {
+ data[KNOT_CTL_IDX_TYPE] = "serial";
+
+ if (zone->contents != NULL) {
+ knot_rdataset_t *soa = node_rdataset(zone->contents->apex,
+ KNOT_RRTYPE_SOA);
+ ret = snprintf(buff, sizeof(buff), "%u", knot_soa_serial(soa->rdata));
+ } else {
+ ret = snprintf(buff, sizeof(buff), "none");
+ }
+ if (ret < 0 || ret >= sizeof(buff)) {
+ return KNOT_ESPACE;
+ }
+
+ data[KNOT_CTL_IDX_DATA] = buff;
+
+ ret = knot_ctl_send(args->ctl, type, &data);
+ if (ret != KNOT_EOK) {
+ return ret;
+ } else {
+ type = KNOT_CTL_TYPE_EXTRA;
+ }
+ }
+
+ if (MATCH_OR_FILTER(args, CTL_FILTER_STATUS_TRANSACTION)) {
+ data[KNOT_CTL_IDX_TYPE] = "transaction";
+ data[KNOT_CTL_IDX_DATA] = (zone->control_update != NULL) ? "open" : "none";
+ ret = knot_ctl_send(args->ctl, type, &data);
+ if (ret != KNOT_EOK) {
+ return ret;
+ } else {
+ type = KNOT_CTL_TYPE_EXTRA;
+ }
+ }
+
+ bool ufrozen = zone->events.ufrozen;
+ if (MATCH_OR_FILTER(args, CTL_FILTER_STATUS_FREEZE)) {
+ data[KNOT_CTL_IDX_TYPE] = "freeze";
+ if (ufrozen) {
+ if (zone_events_get_time(zone, ZONE_EVENT_UTHAW) < time(NULL)) {
+ data[KNOT_CTL_IDX_DATA] = "yes";
+ } else {
+ data[KNOT_CTL_IDX_DATA] = "thawing";
+ }
+ } else {
+ if (zone_events_get_time(zone, ZONE_EVENT_UFREEZE) < time(NULL)) {
+ data[KNOT_CTL_IDX_DATA] = "no";
+ } else {
+ data[KNOT_CTL_IDX_DATA] = "freezing";
+
+ }
+ }
+ ret = knot_ctl_send(args->ctl, type, &data);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ if (MATCH_OR_FILTER(args, CTL_FILTER_STATUS_EVENTS)) {
+ for (zone_event_type_t i = 0; i < ZONE_EVENT_COUNT; i++) {
+ // Events not worth showing or used elsewhere.
+ if (i == ZONE_EVENT_UFREEZE || i == ZONE_EVENT_UTHAW) {
+ continue;
+ }
+
+ // Skip events affected by freeze.
+ if (ufrozen && ufreeze_applies(i)) {
+ continue;
+ }
+
+ data[KNOT_CTL_IDX_TYPE] = zone_events_get_name(i);
+ time_t ev_time = zone_events_get_time(zone, i);
+ if (ev_time <= 0) {
+ ret = snprintf(buff, sizeof(buff), "not scheduled");
+ } else if (ev_time <= time(NULL)) {
+ ret = snprintf(buff, sizeof(buff), "pending");
+ } else {
+ ret = knot_time_print(TIME_PRINT_HUMAN_MIXED,
+ ev_time, buff, sizeof(buff));
+ }
+ if (ret < 0 || ret >= sizeof(buff)) {
+ return KNOT_ESPACE;
+ }
+ data[KNOT_CTL_IDX_DATA] = buff;
+
+ ret = knot_ctl_send(args->ctl, type, &data);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ type = KNOT_CTL_TYPE_EXTRA;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+static int zone_reload(zone_t *zone, ctl_args_t *args)
+{
+ UNUSED(args);
+
+ if (zone_expired(zone)) {
+ return KNOT_ENOTSUP;
+ }
+
+ zone_events_schedule_user(zone, ZONE_EVENT_LOAD);
+
+ return KNOT_EOK;
+}
+
+static int zone_refresh(zone_t *zone, ctl_args_t *args)
+{
+ UNUSED(args);
+
+ if (!zone_is_slave(conf(), zone)) {
+ return KNOT_ENOTSUP;
+ }
+
+ zone_events_schedule_user(zone, ZONE_EVENT_REFRESH);
+
+ return KNOT_EOK;
+}
+
+static int zone_retransfer(zone_t *zone, ctl_args_t *args)
+{
+ UNUSED(args);
+
+ if (!zone_is_slave(conf(), zone)) {
+ return KNOT_ENOTSUP;
+ }
+
+ zone->flags |= ZONE_FORCE_AXFR;
+ zone_events_schedule_user(zone, ZONE_EVENT_REFRESH);
+
+ return KNOT_EOK;
+}
+
+static int zone_notify(zone_t *zone, ctl_args_t *args)
+{
+ UNUSED(args);
+
+ zone_events_schedule_user(zone, ZONE_EVENT_NOTIFY);
+
+ return KNOT_EOK;
+}
+
+static int zone_flush(zone_t *zone, ctl_args_t *args)
+{
+ if (MATCH_AND_FILTER(args, CTL_FILTER_FLUSH_OUTDIR)) {
+ return zone_dump_to_dir(conf(), zone, args->data[KNOT_CTL_IDX_DATA]);
+ }
+
+ if (ctl_has_flag(args->data[KNOT_CTL_IDX_FLAGS], CTL_FLAG_FORCE)) {
+ zone->flags |= ZONE_FORCE_FLUSH;
+ }
+
+ zone_events_schedule_user(zone, ZONE_EVENT_FLUSH);
+
+ return KNOT_EOK;
+}
+
+static int zone_sign(zone_t *zone, ctl_args_t *args)
+{
+ UNUSED(args);
+
+ conf_val_t val = conf_zone_get(conf(), C_DNSSEC_SIGNING, zone->name);
+ if (!conf_bool(&val)) {
+ return KNOT_ENOTSUP;
+ }
+
+ zone->flags |= ZONE_FORCE_RESIGN;
+ zone_events_schedule_user(zone, ZONE_EVENT_DNSSEC);
+
+ return KNOT_EOK;
+}
+
+static int zone_ksk_sbm_confirm(zone_t *zone, ctl_args_t *args)
+{
+ UNUSED(args);
+
+ kdnssec_ctx_t ctx = { 0 };
+
+ int ret = kdnssec_ctx_init(conf(), &ctx, zone->name, NULL);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = knot_dnssec_ksk_sbm_confirm(&ctx, 0);
+ kdnssec_ctx_deinit(&ctx);
+
+ conf_val_t val = conf_zone_get(conf(), C_DNSSEC_SIGNING, zone->name);
+ if (ret == KNOT_EOK && conf_bool(&val)) {
+ // NOT zone_events_schedule_user(), intentionally!
+ zone_events_schedule_now(zone, ZONE_EVENT_DNSSEC);
+ }
+
+ return ret;
+}
+
+static int zone_freeze(zone_t *zone, ctl_args_t *args)
+{
+ UNUSED(args);
+
+ zone_events_schedule_now(zone, ZONE_EVENT_UFREEZE);
+
+ return KNOT_EOK;
+}
+
+static int zone_thaw(zone_t *zone, ctl_args_t *args)
+{
+ UNUSED(args);
+
+ zone_events_schedule_now(zone, ZONE_EVENT_UTHAW);
+
+ return KNOT_EOK;
+}
+
+static int zone_txn_begin(zone_t *zone, ctl_args_t *args)
+{
+ UNUSED(args);
+
+ if (zone->control_update != NULL) {
+ return KNOT_TXN_EEXISTS;
+ }
+
+ zone->control_update = malloc(sizeof(zone_update_t));
+ if (zone->control_update == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ zone_update_flags_t type = (zone->contents == NULL) ? UPDATE_FULL : UPDATE_INCREMENTAL;
+ int ret = zone_update_init(zone->control_update, zone, type | UPDATE_SIGN | UPDATE_STRICT);
+ if (ret != KNOT_EOK) {
+ free(zone->control_update);
+ zone->control_update = NULL;
+ return ret;
+ }
+
+ return KNOT_EOK;
+}
+
+static void zone_txn_update_clear(zone_t *zone)
+{
+ assert(zone->control_update);
+
+ zone_update_clear(zone->control_update);
+ free(zone->control_update);
+ zone->control_update = NULL;
+}
+
+static int zone_txn_commit(zone_t *zone, ctl_args_t *args)
+{
+ UNUSED(args);
+
+ if (zone->control_update == NULL) {
+ return KNOT_TXN_ENOTEXISTS;
+ }
+
+ // NOOP if empty changeset/contents.
+ if (((zone->control_update->flags & UPDATE_INCREMENTAL) &&
+ changeset_empty(&zone->control_update->change)) ||
+ ((zone->control_update->flags & UPDATE_FULL) &&
+ zone_contents_is_empty(zone->control_update->new_cont))) {
+ zone_txn_update_clear(zone);
+ return KNOT_EOK;
+ }
+
+ // Sign update.
+ conf_val_t val = conf_zone_get(conf(), C_DNSSEC_SIGNING, zone->name);
+ bool dnssec_enable = (zone->control_update->flags & UPDATE_SIGN) && conf_bool(&val);
+ if (dnssec_enable) {
+ zone_sign_reschedule_t resch = { 0 };
+ int ret = knot_dnssec_sign_update(zone->control_update, &resch);
+ if (ret != KNOT_EOK) {
+ zone_txn_update_clear(zone);
+ return ret;
+ }
+ event_dnssec_reschedule(conf(), zone, &resch, false);
+ }
+
+ int ret = zone_update_commit(conf(), zone->control_update);
+ if (ret != KNOT_EOK) {
+ /* Invalidate the transaction if aborted. */
+ if (zone->control_update->zone == NULL) {
+ free(zone->control_update);
+ zone->control_update = NULL;
+ }
+ return ret;
+ }
+
+ zone_txn_update_clear(zone);
+
+ zone_events_schedule_now(zone, ZONE_EVENT_NOTIFY);
+
+ return KNOT_EOK;
+}
+
+static int zone_txn_abort(zone_t *zone, ctl_args_t *args)
+{
+ UNUSED(args);
+
+ if (zone->control_update == NULL) {
+ return KNOT_TXN_ENOTEXISTS;
+ }
+
+ zone_txn_update_clear(zone);
+
+ return KNOT_EOK;
+}
+
+typedef struct {
+ ctl_args_t *args;
+ int type_filter; // -1: no specific type, [0, 2^16]: specific type.
+ knot_dump_style_t style;
+ knot_ctl_data_t data;
+ char zone[KNOT_DNAME_TXT_MAXLEN + 1];
+ char owner[KNOT_DNAME_TXT_MAXLEN + 1];
+ char ttl[16];
+ char type[32];
+ char rdata[2 * 65536];
+} send_ctx_t;
+
+static send_ctx_t *create_send_ctx(const knot_dname_t *zone_name, ctl_args_t *args)
+{
+ send_ctx_t *ctx = mm_calloc(&args->mm, 1, sizeof(*ctx));
+ if (ctx == NULL) {
+ return NULL;
+ }
+
+ ctx->args = args;
+
+ // Set the dump style.
+ ctx->style.show_ttl = true;
+ ctx->style.original_ttl = true;
+ ctx->style.human_tmstamp = true;
+
+ // Set the output data buffers.
+ ctx->data[KNOT_CTL_IDX_ZONE] = ctx->zone;
+ ctx->data[KNOT_CTL_IDX_OWNER] = ctx->owner;
+ ctx->data[KNOT_CTL_IDX_TTL] = ctx->ttl;
+ ctx->data[KNOT_CTL_IDX_TYPE] = ctx->type;
+ ctx->data[KNOT_CTL_IDX_DATA] = ctx->rdata;
+
+ // Set the ZONE.
+ if (knot_dname_to_str(ctx->zone, zone_name, sizeof(ctx->zone)) == NULL) {
+ mm_free(&args->mm, ctx);
+ return NULL;
+ }
+
+ // Set the TYPE filter.
+ if (args->data[KNOT_CTL_IDX_TYPE] != NULL) {
+ uint16_t type;
+ if (knot_rrtype_from_string(args->data[KNOT_CTL_IDX_TYPE], &type) != 0) {
+ mm_free(&args->mm, ctx);
+ return NULL;
+ }
+ ctx->type_filter = type;
+ } else {
+ ctx->type_filter = -1;
+ }
+
+ return ctx;
+}
+
+static int send_rrset(knot_rrset_t *rrset, send_ctx_t *ctx)
+{
+ if (rrset->type != KNOT_RRTYPE_RRSIG) {
+ int ret = snprintf(ctx->ttl, sizeof(ctx->ttl), "%u", rrset->ttl);
+ if (ret <= 0 || ret >= sizeof(ctx->ttl)) {
+ return KNOT_ESPACE;
+ }
+ }
+
+ if (knot_rrtype_to_string(rrset->type, ctx->type, sizeof(ctx->type)) < 0) {
+ return KNOT_ESPACE;
+ }
+
+ for (size_t i = 0; i < rrset->rrs.count; ++i) {
+ if (rrset->type == KNOT_RRTYPE_RRSIG) {
+ int ret = snprintf(ctx->ttl, sizeof(ctx->ttl), "%u",
+ knot_rrsig_original_ttl(knot_rdataset_at(&rrset->rrs, i)));
+ if (ret <= 0 || ret >= sizeof(ctx->ttl)) {
+ return KNOT_ESPACE;
+ }
+ }
+
+ int ret = knot_rrset_txt_dump_data(rrset, i, ctx->rdata,
+ sizeof(ctx->rdata), &ctx->style);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = knot_ctl_send(ctx->args->ctl, KNOT_CTL_TYPE_DATA, &ctx->data);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+static int send_node(zone_node_t *node, void *ctx_void)
+{
+ send_ctx_t *ctx = ctx_void;
+ if (knot_dname_to_str(ctx->owner, node->owner, sizeof(ctx->owner)) == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ for (size_t i = 0; i < node->rrset_count; ++i) {
+ knot_rrset_t rrset = node_rrset_at(node, i);
+
+ // Check for requested TYPE.
+ if (ctx->type_filter != -1 && rrset.type != ctx->type_filter) {
+ continue;
+ }
+
+ int ret = send_rrset(&rrset, ctx);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+static int get_owner(uint8_t *out, size_t out_len, knot_dname_t *origin,
+ ctl_args_t *args)
+{
+ const char *owner = args->data[KNOT_CTL_IDX_OWNER];
+ assert(owner != NULL);
+
+ bool fqdn = false;
+ size_t prefix_len = 0;
+
+ size_t owner_len = strlen(owner);
+ if (owner_len > 0 && (owner_len != 1 || owner[0] != '@')) {
+ // Check if the owner is FQDN.
+ if (owner[owner_len - 1] == '.') {
+ fqdn = true;
+ }
+
+ knot_dname_t *dname = knot_dname_from_str(out, owner, out_len);
+ if (dname == NULL) {
+ return KNOT_EINVAL;
+ }
+ knot_dname_to_lower(dname);
+
+ prefix_len = knot_dname_size(out);
+ if (prefix_len == 0) {
+ return KNOT_EINVAL;
+ }
+
+ // Ignore trailing dot.
+ prefix_len--;
+ }
+
+ // Append the origin.
+ if (!fqdn) {
+ size_t origin_len = knot_dname_size(origin);
+ if (origin_len == 0 || origin_len > out_len - prefix_len) {
+ return KNOT_EINVAL;
+ }
+ memcpy(out + prefix_len, origin, origin_len);
+ }
+
+ return KNOT_EOK;
+}
+
+static int zone_read(zone_t *zone, ctl_args_t *args)
+{
+ send_ctx_t *ctx = create_send_ctx(zone->name, args);
+ if (ctx == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ int ret = KNOT_EOK;
+
+ if (args->data[KNOT_CTL_IDX_OWNER] != NULL) {
+ uint8_t owner[KNOT_DNAME_MAXLEN];
+
+ ret = get_owner(owner, sizeof(owner), zone->name, args);
+ if (ret != KNOT_EOK) {
+ goto zone_read_failed;
+ }
+
+ const zone_node_t *node = zone_contents_find_node(zone->contents, owner);
+ if (node == NULL) {
+ ret = KNOT_ENONODE;
+ goto zone_read_failed;
+ }
+
+ ret = send_node((zone_node_t *)node, ctx);
+ } else if (zone->contents != NULL) {
+ ret = zone_contents_apply(zone->contents, send_node, ctx);
+ }
+
+zone_read_failed:
+ mm_free(&args->mm, ctx);
+
+ return ret;
+}
+
+static int zone_flag_txn_get(zone_t *zone, ctl_args_t *args, const char *flag)
+{
+ if (zone->control_update == NULL) {
+ return KNOT_TXN_ENOTEXISTS;
+ }
+
+ send_ctx_t *ctx = create_send_ctx(zone->name, args);
+ if (ctx == NULL) {
+ return KNOT_ENOMEM;
+ }
+ ctx->data[KNOT_CTL_IDX_FLAGS] = flag;
+
+ int ret = KNOT_EOK;
+
+ if (args->data[KNOT_CTL_IDX_OWNER] != NULL) {
+ uint8_t owner[KNOT_DNAME_MAXLEN];
+
+ ret = get_owner(owner, sizeof(owner), zone->name, args);
+ if (ret != KNOT_EOK) {
+ goto zone_txn_get_failed;
+ }
+
+ const zone_node_t *node = zone_update_get_node(zone->control_update, owner);
+ if (node == NULL) {
+ ret = KNOT_ENONODE;
+ goto zone_txn_get_failed;
+ }
+
+ ret = send_node((zone_node_t *)node, ctx);
+ } else {
+ zone_update_iter_t it;
+ ret = zone_update_iter(&it, zone->control_update);
+ if (ret != KNOT_EOK) {
+ goto zone_txn_get_failed;
+ }
+
+ const zone_node_t *iter_node = zone_update_iter_val(&it);
+ while (iter_node != NULL) {
+ ret = send_node((zone_node_t *)iter_node, ctx);
+ if (ret != KNOT_EOK) {
+ zone_update_iter_finish(&it);
+ goto zone_txn_get_failed;
+ }
+
+ ret = zone_update_iter_next(&it);
+ if (ret != KNOT_EOK) {
+ zone_update_iter_finish(&it);
+ goto zone_txn_get_failed;
+ }
+
+ iter_node = zone_update_iter_val(&it);
+ }
+ zone_update_iter_finish(&it);
+ }
+
+zone_txn_get_failed:
+ mm_free(&args->mm, ctx);
+
+ return ret;
+}
+
+static int zone_txn_get(zone_t *zone, ctl_args_t *args)
+{
+ return zone_flag_txn_get(zone, args, NULL);
+}
+
+static int send_changeset_part(changeset_t *ch, send_ctx_t *ctx, bool from)
+{
+ ctx->data[KNOT_CTL_IDX_FLAGS] = from ? CTL_FLAG_REM : CTL_FLAG_ADD;
+
+ // Send SOA only if explicitly changed.
+ if (ch->soa_to != NULL) {
+ knot_rrset_t *soa = from ? ch->soa_from : ch->soa_to;
+ assert(soa);
+
+ char *owner = knot_dname_to_str(ctx->owner, soa->owner, sizeof(ctx->owner));
+ if (owner == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = send_rrset(soa, ctx);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ // Send other records.
+ changeset_iter_t it;
+ int ret = from ? changeset_iter_rem(&it, ch) : changeset_iter_add(&it, ch);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ knot_rrset_t rrset = changeset_iter_next(&it);
+ while (!knot_rrset_empty(&rrset)) {
+ char *owner = knot_dname_to_str(ctx->owner, rrset.owner, sizeof(ctx->owner));
+ if (owner == NULL) {
+ changeset_iter_clear(&it);
+ return KNOT_EINVAL;
+ }
+
+ ret = send_rrset(&rrset, ctx);
+ if (ret != KNOT_EOK) {
+ changeset_iter_clear(&it);
+ return ret;
+ }
+
+ rrset = changeset_iter_next(&it);
+ }
+ changeset_iter_clear(&it);
+
+ return KNOT_EOK;
+}
+
+static int send_changeset(changeset_t *ch, send_ctx_t *ctx)
+{
+ // First send 'from' changeset part.
+ int ret = send_changeset_part(ch, ctx, true);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Second send 'to' changeset part.
+ ret = send_changeset_part(ch, ctx, false);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ return KNOT_EOK;
+}
+
+static int zone_txn_diff(zone_t *zone, ctl_args_t *args)
+{
+ if (zone->control_update == NULL) {
+ return KNOT_TXN_ENOTEXISTS;
+ }
+
+ // FULL update has no changeset to print, do a 'get' instead.
+ if (zone->control_update->flags & UPDATE_FULL) {
+ return zone_flag_txn_get(zone, args, CTL_FLAG_ADD);
+ }
+
+ send_ctx_t *ctx = create_send_ctx(zone->name, args);
+ if (ctx == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ int ret = send_changeset(&zone->control_update->change, ctx);
+ mm_free(&args->mm, ctx);
+ return ret;
+}
+
+static int get_ttl(zone_t *zone, ctl_args_t *args, uint32_t *ttl)
+{
+ uint8_t owner[KNOT_DNAME_MAXLEN];
+
+ int ret = get_owner(owner, sizeof(owner), zone->name, args);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ const zone_node_t *node = zone_update_get_node(zone->control_update, owner);
+ if (node == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ uint16_t type;
+ if (knot_rrtype_from_string(args->data[KNOT_CTL_IDX_TYPE], &type) != 0) {
+ return KNOT_EINVAL;
+ }
+
+ *ttl = node_rrset(node, type).ttl;
+
+ return KNOT_EOK;
+}
+
+static int create_rrset(knot_rrset_t **rrset, zone_t *zone, ctl_args_t *args,
+ bool need_ttl)
+{
+ char origin_buff[KNOT_DNAME_TXT_MAXLEN + 1];
+ char *origin = knot_dname_to_str(origin_buff, zone->name, sizeof(origin_buff));
+ if (origin == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ const char *owner = args->data[KNOT_CTL_IDX_OWNER];
+ const char *type = args->data[KNOT_CTL_IDX_TYPE];
+ const char *data = args->data[KNOT_CTL_IDX_DATA];
+ const char *ttl = need_ttl ? args->data[KNOT_CTL_IDX_TTL] : NULL;
+
+ // Prepare a buffer for a reconstructed record.
+ const size_t buff_len = sizeof(((send_ctx_t *)0)->owner) +
+ sizeof(((send_ctx_t *)0)->ttl) +
+ sizeof(((send_ctx_t *)0)->type) +
+ sizeof(((send_ctx_t *)0)->rdata);
+ char *buff = mm_alloc(&args->mm, buff_len);
+ if (buff == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ uint32_t default_ttl = 0;
+ if (ttl == NULL) {
+ int ret = get_ttl(zone, args, &default_ttl);
+ if (need_ttl && ret != KNOT_EOK) {
+ mm_free(&args->mm, buff);
+ return ret;
+ }
+ }
+
+ // Reconstruct the record.
+ int ret = snprintf(buff, buff_len, "%s %s %s %s\n",
+ (owner != NULL ? owner : ""),
+ (ttl != NULL ? ttl : ""),
+ (type != NULL ? type : ""),
+ (data != NULL ? data : ""));
+ if (ret <= 0 || ret >= buff_len) {
+ mm_free(&args->mm, buff);
+ return KNOT_ESPACE;
+ }
+ size_t rdata_len = ret;
+
+ // Initialize RR parser.
+ zs_scanner_t *scanner = mm_alloc(&args->mm, sizeof(*scanner));
+ if (scanner == NULL) {
+ ret = KNOT_ENOMEM;
+ goto parser_failed;
+ }
+
+ // Parse the record.
+ if (zs_init(scanner, origin, KNOT_CLASS_IN, default_ttl) != 0 ||
+ zs_set_input_string(scanner, buff, rdata_len) != 0 ||
+ zs_parse_record(scanner) != 0 ||
+ scanner->state != ZS_STATE_DATA) {
+ ret = KNOT_EPARSEFAIL;
+ goto parser_failed;
+ }
+
+ // Create output rrset.
+ *rrset = knot_rrset_new(scanner->r_owner, scanner->r_type,
+ scanner->r_class, scanner->r_ttl, NULL);
+ if (*rrset == NULL) {
+ ret = KNOT_ENOMEM;
+ goto parser_failed;
+ }
+
+ ret = knot_rrset_add_rdata(*rrset, scanner->r_data, scanner->r_data_length,
+ NULL);
+parser_failed:
+ zs_deinit(scanner);
+ mm_free(&args->mm, scanner);
+ mm_free(&args->mm, buff);
+
+ return ret;
+}
+
+static int zone_txn_set(zone_t *zone, ctl_args_t *args)
+{
+ if (zone->control_update == NULL) {
+ return KNOT_TXN_ENOTEXISTS;
+ }
+
+ if (args->data[KNOT_CTL_IDX_OWNER] == NULL ||
+ args->data[KNOT_CTL_IDX_TYPE] == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ knot_rrset_t *rrset;
+ int ret = create_rrset(&rrset, zone, args, true);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = zone_update_add(zone->control_update, rrset);
+ knot_rrset_free(rrset, NULL);
+
+ return ret;
+}
+
+static int zone_txn_unset(zone_t *zone, ctl_args_t *args)
+{
+ if (zone->control_update == NULL) {
+ return KNOT_TXN_ENOTEXISTS;
+ }
+
+ if (args->data[KNOT_CTL_IDX_OWNER] == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ // Remove specific record.
+ if (args->data[KNOT_CTL_IDX_DATA] != NULL) {
+ if (args->data[KNOT_CTL_IDX_TYPE] == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ knot_rrset_t *rrset;
+ int ret = create_rrset(&rrset, zone, args, false);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = zone_update_remove(zone->control_update, rrset);
+ knot_rrset_free(rrset, NULL);
+ return ret;
+ } else {
+ uint8_t owner[KNOT_DNAME_MAXLEN];
+
+ int ret = get_owner(owner, sizeof(owner), zone->name, args);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Remove whole rrset.
+ if (args->data[KNOT_CTL_IDX_TYPE] != NULL) {
+ uint16_t type;
+ if (knot_rrtype_from_string(args->data[KNOT_CTL_IDX_TYPE],
+ &type) != 0) {
+ return KNOT_EINVAL;
+ }
+
+ return zone_update_remove_rrset(zone->control_update, owner, type);
+ // Remove whole node.
+ } else {
+ return zone_update_remove_node(zone->control_update, owner);
+ }
+ }
+}
+
+static bool zone_exists(const knot_dname_t *zone, void *data)
+{
+ assert(zone);
+ assert(data);
+
+ knot_zonedb_t *db = data;
+
+ return knot_zonedb_find(db, zone) != NULL;
+}
+
+static bool zone_names_distinct(const knot_dname_t *zone, void *data)
+{
+ assert(zone);
+ assert(data);
+
+ knot_dname_t *zone_to_purge = data;
+
+ return !knot_dname_is_equal(zone, zone_to_purge);
+}
+
+static int orphans_purge(ctl_args_t *args)
+{
+ assert(args->data[KNOT_CTL_IDX_FILTER] != NULL);
+ bool only_orphan = (strlen(args->data[KNOT_CTL_IDX_FILTER]) == 1);
+
+ if (args->data[KNOT_CTL_IDX_ZONE] == NULL) {
+ // Purge KASP DB.
+ if (only_orphan || MATCH_AND_FILTER(args, CTL_FILTER_PURGE_KASPDB)) {
+ list_t zones;
+ init_list(&zones);
+ if (kasp_db_open(*kaspdb()) == KNOT_EOK &&
+ kasp_db_list_zones(*kaspdb(), &zones) == KNOT_EOK) {
+ ptrnode_t *zn;
+ WALK_LIST(zn, zones) {
+ knot_dname_t *zone_name = (knot_dname_t *)zn->d;
+ if (!zone_exists(zone_name, args->server->zone_db)) {
+ (void)kasp_db_delete_all(*kaspdb(), zone_name);
+ }
+ knot_dname_free(zone_name, NULL);
+ }
+ ptrlist_free(&zones, NULL);
+ }
+ }
+
+ // Purge zone journals of unconfigured zones.
+ if (only_orphan || MATCH_AND_FILTER(args, CTL_FILTER_PURGE_JOURNAL)) {
+ list_t zones;
+ init_list(&zones);
+ if (journal_db_list_zones(&args->server->journal_db, &zones) == KNOT_EOK) {
+ ptrnode_t *zn;
+ WALK_LIST(zn, zones) {
+ journal_t journal = { 0 };
+ knot_dname_t *zone_name = (knot_dname_t *)zn->d;
+ if (!zone_exists(zone_name, args->server->zone_db) &&
+ journal_open(&journal, &args->server->journal_db,
+ zone_name) == KNOT_EOK) {
+ journal_scrape(&journal);
+ journal_close(&journal);
+ }
+ knot_dname_free(zone_name, NULL);
+ }
+ ptrlist_free(&zones, NULL);
+ }
+ }
+
+ // Purge timers of unconfigured zones.
+ if (only_orphan || MATCH_AND_FILTER(args, CTL_FILTER_PURGE_TIMERS)) {
+ (void)zone_timers_sweep(args->server->timers_db,
+ zone_exists, args->server->zone_db);
+ }
+ } else {
+ uint8_t buff[KNOT_DNAME_MAXLEN];
+ while (true) {
+ knot_dname_t *zone_name =
+ knot_dname_from_str(buff, args->data[KNOT_CTL_IDX_ZONE],
+ sizeof(buff));
+ if (zone_name == NULL) {
+ log_ctl_zone_str_error(args->data[KNOT_CTL_IDX_ZONE],
+ "control, error (%s)",
+ knot_strerror(KNOT_EINVAL));
+ send_error(args, knot_strerror(KNOT_EINVAL));
+ return KNOT_EINVAL;
+ }
+ knot_dname_to_lower(zone_name);
+
+ if (!zone_exists(zone_name, args->server->zone_db)) {
+ // Purge KASP DB.
+ if (only_orphan || MATCH_AND_FILTER(args, CTL_FILTER_PURGE_KASPDB)) {
+ if (kasp_db_open(*kaspdb()) == KNOT_EOK) {
+ (void) kasp_db_delete_all(*kaspdb(), zone_name);
+ }
+ }
+
+ // Purge zone journal.
+ if (only_orphan || MATCH_AND_FILTER(args, CTL_FILTER_PURGE_JOURNAL)) {
+ journal_t journal = { 0 };
+ if (journal_open(&journal, &args->server->journal_db,
+ zone_name) == KNOT_EOK) {
+ (void)journal_scrape(&journal);
+ journal_close(&journal);
+ }
+ }
+
+ // Purge zone timers.
+ if (only_orphan || MATCH_AND_FILTER(args, CTL_FILTER_PURGE_TIMERS)) {
+ (void)zone_timers_sweep(args->server->timers_db,
+ zone_names_distinct, zone_name);
+ }
+ }
+
+ // Get next zone name.
+ int ret = knot_ctl_receive(args->ctl, &args->type, &args->data);
+ if (ret != KNOT_EOK || args->type != KNOT_CTL_TYPE_DATA) {
+ break;
+ }
+ ctl_log_data(&args->data);
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+static int zone_purge(zone_t *zone, ctl_args_t *args)
+{
+ // Abort possible editing transaction.
+ if (MATCH_OR_FILTER(args, CTL_FILTER_PURGE_EXPIRE)) {
+ (void)zone_txn_abort(zone, args);
+ }
+
+ // Purge the zone timers.
+ if (MATCH_OR_FILTER(args, CTL_FILTER_PURGE_TIMERS)) {
+ memset(&zone->timers, 0, sizeof(zone->timers));
+ (void)zone_timers_sweep(args->server->timers_db,
+ zone_names_distinct, zone->name);
+ }
+
+ // Expire the zone.
+ if (MATCH_OR_FILTER(args, CTL_FILTER_PURGE_EXPIRE)) {
+ zone_events_schedule_user(zone, ZONE_EVENT_EXPIRE);
+ }
+
+ // Purge the zone file.
+ if (MATCH_OR_FILTER(args, CTL_FILTER_PURGE_ZONEFILE)) {
+ char *zonefile = conf_zonefile(conf(), zone->name);
+ (void)unlink(zonefile);
+ free(zonefile);
+ }
+
+ // Purge the zone journal.
+ if (MATCH_OR_FILTER(args, CTL_FILTER_PURGE_JOURNAL)) {
+ if (journal_open(zone->journal, zone->journal_db, zone->name) == KNOT_EOK) {
+ (void)journal_scrape(zone->journal);
+ }
+ }
+
+ // Purge KASP DB.
+ if (MATCH_OR_FILTER(args, CTL_FILTER_PURGE_KASPDB)) {
+ if (kasp_db_open(*kaspdb()) == KNOT_EOK) {
+ (void)kasp_db_delete_all(*kaspdb(), zone->name);
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+static int send_stats_ctr(mod_ctr_t *ctr, ctl_args_t *args, knot_ctl_data_t *data)
+{
+ char index[128];
+ char value[32];
+
+ if (ctr->count == 1) {
+ uint64_t counter = ATOMIC_GET(ctr->counter);
+ int ret = snprintf(value, sizeof(value), "%"PRIu64, counter);
+ if (ret <= 0 || ret >= sizeof(value)) {
+ return KNOT_ESPACE;
+ }
+
+ (*data)[KNOT_CTL_IDX_ID] = NULL;
+ (*data)[KNOT_CTL_IDX_DATA] = value;
+
+ ret = knot_ctl_send(args->ctl, KNOT_CTL_TYPE_DATA, data);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ } else {
+ bool force = ctl_has_flag(args->data[KNOT_CTL_IDX_FLAGS],
+ CTL_FLAG_FORCE);
+
+ for (uint32_t i = 0; i < ctr->count; i++) {
+ uint64_t counter = ATOMIC_GET(ctr->counters[i]);
+
+ // Skip empty counters.
+ if (counter == 0 && !force) {
+ continue;
+ }
+
+ int ret;
+ if (ctr->idx_to_str) {
+ char *str = ctr->idx_to_str(i, ctr->count);
+ if (str == NULL) {
+ continue;
+ }
+ ret = snprintf(index, sizeof(index), "%s", str);
+ free(str);
+ } else {
+ ret = snprintf(index, sizeof(index), "%u", i);
+ }
+ if (ret <= 0 || ret >= sizeof(index)) {
+ return KNOT_ESPACE;
+ }
+
+ ret = snprintf(value, sizeof(value), "%"PRIu64, counter);
+ if (ret <= 0 || ret >= sizeof(value)) {
+ return KNOT_ESPACE;
+ }
+
+ (*data)[KNOT_CTL_IDX_ID] = index;
+ (*data)[KNOT_CTL_IDX_DATA] = value;
+
+ knot_ctl_type_t type = (i == 0) ? KNOT_CTL_TYPE_DATA :
+ KNOT_CTL_TYPE_EXTRA;
+ ret = knot_ctl_send(args->ctl, type, data);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+static int modules_stats(list_t *query_modules, ctl_args_t *args, knot_dname_t *zone)
+{
+ if (query_modules == NULL) {
+ return KNOT_EOK;
+ }
+
+ const char *section = args->data[KNOT_CTL_IDX_SECTION];
+ const char *item = args->data[KNOT_CTL_IDX_ITEM];
+
+ char name[KNOT_DNAME_TXT_MAXLEN + 1] = { 0 };
+ knot_ctl_data_t data = { 0 };
+
+ bool section_found = (section == NULL) ? true : false;
+ bool item_found = (item == NULL) ? true : false;
+
+ knotd_mod_t *mod = NULL;
+ WALK_LIST(mod, *query_modules) {
+ // Skip modules without statistics.
+ if (mod->stats_count == 0) {
+ continue;
+ }
+
+ // Check for specific module.
+ if (section != NULL) {
+ if (section_found) {
+ break;
+ } else if (strcasecmp(mod->id->name + 1, section) == 0) {
+ section_found = true;
+ } else {
+ continue;
+ }
+ }
+
+ data[KNOT_CTL_IDX_SECTION] = mod->id->name + 1;
+
+ for (int i = 0; i < mod->stats_count; i++) {
+ mod_ctr_t *ctr = mod->stats + i;
+
+ // Skip empty counter.
+ if (ctr->name == NULL) {
+ continue;
+ }
+
+ // Check for specific counter.
+ if (item != NULL) {
+ if (item_found) {
+ break;
+ } else if (strcasecmp(ctr->name, item) == 0) {
+ item_found = true;
+ } else {
+ continue;
+ }
+ }
+
+ // Prepare zone name if not already prepared.
+ if (zone != NULL && name[0] == '\0') {
+ if (knot_dname_to_str(name, zone, sizeof(name)) == NULL) {
+ return KNOT_EINVAL;
+ }
+ data[KNOT_CTL_IDX_ZONE] = name;
+ }
+
+ data[KNOT_CTL_IDX_ITEM] = ctr->name;
+
+ // Send the counters.
+ int ret = send_stats_ctr(ctr, args, &data);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+ }
+
+ return (section_found && item_found) ? KNOT_EOK : KNOT_ENOENT;
+}
+
+static int zone_stats(zone_t *zone, ctl_args_t *args)
+{
+ return modules_stats(&zone->query_modules, args, zone->name);
+}
+
+static int ctl_zone(ctl_args_t *args, ctl_cmd_t cmd)
+{
+ switch (cmd) {
+ case CTL_ZONE_STATUS:
+ return zones_apply(args, zone_status);
+ case CTL_ZONE_RELOAD:
+ return zones_apply(args, zone_reload);
+ case CTL_ZONE_REFRESH:
+ return zones_apply(args, zone_refresh);
+ case CTL_ZONE_RETRANSFER:
+ return zones_apply(args, zone_retransfer);
+ case CTL_ZONE_NOTIFY:
+ return zones_apply(args, zone_notify);
+ case CTL_ZONE_FLUSH:
+ return zones_apply(args, zone_flush);
+ case CTL_ZONE_SIGN:
+ return zones_apply(args, zone_sign);
+ case CTL_ZONE_KSK_SBM:
+ return zones_apply(args, zone_ksk_sbm_confirm);
+ case CTL_ZONE_FREEZE:
+ return zones_apply(args, zone_freeze);
+ case CTL_ZONE_THAW:
+ return zones_apply(args, zone_thaw);
+ case CTL_ZONE_READ:
+ return zones_apply(args, zone_read);
+ case CTL_ZONE_BEGIN:
+ return zones_apply(args, zone_txn_begin);
+ case CTL_ZONE_COMMIT:
+ return zones_apply(args, zone_txn_commit);
+ case CTL_ZONE_ABORT:
+ return zones_apply(args, zone_txn_abort);
+ case CTL_ZONE_DIFF:
+ return zones_apply(args, zone_txn_diff);
+ case CTL_ZONE_GET:
+ return zones_apply(args, zone_txn_get);
+ case CTL_ZONE_SET:
+ return zones_apply(args, zone_txn_set);
+ case CTL_ZONE_UNSET:
+ return zones_apply(args, zone_txn_unset);
+ case CTL_ZONE_PURGE:
+ if (MATCH_AND_FILTER(args, CTL_FILTER_PURGE_ORPHAN)) {
+ return orphans_purge(args);
+ } else {
+ return zones_apply(args, zone_purge);
+ }
+ case CTL_ZONE_STATS:
+ return zones_apply(args, zone_stats);
+ default:
+ assert(0);
+ return KNOT_EINVAL;
+ }
+}
+
+static int server_status(ctl_args_t *args)
+{
+ const char *type = args->data[KNOT_CTL_IDX_TYPE];
+
+ if (type == NULL || strlen(type) == 0) {
+ return KNOT_EOK;
+ }
+
+ char buff[2048] = "";
+
+ int ret;
+ if (strcasecmp(type, "version") == 0) {
+ ret = snprintf(buff, sizeof(buff), "Version: %s", PACKAGE_VERSION);
+ } else if (strcasecmp(type, "workers") == 0) {
+ int running_bkg_wrk, wrk_queue;
+ worker_pool_status(args->server->workers, &running_bkg_wrk, &wrk_queue);
+ ret = snprintf(buff, sizeof(buff), "UDP workers: %zu, TCP workers %zu, "
+ "background workers: %zu (running: %d, pending: %d)",
+ conf_udp_threads(conf()), conf_tcp_threads(conf()),
+ conf_bg_threads(conf()), running_bkg_wrk, wrk_queue);
+ } else if (strcasecmp(type, "configure") == 0) {
+ ret = snprintf(buff, sizeof(buff), "%s", CONFIGURE_SUMMARY);
+ } else {
+ return KNOT_EINVAL;
+ }
+ if (ret <= 0 || ret >= sizeof(buff)) {
+ return KNOT_ESPACE;
+ }
+
+ args->data[KNOT_CTL_IDX_DATA] = buff;
+
+ return knot_ctl_send(args->ctl, KNOT_CTL_TYPE_DATA, &args->data);
+}
+
+static int ctl_server(ctl_args_t *args, ctl_cmd_t cmd)
+{
+ int ret = KNOT_EOK;
+
+ switch (cmd) {
+ case CTL_STATUS:
+ ret = server_status(args);
+ if (ret != KNOT_EOK) {
+ send_error(args, knot_strerror(ret));
+ }
+ break;
+ case CTL_STOP:
+ ret = KNOT_CTL_ESTOP;
+ break;
+ case CTL_RELOAD:
+ ret = server_reload(args->server);
+ if (ret != KNOT_EOK) {
+ send_error(args, knot_strerror(ret));
+ }
+ break;
+ default:
+ assert(0);
+ ret = KNOT_EINVAL;
+ }
+
+ return ret;
+}
+
+static int ctl_stats(ctl_args_t *args, ctl_cmd_t cmd)
+{
+ const char *section = args->data[KNOT_CTL_IDX_SECTION];
+ const char *item = args->data[KNOT_CTL_IDX_ITEM];
+
+ bool found = (section == NULL) ? true : false;
+
+ // Process server metrics.
+ if (section == NULL || strcasecmp(section, "server") == 0) {
+ char value[32];
+ knot_ctl_data_t data = {
+ [KNOT_CTL_IDX_SECTION] = "server",
+ [KNOT_CTL_IDX_DATA] = value
+ };
+
+ for (const stats_item_t *i = server_stats; i->name != NULL; i++) {
+ if (item != NULL) {
+ if (found) {
+ break;
+ } else if (strcmp(i->name, item) == 0) {
+ found = true;
+ } else {
+ continue;
+ }
+ } else {
+ found = true;
+ }
+
+ data[KNOT_CTL_IDX_ITEM] = i->name;
+ int ret = snprintf(value, sizeof(value), "%"PRIu64,
+ i->val(args->server));
+ if (ret <= 0 || ret >= sizeof(value)) {
+ ret = KNOT_ESPACE;
+ send_error(args, knot_strerror(ret));
+ return ret;
+ }
+
+ ret = knot_ctl_send(args->ctl, KNOT_CTL_TYPE_DATA, &data);
+ if (ret != KNOT_EOK) {
+ send_error(args, knot_strerror(ret));
+ return ret;
+ }
+ }
+ }
+
+ // Process modules metrics.
+ if (section == NULL || strncasecmp(section, "mod-", strlen("mod-")) == 0) {
+ int ret = modules_stats(conf()->query_modules, args, NULL);
+ if (ret != KNOT_EOK) {
+ send_error(args, knot_strerror(ret));
+ return ret;
+ }
+
+ found = true;
+ }
+
+ if (!found) {
+ send_error(args, knot_strerror(KNOT_EINVAL));
+ return KNOT_EINVAL;
+ }
+
+ return KNOT_EOK;
+}
+
+static int send_block_data(conf_io_t *io, knot_ctl_data_t *data)
+{
+ knot_ctl_t *ctl = (knot_ctl_t *)io->misc;
+
+ const yp_item_t *item = (io->key1 != NULL) ? io->key1 : io->key0;
+ assert(item != NULL);
+
+ char buff[YP_MAX_TXT_DATA_LEN + 1] = "\0";
+
+ (*data)[KNOT_CTL_IDX_DATA] = buff;
+
+ // Format explicit binary data value.
+ if (io->data.bin != NULL) {
+ size_t buff_len = sizeof(buff);
+ int ret = yp_item_to_txt(item, io->data.bin, io->data.bin_len, buff,
+ &buff_len, YP_SNOQUOTE);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ return knot_ctl_send(ctl, KNOT_CTL_TYPE_DATA, data);
+ // Format all multivalued item data if no specified index.
+ } else if ((item->flags & YP_FMULTI) && io->data.index == 0) {
+ size_t values = conf_val_count(io->data.val);
+ for (size_t i = 0; i < values; i++) {
+ conf_val(io->data.val);
+ size_t buff_len = sizeof(buff);
+ int ret = yp_item_to_txt(item, io->data.val->data,
+ io->data.val->len, buff,&buff_len,
+ YP_SNOQUOTE);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ knot_ctl_type_t type = (i == 0) ? KNOT_CTL_TYPE_DATA :
+ KNOT_CTL_TYPE_EXTRA;
+ ret = knot_ctl_send(ctl, type, data);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ conf_val_next(io->data.val);
+ }
+ return KNOT_EOK;
+ // Format singlevalued item data or a specified one from multivalued.
+ } else {
+ conf_val(io->data.val);
+ size_t buff_len = sizeof(buff);
+ int ret = yp_item_to_txt(item, io->data.val->data, io->data.val->len,
+ buff, &buff_len, YP_SNOQUOTE);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ return knot_ctl_send(ctl, KNOT_CTL_TYPE_DATA, data);
+ }
+}
+
+static int send_block(conf_io_t *io)
+{
+ knot_ctl_t *ctl = (knot_ctl_t *)io->misc;
+
+ // Get possible error message.
+ const char *err = io->error.str;
+ if (err == NULL && io->error.code != KNOT_EOK) {
+ err = knot_strerror(io->error.code);
+ }
+
+ knot_ctl_data_t data = {
+ [KNOT_CTL_IDX_ERROR] = err,
+ };
+
+ if (io->key0 != NULL) {
+ data[KNOT_CTL_IDX_SECTION] = io->key0->name + 1;
+ }
+ if (io->key1 != NULL) {
+ data[KNOT_CTL_IDX_ITEM] = io->key1->name + 1;
+ }
+
+ // Get the item prefix.
+ switch (io->type) {
+ case NEW: data[KNOT_CTL_IDX_FLAGS] = CTL_FLAG_ADD; break;
+ case OLD: data[KNOT_CTL_IDX_FLAGS] = CTL_FLAG_REM; break;
+ default: break;
+ }
+
+ char id[KNOT_DNAME_TXT_MAXLEN + 1] = "\0";
+
+ // Get the textual item id.
+ if (io->id_len > 0 && io->key0 != NULL) {
+ size_t id_len = sizeof(id);
+ int ret = yp_item_to_txt(io->key0->var.g.id, io->id, io->id_len,
+ id, &id_len, YP_SNOQUOTE);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ if (io->id_as_data) {
+ data[KNOT_CTL_IDX_DATA] = id;
+ } else {
+ data[KNOT_CTL_IDX_ID] = id;
+ }
+ }
+
+ if (io->data.val == NULL && io->data.bin == NULL) {
+ return knot_ctl_send(ctl, KNOT_CTL_TYPE_DATA, &data);
+ } else {
+ return send_block_data(io, &data);
+ }
+}
+
+static int ctl_conf_txn(ctl_args_t *args, ctl_cmd_t cmd)
+{
+ conf_io_t io = {
+ .fcn = send_block,
+ .misc = args->ctl
+ };
+
+ int ret = KNOT_EOK;
+
+ switch (cmd) {
+ case CTL_CONF_BEGIN:
+ ret = conf_io_begin(false);
+ break;
+ case CTL_CONF_ABORT:
+ conf_io_abort(false);
+ ret = KNOT_EOK;
+ break;
+ case CTL_CONF_COMMIT:
+ // First check the database.
+ ret = conf_io_check(&io);
+ if (ret != KNOT_EOK) {
+ // A semantic error is already sent by the check function.
+ if (io.error.code != KNOT_EOK) {
+ return KNOT_EOK;
+ }
+ // No transaction abort!
+ break;
+ }
+
+ ret = conf_io_commit(false);
+ if (ret != KNOT_EOK) {
+ conf_io_abort(false);
+ break;
+ }
+
+ ret = server_reload(args->server);
+ break;
+ default:
+ assert(0);
+ ret = KNOT_EINVAL;
+ }
+
+ if (ret != KNOT_EOK) {
+ send_error(args, knot_strerror(ret));
+ }
+
+ return ret;
+}
+
+static int ctl_conf_read(ctl_args_t *args, ctl_cmd_t cmd)
+{
+ conf_io_t io = {
+ .fcn = send_block,
+ .misc = args->ctl
+ };
+
+ int ret = KNOT_EOK;
+
+ while (true) {
+ const char *key0 = args->data[KNOT_CTL_IDX_SECTION];
+ const char *key1 = args->data[KNOT_CTL_IDX_ITEM];
+ const char *id = args->data[KNOT_CTL_IDX_ID];
+
+ switch (cmd) {
+ case CTL_CONF_LIST:
+ ret = conf_io_list(key0, &io);
+ break;
+ case CTL_CONF_READ:
+ ret = conf_io_get(key0, key1, id, true, &io);
+ break;
+ case CTL_CONF_DIFF:
+ ret = conf_io_diff(key0, key1, id, &io);
+ break;
+ case CTL_CONF_GET:
+ ret = conf_io_get(key0, key1, id, false, &io);
+ break;
+ default:
+ assert(0);
+ ret = KNOT_EINVAL;
+ }
+ if (ret != KNOT_EOK) {
+ send_error(args, knot_strerror(ret));
+ break;
+ }
+
+ // Get next data unit.
+ ret = knot_ctl_receive(args->ctl, &args->type, &args->data);
+ if (ret != KNOT_EOK || args->type != KNOT_CTL_TYPE_DATA) {
+ break;
+ }
+ ctl_log_data(&args->data);
+ }
+
+ return ret;
+}
+
+static int ctl_conf_modify(ctl_args_t *args, ctl_cmd_t cmd)
+{
+ // Start child transaction.
+ int ret = conf_io_begin(true);
+ if (ret != KNOT_EOK) {
+ send_error(args, knot_strerror(ret));
+ return ret;
+ }
+
+ while (true) {
+ const char *key0 = args->data[KNOT_CTL_IDX_SECTION];
+ const char *key1 = args->data[KNOT_CTL_IDX_ITEM];
+ const char *id = args->data[KNOT_CTL_IDX_ID];
+ const char *data = args->data[KNOT_CTL_IDX_DATA];
+
+ switch (cmd) {
+ case CTL_CONF_SET:
+ ret = conf_io_set(key0, key1, id, data);
+ break;
+ case CTL_CONF_UNSET:
+ ret = conf_io_unset(key0, key1, id, data);
+ break;
+ default:
+ assert(0);
+ ret = KNOT_EINVAL;
+ }
+ if (ret != KNOT_EOK) {
+ send_error(args, knot_strerror(ret));
+ break;
+ }
+
+ // Get next data unit.
+ ret = knot_ctl_receive(args->ctl, &args->type, &args->data);
+ if (ret != KNOT_EOK || args->type != KNOT_CTL_TYPE_DATA) {
+ break;
+ }
+ ctl_log_data(&args->data);
+ }
+
+ // Finish child transaction.
+ if (ret == KNOT_EOK) {
+ ret = conf_io_commit(true);
+ if (ret != KNOT_EOK) {
+ send_error(args, knot_strerror(ret));
+ }
+ } else {
+ conf_io_abort(true);
+ }
+
+ return ret;
+}
+
+typedef struct {
+ const char *name;
+ int (*fcn)(ctl_args_t *, ctl_cmd_t);
+} desc_t;
+
+static const desc_t cmd_table[] = {
+ [CTL_NONE] = { "" },
+
+ [CTL_STATUS] = { "status", ctl_server },
+ [CTL_STOP] = { "stop", ctl_server },
+ [CTL_RELOAD] = { "reload", ctl_server },
+ [CTL_STATS] = { "stats", ctl_stats },
+
+ [CTL_ZONE_STATUS] = { "zone-status", ctl_zone },
+ [CTL_ZONE_RELOAD] = { "zone-reload", ctl_zone },
+ [CTL_ZONE_REFRESH] = { "zone-refresh", ctl_zone },
+ [CTL_ZONE_RETRANSFER] = { "zone-retransfer", ctl_zone },
+ [CTL_ZONE_NOTIFY] = { "zone-notify", ctl_zone },
+ [CTL_ZONE_FLUSH] = { "zone-flush", ctl_zone },
+ [CTL_ZONE_SIGN] = { "zone-sign", ctl_zone },
+ [CTL_ZONE_KSK_SBM] = { "zone-ksk-submitted", ctl_zone },
+ [CTL_ZONE_FREEZE] = { "zone-freeze", ctl_zone },
+ [CTL_ZONE_THAW] = { "zone-thaw", ctl_zone },
+
+ [CTL_ZONE_READ] = { "zone-read", ctl_zone },
+ [CTL_ZONE_BEGIN] = { "zone-begin", ctl_zone },
+ [CTL_ZONE_COMMIT] = { "zone-commit", ctl_zone },
+ [CTL_ZONE_ABORT] = { "zone-abort", ctl_zone },
+ [CTL_ZONE_DIFF] = { "zone-diff", ctl_zone },
+ [CTL_ZONE_GET] = { "zone-get", ctl_zone },
+ [CTL_ZONE_SET] = { "zone-set", ctl_zone },
+ [CTL_ZONE_UNSET] = { "zone-unset", ctl_zone },
+ [CTL_ZONE_PURGE] = { "zone-purge", ctl_zone },
+ [CTL_ZONE_STATS] = { "zone-stats", ctl_zone },
+
+ [CTL_CONF_LIST] = { "conf-list", ctl_conf_read },
+ [CTL_CONF_READ] = { "conf-read", ctl_conf_read },
+ [CTL_CONF_BEGIN] = { "conf-begin", ctl_conf_txn },
+ [CTL_CONF_COMMIT] = { "conf-commit", ctl_conf_txn },
+ [CTL_CONF_ABORT] = { "conf-abort", ctl_conf_txn },
+ [CTL_CONF_DIFF] = { "conf-diff", ctl_conf_read },
+ [CTL_CONF_GET] = { "conf-get", ctl_conf_read },
+ [CTL_CONF_SET] = { "conf-set", ctl_conf_modify },
+ [CTL_CONF_UNSET] = { "conf-unset", ctl_conf_modify },
+};
+
+#define MAX_CTL_CODE (sizeof(cmd_table) / sizeof(desc_t) - 1)
+
+const char *ctl_cmd_to_str(ctl_cmd_t cmd)
+{
+ if (cmd <= CTL_NONE || cmd > MAX_CTL_CODE) {
+ return NULL;
+ }
+
+ return cmd_table[cmd].name;
+}
+
+ctl_cmd_t ctl_str_to_cmd(const char *cmd_str)
+{
+ if (cmd_str == NULL) {
+ return CTL_NONE;
+ }
+
+ for (ctl_cmd_t cmd = CTL_NONE + 1; cmd <= MAX_CTL_CODE; cmd++) {
+ if (strcmp(cmd_str, cmd_table[cmd].name) == 0) {
+ return cmd;
+ }
+ }
+
+ return CTL_NONE;
+}
+
+int ctl_exec(ctl_cmd_t cmd, ctl_args_t *args)
+{
+ if (args == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ return cmd_table[cmd].fcn(args, cmd);
+}
+
+bool ctl_has_flag(const char *flags, const char *flag)
+{
+ if (flags == NULL || flag == NULL) {
+ return false;
+ }
+
+ return strstr(flags, flag) != NULL;
+}
diff --git a/src/knot/ctl/commands.h b/src/knot/ctl/commands.h
new file mode 100644
index 0000000..8b6e351
--- /dev/null
+++ b/src/knot/ctl/commands.h
@@ -0,0 +1,135 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "libknot/libknot.h"
+#include "knot/server/server.h"
+
+#define CTL_FLAG_FORCE "F"
+#define CTL_FLAG_ADD "+"
+#define CTL_FLAG_REM "-"
+
+#define CTL_FILTER_FLUSH_OUTDIR 'd'
+
+#define CTL_FILTER_STATUS_ROLE 'r'
+#define CTL_FILTER_STATUS_SERIAL 's'
+#define CTL_FILTER_STATUS_TRANSACTION 't'
+#define CTL_FILTER_STATUS_FREEZE 'f'
+#define CTL_FILTER_STATUS_EVENTS 'e'
+
+#define CTL_FILTER_PURGE_EXPIRE 'e'
+#define CTL_FILTER_PURGE_TIMERS 't'
+#define CTL_FILTER_PURGE_ZONEFILE 'f'
+#define CTL_FILTER_PURGE_JOURNAL 'j'
+#define CTL_FILTER_PURGE_KASPDB 'k'
+#define CTL_FILTER_PURGE_ORPHAN 'o'
+
+/*! Control commands. */
+typedef enum {
+ CTL_NONE,
+
+ CTL_STATUS,
+ CTL_STOP,
+ CTL_RELOAD,
+ CTL_STATS,
+
+ CTL_ZONE_STATUS,
+ CTL_ZONE_RELOAD,
+ CTL_ZONE_REFRESH,
+ CTL_ZONE_RETRANSFER,
+ CTL_ZONE_NOTIFY,
+ CTL_ZONE_FLUSH,
+ CTL_ZONE_SIGN,
+ CTL_ZONE_KSK_SBM,
+ CTL_ZONE_FREEZE,
+ CTL_ZONE_THAW,
+
+ CTL_ZONE_READ,
+ CTL_ZONE_BEGIN,
+ CTL_ZONE_COMMIT,
+ CTL_ZONE_ABORT,
+ CTL_ZONE_DIFF,
+ CTL_ZONE_GET,
+ CTL_ZONE_SET,
+ CTL_ZONE_UNSET,
+ CTL_ZONE_PURGE,
+ CTL_ZONE_STATS,
+
+ CTL_CONF_LIST,
+ CTL_CONF_READ,
+ CTL_CONF_BEGIN,
+ CTL_CONF_COMMIT,
+ CTL_CONF_ABORT,
+ CTL_CONF_DIFF,
+ CTL_CONF_GET,
+ CTL_CONF_SET,
+ CTL_CONF_UNSET,
+} ctl_cmd_t;
+
+/*! Control command parameters. */
+typedef struct {
+ knot_mm_t mm;
+ knot_ctl_t *ctl;
+ knot_ctl_type_t type;
+ knot_ctl_data_t data;
+ server_t *server;
+} ctl_args_t;
+
+/*!
+ * Returns a string equivalent of the command.
+ *
+ * \param[in] cmd Command.
+ *
+ * \return Command string or NULL.
+ */
+const char *ctl_cmd_to_str(ctl_cmd_t cmd);
+
+/*!
+ * Returns a command corresponding to the string.
+ *
+ * \param[in] cmd_str Command string.
+ *
+ * \return Command.
+ */
+ctl_cmd_t ctl_str_to_cmd(const char *cmd_str);
+
+/*!
+ * Executes a control command.
+ *
+ * \param[in] cmd Control command.
+ * \param[in] args Command arguments.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int ctl_exec(ctl_cmd_t cmd, ctl_args_t *args);
+
+/*!
+ * Logs control data items at the debug level.
+ *
+ * \param[in] data Control data.
+ */
+void ctl_log_data(knot_ctl_data_t *data);
+
+/*!
+ * Checks flag presence in flags.
+ *
+ * \param[in] flags Flags to check presence in.
+ * \param[in] flag Checked flag.
+ *
+ * \return True if presented.
+ */
+bool ctl_has_flag(const char *flags, const char *flag);
diff --git a/src/knot/ctl/process.c b/src/knot/ctl/process.c
new file mode 100644
index 0000000..d845bed
--- /dev/null
+++ b/src/knot/ctl/process.c
@@ -0,0 +1,128 @@
+/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "contrib/mempattern.h"
+#include "contrib/ucw/mempool.h"
+#include "knot/common/log.h"
+#include "knot/ctl/commands.h"
+#include "knot/ctl/process.h"
+#include "libknot/error.h"
+
+int ctl_process(knot_ctl_t *ctl, server_t *server)
+{
+ if (ctl == NULL || server == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ ctl_args_t args = {
+ .ctl = ctl,
+ .type = KNOT_CTL_TYPE_END,
+ .server = server
+ };
+
+ mm_ctx_mempool(&args.mm, MM_DEFAULT_BLKSIZE);
+
+ // Strip redundant/unprocessed data units in the current block.
+ bool strip = false;
+
+ while (true) {
+ // Receive data unit.
+ int ret = knot_ctl_receive(args.ctl, &args.type, &args.data);
+ if (ret != KNOT_EOK) {
+ log_ctl_debug("control, failed to receive (%s)",
+ knot_strerror(ret));
+ mp_delete(args.mm.ctx);
+ return ret;
+ }
+
+ // Decide what to do.
+ switch (args.type) {
+ case KNOT_CTL_TYPE_DATA:
+ // Leading data unit with a command name.
+ if (!strip) {
+ // Set to strip unprocessed data unit.
+ strip = true;
+ break;
+ }
+ // FALLTHROUGH
+ case KNOT_CTL_TYPE_EXTRA:
+ // All non-first data units should be parsed in a callback.
+ // Ignore if probable previous error.
+ continue;
+ case KNOT_CTL_TYPE_BLOCK:
+ strip = false;
+ continue;
+ case KNOT_CTL_TYPE_END:
+ mp_delete(args.mm.ctx);
+ return KNOT_EOF;
+ default:
+ assert(0);
+ }
+
+ const char *cmd_name = args.data[KNOT_CTL_IDX_CMD];
+ const char *zone_name = args.data[KNOT_CTL_IDX_ZONE];
+
+ ctl_cmd_t cmd = ctl_str_to_cmd(cmd_name);
+ if (cmd != CTL_NONE) {
+ if (zone_name != NULL) {
+ log_ctl_zone_str_info(zone_name,
+ "control, received command '%s'", cmd_name);
+ } else {
+ log_ctl_info("control, received command '%s'", cmd_name);
+ }
+ ctl_log_data(&args.data);
+ } else if (cmd_name != NULL){
+ log_ctl_debug("control, invalid command '%s'", cmd_name);
+ continue;
+ } else {
+ log_ctl_debug("control, empty command");
+ continue;
+ }
+
+ // Execute the command.
+ int cmd_ret = ctl_exec(cmd, &args);
+ switch (cmd_ret) {
+ case KNOT_EOK:
+ strip = false;
+ case KNOT_CTL_ESTOP:
+ break;
+ default:
+ log_ctl_debug("control, command '%s' (%s)", cmd_name,
+ knot_strerror(cmd_ret));
+ break;
+ }
+
+ // Finalize the answer block.
+ ret = knot_ctl_send(ctl, KNOT_CTL_TYPE_BLOCK, NULL);
+ if (ret != KNOT_EOK) {
+ log_ctl_debug("control, failed to reply (%s)",
+ knot_strerror(ret));
+ }
+
+ // Stop if required.
+ if (cmd_ret == KNOT_CTL_ESTOP) {
+ // Finalize the answer message.
+ ret = knot_ctl_send(ctl, KNOT_CTL_TYPE_END, NULL);
+ if (ret != KNOT_EOK) {
+ log_ctl_debug("control, failed to reply (%s)",
+ knot_strerror(ret));
+ }
+
+ mp_delete(args.mm.ctx);
+ return cmd_ret;
+ }
+ }
+}
diff --git a/src/knot/ctl/process.h b/src/knot/ctl/process.h
new file mode 100644
index 0000000..8236bfc
--- /dev/null
+++ b/src/knot/ctl/process.h
@@ -0,0 +1,30 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "libknot/libknot.h"
+#include "knot/server/server.h"
+
+/*!
+ * Processes incoming control commands.
+ *
+ * \param[in] ctl Control context.
+ * \param[in] server Server instance.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int ctl_process(knot_ctl_t *ctl, server_t *server);
diff --git a/src/knot/dnssec/context.c b/src/knot/dnssec/context.c
new file mode 100644
index 0000000..c3c6f51
--- /dev/null
+++ b/src/knot/dnssec/context.c
@@ -0,0 +1,218 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdio.h>
+#include <string.h>
+
+#include "contrib/time.h"
+#include "libknot/libknot.h"
+#include "knot/dnssec/context.h"
+#include "knot/dnssec/kasp/keystore.h"
+
+dynarray_define(parent, knot_kasp_parent_t, DYNARRAY_VISIBILITY_PUBLIC)
+
+static void policy_load(knot_kasp_policy_t *policy, conf_val_t *id)
+{
+ if (conf_str(id) == NULL) {
+ policy->string = strdup("default");
+ } else {
+ policy->string = strdup(conf_str(id));
+ }
+
+ conf_val_t val = conf_id_get(conf(), C_POLICY, C_MANUAL, id);
+ policy->manual = conf_bool(&val);
+
+ val = conf_id_get(conf(), C_POLICY, C_SINGLE_TYPE_SIGNING, id);
+ policy->singe_type_signing = conf_bool(&val);
+
+ val = conf_id_get(conf(), C_POLICY, C_ALG, id);
+ policy->algorithm = conf_opt(&val);
+
+ val = conf_id_get(conf(), C_POLICY, C_KSK_SHARED, id);
+ policy->ksk_shared = conf_bool(&val);
+
+ val = conf_id_get(conf(), C_POLICY, C_KSK_SIZE, id);
+ int64_t num = conf_int(&val);
+ policy->ksk_size = (num != YP_NIL) ? num :
+ dnssec_algorithm_key_size_default(policy->algorithm);
+
+ val = conf_id_get(conf(), C_POLICY, C_ZSK_SIZE, id);
+ num = conf_int(&val);
+ policy->zsk_size = (num != YP_NIL) ? num :
+ dnssec_algorithm_key_size_default(policy->algorithm);
+
+ val = conf_id_get(conf(), C_POLICY, C_DNSKEY_TTL, id);
+ int64_t ttl = conf_int(&val);
+ policy->dnskey_ttl = (ttl != YP_NIL) ? ttl : UINT32_MAX;
+
+ val = conf_id_get(conf(), C_POLICY, C_ZSK_LIFETIME, id);
+ policy->zsk_lifetime = conf_int(&val);
+
+ val = conf_id_get(conf(), C_POLICY, C_KSK_LIFETIME, id);
+ policy->ksk_lifetime = conf_int(&val);
+
+ val = conf_id_get(conf(), C_POLICY, C_PROPAG_DELAY, id);
+ policy->propagation_delay = conf_int(&val);
+
+ val = conf_id_get(conf(), C_POLICY, C_RRSIG_LIFETIME, id);
+ policy->rrsig_lifetime = conf_int(&val);
+
+ val = conf_id_get(conf(), C_POLICY, C_RRSIG_REFRESH, id);
+ policy->rrsig_refresh_before = conf_int(&val);
+
+ val = conf_id_get(conf(), C_POLICY, C_NSEC3, id);
+ policy->nsec3_enabled = conf_bool(&val);
+
+ val = conf_id_get(conf(), C_POLICY, C_NSEC3_OPT_OUT, id);
+ policy->nsec3_opt_out = conf_bool(&val);
+
+ val = conf_id_get(conf(), C_POLICY, C_NSEC3_ITER, id);
+ policy->nsec3_iterations = conf_int(&val);
+
+ val = conf_id_get(conf(), C_POLICY, C_NSEC3_SALT_LEN, id);
+ policy->nsec3_salt_length = conf_int(&val);
+
+ val = conf_id_get(conf(), C_POLICY, C_NSEC3_SALT_LIFETIME, id);
+ policy->nsec3_salt_lifetime = conf_int(&val);
+
+ val = conf_id_get(conf(), C_POLICY, C_CHILD_RECORDS, id);
+ policy->child_records_publish = conf_opt(&val);
+
+ conf_val_t ksk_sbm = conf_id_get(conf(), C_POLICY, C_KSK_SBM, id);
+ if (ksk_sbm.code == KNOT_EOK) {
+ val = conf_id_get(conf(), C_SBM, C_CHK_INTERVAL, &ksk_sbm);
+ policy->ksk_sbm_check_interval = conf_int(&val);
+
+ val = conf_id_get(conf(), C_SBM, C_TIMEOUT, &ksk_sbm);
+ policy->ksk_sbm_timeout = conf_int(&val);
+
+ val = conf_id_get(conf(), C_SBM, C_PARENT, &ksk_sbm);
+ while (val.code == KNOT_EOK) {
+ conf_val_t addr = conf_id_get(conf(), C_RMT, C_ADDR, &val);
+ knot_kasp_parent_t p = { .addrs = conf_val_count(&addr) };
+ p.addr = p.addrs ? malloc(p.addrs * sizeof(*p.addr)) : NULL;
+ if (p.addr != NULL) {
+ for (size_t i = 0; i < p.addrs; i++) {
+ p.addr[i] = conf_remote(conf(), &val, i);
+ }
+ parent_dynarray_add(&policy->parents, &p);
+ }
+ conf_val_next(&val);
+ }
+ }
+}
+
+int kdnssec_ctx_init(conf_t *conf, kdnssec_ctx_t *ctx, const knot_dname_t *zone_name,
+ const conf_mod_id_t *from_module)
+{
+ if (ctx == NULL || zone_name == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int ret;
+
+ memset(ctx, 0, sizeof(*ctx));
+
+ ctx->zone = calloc(1, sizeof(*ctx->zone));
+ if (ctx->zone == NULL) {
+ ret = KNOT_ENOMEM;
+ goto init_error;
+ }
+ ctx->kasp_db = kaspdb();
+
+ ret = kasp_db_open(*ctx->kasp_db);
+ if (ret != KNOT_EOK) {
+ goto init_error;
+ }
+
+ ret = kasp_zone_load(ctx->zone, zone_name, *ctx->kasp_db);
+ if (ret != KNOT_EOK) {
+ goto init_error;
+ }
+
+ ctx->kasp_zone_path = conf_kaspdir(conf);
+ if (ctx->kasp_zone_path == NULL) {
+ ret = KNOT_ENOMEM;
+ goto init_error;
+ }
+
+ ctx->policy = calloc(1, sizeof(*ctx->policy));
+ if (ctx->policy == NULL) {
+ ret = KNOT_ENOMEM;
+ goto init_error;
+ }
+
+ conf_val_t policy_id;
+ if (from_module == NULL) {
+ policy_id = conf_zone_get(conf, C_DNSSEC_POLICY, zone_name);
+ } else {
+ policy_id = conf_mod_get(conf, C_POLICY, from_module);
+ }
+ conf_id_fix_default(&policy_id);
+ policy_load(ctx->policy, &policy_id);
+
+ conf_val_t keystore_id = conf_id_get(conf, C_POLICY, C_KEYSTORE, &policy_id);
+ conf_id_fix_default(&keystore_id);
+
+ conf_val_t val = conf_id_get(conf, C_KEYSTORE, C_BACKEND, &keystore_id);
+ unsigned backend = conf_opt(&val);
+
+ val = conf_id_get(conf, C_KEYSTORE, C_CONFIG, &keystore_id);
+ const char *config = conf_str(&val);
+
+ ret = keystore_load(config, backend, ctx->kasp_zone_path, &ctx->keystore);
+ if (ret != KNOT_EOK) {
+ goto init_error;
+ }
+
+ ctx->now = knot_time();
+
+ return KNOT_EOK;
+init_error:
+ kdnssec_ctx_deinit(ctx);
+ return ret;
+}
+
+int kdnssec_ctx_commit(kdnssec_ctx_t *ctx)
+{
+ if (ctx == NULL || ctx->kasp_zone_path == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ // do something with keytore? Probably not..
+
+ return kasp_zone_save(ctx->zone, ctx->zone->dname, *ctx->kasp_db);
+}
+
+void kdnssec_ctx_deinit(kdnssec_ctx_t *ctx)
+{
+ if (ctx == NULL) {
+ return;
+ }
+
+ if (ctx->policy != NULL) {
+ free(ctx->policy->string);
+ dynarray_foreach(parent, knot_kasp_parent_t, i, ctx->policy->parents) {
+ free(i->addr);
+ }
+ free(ctx->policy);
+ }
+ dnssec_keystore_deinit(ctx->keystore);
+ kasp_zone_free(&ctx->zone);
+ free(ctx->kasp_zone_path);
+
+ memset(ctx, 0, sizeof(*ctx));
+}
diff --git a/src/knot/dnssec/context.h b/src/knot/dnssec/context.h
new file mode 100644
index 0000000..77174c2
--- /dev/null
+++ b/src/knot/dnssec/context.h
@@ -0,0 +1,62 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <time.h>
+
+#include "libdnssec/keystore.h"
+
+#include "knot/conf/conf.h"
+#include "knot/dnssec/kasp/kasp_zone.h"
+#include "knot/dnssec/kasp/policy.h"
+
+/*!
+ * \brief DNSSEC signing context.
+ */
+typedef struct {
+ knot_time_t now;
+
+ kasp_db_t **kasp_db;
+ knot_kasp_zone_t *zone;
+ knot_kasp_policy_t *policy;
+ dnssec_keystore_t *keystore;
+
+ char *kasp_zone_path;
+
+ bool rrsig_drop_existing;
+} kdnssec_ctx_t;
+
+/*!
+ * \brief Initialize DNSSEC signing context.
+ *
+ * \param conf Configuration.
+ * \param ctx Signing context to be initialized.
+ * \param zone_name Name of the zone.
+ * \param from_module Module identifier if initialized from a module.
+ */
+int kdnssec_ctx_init(conf_t *conf, kdnssec_ctx_t *ctx, const knot_dname_t *zone_name,
+ const conf_mod_id_t *from_module);
+
+/*!
+ * \brief Save the changes in ctx (in kasp zone).
+ */
+int kdnssec_ctx_commit(kdnssec_ctx_t *ctx);
+
+/*!
+ * \brief Cleanup DNSSEC signing context.
+ */
+void kdnssec_ctx_deinit(kdnssec_ctx_t *ctx);
diff --git a/src/knot/dnssec/ds_query.c b/src/knot/dnssec/ds_query.c
new file mode 100644
index 0000000..89e5c4a
--- /dev/null
+++ b/src/knot/dnssec/ds_query.c
@@ -0,0 +1,244 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "contrib/macros.h"
+#include "knot/common/log.h"
+#include "knot/conf/conf.h"
+#include "knot/dnssec/ds_query.h"
+#include "knot/dnssec/key-events.h"
+#include "knot/query/layer.h"
+#include "knot/query/query.h"
+#include "knot/query/requestor.h"
+
+static bool match_key_ds(zone_key_t *key, knot_rdata_t *ds)
+{
+ assert(key);
+ assert(ds);
+
+ dnssec_binary_t ds_rdata = {
+ .size = ds->len,
+ .data = ds->data,
+ };
+
+ dnssec_binary_t cds_rdata = { 0 };
+
+ int ret = zone_key_calculate_ds(key, &cds_rdata);
+ if (ret != KNOT_EOK) {
+ return false;
+ }
+
+ return (dnssec_binary_cmp(&cds_rdata, &ds_rdata) == 0);
+}
+
+struct ds_query_data {
+ const knot_dname_t *zone_name;
+ const struct sockaddr *remote;
+
+ zone_key_t *key;
+
+ uint16_t edns_max_payload;
+
+ bool ds_ok;
+ bool result_logged;
+
+ uint32_t ttl;
+};
+
+static int ds_query_begin(knot_layer_t *layer, void *params)
+{
+ layer->data = params;
+
+ return KNOT_STATE_PRODUCE;
+}
+
+static int ds_query_produce(knot_layer_t *layer, knot_pkt_t *pkt)
+{
+ struct ds_query_data *data = layer->data;
+ struct query_edns_data edns = { .max_payload = data->edns_max_payload, .do_flag = true, };
+
+ query_init_pkt(pkt);
+
+ int r = knot_pkt_put_question(pkt, data->zone_name, KNOT_CLASS_IN, KNOT_RRTYPE_DS);
+ if (r != KNOT_EOK) {
+ return KNOT_STATE_FAIL;
+ }
+
+ r = query_put_edns(pkt, &edns);
+ if (r != KNOT_EOK) {
+ return KNOT_STATE_FAIL;
+ }
+
+ knot_wire_set_rd(pkt->wire);
+
+ return KNOT_STATE_CONSUME;
+}
+
+static int ds_query_consume(knot_layer_t *layer, knot_pkt_t *pkt)
+{
+ struct ds_query_data *data = layer->data;
+ data->result_logged = true;
+
+ uint16_t rcode = knot_pkt_ext_rcode(pkt);
+ if (rcode != KNOT_RCODE_NOERROR) {
+ ns_log((rcode == KNOT_RCODE_NXDOMAIN ? LOG_NOTICE : LOG_WARNING),
+ data->zone_name, LOG_OPERATION_PARENT,
+ LOG_DIRECTION_OUT, data->remote, "failed (%s)", knot_pkt_ext_rcode_name(pkt));
+ return KNOT_STATE_FAIL;
+ }
+
+ const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER);
+
+ bool match = false;
+
+ for (size_t j = 0; j < answer->count; j++) {
+ const knot_rrset_t *rr = knot_pkt_rr(answer, j);
+ switch ((rr && rr->rrs.count > 0) ? rr->type : 0) {
+ case KNOT_RRTYPE_DS:
+ if (match_key_ds(data->key, rr->rrs.rdata)) {
+ match = true;
+ if (data->ttl == 0) { // fallback: if there is no RRSIG
+ data->ttl = rr->ttl;
+ }
+ }
+ break;
+ case KNOT_RRTYPE_RRSIG:
+ data->ttl = knot_rrsig_original_ttl(rr->rrs.rdata);
+ break;
+ default:
+ break;
+ }
+ }
+
+ ns_log(LOG_INFO, data->zone_name, LOG_OPERATION_PARENT,
+ LOG_DIRECTION_OUT, data->remote, "KSK submission attempt: %s",
+ (match ? "positive" : "negative"));
+
+ if (match) {
+ data->ds_ok = true;
+ }
+ return KNOT_STATE_DONE;
+}
+
+static const knot_layer_api_t ds_query_api = {
+ .begin = ds_query_begin,
+ .produce = ds_query_produce,
+ .consume = ds_query_consume,
+ .reset = NULL,
+ .finish = NULL,
+};
+
+static int try_ds(const knot_dname_t *zone_name, const conf_remote_t *parent, zone_key_t *key,
+ size_t timeout, uint32_t *ds_ttl)
+{
+ // TODO: Abstract interface to issue DNS queries. This is almost copy-pasted.
+
+ assert(zone_name);
+ assert(parent);
+
+ struct ds_query_data data = {
+ .zone_name = zone_name,
+ .remote = (struct sockaddr *)&parent->addr,
+ .key = key,
+ .ds_ok = false,
+ .result_logged = false,
+ .ttl = 0,
+ };
+
+ struct knot_requestor requestor;
+ knot_requestor_init(&requestor, &ds_query_api, &data, NULL);
+
+ knot_pkt_t *pkt = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, NULL);
+ if (!pkt) {
+ knot_requestor_clear(&requestor);
+ return KNOT_ENOMEM;
+ }
+
+ const struct sockaddr *dst = (struct sockaddr *)&parent->addr;
+ const struct sockaddr *src = (struct sockaddr *)&parent->via;
+ struct knot_request *req = knot_request_make(NULL, dst, src, pkt, &parent->key, 0);
+ if (!req) {
+ knot_request_free(req, NULL);
+ knot_requestor_clear(&requestor);
+ return KNOT_ENOMEM;
+ }
+
+ data.edns_max_payload = dst->sa_family == AF_INET6 ?
+ conf()->cache.srv_max_ipv6_udp_payload :
+ conf()->cache.srv_max_ipv4_udp_payload;
+
+ int ret = knot_requestor_exec(&requestor, req, timeout);
+ knot_request_free(req, NULL);
+ knot_requestor_clear(&requestor);
+
+ // alternative: we could put answer back through ctx instead of errcode
+ if (ret == KNOT_EOK && !data.ds_ok) {
+ ret = KNOT_ENORECORD;
+ }
+
+ if (ret != KNOT_EOK && !data.result_logged) {
+ ns_log(LOG_WARNING, zone_name, LOG_OPERATION_PARENT,
+ LOG_DIRECTION_OUT, data.remote, "failed (%s)", knot_strerror(ret));
+ }
+
+ *ds_ttl = data.ttl;
+
+ return ret;
+}
+
+static bool parents_have_ds(kdnssec_ctx_t *kctx, zone_key_t *key, size_t timeout,
+ uint32_t *max_ds_ttl)
+{
+ bool success = false;
+ dynarray_foreach(parent, knot_kasp_parent_t, i, kctx->policy->parents) {
+ success = false;
+ for (size_t j = 0; j < i->addrs; j++) {
+ uint32_t ds_ttl = 0;
+ int ret = try_ds(kctx->zone->dname, &i->addr[j], key, timeout, &ds_ttl);
+ if (ret == KNOT_EOK) {
+ *max_ds_ttl = MAX(*max_ds_ttl, ds_ttl);
+ success = true;
+ break;
+ } else if (ret == KNOT_ENORECORD) {
+ // parent was queried successfully, answer was negative
+ break;
+ }
+ }
+ // Each parent must succeed.
+ if (!success) {
+ return false;
+ }
+ }
+ return success;
+}
+
+int knot_parent_ds_query(kdnssec_ctx_t *kctx, zone_keyset_t *keyset, size_t timeout)
+{
+ uint32_t max_ds_ttl = 0;
+
+ for (size_t i = 0; i < keyset->count; i++) {
+ zone_key_t *key = &keyset->keys[i];
+ if (key->is_ksk && key->cds_priority > 1) {
+ if (parents_have_ds(kctx, key, timeout, &max_ds_ttl)) {
+ return knot_dnssec_ksk_sbm_confirm(kctx, max_ds_ttl);
+ } else {
+ return KNOT_ENOENT;
+ }
+ }
+ }
+ return KNOT_ENOENT;
+}
diff --git a/src/knot/dnssec/ds_query.h b/src/knot/dnssec/ds_query.h
new file mode 100644
index 0000000..5ef40a4
--- /dev/null
+++ b/src/knot/dnssec/ds_query.h
@@ -0,0 +1,22 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "knot/dnssec/zone-keys.h"
+#include "knot/dnssec/context.h"
+
+int knot_parent_ds_query(kdnssec_ctx_t *kctx, zone_keyset_t *keyset, size_t timeout);
diff --git a/src/knot/dnssec/kasp/kasp_db.c b/src/knot/dnssec/kasp/kasp_db.c
new file mode 100644
index 0000000..7b48115
--- /dev/null
+++ b/src/knot/dnssec/kasp/kasp_db.c
@@ -0,0 +1,751 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "knot/dnssec/kasp/kasp_db.h"
+
+#include <stdarg.h> // just for va_free()
+#include <pthread.h>
+#include <sys/stat.h>
+
+#include "contrib/files.h"
+#include "contrib/wire_ctx.h"
+
+struct kasp_db {
+ knot_db_t *keys_db;
+ char *db_path;
+ size_t db_mapsize;
+ pthread_mutex_t opening_mutex;
+};
+
+typedef enum {
+ KASPDBKEY_PARAMS = 0x1,
+ KASPDBKEY_POLICYLAST = 0x2,
+ KASPDBKEY_NSEC3SALT = 0x3,
+ KASPDBKEY_NSEC3TIME = 0x4,
+ KASPDBKEY_MASTERSERIAL = 0x5,
+ KASPDBKEY_LASTSIGNEDSERIAL = 0x6,
+} keyclass_t;
+
+static const knot_db_api_t *db_api = NULL;
+
+static kasp_db_t *global_kasp_db = NULL;
+
+kasp_db_t **kaspdb(void)
+{
+ return &global_kasp_db;
+}
+
+int kasp_db_init(kasp_db_t **db, const char *path, size_t mapsize)
+{
+ if (db == NULL || path == NULL || *db != NULL) {
+ return KNOT_EINVAL;
+ }
+
+ db_api = knot_db_lmdb_api();
+
+ *db = calloc(1, sizeof(**db));
+ if (*db == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ (*db)->db_path = strdup(path);
+ if ((*db)->db_path == NULL) {
+ free(*db);
+ return KNOT_ENOMEM;
+ }
+
+ (*db)->db_mapsize = mapsize;
+
+ pthread_mutex_init(&(*db)->opening_mutex, NULL);
+ return KNOT_EOK;
+}
+
+int kasp_db_reconfigure(kasp_db_t **db, const char *new_path, size_t new_mapsize)
+{
+ if (db == NULL || new_path == NULL || *db == NULL || (*db)->db_path == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ pthread_mutex_lock(&(*db)->opening_mutex);
+
+ bool changed_path = (strcmp(new_path, (*db)->db_path) != 0);
+ bool changed_mapsize = (new_mapsize != (*db)->db_mapsize);
+
+ if ((*db)->keys_db != NULL) {
+ pthread_mutex_unlock(&(*db)->opening_mutex);
+ if (changed_path) {
+ return KNOT_EBUSY;
+ } else if (changed_mapsize) {
+ return KNOT_EEXIST;
+ } else {
+ return KNOT_ENODIFF;
+ }
+ }
+
+ free((*db)->db_path);
+ (*db)->db_path = strdup(new_path);
+ if ((*db)->db_path == NULL) {
+ pthread_mutex_unlock(&(*db)->opening_mutex);
+ return KNOT_ENOMEM;
+ }
+ (*db)->db_mapsize = new_mapsize;
+
+ pthread_mutex_unlock(&(*db)->opening_mutex);
+ return KNOT_EOK;
+}
+
+bool kasp_db_exists(kasp_db_t *db)
+{
+ if (db->keys_db == NULL) {
+ struct stat st;
+ if (stat(db->db_path, &st) != 0) {
+ return false;
+ }
+ }
+ return true;
+}
+
+int kasp_db_open(kasp_db_t *db)
+{
+ if (db == NULL || db->db_path == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ pthread_mutex_lock(&db->opening_mutex);
+
+ if (db->keys_db != NULL) {
+ pthread_mutex_unlock(&db->opening_mutex);
+ return KNOT_EOK; // already open
+ }
+
+ int ret = make_dir(db->db_path, S_IRWXU | S_IRGRP | S_IXGRP, true);
+ if (ret != KNOT_EOK) {
+ pthread_mutex_unlock(&db->opening_mutex);
+ return ret;
+ }
+
+ struct knot_db_lmdb_opts opts = KNOT_DB_LMDB_OPTS_INITIALIZER;
+ opts.path = db->db_path;
+ opts.mapsize = db->db_mapsize;
+ opts.maxdbs = 1;
+ opts.dbname = "keys_db";
+
+ ret = db_api->init(&db->keys_db, NULL, &opts);
+ if (ret != KNOT_EOK) {
+ pthread_mutex_unlock(&db->opening_mutex);
+ return ret;
+ }
+
+ pthread_mutex_unlock(&db->opening_mutex);
+
+ return ret;
+}
+
+void kasp_db_close(kasp_db_t **db)
+{
+ if (db != NULL && *db != NULL) {
+ pthread_mutex_lock(&(*db)->opening_mutex);
+ db_api->deinit((*db)->keys_db);
+ (*db)->keys_db = NULL;
+ pthread_mutex_unlock(&(*db)->opening_mutex);
+ free((*db)->db_path);
+ pthread_mutex_destroy(&(*db)->opening_mutex);
+ free(*db);
+ *db = NULL;
+ }
+}
+
+static knot_db_val_t make_key(keyclass_t kclass, const knot_dname_t *dname, const char *str)
+{
+ size_t dnlen = knot_dname_size(dname);
+ size_t slen = (str == NULL ? 0 : strlen(str) + 1);
+ knot_db_val_t res = { .len = 1 + dnlen + slen, .data = malloc(1 + dnlen + slen) };
+ if (res.data != NULL) {
+ wire_ctx_t wire = wire_ctx_init(res.data, res.len);
+ wire_ctx_write_u8(&wire, (uint8_t)kclass);
+ wire_ctx_write(&wire, dname, dnlen);
+ wire_ctx_write(&wire, str, slen);
+ } else {
+ res.len = 0;
+ }
+ return res;
+}
+
+static void free_key(knot_db_val_t *key)
+{
+ free(key->data);
+ memset(key, 0, sizeof(*key));
+}
+
+static char *keyid_fromkey(const knot_db_val_t *key)
+{
+ if (key->len < 2 || *(uint8_t *)key->data != KASPDBKEY_PARAMS) {
+ return NULL;
+ }
+ size_t skip = knot_dname_size((const uint8_t *)key->data + 1);
+ return (key->len < skip + 2 ? NULL : strdup(key->data + skip + 1));
+}
+
+static bool check_key_zone(const knot_db_val_t *key, const knot_dname_t *zone_name)
+{
+ if (key->len < 2 || *(uint8_t *)key->data == KASPDBKEY_POLICYLAST) {
+ return false;
+ }
+ return knot_dname_is_equal(key->data + 1, zone_name);
+}
+
+static int serialize_key_params(const key_params_t *params, const knot_dname_t *dname, knot_db_val_t *key, knot_db_val_t *val)
+{
+ assert(params != NULL);
+ assert(dname != NULL);
+ assert(key != NULL);
+ assert(val != NULL);
+
+ *key = make_key(KASPDBKEY_PARAMS, dname, params->id);
+ val->len = sizeof(uint16_t) + 2 * sizeof(uint8_t) + 11 * sizeof(uint64_t) +
+ params->public_key.size;
+ val->data = malloc(val->len);
+ if (val->data == NULL) {
+ free(key->data);
+ key->data = NULL;
+ key->len = 0;
+ return KNOT_ENOMEM;
+ }
+ wire_ctx_t wire = wire_ctx_init(val->data, val->len);
+
+ wire_ctx_write_u64(&wire, params->public_key.size);
+ wire_ctx_write_u64(&wire, 0); // length of Unused-future block at the end
+ wire_ctx_write_u16(&wire, params->keytag);
+ wire_ctx_write_u8(&wire, params->algorithm);
+ uint8_t flags = 0x02;
+ flags |= (params->is_ksk ? 0x01 : 0);
+ flags |= (params->is_pub_only ? 0x04 : 0);
+ flags |= (params->is_csk ? 0x08 : 0);
+ wire_ctx_write_u8(&wire, flags);
+ wire_ctx_write_u64(&wire, (uint64_t)params->timing.created);
+ wire_ctx_write_u64(&wire, (uint64_t)params->timing.pre_active);
+ wire_ctx_write_u64(&wire, (uint64_t)params->timing.publish);
+ wire_ctx_write_u64(&wire, (uint64_t)params->timing.ready);
+ wire_ctx_write_u64(&wire, (uint64_t)params->timing.active);
+ wire_ctx_write_u64(&wire, (uint64_t)params->timing.retire_active);
+ wire_ctx_write_u64(&wire, (uint64_t)params->timing.retire);
+ wire_ctx_write_u64(&wire, (uint64_t)params->timing.post_active);
+ wire_ctx_write_u64(&wire, (uint64_t)params->timing.remove);
+ wire_ctx_write(&wire, params->public_key.data, params->public_key.size);
+
+ if (wire.error != KNOT_EOK) {
+ free(key->data);
+ free(val->data);
+ key->data = NULL;
+ key->len = 0;
+ val->data = NULL;
+ val->len = 0;
+ return KNOT_ERROR;
+ }
+ return KNOT_EOK;
+}
+
+static int deserialize_key_params(key_params_t *params, const knot_db_val_t *key, const knot_db_val_t *val)
+{
+ assert(params != NULL);
+ assert(key != NULL);
+ assert(val != NULL);
+ assert(key->data != NULL);
+ assert(val->data != NULL);
+ assert(val->len >= sizeof(uint64_t));
+
+ wire_ctx_t wire = wire_ctx_init_const(val->data, val->len);
+ params->public_key.size = wire_ctx_read_u64(&wire);
+ uint64_t unused_future_length = wire_ctx_read_u64(&wire);
+ params->keytag = wire_ctx_read_u16(&wire);
+ params->algorithm = wire_ctx_read_u8(&wire);
+ uint8_t isksk_plus_flags = wire_ctx_read_u8(&wire);
+ params->is_ksk = ((isksk_plus_flags & (uint8_t)0x01) != (uint8_t)0x00);
+ params->is_pub_only = ((isksk_plus_flags & (uint8_t)0x04) != (uint8_t)0x00);
+ params->is_csk = ((isksk_plus_flags & (uint8_t)0x08) != (uint8_t)0x00);
+ if (params->is_csk && !params->is_ksk) {
+ return KNOT_EMALF;
+ }
+ if ((isksk_plus_flags & (uint8_t)0x02) != (uint8_t)0x00) {
+ params->timing.created = (knot_time_t)wire_ctx_read_u64(&wire);
+ params->timing.pre_active = (knot_time_t)wire_ctx_read_u64(&wire);
+ params->timing.publish = (knot_time_t)wire_ctx_read_u64(&wire);
+ params->timing.ready = (knot_time_t)wire_ctx_read_u64(&wire);
+ params->timing.active = (knot_time_t)wire_ctx_read_u64(&wire);
+ params->timing.retire_active = (knot_time_t)wire_ctx_read_u64(&wire);
+ params->timing.retire = (knot_time_t)wire_ctx_read_u64(&wire);
+ params->timing.post_active = (knot_time_t)wire_ctx_read_u64(&wire);
+ params->timing.remove = (knot_time_t)wire_ctx_read_u64(&wire);
+ } else {
+ // import of old kasp db format missing some timers
+ params->timing.created = (knot_time_t)wire_ctx_read_u64(&wire);
+ params->timing.pre_active = 0;
+ params->timing.publish = (knot_time_t)wire_ctx_read_u64(&wire);
+ params->timing.ready = (knot_time_t)wire_ctx_read_u64(&wire);
+ params->timing.active = (knot_time_t)wire_ctx_read_u64(&wire);
+ params->timing.retire_active = 0;
+ params->timing.retire = (knot_time_t)wire_ctx_read_u64(&wire);
+ params->timing.post_active = 0;
+ params->timing.remove = (knot_time_t)wire_ctx_read_u64(&wire);
+ }
+ if (wire.error != KNOT_EOK) {
+ return KNOT_ERROR;
+ }
+
+ free(params->public_key.data);
+ params->public_key.data = malloc(params->public_key.size);
+ if (params->public_key.data == NULL) {
+ return KNOT_ENOMEM;
+ }
+ wire_ctx_read(&wire, params->public_key.data, params->public_key.size);
+
+ free(params->id);
+ params->id = keyid_fromkey(key);
+ if (params->id == NULL) {
+ wire.error = KNOT_EMALF;
+ }
+
+ if (wire.error != KNOT_EOK || wire_ctx_available(&wire) != unused_future_length) {
+ free(params->id);
+ free(params->public_key.data);
+ params->id = NULL;
+ params->public_key.data = NULL;
+ params->public_key.size = 0;
+ return KNOT_EMALF;
+ }
+ return KNOT_EOK;
+}
+
+static key_params_t *keyval2params(const knot_db_val_t *key, const knot_db_val_t *val)
+{
+ key_params_t *res = calloc(1, sizeof(*res));
+ if (res != NULL) {
+ if (deserialize_key_params(res, key, val) != KNOT_EOK) {
+ free(res);
+ return NULL;
+ }
+ }
+ return res;
+}
+
+#define txn_check(...) \
+ if (ret != KNOT_EOK) { \
+ db_api->txn_abort(txn); \
+ va_free(NULL, __VA_ARGS__); \
+ return ret; \
+ } \
+
+#define with_txn(what, ...) \
+ int ret = KNOT_EOK; \
+ knot_db_txn_t local_txn, *txn = &local_txn; \
+ ret = db_api->txn_begin(db->keys_db, txn, (what & 0x1) ? 0 : KNOT_DB_RDONLY); \
+ txn_check(__VA_ARGS__); \
+
+#define with_txn_end(...) \
+ txn_check(__VA_ARGS__); \
+ ret = db_api->txn_commit(txn); \
+ if (ret != KNOT_EOK) { \
+ db_api->txn_abort(txn); \
+ } \
+
+#define KEYS_RO 0x0
+#define KEYS_RW 0x1
+
+// TODO move elsewhere
+static void va_free(void *p, ...)
+{
+ va_list args;
+ va_start(args, p);
+ for (void *f = p; f != NULL; f = va_arg(args, void *)) {
+ free(f);
+ }
+ va_end(args);
+}
+
+int kasp_db_list_keys(kasp_db_t *db, const knot_dname_t *zone_name, list_t *dst)
+{
+ if (db == NULL || db->keys_db == NULL || zone_name == NULL || dst == NULL) {
+ return KNOT_ENOENT;
+ }
+
+ knot_db_val_t key = make_key(KASPDBKEY_PARAMS, zone_name, NULL), val = { 0 };
+
+ with_txn(KEYS_RO, NULL);
+ knot_db_iter_t *iter = db_api->iter_begin(txn, KNOT_DB_NOOP);
+ if (iter != NULL) {
+ iter = db_api->iter_seek(iter, &key, KNOT_DB_GEQ);
+ }
+ free_key(&key);
+
+ init_list(dst);
+ while (iter != NULL && ret == KNOT_EOK) {
+ ret = db_api->iter_key(iter, &key);
+ if (ret != KNOT_EOK || *(uint8_t *)key.data != KASPDBKEY_PARAMS || !check_key_zone(&key, zone_name)) {
+ break;
+ }
+ ret = db_api->iter_val(iter, &val);
+ if (ret == KNOT_EOK) {
+ key_params_t *parm = keyval2params(&key, &val);
+ if (parm != NULL) {
+ ptrlist_add(dst, parm, NULL);
+ }
+ iter = db_api->iter_next(iter);
+ }
+ }
+ db_api->iter_finish(iter);
+ db_api->txn_abort(txn);
+
+ if (ret != KNOT_EOK) {
+ ptrlist_deep_free(dst, NULL);
+ return ret;
+ }
+ return (EMPTY_LIST(*dst) ? KNOT_ENOENT : KNOT_EOK);
+}
+
+static bool keyid_inuse(knot_db_txn_t *txn, const char *key_id, key_params_t **optional)
+{
+ knot_db_iter_t *iter = db_api->iter_begin(txn, KNOT_DB_FIRST);
+ while (iter != NULL) {
+ knot_db_val_t key, val;
+ if (db_api->iter_key(iter, &key) == KNOT_EOK && *(uint8_t *)key.data == KASPDBKEY_PARAMS) {
+ char *keyid = keyid_fromkey(&key);
+ if (keyid != NULL && strcmp(keyid, key_id) == 0) {
+ if (optional != NULL && db_api->iter_val(iter, &val) == KNOT_EOK) {
+ *optional = keyval2params(&key, &val);
+ }
+ db_api->iter_finish(iter);
+ free(keyid);
+ return true;
+ }
+ free(keyid);
+ }
+ iter = db_api->iter_next(iter);
+ }
+ db_api->iter_finish(iter);
+ return false;
+}
+
+int kasp_db_delete_key(kasp_db_t *db, const knot_dname_t *zone_name, const char *key_id, bool *still_used)
+{
+ if (db == NULL || db->keys_db == NULL || zone_name == NULL || key_id == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ knot_db_val_t key = make_key(KASPDBKEY_PARAMS, zone_name, key_id);
+
+ with_txn(KEYS_RW, key.data, NULL);
+ ret = db_api->del(txn, &key);
+ free_key(&key);
+ if (still_used != NULL) {
+ *still_used = keyid_inuse(txn, key_id, NULL);
+ }
+ with_txn_end(NULL, NULL);
+ return ret;
+}
+
+int kasp_db_delete_all(kasp_db_t *db, const knot_dname_t *zone_name)
+{
+ list_t allkeys;
+ init_list(&allkeys);
+ int r = kasp_db_list_keys(db, zone_name, &allkeys);
+ if (r != KNOT_EOK) {
+ return r;
+ }
+
+ with_txn(KEYS_RW, NULL);
+
+ ptrnode_t *n;
+ WALK_LIST(n, allkeys) {
+ key_params_t *parm = n->d;
+ knot_db_val_t key = make_key(KASPDBKEY_PARAMS, zone_name, parm->id);
+ (void)db_api->del(txn, &key);
+ free_key(&key);
+ free(parm->id);
+ free(parm->public_key.data);
+ memset(parm, 0, sizeof(*parm));
+ }
+ ptrlist_deep_free(&allkeys, NULL);
+
+ for (keyclass_t keyclass = KASPDBKEY_NSEC3SALT; keyclass <= KASPDBKEY_LASTSIGNEDSERIAL; keyclass++) {
+ knot_db_val_t key = make_key(keyclass, zone_name, NULL);
+ (void)db_api->del(txn, &key);
+ free_key(&key);
+ }
+
+ with_txn_end(NULL, NULL);
+ return ret;
+}
+
+int kasp_db_add_key(kasp_db_t *db, const knot_dname_t *zone_name, const key_params_t *params)
+{
+ if (db == NULL || db->keys_db == NULL || zone_name == NULL || params == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ knot_db_val_t key = { 0 }, val = { 0 };
+
+ with_txn(KEYS_RW, NULL);
+ ret = serialize_key_params(params, zone_name, &key, &val);
+ txn_check(NULL);
+ ret = db_api->insert(txn, &key, &val, 0);
+ free_key(&key);
+ free_key(&val);
+ with_txn_end(NULL, NULL);
+ return ret;
+}
+
+int kasp_db_share_key(kasp_db_t *db, const knot_dname_t *zone_from, const knot_dname_t *zone_to, const char *key_id)
+{
+ if (db == NULL || db->keys_db == NULL || zone_from == NULL ||
+ zone_to == NULL || key_id == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ knot_db_val_t key_from = make_key(KASPDBKEY_PARAMS, zone_from, key_id),
+ key_to = make_key(KASPDBKEY_PARAMS, zone_to, key_id), val = { 0 };
+
+ with_txn(KEYS_RW, NULL);
+ ret = db_api->find(txn, &key_from, &val, 0);
+ txn_check(txn, key_from.data, key_to.data, NULL);
+ ret = db_api->insert(txn, &key_to, &val, 0);
+ free_key(&key_from);
+ free_key(&key_to);
+ with_txn_end(NULL);
+ return ret;
+}
+
+int kasp_db_store_nsec3salt(kasp_db_t *db, const knot_dname_t *zone_name,
+ const dnssec_binary_t *nsec3salt, knot_time_t salt_created)
+{
+ if (db == NULL || db->keys_db == NULL ||
+ zone_name == NULL || nsec3salt == NULL || salt_created <= 0) {
+ return KNOT_EINVAL;
+ }
+
+ with_txn(KEYS_RW, NULL);
+ knot_db_val_t key = make_key(KASPDBKEY_NSEC3SALT, zone_name, NULL);
+ knot_db_val_t val = { .len = nsec3salt->size, .data = nsec3salt->data };
+ ret = db_api->insert(txn, &key, &val, 0);
+ free_key(&key);
+ txn_check(NULL);
+ key = make_key(KASPDBKEY_NSEC3TIME, zone_name, NULL);
+ uint64_t tmp = htobe64((uint64_t)salt_created);
+ val.len = sizeof(tmp);
+ val.data = &tmp;
+ ret = db_api->insert(txn, &key, &val, 0);
+ free_key(&key);
+ with_txn_end(NULL);
+ return ret;
+}
+
+int kasp_db_load_nsec3salt(kasp_db_t *db, const knot_dname_t *zone_name,
+ dnssec_binary_t *nsec3salt, knot_time_t *salt_created)
+{
+ if (db == NULL || db->keys_db == NULL ||
+ zone_name == NULL || nsec3salt == NULL || salt_created == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ with_txn(KEYS_RW, NULL);
+ knot_db_val_t key = make_key(KASPDBKEY_NSEC3TIME, zone_name, NULL), val = { 0 };
+ ret = db_api->find(txn, &key, &val, 0);
+ free_key(&key);
+ if (ret == KNOT_EOK) {
+ if (val.len == sizeof(uint64_t)) {
+ *salt_created = (knot_time_t)be64toh(*(uint64_t *)val.data);
+ }
+ else {
+ ret = KNOT_EMALF;
+ }
+ }
+ txn_check(NULL);
+ key = make_key(KASPDBKEY_NSEC3SALT, zone_name, NULL);
+ ret = db_api->find(txn, &key, &val, 0);
+ free_key(&key);
+ if (ret == KNOT_EOK) {
+ nsec3salt->data = malloc(val.len);
+ if (nsec3salt->data == NULL) {
+ ret = KNOT_ENOMEM;
+ } else {
+ nsec3salt->size = val.len;
+ memcpy(nsec3salt->data, val.data, val.len);
+ }
+ }
+ with_txn_end(NULL);
+ return ret;
+}
+
+int kasp_db_store_serial(kasp_db_t *db, const knot_dname_t *zone_name,
+ kaspdb_serial_t serial_type, uint32_t serial)
+{
+ if (db == NULL || db->keys_db == NULL || zone_name == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ uint32_t be = htobe32(serial);
+ with_txn(KEYS_RW, NULL);
+ knot_db_val_t key = make_key((keyclass_t)serial_type, zone_name, NULL);
+ knot_db_val_t val = { .len = sizeof(uint32_t), .data = &be };
+ ret = db_api->insert(txn, &key, &val, 0);
+ free_key(&key);
+ with_txn_end(NULL);
+ return ret;
+}
+
+int kasp_db_load_serial(kasp_db_t *db, const knot_dname_t *zone_name,
+ kaspdb_serial_t serial_type, uint32_t *serial)
+{
+ if (db == NULL || db->keys_db == NULL || zone_name == NULL || serial == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ with_txn(KEYS_RO, NULL);
+ knot_db_val_t key = make_key((keyclass_t)serial_type, zone_name, NULL), val = { 0 };
+ ret = db_api->find(txn, &key, &val, 0);
+ free_key(&key);
+ if (ret == KNOT_EOK) {
+ if (val.len == sizeof(uint32_t)) {
+ *serial = be32toh(*(uint32_t *)val.data);
+ } else {
+ ret = KNOT_EMALF;
+ }
+ }
+ with_txn_end(NULL);
+ return ret;
+}
+
+int kasp_db_get_policy_last(kasp_db_t *db, const char *policy_string, knot_dname_t **lp_zone,
+ char **lp_keyid)
+{
+ if (db == NULL || db->keys_db == NULL || policy_string == NULL ||
+ lp_zone == NULL || lp_keyid == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ with_txn(KEYS_RO, NULL);
+ knot_db_val_t key = make_key(KASPDBKEY_POLICYLAST, NULL, policy_string), val = { 0 };
+ ret = db_api->find(txn, &key, &val, 0);
+ free_key(&key);
+ if (ret == KNOT_EOK) {
+ if (*(uint8_t *)val.data != KASPDBKEY_PARAMS) {
+ ret = KNOT_EMALF;
+ } else {
+ *lp_zone = knot_dname_copy((knot_dname_t *)(val.data + 1), NULL);
+ *lp_keyid = keyid_fromkey(&val);
+ if (*lp_zone == NULL || *lp_keyid == NULL) {
+ free(*lp_zone);
+ free(*lp_keyid);
+ ret = KNOT_ENOMEM;
+ } else {
+ // check that the shared key ID really exists
+ key = make_key(KASPDBKEY_PARAMS, *lp_zone, *lp_keyid);
+ ret = db_api->find(txn, &key, &val, 0);
+ free_key(&key);
+ if (ret != KNOT_EOK) {
+ free(*lp_zone);
+ free(*lp_keyid);
+ }
+ }
+ }
+ }
+ with_txn_end(NULL);
+ return ret;
+}
+
+int kasp_db_set_policy_last(kasp_db_t *db, const char *policy_string, const char *last_lp_keyid,
+ const knot_dname_t *new_lp_zone, const char *new_lp_keyid)
+{
+ if (db == NULL || db->keys_db == NULL ||
+ new_lp_zone == NULL || new_lp_keyid == NULL) {
+ return KNOT_EINVAL;
+ }
+ with_txn(KEYS_RW, NULL);
+ knot_db_val_t key = make_key(KASPDBKEY_POLICYLAST, NULL, policy_string), val = { 0 };
+ ret = db_api->find(txn, &key, &val, 0);
+ switch (ret) {
+ case KNOT_EOK:
+ if (*(uint8_t *)val.data != KASPDBKEY_PARAMS) {
+ ret = KNOT_EMALF;
+ } else {
+ char *real_last = keyid_fromkey(&val);
+ if (real_last == NULL) {
+ ret = KNOT_ENOMEM;
+ } else {
+ if (last_lp_keyid == NULL || strcmp(real_last, last_lp_keyid) != 0) {
+ ret = KNOT_ESEMCHECK;
+ }
+ free(real_last);
+ }
+ }
+ break;
+ case KNOT_ENOENT:
+ ret = KNOT_EOK;
+ break;
+ }
+ if (ret == KNOT_EOK) {
+ val = make_key(KASPDBKEY_PARAMS, new_lp_zone, new_lp_keyid);
+ ret = db_api->insert(txn, &key, &val, 0);
+ free(val.data);
+ }
+ free(key.data);
+ with_txn_end(NULL);
+ return ret;
+}
+
+int kasp_db_list_zones(kasp_db_t *db, list_t *dst)
+{
+ if (db == NULL || db->keys_db == NULL || dst == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ with_txn(KEYS_RO, NULL);
+ knot_db_iter_t *iter = db_api->iter_begin(txn, KNOT_DB_FIRST);
+ while (iter != NULL) {
+ knot_db_val_t key;
+ if (db_api->iter_key(iter, &key) == KNOT_EOK && key.len > 1 &&
+ *(uint8_t *)key.data != KASPDBKEY_POLICYLAST) {
+ // obtain a domain name of a record in KASP db
+ knot_dname_t *key_dn = (knot_dname_t *)(key.data + 1);
+ // check if not already in dst
+ ptrnode_t *n;
+ WALK_LIST(n, *dst) {
+ knot_dname_t *exist_dn = (knot_dname_t *)n->d;
+ if (knot_dname_is_equal(key_dn, exist_dn)) {
+ key_dn = NULL;
+ break;
+ }
+ }
+ // copy it from txn and add to dst
+ if (key_dn != NULL) {
+ knot_dname_t *add_dn = knot_dname_copy(key_dn, NULL);
+ if (add_dn == NULL) {
+ ret = KNOT_ENOMEM;
+ break;
+ }
+ ptrlist_add(dst, add_dn, NULL);
+ }
+ }
+ iter = db_api->iter_next(iter);
+ }
+ db_api->iter_finish(iter);
+ db_api->txn_abort(txn);
+
+ if (ret != KNOT_EOK) {
+ ptrlist_deep_free(dst, NULL);
+ return ret;
+ }
+ return (EMPTY_LIST(*dst) ? KNOT_ENOENT : KNOT_EOK);
+}
diff --git a/src/knot/dnssec/kasp/kasp_db.h b/src/knot/dnssec/kasp/kasp_db.h
new file mode 100644
index 0000000..a6f1b97
--- /dev/null
+++ b/src/knot/dnssec/kasp/kasp_db.h
@@ -0,0 +1,235 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <time.h>
+
+#include "contrib/time.h"
+#include "contrib/ucw/lists.h"
+#include "libknot/db/db_lmdb.h"
+#include "libknot/dname.h"
+#include "knot/dnssec/kasp/policy.h"
+
+typedef struct kasp_db kasp_db_t;
+
+typedef enum { // the enum values MUST match those from keyclass_t !!
+ KASPDB_SERIAL_MASTER = 0x5,
+ KASPDB_SERIAL_LASTSIGNED = 0x6,
+} kaspdb_serial_t;
+
+/*!
+ * \brief Returns kasp_db_t singleton, to be used for signing all zones.
+ *
+ * De/initialized with server_t, used in zone contents signing context.
+ */
+kasp_db_t **kaspdb(void);
+
+/*!
+ * \brief Initialize kasp_db_t, prepare to simple open on-demand.
+ *
+ * \param db structure to initialize
+ * \param path path to the LMDB directory (will be created)
+ * \param mapsize LMDB map size
+ *
+ * \return KNOT_E*
+ */
+int kasp_db_init(kasp_db_t **db, const char *path, size_t mapsize);
+
+/*!
+ * \brief Re-initialize kasp_db_t if not already open.
+ *
+ * \param db structure to initialize
+ * \param new_path new path to LMDB
+ * \param new_mapsize new LMDB map size
+ *
+ * \retval KNOT_EBUSY can't reconfigure DB path because already open
+ * \retval KNOT_EEXIST can't reconfigure mapsize because already open
+ * \retval KNOT_ENODIFF already open, but no change needed => OK
+ * \retval KNOT_EINVAL, KNOT_ENOMEM, etc. standard errors
+ * \return KNOT_EOK reconfigured successfully
+ */
+int kasp_db_reconfigure(kasp_db_t **db, const char *new_path, size_t new_mapsize);
+
+/*!
+ * \brief Determine if kasp_db possibly exists at all.
+ *
+ * This is useful to avoid creating kasp_db by opening it just to check if anything is there.
+ */
+bool kasp_db_exists(kasp_db_t *db);
+
+/*!
+ * \brief Perform real ctreate/open of KASP db.
+ */
+int kasp_db_open(kasp_db_t *db);
+
+/*!
+ * \brief Close KASP db if open and free the structure.
+ */
+void kasp_db_close(kasp_db_t **db);
+
+/*!
+ * \brief For given zone, list all keys (their IDs) belonging to it.
+ *
+ * \param db KASP db
+ * \param zone_name name of the zone in question
+ * \param dst output if KNOT_EOK: ptrlist of keys' params
+ *
+ * \return KNOT_E* (KNOT_ENOENT if no keys)
+ */
+int kasp_db_list_keys(kasp_db_t *db, const knot_dname_t *zone_name, list_t *dst);
+
+/*!
+ * \brief Remove a key from zone. Delete the key if no zone has it anymore.
+ *
+ * \param db KASP db
+ * \param zone_name zone to be removed from
+ * \param key_id ID of key to be removed
+ * \param still_used output if KNOT_EOK: is the key still in use by other zones?
+ *
+ * \return KNOT_E*
+ */
+int kasp_db_delete_key(kasp_db_t *db, const knot_dname_t *zone_name, const char *key_id, bool *still_used);
+
+/*!
+ * \brief Remove all zone's keys from DB, including nsec3param
+ * \param db KASP db
+ * \param zone_name zoen to be removed
+ *
+ * \return KNOT_E*
+ */
+int kasp_db_delete_all(kasp_db_t *db, const knot_dname_t *zone_name);
+
+/*!
+ * \brief Add a key to the DB (possibly overwrite) and link it to a zone.
+ *
+ * Stores new key with given params into KASP db. If a key with the same ID had been present
+ * in KASP db already, its params get silently overwritten by those new params.
+ * Moreover, the key ID is linked to the zone.
+ *
+ * \param db KASP db
+ * \param zone_name name of the zone the new key shall belong to
+ * \param params key params, incl. ID
+ *
+ * \return KNOT_E*
+ */
+int kasp_db_add_key(kasp_db_t *db, const knot_dname_t *zone_name, const key_params_t *params);
+
+/*!
+ * \brief Link a key from another zone.
+ *
+ * \param db KASP db
+ * \param zone_from name of the zone the key belongs to
+ * \param zone_to name of the zone the key shall belong to as well
+ * \param key_id ID of the key in question
+ *
+ * \return KNOT_E*
+ */
+int kasp_db_share_key(kasp_db_t *db, const knot_dname_t *zone_from, const knot_dname_t *zone_to, const char *key_id);
+
+/*!
+ * \brief Store NSEC3 salt for given zone (possibly overwrites old salt).
+ *
+ * \param db KASP db
+ * \param zone_name zone name
+ * \param nsec3salt new NSEC3 salt
+ * \param salt_created timestamp when the salt was created
+ *
+ * \return KNOT_E*
+ */
+int kasp_db_store_nsec3salt(kasp_db_t *db, const knot_dname_t *zone_name,
+ const dnssec_binary_t *nsec3salt, knot_time_t salt_created);
+
+/*!
+ * \brief Load NSEC3 salt for given zone.
+ *
+ * \param db KASP db
+ * \param zone_name zone name
+ * \param nsec3salt output if KNOT_EOK: the zone's NSEC3 salt
+ * \param salt_created output if KNOT_EOK: timestamp when the salt was created
+ *
+ * \return KNOT_E* (KNOT_ENOENT if not stored before)
+ */
+int kasp_db_load_nsec3salt(kasp_db_t *db, const knot_dname_t *zone_name,
+ dnssec_binary_t *nsec3salt, knot_time_t *salt_created);
+
+/*!
+ * \brief Store SOA serial number of master or last signed serial.
+ *
+ * \param db KASP db
+ * \param zone_name zone name
+ * \param serial_type kind of serial to be stored
+ * \param serial new serial to be stored
+ *
+ * \return KNOT_E*
+ */
+int kasp_db_store_serial(kasp_db_t *db, const knot_dname_t *zone_name,
+ kaspdb_serial_t serial_type, uint32_t serial);
+
+/*!
+ * \brief Load saved SOA serial number of master or last signed serial.
+ *
+ * \param db KASP db
+ * \param zone_name zone name
+ * \param serial_type kind of serial to be loaded
+ * \param serial output if KNOT_EOK: desired serial number
+ *
+ * \return KNOT_E* (KNOT_ENOENT if not stored before)
+ */
+int kasp_db_load_serial(kasp_db_t *db, const knot_dname_t *zone_name,
+ kaspdb_serial_t serial_type, uint32_t *serial);
+
+/*!
+ * \brief For given policy name, obtain last generated key.
+ *
+ * \param db KASP db
+ * \param policy_string a name identifying the signing policy with shared keys
+ * \param lp_zone out: the zone owning the last generated key
+ * \param lp_keyid out: the ID of the last generated key
+ *
+ * \return KNOT_E*
+ */
+int kasp_db_get_policy_last(kasp_db_t *db, const char *policy_string, knot_dname_t **lp_zone,
+ char **lp_keyid);
+
+/*!
+ * \brief For given policy name, try to reset last generated key.
+ *
+ * \param db KASP db
+ * \param policy_string a name identifying the signing policy with shared keys
+ * \param last_lp_keyid just for check: ID of the key the caller thinks is the policy-last
+ * \param new_lp_zone zone name of the new policy-last key
+ * \param new_lp_keyid ID of the new policy-last key
+ *
+ * \retval KNOT_ESEMCHECK lasp_lp_keyid does not correspond to real last key. Probably another zone
+ * changed policy-last key in the meantime. Re-run kasp_db_get_policy_last()
+ * \retval KNOT_EOK policy-last key set up successfully to given zone/ID
+ * \return KNOT_E* common error
+ */
+int kasp_db_set_policy_last(kasp_db_t *db, const char *policy_string, const char *last_lp_keyid,
+ const knot_dname_t *new_lp_zone, const char *new_lp_keyid);
+
+/*!
+ * \brief List all zones that have anything stored in KASP db.
+ *
+ * It's quite slow, but we expect KASP db not to be so large.
+ *
+ * \param db KASP db
+ * \param dst List of zone names
+ *
+ * \return KNOT_E*
+ */
+int kasp_db_list_zones(kasp_db_t *db, list_t *dst);
diff --git a/src/knot/dnssec/kasp/kasp_zone.c b/src/knot/dnssec/kasp/kasp_zone.c
new file mode 100644
index 0000000..57a435e
--- /dev/null
+++ b/src/knot/dnssec/kasp/kasp_zone.c
@@ -0,0 +1,296 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "knot/dnssec/kasp/kasp_zone.h"
+#include "knot/dnssec/zone-keys.h"
+#include "libdnssec/binary.h"
+
+// FIXME DNSSEC errors versus knot errors
+
+/*!
+ * Check if key parameters allow to create a key.
+ */
+static int key_params_check(key_params_t *params)
+{
+ assert(params);
+
+ if (params->algorithm == 0) {
+ return KNOT_INVALID_KEY_ALGORITHM;
+ }
+
+ if (params->public_key.size == 0) {
+ return KNOT_NO_PUBLIC_KEY;
+ }
+
+ return KNOT_EOK;
+}
+
+/*! \brief Determine presence of SEP bit by trial-end-error using known keytag. */
+static int dnskey_guess_flags(dnssec_key_t *key, uint16_t keytag)
+{
+ dnssec_key_set_flags(key, DNSKEY_FLAGS_KSK);
+ if (dnssec_key_get_keytag(key) == keytag) {
+ return KNOT_EOK;
+ }
+
+ dnssec_key_set_flags(key, DNSKEY_FLAGS_ZSK);
+ if (dnssec_key_get_keytag(key) == keytag) {
+ return KNOT_EOK;
+ }
+
+ return KNOT_EMALF;
+}
+
+static int params2dnskey(const knot_dname_t *dname, key_params_t *params,
+ dnssec_key_t **key_ptr)
+{
+ assert(dname);
+ assert(params);
+ assert(key_ptr);
+
+ int ret = key_params_check(params);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ dnssec_key_t *key = NULL;
+ ret = dnssec_key_new(&key);
+ if (ret != KNOT_EOK) {
+ return knot_error_from_libdnssec(ret);
+ }
+
+ ret = dnssec_key_set_dname(key, dname);
+ if (ret != KNOT_EOK) {
+ dnssec_key_free(key);
+ return knot_error_from_libdnssec(ret);
+ }
+
+ dnssec_key_set_algorithm(key, params->algorithm);
+
+ ret = dnssec_key_set_pubkey(key, &params->public_key);
+ if (ret != KNOT_EOK) {
+ dnssec_key_free(key);
+ return knot_error_from_libdnssec(ret);
+ }
+
+ ret = dnskey_guess_flags(key, params->keytag);
+ if (ret != KNOT_EOK) {
+ dnssec_key_free(key);
+ return ret;
+ }
+
+ *key_ptr = key;
+
+ return KNOT_EOK;
+}
+
+static int params2kaspkey(const knot_dname_t *dname, key_params_t *params,
+ knot_kasp_key_t *key)
+{
+ assert(dname != NULL);
+ assert(params != NULL);
+ assert(key != NULL);
+
+ int ret = params2dnskey(dname, params, &key->key);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ key->id = strdup(params->id);
+ if (key->id == NULL) {
+ dnssec_key_free(key->key);
+ return KNOT_ENOMEM;
+ }
+
+ key->timing = params->timing;
+ key->is_pub_only = params->is_pub_only;
+ assert(params->is_ksk || !params->is_csk);
+ key->is_ksk = params->is_ksk;
+ key->is_zsk = (params->is_csk || !params->is_ksk);
+ return KNOT_EOK;
+}
+
+static void kaspkey2params(knot_kasp_key_t *key, key_params_t *params)
+{
+ assert(key);
+ assert(params);
+
+ params->id = key->id;
+ params->keytag = dnssec_key_get_keytag(key->key);
+ dnssec_key_get_pubkey(key->key, &params->public_key);
+ params->algorithm = dnssec_key_get_algorithm(key->key);
+ params->is_ksk = key->is_ksk;
+ params->is_csk = (key->is_ksk && key->is_zsk);
+ params->timing = key->timing;
+ params->is_pub_only = key->is_pub_only;
+}
+
+int kasp_zone_load(knot_kasp_zone_t *zone,
+ const knot_dname_t *zone_name,
+ kasp_db_t *kdb)
+{
+ if (zone == NULL || zone_name == NULL || kdb == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ knot_kasp_key_t *dkeys = NULL;
+ size_t num_dkeys = 0;
+ dnssec_binary_t salt = { 0 };
+ knot_time_t sc = 0;
+
+ list_t key_params;
+ init_list(&key_params);
+ int ret = kasp_db_list_keys(kdb, zone_name, &key_params);
+ if (ret == KNOT_ENOENT) {
+ zone->keys = NULL;
+ zone->num_keys = 0;
+ ret = KNOT_EOK;
+ goto kzl_salt;
+ } else if (ret != KNOT_EOK) {
+ goto kzl_end;
+ }
+
+ num_dkeys = list_size(&key_params);
+ dkeys = calloc(num_dkeys, sizeof(*dkeys));
+ if (dkeys == NULL) {
+ goto kzl_end;
+ }
+
+ ptrnode_t *n;
+ int i = 0;
+ WALK_LIST(n, key_params) {
+ key_params_t *parm = n->d;
+ ret = params2kaspkey(zone_name, parm, &dkeys[i++]);
+ free_key_params(parm);
+ if (ret != KNOT_EOK) {
+ goto kzl_end;
+ }
+ }
+
+kzl_salt:
+ (void)kasp_db_load_nsec3salt(kdb, zone_name, &salt, &sc);
+ // if error, salt was probably not present, no problem to have zero ?
+
+ zone->dname = knot_dname_copy(zone_name, NULL);
+ if (zone->dname == NULL) {
+ ret = KNOT_ENOMEM;
+ goto kzl_end;
+ }
+ zone->keys = dkeys;
+ zone->num_keys = num_dkeys;
+ zone->nsec3_salt = salt;
+ zone->nsec3_salt_created = sc;
+
+kzl_end:
+ ptrlist_deep_free(&key_params, NULL);
+ if (ret != KNOT_EOK) {
+ free(dkeys);
+ }
+ return ret;
+}
+
+int kasp_zone_append(knot_kasp_zone_t *zone, const knot_kasp_key_t *appkey)
+{
+ if (zone == NULL || appkey == NULL || (zone->keys == NULL && zone->num_keys > 0)) {
+ return KNOT_EINVAL;
+ }
+
+ size_t new_num_keys = zone->num_keys + 1;
+ knot_kasp_key_t *new_keys = calloc(new_num_keys, sizeof(*new_keys));
+ if (!new_keys) {
+ return KNOT_ENOMEM;
+ }
+ if (zone->num_keys > 0) {
+ memcpy(new_keys, zone->keys, zone->num_keys * sizeof(*new_keys));
+ }
+ memcpy(&new_keys[new_num_keys - 1], appkey, sizeof(*appkey));
+ free(zone->keys);
+ zone->keys = new_keys;
+ zone->num_keys = new_num_keys;
+ return KNOT_EOK;
+}
+
+int kasp_zone_save(const knot_kasp_zone_t *zone,
+ const knot_dname_t *zone_name,
+ kasp_db_t *kdb)
+{
+ if (zone == NULL || zone_name == NULL || kdb == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ key_params_t parm;
+ for (size_t i = 0; i < zone->num_keys; i++) {
+ kaspkey2params(&zone->keys[i], &parm);
+
+ // Force overwrite already existing key-val pairs.
+ int ret = kasp_db_add_key(kdb, zone_name, &parm);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ if (zone->nsec3_salt.size > 0) {
+ int ret = kasp_db_store_nsec3salt(kdb, zone_name, &zone->nsec3_salt,
+ zone->nsec3_salt_created);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+int kasp_zone_init(knot_kasp_zone_t **zone)
+{
+ if (zone == NULL) {
+ return KNOT_EINVAL;
+ }
+ *zone = calloc(1, sizeof(**zone));
+ return (*zone ? KNOT_EOK : KNOT_ENOMEM);
+}
+
+void kasp_zone_clear(knot_kasp_zone_t *zone)
+{
+ if (zone == NULL) {
+ return;
+ }
+ knot_dname_free(zone->dname, NULL);
+ for (size_t i = 0; i < zone->num_keys; i++) {
+ dnssec_key_free(zone->keys[i].key);
+ free(zone->keys[i].id);
+ }
+ free(zone->keys);
+ free(zone->nsec3_salt.data);
+ memset(zone, 0, sizeof(*zone));
+}
+
+void kasp_zone_free(knot_kasp_zone_t **zone)
+{
+ if (zone != NULL) {
+ kasp_zone_clear(*zone);
+ free(*zone);
+ *zone = NULL;
+ }
+}
+
+void free_key_params(key_params_t *parm)
+{
+ if (parm != NULL) {
+ free(parm->id);
+ dnssec_binary_free(&parm->public_key);
+ memset(parm, 0 , sizeof(*parm));
+ }
+}
diff --git a/src/knot/dnssec/kasp/kasp_zone.h b/src/knot/dnssec/kasp/kasp_zone.h
new file mode 100644
index 0000000..83eaea2
--- /dev/null
+++ b/src/knot/dnssec/kasp/kasp_zone.h
@@ -0,0 +1,45 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include "knot/dnssec/kasp/kasp_db.h"
+
+typedef struct {
+ knot_dname_t *dname;
+
+ knot_kasp_key_t *keys;
+ size_t num_keys;
+
+ dnssec_binary_t nsec3_salt;
+ knot_time_t nsec3_salt_created;
+} knot_kasp_zone_t;
+
+int kasp_zone_load(knot_kasp_zone_t *zone,
+ const knot_dname_t *zone_name,
+ kasp_db_t *kdb);
+
+int kasp_zone_save(const knot_kasp_zone_t *zone,
+ const knot_dname_t *zone_name,
+ kasp_db_t *kdb);
+
+int kasp_zone_append(knot_kasp_zone_t *zone,
+ const knot_kasp_key_t *appkey);
+
+void kasp_zone_clear(knot_kasp_zone_t *zone);
+void kasp_zone_free(knot_kasp_zone_t **zone);
+
+void free_key_params(key_params_t *parm);
diff --git a/src/knot/dnssec/kasp/keystate.c b/src/knot/dnssec/kasp/keystate.c
new file mode 100644
index 0000000..acf7cee
--- /dev/null
+++ b/src/knot/dnssec/kasp/keystate.c
@@ -0,0 +1,70 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "knot/dnssec/kasp/keystate.h"
+
+key_state_t get_key_state(const knot_kasp_key_t *key, knot_time_t moment)
+{
+ if (!key || moment <= 0) {
+ return DNSSEC_KEY_STATE_INVALID;
+ }
+
+ const knot_kasp_key_timing_t *t = &key->timing;
+
+ bool removed = (knot_time_cmp(t->remove, moment) <= 0);
+ bool post_active = (knot_time_cmp(t->post_active, moment) <= 0);
+ bool retired = (knot_time_cmp(t->retire, moment) <= 0);
+ bool retire_active = (knot_time_cmp(t->retire_active, moment) <= 0);
+ bool active = (knot_time_cmp(t->active, moment) <= 0);
+ bool ready = (knot_time_cmp(t->ready, moment) <= 0);
+ bool published = (knot_time_cmp(t->publish, moment) <= 0);
+ bool pre_active = (knot_time_cmp(t->pre_active, moment) <= 0);
+ bool created = (knot_time_cmp(t->created, moment) <= 0);
+
+ if (removed) {
+ return DNSSEC_KEY_STATE_REMOVED;
+ }
+ if (post_active) {
+ if (retired) {
+ return DNSSEC_KEY_STATE_INVALID;
+ } else {
+ return DNSSEC_KEY_STATE_POST_ACTIVE;
+ }
+ }
+ if (retired) {
+ return DNSSEC_KEY_STATE_RETIRED;
+ }
+ if (retire_active) {
+ return DNSSEC_KEY_STATE_RETIRE_ACTIVE;
+ }
+ if (active) {
+ return DNSSEC_KEY_STATE_ACTIVE;
+ }
+ if (ready) {
+ return DNSSEC_KEY_STATE_READY;
+ }
+ if (published) {
+ return DNSSEC_KEY_STATE_PUBLISHED;
+ }
+ if (pre_active) {
+ return DNSSEC_KEY_STATE_PRE_ACTIVE;
+ }
+ if (created) {
+ // don't care
+ }
+
+ return DNSSEC_KEY_STATE_INVALID;
+}
diff --git a/src/knot/dnssec/kasp/keystate.h b/src/knot/dnssec/kasp/keystate.h
new file mode 100644
index 0000000..9da9f14
--- /dev/null
+++ b/src/knot/dnssec/kasp/keystate.h
@@ -0,0 +1,34 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include "contrib/time.h"
+#include "knot/dnssec/kasp/policy.h"
+
+typedef enum {
+ DNSSEC_KEY_STATE_INVALID = 0,
+ DNSSEC_KEY_STATE_PRE_ACTIVE,
+ DNSSEC_KEY_STATE_PUBLISHED,
+ DNSSEC_KEY_STATE_READY,
+ DNSSEC_KEY_STATE_ACTIVE,
+ DNSSEC_KEY_STATE_RETIRE_ACTIVE,
+ DNSSEC_KEY_STATE_RETIRED,
+ DNSSEC_KEY_STATE_POST_ACTIVE,
+ DNSSEC_KEY_STATE_REMOVED,
+} key_state_t;
+
+key_state_t get_key_state(const knot_kasp_key_t *key, knot_time_t moment);
diff --git a/src/knot/dnssec/kasp/keystore.c b/src/knot/dnssec/kasp/keystore.c
new file mode 100644
index 0000000..96dee8f
--- /dev/null
+++ b/src/knot/dnssec/kasp/keystore.c
@@ -0,0 +1,89 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libdnssec/error.h"
+#include "knot/dnssec/kasp/keystore.h"
+#include "knot/conf/schema.h"
+#include "libknot/error.h"
+
+static char *fix_path(const char *config, const char *base_path)
+{
+ assert(config);
+ assert(base_path);
+
+ char *path = NULL;
+
+ if (config[0] == '/') {
+ path = strdup(config);
+ } else {
+ if (asprintf(&path, "%s/%s", base_path, config) == -1) {
+ path = NULL;
+ }
+ }
+
+ return path;
+}
+
+int keystore_load(const char *config, unsigned backend,
+ const char *kasp_base_path, dnssec_keystore_t **keystore)
+{
+ int ret = DNSSEC_EINVAL;
+ char *fixed_config = NULL;
+
+ switch (backend) {
+ case KEYSTORE_BACKEND_PEM:
+ ret = dnssec_keystore_init_pkcs8_dir(keystore);
+ fixed_config = fix_path(config, kasp_base_path);
+ break;
+ case KEYSTORE_BACKEND_PKCS11:
+ ret = dnssec_keystore_init_pkcs11(keystore);
+ fixed_config = strdup(config);
+ break;
+ default:
+ assert(0);
+ }
+ if (ret != DNSSEC_EOK) {
+ free(fixed_config);
+ return knot_error_from_libdnssec(ret);
+ }
+ if (fixed_config == NULL) {
+ dnssec_keystore_deinit(*keystore);
+ *keystore = NULL;
+ return KNOT_ENOMEM;
+ }
+
+ ret = dnssec_keystore_init(*keystore, fixed_config);
+ if (ret != DNSSEC_EOK) {
+ free(fixed_config);
+ dnssec_keystore_deinit(*keystore);
+ *keystore = NULL;
+ return knot_error_from_libdnssec(ret);
+ }
+
+ ret = dnssec_keystore_open(*keystore, fixed_config);
+ free(fixed_config);
+ if (ret != DNSSEC_EOK) {
+ dnssec_keystore_deinit(*keystore);
+ *keystore = NULL;
+ return knot_error_from_libdnssec(ret);
+ }
+
+ return KNOT_EOK;
+}
diff --git a/src/knot/dnssec/kasp/keystore.h b/src/knot/dnssec/kasp/keystore.h
new file mode 100644
index 0000000..028d6fc
--- /dev/null
+++ b/src/knot/dnssec/kasp/keystore.h
@@ -0,0 +1,22 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include "libdnssec/keystore.h"
+
+int keystore_load(const char *config, unsigned backend,
+ const char *kasp_base_path, dnssec_keystore_t **keystore);
diff --git a/src/knot/dnssec/kasp/policy.h b/src/knot/dnssec/kasp/policy.h
new file mode 100644
index 0000000..2ce236e
--- /dev/null
+++ b/src/knot/dnssec/kasp/policy.h
@@ -0,0 +1,112 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <stdbool.h>
+
+#include "contrib/time.h"
+#include "libdnssec/key.h"
+#include "knot/conf/conf.h"
+
+/*!
+ * KASP key timing information.
+ */
+typedef struct {
+ knot_time_t created; /*!< Time the key was generated/imported. */
+ knot_time_t pre_active; /*!< Signing start with new algorithm. */
+ knot_time_t publish; /*!< Time of DNSKEY record publication. */
+ knot_time_t ready; /*!< Start of RRSIG generation, waiting for parent zone. */
+ knot_time_t active; /*!< RRSIG records generating, other keys can be retired */
+ knot_time_t retire_active; /*!< Still active, but obsoleted. */
+ knot_time_t retire; /*!< End of RRSIG records generating. */
+ knot_time_t post_active; /*!< Still signing with old algorithm, not published. */
+ knot_time_t remove; /*!< Time of DNSKEY record removal. */
+} knot_kasp_key_timing_t;
+
+/*!
+ * Key parameters as writing in zone config file.
+ */
+typedef struct {
+ char *id;
+ bool is_ksk;
+ bool is_csk;
+ bool is_pub_only;
+ uint16_t keytag;
+ uint8_t algorithm;
+ dnssec_binary_t public_key;
+ knot_kasp_key_timing_t timing;
+} key_params_t;
+
+/*!
+ * Zone key.
+ */
+typedef struct {
+ char *id; /*!< Keystore unique key ID. */
+ dnssec_key_t *key; /*!< Instance of the key. */
+ knot_kasp_key_timing_t timing; /*!< Key timing information. */
+ bool is_pub_only;
+ bool is_ksk;
+ bool is_zsk;
+} knot_kasp_key_t;
+
+/*!
+ * Parent for DS checks.
+ */
+typedef struct {
+ conf_remote_t *addr;
+ size_t addrs;
+} knot_kasp_parent_t;
+
+dynarray_declare(parent, knot_kasp_parent_t, DYNARRAY_VISIBILITY_PUBLIC, 3)
+
+/*!
+ * Key and signature policy.
+ */
+typedef struct {
+ bool manual;
+ char *string;
+ // DNSKEY
+ dnssec_key_algorithm_t algorithm;
+ uint16_t ksk_size;
+ uint16_t zsk_size;
+ uint32_t dnskey_ttl;
+ uint32_t zsk_lifetime;
+ uint32_t ksk_lifetime;
+ bool ksk_shared;
+ bool singe_type_signing;
+ // RRSIG
+ uint32_t rrsig_lifetime;
+ uint32_t rrsig_refresh_before;
+ // NSEC3
+ bool nsec3_enabled;
+ bool nsec3_opt_out;
+ uint32_t nsec3_salt_lifetime;
+ uint16_t nsec3_iterations;
+ uint8_t nsec3_salt_length;
+ // SOA
+ uint32_t soa_minimal_ttl;
+ // zone
+ uint32_t zone_maximal_ttl;
+ // data propagation delay
+ uint32_t propagation_delay;
+ // various
+ uint32_t ksk_sbm_timeout;
+ uint32_t ksk_sbm_check_interval;
+ unsigned child_records_publish;
+ parent_dynarray_t parents;
+} knot_kasp_policy_t;
+// TODO make the time parameters knot_timediff_t ??
diff --git a/src/knot/dnssec/key-events.c b/src/knot/dnssec/key-events.c
new file mode 100644
index 0000000..6551db5
--- /dev/null
+++ b/src/knot/dnssec/key-events.c
@@ -0,0 +1,713 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "contrib/macros.h"
+#include "knot/common/log.h"
+#include "knot/dnssec/kasp/keystate.h"
+#include "knot/dnssec/key-events.h"
+#include "knot/dnssec/policy.h"
+#include "knot/dnssec/zone-keys.h"
+
+static bool key_present(const kdnssec_ctx_t *ctx, bool ksk, bool zsk)
+{
+ assert(ctx);
+ assert(ctx->zone);
+ for (size_t i = 0; i < ctx->zone->num_keys; i++) {
+ const knot_kasp_key_t *key = &ctx->zone->keys[i];
+ if (key->is_ksk == ksk && key->is_zsk == zsk) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool key_id_present(const kdnssec_ctx_t *ctx, const char *keyid, bool want_ksk)
+{
+ assert(ctx);
+ assert(ctx->zone);
+ for (size_t i = 0; i < ctx->zone->num_keys; i++) {
+ const knot_kasp_key_t *key = &ctx->zone->keys[i];
+ if (strcmp(keyid, key->id) == 0 &&
+ key->is_ksk == want_ksk) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static unsigned algorithm_present(const kdnssec_ctx_t *ctx, uint8_t alg)
+{
+ assert(ctx);
+ assert(ctx->zone);
+ unsigned ret = 0;
+ for (size_t i = 0; i < ctx->zone->num_keys; i++) {
+ const knot_kasp_key_t *key = &ctx->zone->keys[i];
+ knot_time_t activated = knot_time_min(key->timing.pre_active, key->timing.ready);
+ if (knot_time_cmp(knot_time_min(activated, key->timing.active), ctx->now) <= 0 &&
+ dnssec_key_get_algorithm(key->key) == alg) {
+ ret++;
+ }
+ }
+ return ret;
+}
+
+static bool signing_scheme_present(const kdnssec_ctx_t *ctx)
+{
+ if (ctx->policy->singe_type_signing) {
+ return (!key_present(ctx, true, false) || !key_present(ctx, false, true) || key_present(ctx, true, true));
+ } else {
+ return (key_present(ctx, true, false) && key_present(ctx, false, true));
+ }
+}
+
+static knot_kasp_key_t *key_get_by_id(kdnssec_ctx_t *ctx, const char *keyid)
+{
+ assert(ctx);
+ assert(ctx->zone);
+ for (size_t i = 0; i < ctx->zone->num_keys; i++) {
+ knot_kasp_key_t *key = &ctx->zone->keys[i];
+ if (strcmp(keyid, key->id) == 0) {
+ return key;
+ }
+ }
+ return NULL;
+}
+
+static int generate_key(kdnssec_ctx_t *ctx, kdnssec_generate_flags_t flags,
+ knot_time_t when_active, bool pre_active)
+{
+ assert(!pre_active || when_active == 0);
+
+ knot_kasp_key_t *key = NULL;
+ int ret = kdnssec_generate_key(ctx, flags, &key);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ key->timing.remove = 0;
+ key->timing.retire = 0;
+ key->timing.active = ((flags & DNSKEY_GENERATE_KSK) ? 0 : when_active);
+ key->timing.ready = ((flags & DNSKEY_GENERATE_KSK) ? when_active : 0);
+ key->timing.publish = (pre_active ? 0 : ctx->now);
+ key->timing.pre_active = (pre_active ? ctx->now : 0);
+
+ return KNOT_EOK;
+}
+
+static int share_or_generate_key(kdnssec_ctx_t *ctx, kdnssec_generate_flags_t flags,
+ knot_time_t when_active, bool pre_active)
+{
+ assert(!pre_active || when_active == 0);
+
+ knot_dname_t *borrow_zone = NULL;
+ char *borrow_key = NULL;
+
+ if (!(flags & DNSKEY_GENERATE_KSK)) {
+ return KNOT_EINVAL;
+ } // for now not designed for rotating shared ZSK
+
+ int ret = kasp_db_get_policy_last(*ctx->kasp_db, ctx->policy->string,
+ &borrow_zone, &borrow_key);
+ if (ret != KNOT_EOK && ret != KNOT_ENOENT) {
+ return ret;
+ }
+
+ // if we already have the policy-last key, we have to generate new one
+ if (ret == KNOT_ENOENT || key_id_present(ctx, borrow_key, true)) {
+ knot_kasp_key_t *key = NULL;
+ ret = kdnssec_generate_key(ctx, flags, &key);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ key->timing.remove = 0;
+ key->timing.retire = 0;
+ key->timing.active = ((flags & DNSKEY_GENERATE_KSK) ? 0 : when_active);
+ key->timing.ready = ((flags & DNSKEY_GENERATE_KSK) ? when_active : 0);
+ key->timing.publish = (pre_active ? 0 : ctx->now);
+ key->timing.pre_active = (pre_active ? ctx->now : 0);
+
+ ret = kdnssec_ctx_commit(ctx);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = kasp_db_set_policy_last(*ctx->kasp_db, ctx->policy->string,
+ borrow_key, ctx->zone->dname, key->id);
+ free(borrow_zone);
+ free(borrow_key);
+ borrow_zone = NULL;
+ borrow_key = NULL;
+ if (ret != KNOT_ESEMCHECK) {
+ // all ok, we generated new kay and updated policy-last
+ return ret;
+ } else {
+ // another zone updated policy-last key in the meantime
+ ret = kdnssec_delete_key(ctx, key);
+ if (ret == KNOT_EOK) {
+ ret = kdnssec_ctx_commit(ctx);
+ }
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = kasp_db_get_policy_last(*ctx->kasp_db, ctx->policy->string,
+ &borrow_zone, &borrow_key);
+ }
+ }
+
+ if (ret == KNOT_EOK) {
+ ret = kdnssec_share_key(ctx, borrow_zone, borrow_key);
+ if (ret == KNOT_EOK) {
+ knot_kasp_key_t *newkey = key_get_by_id(ctx, borrow_key);
+ assert(newkey != NULL);
+ newkey->timing.remove = 0;
+ newkey->timing.retire = 0;
+ newkey->timing.active = ((flags & DNSKEY_GENERATE_KSK) ? 0 : when_active);
+ newkey->timing.ready = ((flags & DNSKEY_GENERATE_KSK) ? when_active : 0);
+ newkey->timing.publish = (pre_active ? 0 : ctx->now);
+ newkey->timing.pre_active = (pre_active ? ctx->now : 0);
+ newkey->is_ksk = (flags & DNSKEY_GENERATE_KSK);
+ newkey->is_zsk = (flags & DNSKEY_GENERATE_ZSK);
+ }
+ }
+ free(borrow_zone);
+ free(borrow_key);
+ return ret;
+}
+
+#define GEN_KSK_FLAGS (DNSKEY_GENERATE_KSK | (ctx->policy->singe_type_signing ? DNSKEY_GENERATE_ZSK : 0))
+
+static bool running_rollover(const kdnssec_ctx_t *ctx)
+{
+ bool res = false;
+ bool ready_ksk = false, active_ksk = false;
+
+ for (size_t i = 0; i < ctx->zone->num_keys; i++) {
+ knot_kasp_key_t *key = &ctx->zone->keys[i];
+ switch (get_key_state(key, ctx->now)) {
+ case DNSSEC_KEY_STATE_PRE_ACTIVE:
+ res = true;
+ break;
+ case DNSSEC_KEY_STATE_PUBLISHED:
+ res = (res || !key->is_pub_only);
+ break;
+ case DNSSEC_KEY_STATE_READY:
+ ready_ksk = (ready_ksk || key->is_ksk);
+ break;
+ case DNSSEC_KEY_STATE_ACTIVE:
+ active_ksk = (active_ksk || key->is_ksk);
+ break;
+ case DNSSEC_KEY_STATE_RETIRE_ACTIVE:
+ case DNSSEC_KEY_STATE_POST_ACTIVE:
+ res = true;
+ break;
+ case DNSSEC_KEY_STATE_RETIRED:
+ case DNSSEC_KEY_STATE_REMOVED:
+ default:
+ break;
+ }
+ }
+ if (ready_ksk && active_ksk) {
+ res = true;
+ }
+ return res;
+}
+
+typedef enum {
+ INVALID = 0,
+ GENERATE = 1,
+ PUBLISH,
+ SUBMIT,
+ REPLACE,
+ RETIRE,
+ REMOVE,
+} roll_action_type_t;
+
+typedef struct {
+ roll_action_type_t type;
+ bool ksk;
+ knot_time_t time;
+ knot_kasp_key_t *key;
+} roll_action_t;
+
+static const char *roll_action_name(roll_action_type_t type)
+{
+ switch (type) {
+ case GENERATE: return "generate";
+ case PUBLISH: return "publish";
+ case SUBMIT: return "submit";
+ case REPLACE: return "replace";
+ case RETIRE: return "retire";
+ case REMOVE: return "remove";
+ case INVALID:
+ // FALLTHROUGH
+ default: return "invalid";
+ }
+}
+
+static knot_time_t zsk_rollover_time(knot_time_t active_time, const kdnssec_ctx_t *ctx)
+{
+ if (active_time <= 0 || ctx->policy->zsk_lifetime == 0) {
+ return 0;
+ }
+ return knot_time_add(active_time, ctx->policy->zsk_lifetime);
+}
+
+static knot_time_t zsk_active_time(knot_time_t publish_time, const kdnssec_ctx_t *ctx)
+{
+ if (publish_time <= 0) {
+ return 0;
+ }
+ return knot_time_add(publish_time, ctx->policy->propagation_delay + ctx->policy->dnskey_ttl);
+}
+
+static knot_time_t zsk_remove_time(knot_time_t retire_time, const kdnssec_ctx_t *ctx)
+{
+ if (retire_time <= 0) {
+ return 0;
+ }
+ return knot_time_add(retire_time, ctx->policy->propagation_delay + ctx->policy->zone_maximal_ttl);
+}
+
+static knot_time_t ksk_rollover_time(knot_time_t created_time, const kdnssec_ctx_t *ctx)
+{
+ if (created_time <= 0 || ctx->policy->ksk_lifetime == 0) {
+ return 0;
+ }
+ return knot_time_add(created_time, ctx->policy->ksk_lifetime);
+}
+
+static knot_time_t ksk_ready_time(knot_time_t publish_time, const kdnssec_ctx_t *ctx)
+{
+ if (publish_time <= 0) {
+ return 0;
+ }
+ return knot_time_add(publish_time, ctx->policy->propagation_delay + ctx->policy->dnskey_ttl);
+}
+
+static knot_time_t ksk_sbm_max_time(knot_time_t ready_time, const kdnssec_ctx_t *ctx)
+{
+ if (ready_time <= 0 || ctx->policy->ksk_sbm_timeout == 0) {
+ return 0;
+ }
+ return knot_time_add(ready_time, ctx->policy->ksk_sbm_timeout);
+}
+
+static knot_time_t ksk_retire_time(knot_time_t retire_active_time, const kdnssec_ctx_t *ctx)
+{
+ if (retire_active_time <= 0) {
+ return 0;
+ }
+ // this is not correct! It should be parent DS TTL.
+ return knot_time_add(retire_active_time, ctx->policy->propagation_delay + ctx->policy->dnskey_ttl);
+}
+
+static knot_time_t ksk_remove_time(knot_time_t retire_time, const kdnssec_ctx_t *ctx)
+{
+ if (retire_time <= 0) {
+ return 0;
+ }
+ knot_timediff_t use_ttl = ctx->policy->dnskey_ttl;
+ if (ctx->policy->singe_type_signing && ctx->policy->zone_maximal_ttl > use_ttl) {
+ use_ttl = ctx->policy->zone_maximal_ttl;
+ }
+ return knot_time_add(retire_time, ctx->policy->propagation_delay + use_ttl);
+}
+
+// algorithm rollover related timers must be the same for KSK and ZSK
+
+static knot_time_t alg_publish_time(knot_time_t pre_active_time, const kdnssec_ctx_t *ctx)
+{
+ if (pre_active_time <= 0) {
+ return 0;
+ }
+ return knot_time_add(pre_active_time, ctx->policy->propagation_delay + ctx->policy->zone_maximal_ttl);
+}
+
+static knot_time_t alg_remove_time(knot_time_t post_active_time, const kdnssec_ctx_t *ctx)
+{
+ return MAX(ksk_remove_time(post_active_time, ctx), zsk_remove_time(post_active_time, ctx));
+}
+
+static roll_action_t next_action(kdnssec_ctx_t *ctx)
+{
+ roll_action_t res = { 0 };
+ res.time = 0;
+
+ for (size_t i = 0; i < ctx->zone->num_keys; i++) {
+ knot_kasp_key_t *key = &ctx->zone->keys[i];
+ knot_time_t keytime = 0;
+ roll_action_type_t restype = INVALID;
+ if (key->is_pub_only) {
+ continue;
+ }
+ if (key->is_ksk) {
+ switch (get_key_state(key, ctx->now)) {
+ case DNSSEC_KEY_STATE_PRE_ACTIVE:
+ keytime = alg_publish_time(key->timing.pre_active, ctx);
+ restype = PUBLISH;
+ break;
+ case DNSSEC_KEY_STATE_PUBLISHED:
+ keytime = ksk_ready_time(key->timing.publish, ctx);
+ restype = SUBMIT;
+ break;
+ case DNSSEC_KEY_STATE_READY:
+ keytime = ksk_sbm_max_time(key->timing.ready, ctx);
+ restype = REPLACE;
+ break;
+ case DNSSEC_KEY_STATE_ACTIVE:
+ if (!running_rollover(ctx) &&
+ dnssec_key_get_algorithm(key->key) == ctx->policy->algorithm) {
+ keytime = ksk_rollover_time(key->timing.created, ctx);
+ restype = GENERATE;
+ }
+ break;
+ case DNSSEC_KEY_STATE_RETIRE_ACTIVE:
+ if (key->timing.retire == 0 && key->timing.post_active == 0) { // this shouldn't normally happen
+ // when a KSK is retire_active, it has already retire or post_active timer set
+ keytime = ksk_retire_time(key->timing.retire_active, ctx);
+ restype = RETIRE;
+ }
+ break;
+ case DNSSEC_KEY_STATE_POST_ACTIVE:
+ keytime = alg_remove_time(key->timing.post_active, ctx);
+ restype = REMOVE;
+ break;
+ case DNSSEC_KEY_STATE_RETIRED:
+ case DNSSEC_KEY_STATE_REMOVED:
+ // ad REMOVED state: normally this wouldn't happen
+ // (key in removed state is instantly deleted)
+ // but if imported keys, they can be in this state
+ keytime = knot_time_min(key->timing.retire, key->timing.remove);
+ keytime = ksk_remove_time(keytime, ctx);
+ restype = REMOVE;
+ break;
+ default:
+ continue;
+ }
+ } else {
+ switch (get_key_state(key, ctx->now)) {
+ case DNSSEC_KEY_STATE_PRE_ACTIVE:
+ keytime = alg_publish_time(key->timing.pre_active, ctx);
+ restype = PUBLISH;
+ break;
+ case DNSSEC_KEY_STATE_PUBLISHED:
+ keytime = zsk_active_time(key->timing.publish, ctx);
+ restype = REPLACE;
+ break;
+ case DNSSEC_KEY_STATE_ACTIVE:
+ if (!running_rollover(ctx) &&
+ dnssec_key_get_algorithm(key->key) == ctx->policy->algorithm) {
+ keytime = zsk_rollover_time(key->timing.active, ctx);
+ restype = GENERATE;
+ }
+ break;
+ case DNSSEC_KEY_STATE_RETIRE_ACTIVE:
+ // simply waiting for submitted KSK to retire me.
+ break;
+ case DNSSEC_KEY_STATE_POST_ACTIVE:
+ keytime = alg_remove_time(key->timing.post_active, ctx);
+ restype = REMOVE;
+ break;
+ case DNSSEC_KEY_STATE_RETIRED:
+ case DNSSEC_KEY_STATE_REMOVED:
+ // ad REMOVED state: normally this wouldn't happen
+ // (key in removed state is instantly deleted)
+ // but if imported keys, they can be in this state
+ keytime = knot_time_min(key->timing.retire, key->timing.remove);
+ keytime = zsk_remove_time(keytime, ctx);
+ restype = REMOVE;
+ break;
+ case DNSSEC_KEY_STATE_READY:
+ default:
+ continue;
+ }
+ }
+ if (knot_time_cmp(keytime, res.time) < 0) {
+ res.key = key;
+ res.ksk = key->is_ksk;
+ res.time = keytime;
+ res.type = restype;
+ }
+ }
+
+ return res;
+}
+
+static int submit_key(kdnssec_ctx_t *ctx, knot_kasp_key_t *newkey)
+{
+ assert(get_key_state(newkey, ctx->now) == DNSSEC_KEY_STATE_PUBLISHED);
+ assert(newkey->is_ksk);
+
+ // pushing from READY into ACTIVE decreases the other key's cds_priority
+ for (size_t i = 0; i < ctx->zone->num_keys; i++) {
+ knot_kasp_key_t *key = &ctx->zone->keys[i];
+ if (key->is_ksk && get_key_state(key, ctx->now) == DNSSEC_KEY_STATE_READY) {
+ key->timing.active = ctx->now;
+ }
+ }
+
+ newkey->timing.ready = ctx->now;
+ return KNOT_EOK;
+}
+
+static int exec_new_signatures(kdnssec_ctx_t *ctx, knot_kasp_key_t *newkey, uint32_t active_retire_delay)
+{
+ if (newkey->is_ksk) {
+ log_zone_notice(ctx->zone->dname, "DNSSEC, KSK submission, confirmed");
+ }
+
+ for (size_t i = 0; i < ctx->zone->num_keys; i++) {
+ knot_kasp_key_t *key = &ctx->zone->keys[i];
+ key_state_t keystate = get_key_state(key, ctx->now);
+ uint8_t keyalg = dnssec_key_get_algorithm(key->key);
+ if (((newkey->is_ksk && key->is_ksk) || (newkey->is_zsk && key->is_zsk && !key->is_ksk))
+ && keystate == DNSSEC_KEY_STATE_ACTIVE) {
+ if (key->is_ksk || keyalg != dnssec_key_get_algorithm(newkey->key)) {
+ key->timing.retire_active = ctx->now;
+ } else {
+ key->timing.retire = ctx->now;
+ }
+ }
+ if (newkey->is_ksk && (keystate == DNSSEC_KEY_STATE_ACTIVE ||
+ keystate == DNSSEC_KEY_STATE_RETIRE_ACTIVE)) {
+ if (keyalg != dnssec_key_get_algorithm(newkey->key)) {
+ key->timing.post_active = ctx->now + active_retire_delay;
+ } else if (key->is_ksk) {
+ key->timing.retire = ctx->now + active_retire_delay;
+ }
+ }
+ }
+
+ if (newkey->is_ksk) {
+ assert(get_key_state(newkey, ctx->now) == DNSSEC_KEY_STATE_READY);
+ } else {
+ assert(get_key_state(newkey, ctx->now) == DNSSEC_KEY_STATE_PUBLISHED);
+ }
+ newkey->timing.active = knot_time_min(ctx->now, newkey->timing.active);
+
+ return KNOT_EOK;
+}
+
+static int exec_publish(kdnssec_ctx_t *ctx, knot_kasp_key_t *key)
+{
+ assert(get_key_state(key, ctx->now) == DNSSEC_KEY_STATE_PRE_ACTIVE);
+ key->timing.publish = ctx->now;
+
+ return KNOT_EOK;
+}
+
+static int exec_ksk_retire(kdnssec_ctx_t *ctx, knot_kasp_key_t *key)
+{
+ bool alg_rollover = false;
+ knot_kasp_key_t *alg_rollover_friend = NULL;
+
+ for (size_t i = 0; i < ctx->zone->num_keys; i++) {
+ knot_kasp_key_t *k = &ctx->zone->keys[i];
+ int magic = (k->is_ksk && k->is_zsk ? 2 : 3); // :(
+ if (k->is_zsk && get_key_state(k, ctx->now) == DNSSEC_KEY_STATE_RETIRE_ACTIVE &&
+ algorithm_present(ctx, dnssec_key_get_algorithm(k->key)) < magic) {
+ alg_rollover = true;
+ alg_rollover_friend = k;
+ }
+ }
+
+ assert(get_key_state(key, ctx->now) == DNSSEC_KEY_STATE_RETIRE_ACTIVE);
+
+ if (alg_rollover) {
+ key->timing.post_active = ctx->now;
+ alg_rollover_friend->timing.post_active = ctx->now;
+ } else {
+ key->timing.retire = ctx->now;
+ }
+
+ return KNOT_EOK;
+}
+
+static int exec_remove_old_key(kdnssec_ctx_t *ctx, knot_kasp_key_t *key)
+{
+ assert(get_key_state(key, ctx->now) == DNSSEC_KEY_STATE_RETIRED ||
+ get_key_state(key, ctx->now) == DNSSEC_KEY_STATE_POST_ACTIVE ||
+ get_key_state(key, ctx->now) == DNSSEC_KEY_STATE_REMOVED);
+ key->timing.remove = ctx->now;
+
+ return kdnssec_delete_key(ctx, key);
+}
+
+int knot_dnssec_key_rollover(kdnssec_ctx_t *ctx, zone_sign_reschedule_t *reschedule)
+{
+ if (ctx == NULL || reschedule == NULL) {
+ return KNOT_EINVAL;
+ }
+ if (ctx->policy->manual) {
+ return KNOT_EOK;
+ }
+ int ret = KNOT_EOK;
+ uint16_t plan_ds_keytag = 0;
+ // generate initial keys if missing
+ if (!key_present(ctx, true, false) && !key_present(ctx, true, true)) {
+ if (ctx->policy->ksk_shared) {
+ ret = share_or_generate_key(ctx, GEN_KSK_FLAGS, ctx->now, false);
+ } else {
+ ret = generate_key(ctx, GEN_KSK_FLAGS, ctx->now, false);
+ }
+ if (ret == KNOT_EOK) {
+ reschedule->plan_ds_query = true;
+ plan_ds_keytag = dnssec_key_get_keytag(ctx->zone->keys[0].key);
+ reschedule->keys_changed = true;
+ if (!ctx->policy->singe_type_signing &&
+ !key_present(ctx, false, true)) {
+ ret = generate_key(ctx, DNSKEY_GENERATE_ZSK, ctx->now, false);
+ }
+ }
+ }
+ // algorithm rollover
+ if (algorithm_present(ctx, ctx->policy->algorithm) == 0 &&
+ !running_rollover(ctx) && ret == KNOT_EOK) {
+ if (ctx->policy->ksk_shared) {
+ ret = share_or_generate_key(ctx, GEN_KSK_FLAGS, 0, true);
+ } else {
+ ret = generate_key(ctx, GEN_KSK_FLAGS, 0, true);
+ }
+ if (!ctx->policy->singe_type_signing && ret == KNOT_EOK) {
+ ret = generate_key(ctx, DNSKEY_GENERATE_ZSK, 0, true);
+ }
+ log_zone_info(ctx->zone->dname, "DNSSEC, algorithm rollover started");
+ if (ret == KNOT_EOK) {
+ reschedule->keys_changed = true;
+ }
+ }
+ // scheme rollover
+ if (!signing_scheme_present(ctx) &&
+ !running_rollover(ctx) && ret == KNOT_EOK) {
+ if (ctx->policy->ksk_shared) {
+ ret = share_or_generate_key(ctx, GEN_KSK_FLAGS, 0, false);
+ } else {
+ ret = generate_key(ctx, GEN_KSK_FLAGS, 0, false);
+ }
+ if (!ctx->policy->singe_type_signing && ret == KNOT_EOK) {
+ ret = generate_key(ctx, DNSKEY_GENERATE_ZSK, 0, false);
+ }
+ log_zone_info(ctx->zone->dname, "DNSSEC, signing scheme rollover started");
+ if (ret == KNOT_EOK) {
+ reschedule->keys_changed = true;
+ }
+ }
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ roll_action_t next = next_action(ctx);
+
+ reschedule->next_rollover = next.time;
+
+ if (knot_time_cmp(reschedule->next_rollover, ctx->now) <= 0) {
+ switch (next.type) {
+ case GENERATE:
+ if (next.ksk && ctx->policy->ksk_shared) {
+ ret = share_or_generate_key(ctx, GEN_KSK_FLAGS, 0, false);
+ } else {
+ ret = generate_key(ctx, next.ksk ? GEN_KSK_FLAGS : DNSKEY_GENERATE_ZSK, 0, false);
+ }
+ if (ret == KNOT_EOK) {
+ log_zone_info(ctx->zone->dname, "DNSSEC, %cSK rollover started",
+ (next.ksk ? 'K' : 'Z'));
+ }
+ break;
+ case PUBLISH:
+ ret = exec_publish(ctx, next.key);
+ break;
+ case SUBMIT:
+ ret = submit_key(ctx, next.key);
+ if (ret == KNOT_EOK) {
+ reschedule->plan_ds_query = true;
+ plan_ds_keytag = dnssec_key_get_keytag(next.key->key);
+ }
+ break;
+ case REPLACE:
+ ret = exec_new_signatures(ctx, next.key, 0);
+ break;
+ case RETIRE:
+ ret = exec_ksk_retire(ctx, next.key);
+ break;
+ case REMOVE:
+ ret = exec_remove_old_key(ctx, next.key);
+ break;
+ default:
+ ret = KNOT_EINVAL;
+ }
+
+ if (ret == KNOT_EOK) {
+ reschedule->keys_changed = true;
+ next = next_action(ctx);
+ reschedule->next_rollover = next.time;
+ } else {
+ log_zone_warning(ctx->zone->dname, "DNSSEC, key rollover, action %s (%s)",
+ roll_action_name(next.type), knot_strerror(ret));
+ // fail => try in 10 seconds #TODO better?
+ reschedule->next_rollover = knot_time_add(knot_time(), 10);
+ }
+ }
+
+ if (ret == KNOT_EOK && knot_time_cmp(reschedule->next_rollover, ctx->now) <= 0) {
+ ret = knot_dnssec_key_rollover(ctx, reschedule);
+ }
+
+ if (ret == KNOT_EOK && reschedule->keys_changed) {
+ ret = kdnssec_ctx_commit(ctx);
+ }
+
+ if (ret == KNOT_EOK && reschedule->plan_ds_query) {
+ char param[32];
+ (void)snprintf(param, sizeof(param), "KEY_SUBMISSION=%hu", plan_ds_keytag);
+ log_fmt_zone(LOG_NOTICE, LOG_SOURCE_ZONE, ctx->zone->dname, param,
+ "DNSSEC, KSK submission, waiting for confirmation");
+ }
+
+ return ret;
+}
+
+int knot_dnssec_ksk_sbm_confirm(kdnssec_ctx_t *ctx, uint32_t retire_delay)
+{
+ for (size_t i = 0; i < ctx->zone->num_keys; i++) {
+ knot_kasp_key_t *key = &ctx->zone->keys[i];
+ if (key->is_ksk && get_key_state(key, ctx->now) == DNSSEC_KEY_STATE_READY) {
+ int ret = exec_new_signatures(ctx, key, retire_delay);
+ if (ret == KNOT_EOK) {
+ ret = kdnssec_ctx_commit(ctx);
+ }
+ return ret;
+ }
+ }
+ return KNOT_ENOENT;
+}
+
+bool zone_has_key_sbm(const kdnssec_ctx_t *ctx)
+{
+ assert(ctx->zone);
+
+ for (size_t i = 0; i < ctx->zone->num_keys; i++) {
+ knot_kasp_key_t *key = &ctx->zone->keys[i];
+ if (key->is_ksk &&
+ (get_key_state(key, ctx->now) == DNSSEC_KEY_STATE_READY ||
+ get_key_state(key, ctx->now) == DNSSEC_KEY_STATE_ACTIVE)) {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/src/knot/dnssec/key-events.h b/src/knot/dnssec/key-events.h
new file mode 100644
index 0000000..ce0b72e
--- /dev/null
+++ b/src/knot/dnssec/key-events.h
@@ -0,0 +1,57 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "knot/dnssec/context.h"
+#include "knot/dnssec/zone-events.h"
+
+/*!
+ * \brief Perform correct ZSK and KSK rollover action and plan next one.
+ *
+ * For given zone, check keys in KASP db and decide what shall be done
+ * according to their timers. Perform the action if they shall be done now,
+ * and tell the user the next time it shall be called.
+ *
+ * This function is optimized to be called from KEY_ROLLOVER_EVENT,
+ * but also during zone load so that the zone gets loaded already with
+ * proper DNSSEC chain.
+ *
+ * \param ctx zone signing context
+ * \param reschedule Out: timestamp of desired next invoke
+ *
+ * \return KNOT_E*
+ */
+int knot_dnssec_key_rollover(kdnssec_ctx_t *ctx, zone_sign_reschedule_t *reschedule);
+
+/*!
+ * \brief Set the submitted KSK to active state and the active one to retired
+ *
+ * \param ctx Zone signing context.
+ * \param retire_delay Retire event delay.
+ *
+ * \return KNOT_E*
+ */
+int knot_dnssec_ksk_sbm_confirm(kdnssec_ctx_t *ctx, uint32_t retire_delay);
+
+/*!
+ * \brief Is there a key in sumbmission phase?
+ *
+ * \param ctx zone signing context
+ *
+ * \return False if there is no submitted key or if error; True otherwise
+ */
+bool zone_has_key_sbm(const kdnssec_ctx_t *ctx);
diff --git a/src/knot/dnssec/nsec-chain.c b/src/knot/dnssec/nsec-chain.c
new file mode 100644
index 0000000..dddb8b2
--- /dev/null
+++ b/src/knot/dnssec/nsec-chain.c
@@ -0,0 +1,444 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "knot/dnssec/nsec-chain.h"
+#include "knot/dnssec/rrset-sign.h"
+#include "knot/dnssec/zone-nsec.h"
+#include "knot/dnssec/zone-sign.h"
+
+/* - NSEC chain construction ------------------------------------------------ */
+
+/*!
+ * \brief Create NSEC RR set.
+ *
+ * \param rrset RRSet to be initialized.
+ * \param from Node that should contain the new RRSet.
+ * \param to Node that should be pointed to from 'from'.
+ * \param ttl Record TTL (SOA's minimum TTL).
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+static int create_nsec_rrset(knot_rrset_t *rrset, const zone_node_t *from,
+ const zone_node_t *to, uint32_t ttl)
+{
+ assert(from);
+ assert(to);
+ knot_rrset_init(rrset, from->owner, KNOT_RRTYPE_NSEC, KNOT_CLASS_IN, ttl);
+
+ // Create bitmap
+ dnssec_nsec_bitmap_t *rr_types = dnssec_nsec_bitmap_new();
+ if (!rr_types) {
+ return KNOT_ENOMEM;
+ }
+
+ bitmap_add_node_rrsets(rr_types, KNOT_RRTYPE_NSEC, from);
+ dnssec_nsec_bitmap_add(rr_types, KNOT_RRTYPE_NSEC);
+ dnssec_nsec_bitmap_add(rr_types, KNOT_RRTYPE_RRSIG);
+
+ // Create RDATA
+ assert(to->owner);
+ size_t next_owner_size = knot_dname_size(to->owner);
+ size_t rdata_size = next_owner_size + dnssec_nsec_bitmap_size(rr_types);
+ uint8_t rdata[rdata_size];
+
+ // Fill RDATA
+ memcpy(rdata, to->owner, next_owner_size);
+ dnssec_nsec_bitmap_write(rr_types, rdata + next_owner_size);
+ dnssec_nsec_bitmap_free(rr_types);
+
+ return knot_rrset_add_rdata(rrset, rdata, rdata_size, NULL);
+}
+
+/*!
+ * \brief Connect two nodes by adding a NSEC RR into the first node.
+ *
+ * Callback function, signature chain_iterate_cb.
+ *
+ * \param a First node.
+ * \param b Second node (immediate follower of a).
+ * \param data Pointer to nsec_chain_iterate_data_t holding parameters
+ * including changeset.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+static int connect_nsec_nodes(zone_node_t *a, zone_node_t *b,
+ nsec_chain_iterate_data_t *data)
+{
+ assert(a);
+ assert(b);
+ assert(data);
+
+ if (b->rrset_count == 0 || b->flags & NODE_FLAGS_NONAUTH) {
+ return NSEC_NODE_SKIP;
+ }
+
+ int ret = KNOT_EOK;
+
+ /*!
+ * If the node has no other RRSets than NSEC (and possibly RRSIGs),
+ * just remove the NSEC and its RRSIG, they are redundant
+ */
+ if (node_rrtype_exists(b, KNOT_RRTYPE_NSEC)
+ && knot_nsec_empty_nsec_and_rrsigs_in_node(b)) {
+ ret = knot_nsec_changeset_remove(b, data->changeset);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ // Skip the 'b' node
+ return NSEC_NODE_SKIP;
+ }
+
+ // create new NSEC
+ knot_rrset_t new_nsec;
+ ret = create_nsec_rrset(&new_nsec, a, b, data->ttl);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ knot_rrset_t old_nsec = node_rrset(a, KNOT_RRTYPE_NSEC);
+
+ if (!knot_rrset_empty(&old_nsec)) {
+ /* Convert old NSEC to lowercase, just in case it's not. */
+ knot_rrset_t *old_nsec_lc = knot_rrset_copy(&old_nsec, NULL);
+ ret = knot_rrset_rr_to_canonical(old_nsec_lc);
+ if (ret != KNOT_EOK) {
+ knot_rrset_free(old_nsec_lc, NULL);
+ return ret;
+ }
+
+ bool equal = knot_rrset_equal(&new_nsec, old_nsec_lc,
+ KNOT_RRSET_COMPARE_WHOLE);
+ equal = (equal && (old_nsec_lc->ttl == new_nsec.ttl));
+ knot_rrset_free(old_nsec_lc, NULL);
+
+ if (equal) {
+ // current NSEC is valid, do nothing
+ knot_rdataset_clear(&new_nsec.rrs, NULL);
+ return KNOT_EOK;
+ }
+
+ ret = knot_nsec_changeset_remove(a, data->changeset);
+ if (ret != KNOT_EOK) {
+ knot_rdataset_clear(&new_nsec.rrs, NULL);
+ return ret;
+ }
+ }
+
+ // Add new NSEC to the changeset (no matter if old was removed)
+ ret = changeset_add_addition(data->changeset, &new_nsec, 0);
+ knot_rdataset_clear(&new_nsec.rrs, NULL);
+ return ret;
+}
+
+/* - API - iterations ------------------------------------------------------- */
+
+/*!
+ * \brief Call a function for each piece of the chain formed by sorted nodes.
+ */
+int knot_nsec_chain_iterate_create(zone_tree_t *nodes,
+ chain_iterate_create_cb callback,
+ nsec_chain_iterate_data_t *data)
+{
+ assert(nodes);
+ assert(callback);
+
+ trie_it_t *it = trie_it_begin(nodes);
+ if (!it) {
+ return KNOT_ENOMEM;
+ }
+
+ if (trie_it_finished(it)) {
+ trie_it_free(it);
+ return KNOT_EINVAL;
+ }
+
+ zone_node_t *first = (zone_node_t *)*trie_it_val(it);
+ zone_node_t *previous = first;
+ zone_node_t *current = first;
+
+ trie_it_next(it);
+
+ int result = KNOT_EOK;
+ while (!trie_it_finished(it)) {
+ current = (zone_node_t *)*trie_it_val(it);
+
+ result = callback(previous, current, data);
+ if (result == NSEC_NODE_SKIP) {
+ // No NSEC should be created for 'current' node, skip
+ ;
+ } else if (result == KNOT_EOK) {
+ previous = current;
+ } else {
+ trie_it_free(it);
+ return result;
+ }
+ trie_it_next(it);
+ }
+
+ trie_it_free(it);
+
+ return result == NSEC_NODE_SKIP ? callback(previous, first, data) :
+ callback(current, first, data);
+}
+
+inline static zone_node_t *it_val(trie_it_t *it)
+{
+ return (zone_node_t *)*trie_it_val(it);
+}
+
+inline static zone_node_t *it_next0(trie_it_t *it, zone_node_t *first)
+{
+ trie_it_next(it);
+ return (trie_it_finished(it) ? first : it_val(it));
+}
+
+static zone_node_t *it_next1(trie_it_t *it, zone_node_t *first)
+{
+ zone_node_t *res;
+ do {
+ res = it_next0(it, first);
+ } while (knot_nsec_empty_nsec_and_rrsigs_in_node(res) || (res->flags & NODE_FLAGS_NONAUTH));
+ return res;
+}
+
+static zone_node_t *it_next2(trie_it_t *it, zone_node_t *first, changeset_t *ch)
+{
+ zone_node_t *res = it_next0(it, first);
+ while (knot_nsec_empty_nsec_and_rrsigs_in_node(res) || (res->flags & NODE_FLAGS_NONAUTH)) {
+ (void)knot_nsec_changeset_remove(res, ch);
+ res = it_next0(it, first);
+ }
+ return res;
+}
+
+static int node_cmp(zone_node_t *a, zone_node_t *b, zone_node_t *first_a, zone_node_t *first_b)
+{
+ assert(knot_dname_is_equal(first_a->owner, first_b->owner));
+ assert(knot_dname_cmp(first_a->owner, a->owner) <= 0);
+ assert(knot_dname_cmp(first_b->owner, b->owner) <= 0);
+ int rev = (a == first_a || b == first_b ? -1 : 1);
+ return rev * knot_dname_cmp(a->owner, b->owner);
+}
+
+#define CHECK_RET if (ret != KNOT_EOK) goto cleanup
+
+int knot_nsec_chain_iterate_fix(zone_tree_t *old_nodes, zone_tree_t *new_nodes,
+ chain_iterate_create_cb callback,
+ nsec_chain_iterate_data_t *data)
+{
+ assert(old_nodes);
+ assert(new_nodes);
+ assert(callback);
+
+ int ret = KNOT_EOK;
+
+ trie_it_t *old_it = trie_it_begin(old_nodes), *new_it = trie_it_begin(new_nodes);
+ if (old_it == NULL || new_it == NULL) {
+ ret = KNOT_ENOMEM;
+ goto cleanup;
+ }
+
+ if (trie_it_finished(new_it)) {
+ ret = KNOT_ENORECORD;
+ goto cleanup;
+ }
+ if (trie_it_finished(old_it)) {
+ ret = KNOT_ENORECORD;
+ goto cleanup;
+ }
+
+ zone_node_t *old_first = it_val(old_it), *new_first = it_val(new_it);
+
+ if (!knot_dname_is_equal(old_first->owner, new_first->owner)) {
+ // this may happen with NSEC3 (on NSEC, it will be apex)
+ // it can be solved, but it would complicate the code
+ // 1. find a common node in both trees (ENORECORD if none)
+ // 2. start from there and cycle around trie_it_finished() until hit first again
+ // 3. modify the dname comparison operator !
+ ret = KNOT_ENORECORD;
+ goto cleanup;
+ }
+
+ if (knot_nsec_empty_nsec_and_rrsigs_in_node(new_first)) {
+ ret = KNOT_EINVAL;
+ goto cleanup;
+ }
+
+ zone_node_t *old_prev = old_first, *new_prev = new_first;
+ zone_node_t *old_curr = it_next1(old_it, old_first);
+ zone_node_t *new_curr = it_next2(new_it, new_first, data->changeset);
+
+ while (1) {
+ bool bitmap_change = !node_bitmap_equal(old_prev, new_prev);
+
+ int cmp = node_cmp(old_curr, new_curr, old_first, new_first);
+ if (bitmap_change && cmp == 0) {
+ // if cmp != 0, the nsec chain will be locally rebuilt anyway,
+ // so no need to update bitmap in such case
+ // overall, we now have dnames: old_prev == new_prev && old_curr == new_curr
+ ret = knot_nsec_changeset_remove(old_prev, data->changeset);
+ CHECK_RET;
+ ret = callback(new_prev, new_curr, data);
+ CHECK_RET;
+ }
+
+ while (cmp != 0) {
+ if (cmp < 0) {
+ // a node was removed
+ ret = knot_nsec_changeset_remove(old_prev, data->changeset);
+ CHECK_RET;
+ ret = knot_nsec_changeset_remove(old_curr, data->changeset);
+ CHECK_RET;
+ old_prev = old_curr;
+ old_curr = it_next1(old_it, old_first);
+ ret = callback(new_prev, new_curr, data);
+ CHECK_RET;
+ } else {
+ // a node was added
+ ret = knot_nsec_changeset_remove(old_prev, data->changeset);
+ CHECK_RET;
+ ret = callback(new_prev, new_curr, data);
+ CHECK_RET;
+ new_prev = new_curr;
+ new_curr = it_next2(new_it, new_first, data->changeset);
+ ret = callback(new_prev, new_curr, data);
+ CHECK_RET;
+ }
+ cmp = node_cmp(old_curr, new_curr, old_first, new_first);
+ }
+
+ if (old_curr == old_first && new_curr == new_first) {
+ break;
+ }
+
+ old_prev = old_curr;
+ new_prev = new_curr;
+ old_curr = it_next1(old_it, old_first);
+ new_curr = it_next2(new_it, new_first, data->changeset);
+ }
+
+cleanup:
+ trie_it_free(old_it);
+ trie_it_free(new_it);
+ return ret;
+}
+
+/* - API - utility functions ------------------------------------------------ */
+
+/*!
+ * \brief Add entry for removed NSEC to the changeset.
+ */
+int knot_nsec_changeset_remove(const zone_node_t *n, changeset_t *changeset)
+{
+ if (changeset == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int result = KNOT_EOK;
+
+ knot_rrset_t nsec = node_rrset(n, KNOT_RRTYPE_NSEC);
+ if (knot_rrset_empty(&nsec)) {
+ nsec = node_rrset(n, KNOT_RRTYPE_NSEC3);
+ }
+ if (!knot_rrset_empty(&nsec)) {
+ // update changeset
+ result = changeset_add_removal(changeset, &nsec, 0);
+ if (result != KNOT_EOK) {
+ return result;
+ }
+ }
+
+ knot_rrset_t rrsigs = node_rrset(n, KNOT_RRTYPE_RRSIG);
+ if (!knot_rrset_empty(&rrsigs)) {
+ knot_rrset_t synth_rrsigs;
+ knot_rrset_init(&synth_rrsigs, n->owner, KNOT_RRTYPE_RRSIG,
+ KNOT_CLASS_IN, rrsigs.ttl);
+ result = knot_synth_rrsig(KNOT_RRTYPE_NSEC, &rrsigs.rrs,
+ &synth_rrsigs.rrs, NULL);
+ if (result == KNOT_ENOENT) {
+ // Try removing NSEC3 RRSIGs
+ result = knot_synth_rrsig(KNOT_RRTYPE_NSEC3, &rrsigs.rrs,
+ &synth_rrsigs.rrs, NULL);
+ }
+
+ if (result != KNOT_EOK) {
+ knot_rdataset_clear(&synth_rrsigs.rrs, NULL);
+ if (result != KNOT_ENOENT) {
+ return result;
+ }
+ return KNOT_EOK;
+ }
+
+ // store RRSIG
+ result = changeset_add_removal(changeset, &synth_rrsigs, 0);
+ knot_rdataset_clear(&synth_rrsigs.rrs, NULL);
+ }
+
+ return result;
+}
+
+/*!
+ * \brief Checks whether the node is empty or eventually contains only NSEC and
+ * RRSIGs.
+ */
+bool knot_nsec_empty_nsec_and_rrsigs_in_node(const zone_node_t *n)
+{
+ assert(n);
+ for (int i = 0; i < n->rrset_count; ++i) {
+ knot_rrset_t rrset = node_rrset_at(n, i);
+ if (rrset.type != KNOT_RRTYPE_NSEC &&
+ rrset.type != KNOT_RRTYPE_RRSIG) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* - API - Chain creation --------------------------------------------------- */
+
+/*!
+ * \brief Create new NSEC chain, add differences from current into a changeset.
+ */
+int knot_nsec_create_chain(const zone_contents_t *zone, uint32_t ttl,
+ changeset_t *changeset)
+{
+ assert(zone);
+ assert(zone->nodes);
+ assert(changeset);
+
+ nsec_chain_iterate_data_t data = { ttl, changeset, zone };
+
+ return knot_nsec_chain_iterate_create(zone->nodes,
+ connect_nsec_nodes, &data);
+}
+
+int knot_nsec_fix_chain(const zone_contents_t *old_zone, const zone_contents_t *new_zone,
+ uint32_t ttl, changeset_t *changeset)
+{
+ assert(old_zone);
+ assert(new_zone);
+ assert(old_zone->nodes);
+ assert(new_zone->nodes);
+ assert(changeset);
+
+ nsec_chain_iterate_data_t data = { ttl, changeset, new_zone };
+
+ return knot_nsec_chain_iterate_fix(old_zone->nodes, new_zone->nodes,
+ connect_nsec_nodes, &data);
+}
diff --git a/src/knot/dnssec/nsec-chain.h b/src/knot/dnssec/nsec-chain.h
new file mode 100644
index 0000000..a2f102e
--- /dev/null
+++ b/src/knot/dnssec/nsec-chain.h
@@ -0,0 +1,151 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "knot/zone/contents.h"
+#include "knot/updates/changesets.h"
+#include "libdnssec/nsec.h"
+
+/*!
+ * \brief Parameters to be used in connect_nsec_nodes callback.
+ */
+typedef struct {
+ uint32_t ttl; // TTL for NSEC(3) records
+ changeset_t *changeset; // Changeset for NSEC(3) changes
+ const zone_contents_t *zone; // Updated zone
+} nsec_chain_iterate_data_t;
+
+/*!
+ * \brief Used to control changeset iteration functions.
+ */
+enum {
+ NSEC_NODE_SKIP = 1,
+};
+
+/*!
+ * \brief Callback used when creating NSEC chains.
+ */
+typedef int (*chain_iterate_create_cb)(zone_node_t *, zone_node_t *,
+ nsec_chain_iterate_data_t *);
+
+/*!
+ * \brief Add all RR types from a node into the bitmap.
+ */
+inline static void bitmap_add_node_rrsets(dnssec_nsec_bitmap_t *bitmap,
+ enum knot_rr_type nsec_type,
+ const zone_node_t *node)
+{
+ bool deleg = node->flags & NODE_FLAGS_DELEG;
+ bool apex = node->parent == NULL;
+ for (int i = 0; i < node->rrset_count; i++) {
+ knot_rrset_t rr = node_rrset_at(node, i);
+ if (deleg && (rr.type != KNOT_RRTYPE_NS && rr.type != KNOT_RRTYPE_DS)) {
+ continue;
+ }
+ if (rr.type == KNOT_RRTYPE_NSEC || rr.type == KNOT_RRTYPE_RRSIG) {
+ continue;
+ }
+ // NSEC3PARAM in zone apex is maintained automatically
+ if (apex && rr.type == KNOT_RRTYPE_NSEC3PARAM && nsec_type != KNOT_RRTYPE_NSEC3) {
+ continue;
+ }
+
+ dnssec_nsec_bitmap_add(bitmap, rr.type);
+ }
+}
+
+/*!
+ * \brief Call a function for each piece of the chain formed by sorted nodes.
+ *
+ * \note If the callback function returns anything other than KNOT_EOK, the
+ * iteration is terminated and the error code is propagated.
+ *
+ * \param nodes Zone nodes.
+ * \param callback Callback function.
+ * \param data Custom data supplied to the callback function.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_nsec_chain_iterate_create(zone_tree_t *nodes,
+ chain_iterate_create_cb callback,
+ nsec_chain_iterate_data_t *data);
+
+/*!
+ * \brief Call the chain-connecting function for modified records and their neighbours.
+ *
+ * \param old_nodes Old state of zone nodes.
+ * \param new_nodes New state of zone nodes.
+ * \param callback Callback function.
+ * \param data Custom data supplied, incl. changeset to be updated.
+ *
+ * \retval KNOT_ENORECORD if the chain must be recreated from scratch.
+ * \return KNOT_E*
+ */
+int knot_nsec_chain_iterate_fix(zone_tree_t *old_nodes, zone_tree_t *new_nodes,
+ chain_iterate_create_cb callback,
+ nsec_chain_iterate_data_t *data);
+
+/*!
+ * \brief Add entry for removed NSEC(3) and its RRSIG to the changeset.
+ *
+ * \param n Node to extract NSEC(3) from.
+ * \param changeset Changeset to add the old RR into.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_nsec_changeset_remove(const zone_node_t *n, changeset_t *changeset);
+
+/*!
+ * \brief Checks whether the node is empty or eventually contains only NSEC and
+ * RRSIGs.
+ *
+ * \param n Node to check.
+ *
+ * \retval true if the node is empty or contains only NSEC and RRSIGs.
+ * \retval false otherwise.
+ */
+bool knot_nsec_empty_nsec_and_rrsigs_in_node(const zone_node_t *n);
+
+/*!
+ * \brief Create new NSEC chain, add differences from current into a changeset.
+ *
+ * \param zone Zone.
+ * \param ttl TTL for created NSEC records.
+ * \param changeset Changeset the differences will be put into.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_nsec_create_chain(const zone_contents_t *zone, uint32_t ttl,
+ changeset_t *changeset);
+
+/*!
+ * \brief Fix existing NSEC chain to cover the changes in zone contents.
+ *
+ * \param old_zone Old zone contents.
+ * \param new_zone New zone contents.
+ * \param ttl TTL for created NSEC records.
+ * \param changeset Changeset the differences will be put into.
+ *
+ * \retval KNOT_ENORECORD if the chain must be recreated from scratch.
+ * \return KNOT_E*
+ */
+int knot_nsec_fix_chain(const zone_contents_t *old_zone, const zone_contents_t *new_zone,
+ uint32_t ttl, changeset_t *changeset);
diff --git a/src/knot/dnssec/nsec3-chain.c b/src/knot/dnssec/nsec3-chain.c
new file mode 100644
index 0000000..eb756e1
--- /dev/null
+++ b/src/knot/dnssec/nsec3-chain.c
@@ -0,0 +1,830 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "libknot/dname.h"
+#include "knot/dnssec/nsec-chain.h"
+#include "knot/dnssec/nsec3-chain.h"
+#include "knot/dnssec/zone-sign.h"
+#include "knot/dnssec/zone-nsec.h"
+#include "knot/zone/zone-diff.h"
+#include "contrib/base32hex.h"
+#include "contrib/macros.h"
+#include "contrib/wire_ctx.h"
+
+/* - NSEC3 node comparison -------------------------------------------------- */
+
+/*!
+ * \brief Perform some basic checks that the node is a valid NSEC3 node.
+ */
+inline static bool valid_nsec3_node(const zone_node_t *node)
+{
+ assert(node);
+
+ if (node->rrset_count > 2) {
+ return false;
+ }
+
+ const knot_rdataset_t *nsec3 = node_rdataset(node, KNOT_RRTYPE_NSEC3);
+ if (nsec3 == NULL) {
+ return false;
+ }
+
+ if (nsec3->count != 1) {
+ return false;
+ }
+
+ return true;
+}
+
+/*!
+ * \brief Check if two nodes are equal.
+ */
+static bool are_nsec3_nodes_equal(const zone_node_t *a, const zone_node_t *b)
+{
+ if (!(valid_nsec3_node(a) && valid_nsec3_node(b))) {
+ return false;
+ }
+
+ knot_rrset_t a_rrset = node_rrset(a, KNOT_RRTYPE_NSEC3);
+ knot_rrset_t b_rrset = node_rrset(b, KNOT_RRTYPE_NSEC3);
+ return knot_rrset_equal(&a_rrset, &b_rrset, KNOT_RRSET_COMPARE_WHOLE) &&
+ (a_rrset.ttl == b_rrset.ttl);
+}
+
+static bool nsec3_opt_out(const zone_node_t *node, bool opt_out_enabled)
+{
+ return (opt_out_enabled && (node->flags & NODE_FLAGS_DELEG) &&
+ !node_rrtype_exists(node, KNOT_RRTYPE_DS));
+}
+
+/*!
+ * \brief Check whether at least one RR type in node should be signed,
+ * used when signing with NSEC3.
+ *
+ * \param node Node for which the check is done.
+ *
+ * \return true/false.
+ */
+static bool node_should_be_signed_nsec3(const zone_node_t *n)
+{
+ for (int i = 0; i < n->rrset_count; i++) {
+ knot_rrset_t rrset = node_rrset_at(n, i);
+ if (rrset.type == KNOT_RRTYPE_NSEC ||
+ rrset.type == KNOT_RRTYPE_RRSIG) {
+ continue;
+ }
+
+ if (knot_zone_sign_rr_should_be_signed(n, &rrset)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* - RRSIGs handling for NSEC3 ---------------------------------------------- */
+
+/*!
+ * \brief Shallow copy NSEC3 signatures from the one node to the second one.
+ * Just sets the pointer, needed only for comparison.
+ */
+static int shallow_copy_signature(const zone_node_t *from, zone_node_t *to)
+{
+ assert(valid_nsec3_node(from));
+ assert(valid_nsec3_node(to));
+
+ knot_rrset_t from_sig = node_rrset(from, KNOT_RRTYPE_RRSIG);
+ if (knot_rrset_empty(&from_sig)) {
+ return KNOT_EOK;
+ }
+ return node_add_rrset(to, &from_sig, NULL);
+}
+
+/*!
+ * \brief Reuse signatatures by shallow copying them from one tree to another.
+ */
+static int copy_signatures(zone_tree_t *from, zone_tree_t *to)
+{
+ if (zone_tree_is_empty(from)) {
+ return KNOT_EOK;
+ }
+
+ assert(to);
+
+ trie_it_t *it = trie_it_begin(from);
+
+ for (/* NOP */; !trie_it_finished(it); trie_it_next(it)) {
+ zone_node_t *node_from = (zone_node_t *)*trie_it_val(it);
+
+ zone_node_t *node_to = zone_tree_get(to, node_from->owner);
+ if (node_to == NULL) {
+ continue;
+ }
+
+ if (!are_nsec3_nodes_equal(node_from, node_to)) {
+ continue;
+ }
+
+ int ret = shallow_copy_signature(node_from, node_to);
+ if (ret != KNOT_EOK) {
+ trie_it_free(it);
+ return ret;
+ }
+ }
+
+ trie_it_free(it);
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Custom NSEC3 tree free function.
+ *
+ */
+static void free_nsec3_tree(zone_tree_t *nodes)
+{
+ assert(nodes);
+
+ trie_it_t *it = trie_it_begin(nodes);
+ for (/* NOP */; !trie_it_finished(it); trie_it_next(it)) {
+ zone_node_t *node = (zone_node_t *)*trie_it_val(it);
+ // newly allocated NSEC3 nodes
+ knot_rdataset_t *nsec3 = node_rdataset(node, KNOT_RRTYPE_NSEC3);
+ knot_rdataset_t *rrsig = node_rdataset(node, KNOT_RRTYPE_RRSIG);
+ knot_rdataset_clear(nsec3, NULL);
+ knot_rdataset_clear(rrsig, NULL);
+ node_free(node, NULL);
+ }
+
+ trie_it_free(it);
+ zone_tree_free(&nodes);
+}
+
+/* - NSEC3 nodes construction ----------------------------------------------- */
+
+/*!
+ * \brief Get NSEC3 RDATA size.
+ */
+static size_t nsec3_rdata_size(const dnssec_nsec3_params_t *params,
+ const dnssec_nsec_bitmap_t *rr_types)
+{
+ assert(params);
+ assert(rr_types);
+
+ return 6 + params->salt.size
+ + dnssec_nsec3_hash_length(params->algorithm)
+ + dnssec_nsec_bitmap_size(rr_types);
+}
+
+/*!
+ * \brief Fill NSEC3 RDATA.
+ *
+ * \note Content of next hash field is not changed.
+ */
+static int nsec3_fill_rdata(uint8_t *rdata, size_t rdata_len,
+ const dnssec_nsec3_params_t *params,
+ const dnssec_nsec_bitmap_t *rr_types,
+ const uint8_t *next_hashed)
+{
+ assert(rdata);
+ assert(params);
+ assert(rr_types);
+
+ uint8_t hash_length = dnssec_nsec3_hash_length(params->algorithm);
+
+ wire_ctx_t wire = wire_ctx_init(rdata, rdata_len);
+
+ wire_ctx_write_u8(&wire, params->algorithm);
+ wire_ctx_write_u8(&wire, params->flags);
+ wire_ctx_write_u16(&wire, params->iterations);
+ wire_ctx_write_u8(&wire, params->salt.size);
+ wire_ctx_write(&wire, params->salt.data, params->salt.size);
+ wire_ctx_write_u8(&wire, hash_length);
+
+ if (next_hashed != NULL) {
+ wire_ctx_write(&wire, next_hashed, hash_length);
+ } else {
+ wire_ctx_skip(&wire, hash_length);
+ }
+
+ if (wire.error != KNOT_EOK) {
+ return wire.error;
+ }
+
+ dnssec_nsec_bitmap_write(rr_types, wire.position);
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Creates NSEC3 RRSet.
+ *
+ * \param owner Owner for the RRSet.
+ * \param params Parsed NSEC3PARAM.
+ * \param rr_types Bitmap.
+ * \param next_hashed Next hashed.
+ * \param ttl TTL for the RRSet.
+ *
+ * \return Pointer to created RRSet on success, NULL on errors.
+ */
+static int create_nsec3_rrset(knot_rrset_t *rrset,
+ const knot_dname_t *owner,
+ const dnssec_nsec3_params_t *params,
+ const dnssec_nsec_bitmap_t *rr_types,
+ const uint8_t *next_hashed,
+ uint32_t ttl)
+{
+ assert(rrset);
+ assert(owner);
+ assert(params);
+ assert(rr_types);
+
+ knot_dname_t *owner_copy = knot_dname_copy(owner, NULL);
+ if (owner_copy == NULL) {
+ return KNOT_ENOMEM;
+ }
+ knot_rrset_init(rrset, owner_copy, KNOT_RRTYPE_NSEC3, KNOT_CLASS_IN, ttl);
+
+ size_t rdata_size = nsec3_rdata_size(params, rr_types);
+ uint8_t rdata[rdata_size];
+ memset(rdata, 0, rdata_size);
+ int ret = nsec3_fill_rdata(rdata, rdata_size, params, rr_types,
+ next_hashed);
+ if (ret != KNOT_EOK) {
+ knot_dname_free(owner_copy, NULL);
+ return ret;
+ }
+
+ ret = knot_rrset_add_rdata(rrset, rdata, rdata_size, NULL);
+ if (ret != KNOT_EOK) {
+ knot_dname_free(owner_copy, NULL);
+ return ret;
+ }
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Create NSEC3 node.
+ */
+static zone_node_t *create_nsec3_node(const knot_dname_t *owner,
+ const dnssec_nsec3_params_t *nsec3_params,
+ zone_node_t *apex_node,
+ const dnssec_nsec_bitmap_t *rr_types,
+ uint32_t ttl)
+{
+ assert(owner);
+ assert(nsec3_params);
+ assert(apex_node);
+ assert(rr_types);
+
+ zone_node_t *new_node = node_new(owner, NULL);
+ if (!new_node) {
+ return NULL;
+ }
+
+ node_set_parent(new_node, apex_node);
+
+ knot_rrset_t nsec3_rrset;
+ int ret = create_nsec3_rrset(&nsec3_rrset, owner, nsec3_params,
+ rr_types, NULL, ttl);
+ if (ret != KNOT_EOK) {
+ node_free(new_node, NULL);
+ return NULL;
+ }
+
+ ret = node_add_rrset(new_node, &nsec3_rrset, NULL);
+ knot_rrset_clear(&nsec3_rrset, NULL);
+ if (ret != KNOT_EOK) {
+ node_free(new_node, NULL);
+ return NULL;
+ }
+
+ return new_node;
+}
+
+/*!
+ * \brief Create new NSEC3 node for given regular node.
+ *
+ * \param node Node for which the NSEC3 node is created.
+ * \param apex Zone apex node.
+ * \param params NSEC3 hash function parameters.
+ * \param ttl TTL of the new NSEC3 node.
+ * \param apex_cds Hint to guess apex node type bitmap: false=just DNSKEY, true=DNSKEY,CDS,CDNSKEY.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+static zone_node_t *create_nsec3_node_for_node(const zone_node_t *node,
+ zone_node_t *apex,
+ const dnssec_nsec3_params_t *params,
+ uint32_t ttl)
+{
+ assert(node);
+ assert(apex);
+ assert(params);
+
+ uint8_t nsec3_owner[KNOT_DNAME_MAXLEN];
+ int ret = knot_create_nsec3_owner(nsec3_owner, sizeof(nsec3_owner),
+ node->owner, apex->owner, params);
+ if (ret != KNOT_EOK) {
+ return NULL;
+ }
+
+ dnssec_nsec_bitmap_t *rr_types = dnssec_nsec_bitmap_new();
+ if (!rr_types) {
+ return NULL;
+ }
+
+ bitmap_add_node_rrsets(rr_types, KNOT_RRTYPE_NSEC3, node);
+ if (node->rrset_count > 0 && node_should_be_signed_nsec3(node)) {
+ dnssec_nsec_bitmap_add(rr_types, KNOT_RRTYPE_RRSIG);
+ }
+ if (node == apex) {
+ dnssec_nsec_bitmap_add(rr_types, KNOT_RRTYPE_NSEC3PARAM);
+ }
+
+ zone_node_t *nsec3_node = create_nsec3_node(nsec3_owner, params, apex,
+ rr_types, ttl);
+ dnssec_nsec_bitmap_free(rr_types);
+
+ return nsec3_node;
+}
+
+/* - NSEC3 chain creation --------------------------------------------------- */
+
+// see connect_nsec3_nodes() for what this function does
+static int connect_nsec3_base(knot_rdataset_t *a_rrs, const knot_dname_t *b_name)
+{
+ assert(a_rrs);
+ uint8_t algorithm = knot_nsec3_alg(a_rrs->rdata);
+ if (algorithm == 0) {
+ return KNOT_EINVAL;
+ }
+
+ uint8_t raw_length = knot_nsec3_next_len(a_rrs->rdata);
+ uint8_t *raw_hash = (uint8_t *)knot_nsec3_next(a_rrs->rdata);
+ if (raw_hash == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ assert(raw_length == dnssec_nsec3_hash_length(algorithm));
+
+ char *b32_hash = knot_dname_to_str_alloc(b_name);
+ if (!b32_hash) {
+ return KNOT_ENOMEM;
+ }
+
+ char *b32_end = strchr(b32_hash, '.');
+ if (!b32_end) {
+ free(b32_hash);
+ return KNOT_EINVAL;
+ }
+
+ size_t b32_length = b32_end - b32_hash;
+ int32_t written = base32hex_decode((uint8_t *)b32_hash, b32_length,
+ raw_hash, raw_length);
+
+ free(b32_hash);
+
+ if (written != raw_length) {
+ return KNOT_EINVAL;
+ }
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Connect two nodes by filling 'hash' field of NSEC3 RDATA of the first node.
+ *
+ * \param a First node. Gets modified in-place!
+ * \param b Second node (immediate follower of a).
+ * \param data Unused parameter.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+static int connect_nsec3_nodes(zone_node_t *a, zone_node_t *b,
+ nsec_chain_iterate_data_t *data)
+{
+ assert(a);
+ assert(b);
+ UNUSED(data);
+
+ assert(a->rrset_count == 1);
+
+ return connect_nsec3_base(node_rdataset(a, KNOT_RRTYPE_NSEC3), b->owner);
+}
+
+/*!
+ * \brief Connect two nodes by updating the changeset.
+ *
+ * \param a First node.
+ * \param b Second node.
+ * \param data Contains the changeset to be updated.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+static int connect_nsec3_nodes2(zone_node_t *a, zone_node_t *b,
+ nsec_chain_iterate_data_t *data)
+{
+ assert(data);
+
+ // check if the NSEC3 rrset has not been updated in changeset
+ knot_rrset_t aorig = node_rrset(a, KNOT_RRTYPE_NSEC3);
+ const zone_node_t *ch_a = zone_contents_find_nsec3_node(data->changeset->add, a->owner);
+ if (node_rrtype_exists(ch_a, KNOT_RRTYPE_NSEC3)) {
+ aorig = node_rrset(ch_a, KNOT_RRTYPE_NSEC3);
+ }
+
+ // prepare a copy of NSEC3 rrsets in question
+ knot_rrset_t *acopy = knot_rrset_copy(&aorig, NULL);
+ if (acopy == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ // connect the copied rrset
+ int ret = connect_nsec3_base(&acopy->rrs, b->owner);
+ if (ret != KNOT_EOK || knot_rrset_equal(&aorig, acopy, KNOT_RRSET_COMPARE_WHOLE)) {
+ knot_rrset_free(acopy, NULL);
+ return ret;
+ }
+
+ // add the removed original and the updated copy to changeset
+ if (node_rrtype_exists(ch_a, KNOT_RRTYPE_NSEC3)) {
+ ret = changeset_remove_addition(data->changeset, &aorig);
+ } else {
+ ret = changeset_add_removal(data->changeset, &aorig, 0);
+ }
+ if (ret == KNOT_EOK) {
+ ret = changeset_add_addition(data->changeset, acopy, CHANGESET_CHECK | CHANGESET_CHECK_CANCELOUT);
+ }
+ knot_rrset_free(acopy, NULL);
+ return ret;
+}
+
+/*!
+ * \brief Create NSEC3 node for each regular node in the zone.
+ *
+ * \param zone Zone.
+ * \param params NSEC3 params.
+ * \param ttl TTL for the created NSEC records.
+ * \param cds_in_apex Hint to guess apex node type bitmap: false=just DNSKEY, true=DNSKEY,CDS,CDNSKEY.
+ * \param nsec3_nodes Tree whereto new NSEC3 nodes will be added.
+ * \param chgset Changeset used for possible NSEC removals
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+static int create_nsec3_nodes(const zone_contents_t *zone,
+ const dnssec_nsec3_params_t *params,
+ uint32_t ttl,
+ zone_tree_t *nsec3_nodes,
+ changeset_t *chgset)
+{
+ assert(zone);
+ assert(nsec3_nodes);
+ assert(chgset);
+
+ int result = KNOT_EOK;
+
+ trie_it_t *it = trie_it_begin(zone->nodes);
+ while (!trie_it_finished(it)) {
+ zone_node_t *node = (zone_node_t *)*trie_it_val(it);
+
+ /*!
+ * Remove possible NSEC from the node. (Do not allow both NSEC
+ * and NSEC3 in the zone at once.)
+ */
+ result = knot_nsec_changeset_remove(node, chgset);
+ if (result != KNOT_EOK) {
+ break;
+ }
+ if (node->flags & NODE_FLAGS_NONAUTH || node->flags & NODE_FLAGS_EMPTY) {
+ trie_it_next(it);
+ continue;
+ }
+
+ zone_node_t *nsec3_node;
+ nsec3_node = create_nsec3_node_for_node(node, zone->apex,
+ params, ttl);
+ if (!nsec3_node) {
+ result = KNOT_ENOMEM;
+ break;
+ }
+
+ result = zone_tree_insert(nsec3_nodes, nsec3_node);
+ if (result != KNOT_EOK) {
+ break;
+ }
+
+ trie_it_next(it);
+ }
+
+ trie_it_free(it);
+
+ return result;
+}
+
+/*!
+ * \brief For given dname, check if anything changed in zone_update, and recreate (possibly unconnected) NSEC3 nodes appropriately.
+ *
+ * The removed/added/modified NSEC3 records are stored in two ways depending of their nature:
+ * a) Those NSEC3 records pre-created with (probably) empty "next dname", waiting to be connected with 2nd round, are put directly into the zone_update_t structure.
+ * b) Those with just recreated bitmap are just added into the changeset. We must note them in the changeset anyway when reconnecting!
+ * The reason is, that the (a) type of records are not going to be signed, but they are needed for proper connecting the NSEC3 chain.
+ * On the other hand, the (b) type of records need to be signed and they have no influence on the chain structure.
+ *
+ * \param update Zone update structure holding zone contents changes.
+ * \param params NSEC3 params.
+ * \param ttl TTL for newly created NSEC3 records.
+ * \param chgset Changeset to hold the changes.
+ * \param for_node Domain name of the node in question.
+ *
+ * \retval KNOT_ENORECORD if the NSEC3 chain shall be rather recreated completely.
+ * \return KNOT_EOK, KNOT_E* if any error.
+ */
+static int fix_nsec3_for_node(zone_update_t *update, const dnssec_nsec3_params_t *params,
+ uint32_t ttl, bool opt_out, changeset_t *chgset, const knot_dname_t *for_node)
+{
+ // check if we need to do something
+ const zone_node_t *old_n = zone_contents_find_node(update->zone->contents, for_node);
+ const zone_node_t *new_n = zone_contents_find_node(update->new_cont, for_node);
+ if (node_bitmap_equal(old_n, new_n)) {
+ return KNOT_EOK;
+ }
+
+ if ((new_n != NULL && knot_nsec_empty_nsec_and_rrsigs_in_node(new_n) && new_n->children > 0) ||
+ (old_n != NULL && knot_nsec_empty_nsec_and_rrsigs_in_node(old_n) && old_n->children > 0)) {
+ // handling empty non-terminal creation and downfall is too difficult, recreate NSEC3 from scratch
+ return KNOT_ENORECORD;
+ }
+
+ uint8_t for_node_hashed[KNOT_DNAME_MAXLEN];
+ int ret = knot_create_nsec3_owner(for_node_hashed, sizeof(for_node_hashed),
+ for_node, update->new_cont->apex->owner, params);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // saved hash of next node
+ uint8_t *next_hash = NULL;
+ uint8_t next_length = 0;
+
+ bool add_nsec3 = (new_n != NULL && !node_empty(new_n) && !(new_n->flags & NODE_FLAGS_NONAUTH) &&
+ !nsec3_opt_out(new_n, opt_out));
+
+ // remove (all) existing NSEC3
+ const zone_node_t *old_nsec3_n = zone_contents_find_nsec3_node(update->zone->contents, for_node_hashed);
+ if (old_nsec3_n != NULL) {
+ knot_rrset_t rem_nsec3 = node_rrset(old_nsec3_n, KNOT_RRTYPE_NSEC3);
+ if (!knot_rrset_empty(&rem_nsec3)) {
+ knot_rrset_t rem_rrsig = node_rrset(old_nsec3_n, KNOT_RRTYPE_RRSIG);
+ if (!add_nsec3) {
+ ret = zone_update_remove(update, &rem_nsec3);
+ if (ret == KNOT_EOK && !knot_rrset_empty(&rem_rrsig)) {
+ ret = zone_update_remove(update, &rem_rrsig);
+ }
+ } else {
+ ret = changeset_add_removal(chgset, &rem_nsec3, CHANGESET_CHECK | CHANGESET_CHECK_CANCELOUT);
+ if (ret == KNOT_EOK && !knot_rrset_empty(&rem_rrsig)) {
+ ret = changeset_add_removal(chgset, &rem_rrsig, 0);
+ }
+ }
+ next_hash = (uint8_t *)knot_nsec3_next(rem_nsec3.rrs.rdata);
+ next_length = knot_nsec3_next_len(rem_nsec3.rrs.rdata);
+ }
+ }
+
+ // add NSEC3 with correct bitmap
+ if (add_nsec3 && ret == KNOT_EOK) {
+ zone_node_t *new_nsec3_n = create_nsec3_node_for_node(new_n, update->new_cont->apex, params, ttl);
+ if (new_nsec3_n == NULL) {
+ return KNOT_ENOMEM;
+ }
+ knot_rrset_t add_nsec3 = node_rrset(new_nsec3_n, KNOT_RRTYPE_NSEC3);
+ assert(!knot_rrset_empty(&add_nsec3));
+
+ // copy hash of next element from removed record
+ if (next_hash != NULL) {
+ uint8_t *raw_hash = (uint8_t *)knot_nsec3_next(add_nsec3.rrs.rdata);
+ uint8_t raw_length = knot_nsec3_next_len(add_nsec3.rrs.rdata);
+ assert(raw_hash != NULL);
+ if (raw_length != next_length) {
+ ret = KNOT_EMALF;
+ } else {
+ memcpy(raw_hash, next_hash, raw_length);
+ }
+ }
+ if (ret == KNOT_EOK) {
+ if (next_hash == NULL) {
+ ret = zone_update_add(update, &add_nsec3);
+ } else {
+ ret = changeset_add_addition(chgset, &add_nsec3, CHANGESET_CHECK | CHANGESET_CHECK_CANCELOUT);
+ }
+ }
+ node_free_rrsets(new_nsec3_n, NULL);
+ node_free(new_nsec3_n, NULL);
+ }
+
+ return ret;
+}
+
+static int fix_nsec3_nodes(zone_update_t *update, const dnssec_nsec3_params_t *params,
+ uint32_t ttl, bool opt_out, changeset_t *chgset)
+{
+ assert(update);
+
+ int ret = KNOT_EOK;
+
+ trie_it_t *rem_it = trie_it_begin(update->change.remove->nodes);
+ while (!trie_it_finished(rem_it) && ret == KNOT_EOK) {
+ zone_node_t *n = (zone_node_t *)*trie_it_val(rem_it);
+ ret = fix_nsec3_for_node(update, params, ttl, opt_out, chgset, n->owner);
+ trie_it_next(rem_it);
+ }
+ trie_it_free(rem_it);
+
+ trie_it_t *add_it = trie_it_begin(update->change.add->nodes);
+ while (!trie_it_finished(add_it) && ret == KNOT_EOK) {
+ zone_node_t *n = (zone_node_t *)*trie_it_val(add_it);
+ ret = fix_nsec3_for_node(update, params, ttl, opt_out, chgset, n->owner);
+ trie_it_next(add_it);
+ }
+ trie_it_free(add_it);
+
+ return ret;
+}
+
+/*!
+ * \brief Checks if NSEC3 should be generated for this node.
+ *
+ * \retval true if the node has no children and contains no RRSets or only
+ * RRSIGs and NSECs.
+ * \retval false otherwise.
+ */
+static bool nsec3_is_empty(zone_node_t *node, bool opt_out)
+{
+ if (node->children > 0) {
+ return false;
+ }
+
+ return knot_nsec_empty_nsec_and_rrsigs_in_node(node) || nsec3_opt_out(node, opt_out);
+}
+
+/*!
+ * \brief Marks node and its parents as empty if NSEC3 should not be generated
+ * for them.
+ *
+ * It also lowers the children count for the parent of marked node. This must be
+ * fixed before further operations on the zone.
+ */
+static int nsec3_mark_empty(zone_node_t **node_p, void *data)
+{
+ zone_node_t *node = *node_p;
+
+ if (!(node->flags & NODE_FLAGS_EMPTY) && nsec3_is_empty(node, (data != NULL))) {
+ /*!
+ * Mark this node and all parent nodes that meet the same
+ * criteria as empty.
+ */
+ node->flags |= NODE_FLAGS_EMPTY;
+
+ if (node->parent) {
+ /* We must decrease the parent's children count,
+ * but only temporarily! It must be set back right after
+ * the operation
+ */
+ node->parent->children--;
+ /* Recurse using the parent node */
+ return nsec3_mark_empty(&node->parent, data);
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Resets the empty flag in the node and increases its parent's children
+ * count if the node was marked as empty.
+ *
+ * The children count of node's parent is increased if this node was marked as
+ * empty, as it was previously decreased in the \a nsec3_mark_empty() function.
+ */
+static int nsec3_reset(zone_node_t **node_p, void *data)
+{
+ UNUSED(data);
+ zone_node_t *node = *node_p;
+
+ if (node->flags & NODE_FLAGS_EMPTY) {
+ /* If node was marked as empty, increase its parent's children
+ * count.
+ */
+ node->parent->children++;
+ /* Clear the 'empty' flag. */
+ node->flags &= ~NODE_FLAGS_EMPTY;
+ }
+
+ return KNOT_EOK;
+}
+
+/* - Public API ------------------------------------------------------------- */
+
+/*!
+ * \brief Create new NSEC3 chain, add differences from current into a changeset.
+ */
+int knot_nsec3_create_chain(const zone_contents_t *zone,
+ const dnssec_nsec3_params_t *params,
+ uint32_t ttl,
+ bool opt_out,
+ changeset_t *changeset)
+{
+ assert(zone);
+ assert(params);
+ assert(changeset);
+
+ int result;
+
+ zone_tree_t *nsec3_nodes = zone_tree_create();
+ if (!nsec3_nodes) {
+ return KNOT_ENOMEM;
+ }
+
+ /* Before creating NSEC3 nodes, we must temporarily mark those nodes
+ * that may still be in the zone, but for which the NSEC3s should not
+ * be created. I.e. nodes with only RRSIG (or NSEC+RRSIG) and their
+ * predecessors if they are empty.
+ *
+ * The flag will be removed when the node is encountered during NSEC3
+ * creation procedure.
+ */
+ result = zone_tree_apply(zone->nodes, nsec3_mark_empty, (opt_out ? (void *)zone : NULL));
+ if (result != KNOT_EOK) {
+ free_nsec3_tree(nsec3_nodes);
+ return result;
+ }
+
+ result = create_nsec3_nodes(zone, params, ttl, nsec3_nodes, changeset);
+ if (result != KNOT_EOK) {
+ free_nsec3_tree(nsec3_nodes);
+ return result;
+ }
+
+ /* Resets empty node flag and children count in nodes that were
+ * previously marked as empty. Must be called after NSEC3 generation,
+ * so that flags and children count are back to normal before further
+ * processing.
+ */
+ result = zone_tree_apply(zone->nodes, nsec3_reset, NULL);
+ if (result != KNOT_EOK) {
+ free_nsec3_tree(nsec3_nodes);
+ return result;
+ }
+
+ result = knot_nsec_chain_iterate_create(nsec3_nodes,
+ connect_nsec3_nodes, NULL);
+ if (result != KNOT_EOK) {
+ free_nsec3_tree(nsec3_nodes);
+ return result;
+ }
+
+ copy_signatures(zone->nsec3_nodes, nsec3_nodes);
+
+ result = zone_tree_add_diff(zone->nsec3_nodes, nsec3_nodes, changeset);
+
+ free_nsec3_tree(nsec3_nodes);
+
+ return result;
+}
+
+int knot_nsec3_fix_chain(zone_update_t *update,
+ const dnssec_nsec3_params_t *params,
+ uint32_t ttl,
+ bool opt_out,
+ changeset_t *changeset)
+{
+
+ int ret = fix_nsec3_nodes(update, params, ttl, opt_out, changeset);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ nsec_chain_iterate_data_t data = { ttl, changeset, update->new_cont };
+
+ ret = knot_nsec_chain_iterate_fix(update->zone->contents->nsec3_nodes,
+ update->new_cont->nsec3_nodes,
+ connect_nsec3_nodes2, &data);
+
+ return ret;
+}
diff --git a/src/knot/dnssec/nsec3-chain.h b/src/knot/dnssec/nsec3-chain.h
new file mode 100644
index 0000000..6dafc88
--- /dev/null
+++ b/src/knot/dnssec/nsec3-chain.h
@@ -0,0 +1,57 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include "libdnssec/nsec.h"
+#include "knot/updates/changesets.h"
+#include "knot/updates/zone-update.h"
+#include "knot/zone/contents.h"
+
+/*!
+ * \brief Creates new NSEC3 chain, add differences from current into a changeset.
+ *
+ * \param zone Zone to be checked.
+ * \param params NSEC3 parameters.
+ * \param ttl TTL for new records.
+ * \param opt_out NSEC3 opt-out enabled for insecure delegations.
+ * \param changeset Changeset to store changes into.
+ *
+ * \return KNOT_E*
+ */
+int knot_nsec3_create_chain(const zone_contents_t *zone,
+ const dnssec_nsec3_params_t *params,
+ uint32_t ttl,
+ bool opt_out,
+ changeset_t *changeset);
+
+/*!
+ * \brief Updates zone's NSEC3 chain to follow the differences in zone update.
+ *
+ * \param update Zone Update structure holding the zone and its update. Also modified!
+ * \param params NSEC3 parameters.
+ * \param ttl TTL for new records.
+ * \param opt_out NSEC3 opt-out enabled for insecure delegations.
+ * \param changeset Changeset to store changes into. Some changes are pushed directly to update.
+ *
+ * \retval KNOT_ENORECORD if the chain must be recreated from scratch.
+ * \return KNOT_E*
+ */
+int knot_nsec3_fix_chain(zone_update_t *update,
+ const dnssec_nsec3_params_t *params,
+ uint32_t ttl, bool opt_out,
+ changeset_t *changeset);
diff --git a/src/knot/dnssec/policy.c b/src/knot/dnssec/policy.c
new file mode 100644
index 0000000..fdafb4c
--- /dev/null
+++ b/src/knot/dnssec/policy.c
@@ -0,0 +1,47 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+
+#include "knot/dnssec/policy.h"
+#include "libknot/rrtype/soa.h"
+
+static uint32_t zone_soa_min_ttl(const zone_contents_t *zone)
+{
+ knot_rrset_t soa = node_rrset(zone->apex, KNOT_RRTYPE_SOA);
+ return knot_soa_minimum(soa.rrs.rdata);
+}
+
+static uint32_t zone_soa_ttl(const zone_contents_t *zone)
+{
+ knot_rrset_t soa = node_rrset(zone->apex, KNOT_RRTYPE_SOA);
+ return soa.ttl;
+}
+
+void update_policy_from_zone(knot_kasp_policy_t *policy,
+ const zone_contents_t *zone)
+{
+ assert(policy);
+ assert(zone);
+
+ // Use SOA TTL if not configured.
+ if (policy->dnskey_ttl == UINT32_MAX) {
+ policy->dnskey_ttl = zone_soa_ttl(zone);
+ }
+
+ policy->soa_minimal_ttl = zone_soa_min_ttl(zone);
+ policy->zone_maximal_ttl = zone->max_ttl;
+}
diff --git a/src/knot/dnssec/policy.h b/src/knot/dnssec/policy.h
new file mode 100644
index 0000000..b6ba4d1
--- /dev/null
+++ b/src/knot/dnssec/policy.h
@@ -0,0 +1,26 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include "knot/dnssec/context.h"
+#include "knot/zone/contents.h"
+
+/*!
+ * \brief Update policy parameters depending on zone content.
+ */
+void update_policy_from_zone(knot_kasp_policy_t *policy,
+ const zone_contents_t *zone);
diff --git a/src/knot/dnssec/rrset-sign.c b/src/knot/dnssec/rrset-sign.c
new file mode 100644
index 0000000..6004ab9
--- /dev/null
+++ b/src/knot/dnssec/rrset-sign.c
@@ -0,0 +1,395 @@
+/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "contrib/wire_ctx.h"
+#include "libdnssec/error.h"
+#include "knot/dnssec/rrset-sign.h"
+#include "knot/dnssec/zone-sign.h"
+#include "libknot/libknot.h"
+
+#define RRSIG_RDATA_SIGNER_OFFSET 18
+
+#define RRSIG_INCEPT_IN_PAST (90 * 60)
+
+/*- Creating of RRSIGs -------------------------------------------------------*/
+
+/*!
+ * \brief Get size of RRSIG RDATA for a given key without signature.
+ */
+static size_t rrsig_rdata_header_size(const dnssec_key_t *key)
+{
+ if (!key) {
+ return 0;
+ }
+
+ size_t size;
+
+ // static part
+
+ size = sizeof(uint16_t) // type covered
+ + sizeof(uint8_t) // algorithm
+ + sizeof(uint8_t) // labels
+ + sizeof(uint32_t) // original TTL
+ + sizeof(uint32_t) // signature expiration
+ + sizeof(uint32_t) // signature inception
+ + sizeof(uint16_t); // key tag (footprint)
+
+ assert(size == RRSIG_RDATA_SIGNER_OFFSET);
+
+ // variable part
+
+ size += knot_dname_size(dnssec_key_get_dname(key));
+
+ return size;
+}
+
+/*!
+ * \brief Write RRSIG RDATA except signature.
+ *
+ * \note This can be also used for SIG(0) if proper parameters are supplied.
+ *
+ * \param rdata_len Length of RDATA.
+ * \param rdata Pointer to RDATA.
+ * \param key Key used for signing.
+ * \param covered_type Type of the covered RR.
+ * \param owner_labels Number of labels covered by the signature.
+ * \param sig_incepted Timestamp of signature inception.
+ * \param sig_expires Timestamp of signature expiration.
+ */
+static int rrsig_write_rdata(uint8_t *rdata, size_t rdata_len,
+ const dnssec_key_t *key,
+ uint16_t covered_type, uint8_t owner_labels,
+ uint32_t owner_ttl, uint32_t sig_incepted,
+ uint32_t sig_expires)
+{
+ if (!rdata || !key || sig_incepted >= sig_expires) {
+ return KNOT_EINVAL;
+ }
+
+ uint8_t algorithm = dnssec_key_get_algorithm(key);
+ uint16_t keytag = dnssec_key_get_keytag(key);
+ const uint8_t *signer = dnssec_key_get_dname(key);
+ assert(signer);
+
+ wire_ctx_t wire = wire_ctx_init(rdata, rdata_len);
+
+ wire_ctx_write_u16(&wire, covered_type); // type covered
+ wire_ctx_write_u8(&wire, algorithm); // algorithm
+ wire_ctx_write_u8(&wire, owner_labels); // labels
+ wire_ctx_write_u32(&wire, owner_ttl); // original TTL
+ wire_ctx_write_u32(&wire, sig_expires); // signature expiration
+ wire_ctx_write_u32(&wire, sig_incepted); // signature inception
+ wire_ctx_write_u16(&wire, keytag); // key fingerprint
+ assert(wire_ctx_offset(&wire) == RRSIG_RDATA_SIGNER_OFFSET);
+ wire_ctx_write(&wire, signer, knot_dname_size(signer)); // signer
+
+ return wire.error;
+}
+
+/*- Computation of signatures ------------------------------------------------*/
+
+/*!
+ * \brief Add RRSIG RDATA without signature to signing context.
+ *
+ * Requires signer name in RDATA in canonical form.
+ *
+ * \param ctx Signing context.
+ * \param rdata Pointer to RRSIG RDATA.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+static int sign_ctx_add_self(dnssec_sign_ctx_t *ctx, const uint8_t *rdata)
+{
+ assert(ctx);
+ assert(rdata);
+
+ int result;
+
+ // static header
+
+ dnssec_binary_t header = { 0 };
+ header.data = (uint8_t *)rdata;
+ header.size = RRSIG_RDATA_SIGNER_OFFSET;
+
+ result = dnssec_sign_add(ctx, &header);
+ if (result != DNSSEC_EOK) {
+ return result;
+ }
+
+ // signer name
+
+ const uint8_t *rdata_signer = rdata + RRSIG_RDATA_SIGNER_OFFSET;
+ dnssec_binary_t signer = { 0 };
+ signer.data = knot_dname_copy(rdata_signer, NULL);
+ signer.size = knot_dname_size(signer.data);
+
+ result = dnssec_sign_add(ctx, &signer);
+ free(signer.data);
+
+ return result;
+}
+
+/*!
+ * \brief Add covered RRs to signing context.
+ *
+ * Requires all DNAMEs in canonical form and all RRs ordered canonically.
+ *
+ * \param ctx Signing context.
+ * \param covered Covered RRs.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+static int sign_ctx_add_records(dnssec_sign_ctx_t *ctx, const knot_rrset_t *covered)
+{
+ // huge block of rrsets can be optionally created
+ uint8_t *rrwf = malloc(KNOT_WIRE_MAX_PKTSIZE);
+ if (!rrwf) {
+ return KNOT_ENOMEM;
+ }
+
+ int written = knot_rrset_to_wire(covered, rrwf, KNOT_WIRE_MAX_PKTSIZE, NULL);
+ if (written < 0) {
+ free(rrwf);
+ return written;
+ }
+
+ dnssec_binary_t rrset_wire = { 0 };
+ rrset_wire.size = written;
+ rrset_wire.data = rrwf;
+ int result = dnssec_sign_add(ctx, &rrset_wire);
+ free(rrwf);
+
+ return result;
+}
+
+int knot_sign_ctx_add_data(dnssec_sign_ctx_t *ctx,
+ const uint8_t *rrsig_rdata,
+ const knot_rrset_t *covered)
+{
+ if (!ctx || !rrsig_rdata || knot_rrset_empty(covered)) {
+ return KNOT_EINVAL;
+ }
+
+ int result = sign_ctx_add_self(ctx, rrsig_rdata);
+ if (result != KNOT_EOK) {
+ return result;
+ }
+
+ return sign_ctx_add_records(ctx, covered);
+}
+
+/*!
+ * \brief Create RRSIG RDATA.
+ *
+ * \param[in] rrsigs RR set with RRSIGS.
+ * \param[in] ctx DNSSEC signing context.
+ * \param[in] covered RR covered by the signature.
+ * \param[in] key Key used for signing.
+ * \param[in] sig_incepted Timestamp of signature inception.
+ * \param[in] sig_expires Timestamp of signature expiration.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+static int rrsigs_create_rdata(knot_rrset_t *rrsigs, dnssec_sign_ctx_t *ctx,
+ const knot_rrset_t *covered,
+ const dnssec_key_t *key,
+ uint32_t sig_incepted, uint32_t sig_expires,
+ knot_mm_t *mm)
+{
+ assert(rrsigs);
+ assert(rrsigs->type == KNOT_RRTYPE_RRSIG);
+ assert(!knot_rrset_empty(covered));
+ assert(key);
+
+ size_t header_size = rrsig_rdata_header_size(key);
+ assert(header_size != 0);
+
+ uint8_t owner_labels = knot_dname_labels(covered->owner, NULL);
+ if (knot_dname_is_wildcard(covered->owner)) {
+ owner_labels -= 1;
+ }
+
+ uint8_t header[header_size];
+ int res = rrsig_write_rdata(header, header_size,
+ key, covered->type, owner_labels,
+ covered->ttl, sig_incepted, sig_expires);
+ assert(res == KNOT_EOK);
+
+ res = dnssec_sign_init(ctx);
+ if (res != KNOT_EOK) {
+ return res;
+ }
+
+ res = knot_sign_ctx_add_data(ctx, header, covered);
+ if (res != KNOT_EOK) {
+ return res;
+ }
+
+ dnssec_binary_t signature = { 0 };
+ res = dnssec_sign_write(ctx, &signature);
+ if (res != DNSSEC_EOK) {
+ return res;
+ }
+ assert(signature.size > 0);
+
+ size_t rrsig_size = header_size + signature.size;
+ uint8_t rrsig[rrsig_size];
+ memcpy(rrsig, header, header_size);
+ memcpy(rrsig + header_size, signature.data, signature.size);
+
+ dnssec_binary_free(&signature);
+
+ return knot_rrset_add_rdata(rrsigs, rrsig, rrsig_size, mm);
+}
+
+int knot_sign_rrset(knot_rrset_t *rrsigs, const knot_rrset_t *covered,
+ const dnssec_key_t *key, dnssec_sign_ctx_t *sign_ctx,
+ const kdnssec_ctx_t *dnssec_ctx, knot_mm_t *mm, knot_time_t *expires)
+{
+ if (knot_rrset_empty(covered) || !key || !sign_ctx || !dnssec_ctx ||
+ rrsigs->type != KNOT_RRTYPE_RRSIG ||
+ !knot_dname_is_equal(rrsigs->owner, covered->owner)
+ ) {
+ return KNOT_EINVAL;
+ }
+
+ uint32_t sig_incept = dnssec_ctx->now - RRSIG_INCEPT_IN_PAST;
+ uint32_t sig_expire = dnssec_ctx->now + dnssec_ctx->policy->rrsig_lifetime;
+
+ int ret = rrsigs_create_rdata(rrsigs, sign_ctx, covered, key, sig_incept,
+ sig_expire, mm);
+ if (ret == KNOT_EOK && expires != NULL) {
+ *expires = knot_time_min(*expires, sig_expire);
+ }
+ return ret;
+}
+
+int knot_sign_rrset2(knot_rrset_t *rrsigs, const knot_rrset_t *rrset,
+ zone_sign_ctx_t *sign_ctx, knot_mm_t *mm)
+{
+ if (rrsigs == NULL || rrset == NULL || sign_ctx == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ for (size_t i = 0; i < sign_ctx->count; i++) {
+ zone_key_t *key = &sign_ctx->keys[i];
+
+ if (!knot_zone_sign_use_key(key, rrset)) {
+ continue;
+ }
+
+ int ret = knot_sign_rrset(rrsigs, rrset, key->key, sign_ctx->sign_ctxs[i],
+ sign_ctx->dnssec_ctx, mm, NULL);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+int knot_synth_rrsig(uint16_t type, const knot_rdataset_t *rrsig_rrs,
+ knot_rdataset_t *out_sig, knot_mm_t *mm)
+{
+ if (rrsig_rrs == NULL) {
+ return KNOT_ENOENT;
+ }
+
+ if (out_sig == NULL || out_sig->count > 0) {
+ return KNOT_EINVAL;
+ }
+
+ knot_rdata_t *rr_to_copy = rrsig_rrs->rdata;
+ for (int i = 0; i < rrsig_rrs->count; ++i) {
+ if (type == knot_rrsig_type_covered(rr_to_copy)) {
+ int ret = knot_rdataset_add(out_sig, rr_to_copy, mm);
+ if (ret != KNOT_EOK) {
+ knot_rdataset_clear(out_sig, mm);
+ return ret;
+ }
+ }
+ rr_to_copy = knot_rdataset_next(rr_to_copy);
+ }
+
+ return out_sig->count > 0 ? KNOT_EOK : KNOT_ENOENT;
+}
+
+/*- Verification of signatures -----------------------------------------------*/
+
+/*!
+ * \brief Check if the signature is expired.
+ *
+ * \param rrsig RRSIG rdata.
+ * \param policy DNSSEC policy.
+ *
+ * \return Signature is expired or should be replaced soon.
+ */
+static bool is_expired_signature(const knot_rdata_t *rrsig, uint32_t now,
+ uint32_t refresh_before)
+{
+ assert(rrsig);
+
+ uint32_t expire_at = knot_rrsig_sig_expiration(rrsig);
+ uint32_t expire_in = expire_at > now ? expire_at - now : 0;
+
+ return expire_in <= refresh_before;
+}
+
+int knot_check_signature(const knot_rrset_t *covered,
+ const knot_rrset_t *rrsigs, size_t pos,
+ const dnssec_key_t *key,
+ dnssec_sign_ctx_t *sign_ctx,
+ const kdnssec_ctx_t *dnssec_ctx)
+{
+ if (knot_rrset_empty(covered) || knot_rrset_empty(rrsigs) || !key ||
+ !sign_ctx || !dnssec_ctx) {
+ return KNOT_EINVAL;
+ }
+
+ knot_rdata_t *rrsig = knot_rdataset_at(&rrsigs->rrs, pos);
+ assert(rrsig);
+
+ if (is_expired_signature(rrsig, dnssec_ctx->now,
+ dnssec_ctx->policy->rrsig_refresh_before)) {
+ return DNSSEC_INVALID_SIGNATURE;
+ }
+
+ // identify fields in the signature being validated
+
+ dnssec_binary_t signature = {
+ .size = knot_rrsig_signature_len(rrsig),
+ .data = (uint8_t *)knot_rrsig_signature(rrsig)
+ };
+ if (signature.data == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ // perform the validation
+
+ int result = dnssec_sign_init(sign_ctx);
+ if (result != KNOT_EOK) {
+ return result;
+ }
+
+ result = knot_sign_ctx_add_data(sign_ctx, rrsig->data, covered);
+ if (result != KNOT_EOK) {
+ return result;
+ }
+
+ return dnssec_sign_verify(sign_ctx, &signature);
+}
diff --git a/src/knot/dnssec/rrset-sign.h b/src/knot/dnssec/rrset-sign.h
new file mode 100644
index 0000000..b1dd74c
--- /dev/null
+++ b/src/knot/dnssec/rrset-sign.h
@@ -0,0 +1,112 @@
+/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "libdnssec/key.h"
+#include "libdnssec/sign.h"
+#include "knot/dnssec/context.h"
+#include "knot/dnssec/zone-keys.h"
+#include "libknot/rrset.h"
+
+/*!
+ * \brief Create RRSIG RR for given RR set.
+ *
+ * \param rrsigs RR set with RRSIGs into which the result will be added.
+ * \param covered RR set to create a new signature for.
+ * \param key Signing key.
+ * \param sign_ctx Signing context.
+ * \param dnssec_ctx DNSSEC context.
+ * \param mm Memory context.
+ * \param expires Out: When will the new RRSIG expire.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_sign_rrset(knot_rrset_t *rrsigs,
+ const knot_rrset_t *covered,
+ const dnssec_key_t *key,
+ dnssec_sign_ctx_t *sign_ctx,
+ const kdnssec_ctx_t *dnssec_ctx,
+ knot_mm_t *mm,
+ knot_time_t *expires);
+
+/*!
+ * \brief Create RRSIG RR for given RR set, choose which key to use.
+ *
+ * \param rrsigs RR set with RRSIGs into which the result will be added.
+ * \param rrset RR set to create a new signature for.
+ * \param sign_ctx Zone signing context.
+ * \param mm Memory context.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_sign_rrset2(knot_rrset_t *rrsigs,
+ const knot_rrset_t *rrset,
+ zone_sign_ctx_t *sign_ctx,
+ knot_mm_t *mm);
+
+/*!
+ * \brief Add all data covered by signature into signing context.
+ *
+ * RFC 4034: The signature covers RRSIG RDATA field (excluding the signature)
+ * and all matching RR records, which are ordered canonically.
+ *
+ * Requires all DNAMEs in canonical form and all RRs ordered canonically.
+ *
+ * \param ctx Signing context.
+ * \param rrsig_rdata RRSIG RDATA with populated fields except signature.
+ * \param covered Covered RRs.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_sign_ctx_add_data(dnssec_sign_ctx_t *ctx,
+ const uint8_t *rrsig_rdata,
+ const knot_rrset_t *covered);
+
+/*!
+ * \brief Creates new RRS using \a rrsig_rrs as a source. Only those RRs that
+ * cover given \a type are copied into \a out_sig
+ *
+ * \param type Covered type.
+ * \param rrsig_rrs Source RRS.
+ * \param out_sig Output RRS.
+ * \param mm Memory context.
+ *
+ * \retval KNOT_EOK if some RRSIG was found.
+ * \retval KNOT_EINVAL if no RRSIGs were found.
+ * \retval Error code other than EINVAL on error.
+ */
+int knot_synth_rrsig(uint16_t type, const knot_rdataset_t *rrsig_rrs,
+ knot_rdataset_t *out_sig, knot_mm_t *mm);
+
+/*!
+ * \brief Check if RRSIG signature is valid.
+ *
+ * \param covered RRs covered by the signature.
+ * \param rrsigs RR set with RRSIGs.
+ * \param pos Number of RRSIG RR in 'rrsigs' to be validated.
+ * \param key Signing key.
+ * \param sign_ctx Signing context.
+ * \param dnssec_ctx DNSSEC context.
+ *
+ * \return Error code, KNOT_EOK if successful and the signature is valid.
+ * \retval KNOT_DNSSEC_EINVALID_SIGNATURE The signature is invalid.
+ */
+int knot_check_signature(const knot_rrset_t *covered,
+ const knot_rrset_t *rrsigs, size_t pos,
+ const dnssec_key_t *key,
+ dnssec_sign_ctx_t *sign_ctx,
+ const kdnssec_ctx_t *dnssec_ctx);
diff --git a/src/knot/dnssec/zone-events.c b/src/knot/dnssec/zone-events.c
new file mode 100644
index 0000000..b919ee9
--- /dev/null
+++ b/src/knot/dnssec/zone-events.c
@@ -0,0 +1,312 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "libdnssec/error.h"
+#include "libdnssec/random.h"
+#include "libknot/libknot.h"
+#include "knot/conf/conf.h"
+#include "knot/common/log.h"
+#include "knot/dnssec/key-events.h"
+#include "knot/dnssec/policy.h"
+#include "knot/dnssec/zone-events.h"
+#include "knot/dnssec/zone-keys.h"
+#include "knot/dnssec/zone-nsec.h"
+#include "knot/dnssec/zone-sign.h"
+
+static int sign_init(zone_contents_t *zone, zone_sign_flags_t flags,
+ kdnssec_ctx_t *ctx, zone_sign_reschedule_t *reschedule)
+{
+ assert(zone);
+ assert(ctx);
+
+ const knot_dname_t *zone_name = zone->apex->owner;
+
+ int r = kdnssec_ctx_init(conf(), ctx, zone_name, NULL);
+ if (r != KNOT_EOK) {
+ return r;
+ }
+
+ // perform nsec3resalt if pending
+
+ if (reschedule->allow_nsec3resalt) {
+ r = knot_dnssec_nsec3resalt(ctx, &reschedule->allow_nsec3resalt, &reschedule->next_nsec3resalt);
+ if (r != KNOT_EOK) {
+ return r;
+ }
+ }
+
+ r = zone_contents_adjust_full(zone);
+ if (r != KNOT_EOK) {
+ return r;
+ }
+
+ // update policy based on the zone content
+
+ update_policy_from_zone(ctx->policy, zone);
+
+ // perform key rollover if needed
+
+ if (reschedule->allow_rollover) {
+ r = knot_dnssec_key_rollover(ctx, reschedule);
+ }
+ if (r != KNOT_EOK) {
+ return r;
+ }
+
+ // RRSIG handling
+
+ ctx->rrsig_drop_existing = flags & ZONE_SIGN_DROP_SIGNATURES;
+
+ return KNOT_EOK;
+}
+
+static knot_time_t schedule_next(kdnssec_ctx_t *kctx, const zone_keyset_t *keyset,
+ knot_time_t zone_expire)
+{
+ knot_time_t zone_refresh = knot_time_add(zone_expire, -(knot_timediff_t)kctx->policy->rrsig_refresh_before);
+
+ knot_time_t dnskey_update = knot_get_next_zone_key_event(keyset);
+ knot_time_t next = knot_time_min(zone_refresh, dnskey_update);
+
+ return next;
+}
+
+static int generate_salt(dnssec_binary_t *salt, uint16_t length)
+{
+ assert(salt);
+ dnssec_binary_t new_salt = { 0 };
+
+ if (length > 0) {
+ int r = dnssec_binary_alloc(&new_salt, length);
+ if (r != KNOT_EOK) {
+ return knot_error_from_libdnssec(r);
+ }
+
+ r = dnssec_random_binary(&new_salt);
+ if (r != KNOT_EOK) {
+ dnssec_binary_free(&new_salt);
+ return knot_error_from_libdnssec(r);
+ }
+ }
+
+ dnssec_binary_free(salt);
+ *salt = new_salt;
+
+ return KNOT_EOK;
+}
+
+// TODO preserve the resalt timeout in timers-db instead of kasp_db
+
+int knot_dnssec_nsec3resalt(kdnssec_ctx_t *ctx, bool *salt_changed, knot_time_t *when_resalt)
+{
+ int ret = KNOT_EOK;
+
+ if (!ctx->policy->nsec3_enabled || ctx->policy->nsec3_salt_length == 0) {
+ return KNOT_EOK;
+ }
+
+ if (ctx->policy->manual) {
+ return KNOT_EOK;
+ }
+
+ if (ctx->zone->nsec3_salt.size != ctx->policy->nsec3_salt_length) {
+ *when_resalt = ctx->now;
+ } else if (knot_time_cmp(ctx->now, ctx->zone->nsec3_salt_created) < 0) {
+ return KNOT_EINVAL;
+ } else {
+ *when_resalt = ctx->zone->nsec3_salt_created + ctx->policy->nsec3_salt_lifetime;
+ }
+
+ if (knot_time_cmp(*when_resalt, ctx->now) <= 0) {
+ ret = generate_salt(&ctx->zone->nsec3_salt, ctx->policy->nsec3_salt_length);
+ if (ret == KNOT_EOK) {
+ ctx->zone->nsec3_salt_created = ctx->now;
+ ret = kdnssec_ctx_commit(ctx);
+ *salt_changed = true;
+ }
+ // continue to planning next resalt even if NOK
+ *when_resalt = knot_time_add(ctx->now, ctx->policy->nsec3_salt_lifetime);
+ }
+
+ return ret;
+}
+
+int knot_dnssec_zone_sign(zone_update_t *update,
+ zone_sign_flags_t flags,
+ zone_sign_reschedule_t *reschedule)
+{
+ if (!update || !reschedule) {
+ return KNOT_EINVAL;
+ }
+
+ int result = KNOT_ERROR;
+ const knot_dname_t *zone_name = update->new_cont->apex->owner;
+ kdnssec_ctx_t ctx = { 0 };
+ zone_keyset_t keyset = { 0 };
+
+ // signing pipeline
+
+ result = sign_init(update->new_cont, flags, &ctx, reschedule);
+ if (result != KNOT_EOK) {
+ log_zone_error(zone_name, "DNSSEC, failed to initialize (%s)",
+ knot_strerror(result));
+ goto done;
+ }
+
+ result = load_zone_keys(&ctx, &keyset, true);
+ if (result != KNOT_EOK) {
+ log_zone_error(zone_name, "DNSSEC, failed to load keys (%s)",
+ knot_strerror(result));
+ goto done;
+ }
+
+ log_zone_info(zone_name, "DNSSEC, signing started");
+
+ result = knot_zone_sign_update_dnskeys(update, &keyset, &ctx);
+ if (result != KNOT_EOK) {
+ log_zone_error(zone_name, "DNSSEC, failed to update DNSKEY records (%s)",
+ knot_strerror(result));
+ goto done;
+ }
+
+ result = knot_zone_create_nsec_chain(update, &keyset, &ctx, false);
+ if (result != KNOT_EOK) {
+ log_zone_error(zone_name, "DNSSEC, failed to create NSEC%s chain (%s)",
+ ctx.policy->nsec3_enabled ? "3" : "",
+ knot_strerror(result));
+ goto done;
+ }
+
+ knot_time_t zone_expire = 0;
+ result = knot_zone_sign(update, &keyset, &ctx, &zone_expire);
+ if (result != KNOT_EOK) {
+ log_zone_error(zone_name, "DNSSEC, failed to sign zone content (%s)",
+ knot_strerror(result));
+ goto done;
+ }
+
+ // SOA finishing
+
+ if (zone_update_no_change(update) &&
+ !knot_zone_sign_soa_expired(update->new_cont, &keyset, &ctx)) {
+ log_zone_info(zone_name, "DNSSEC, zone is up-to-date");
+ goto done;
+ }
+
+ if (!(flags & ZONE_SIGN_KEEP_SERIAL) && zone_update_to(update) == NULL) {
+ result = zone_update_increment_soa(update, conf());
+ if (result == KNOT_EOK) {
+ result = knot_zone_sign_soa(update, &keyset, &ctx);
+ }
+ if (result != KNOT_EOK) {
+ log_zone_error(zone_name, "DNSSEC, failed to update SOA record (%s)",
+ knot_strerror(result));
+ goto done;
+ }
+ }
+
+ log_zone_info(zone_name, "DNSSEC, successfully signed");
+
+done:
+ if (result == KNOT_EOK) {
+ reschedule->next_sign = schedule_next(&ctx, &keyset, zone_expire);
+ }
+
+ free_zone_keys(&keyset);
+ kdnssec_ctx_deinit(&ctx);
+
+ return result;
+}
+
+int knot_dnssec_sign_update(zone_update_t *update, zone_sign_reschedule_t *reschedule)
+{
+ if (update == NULL || reschedule == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int result = KNOT_ERROR;
+ const knot_dname_t *zone_name = update->new_cont->apex->owner;
+ kdnssec_ctx_t ctx = { 0 };
+ zone_keyset_t keyset = { 0 };
+
+ // signing pipeline
+
+ result = sign_init(update->new_cont, 0, &ctx, reschedule);
+ if (result != KNOT_EOK) {
+ log_zone_error(zone_name, "DNSSEC, failed to initialize (%s)",
+ knot_strerror(result));
+ goto done;
+ }
+
+ result = load_zone_keys(&ctx, &keyset, false);
+ if (result != KNOT_EOK) {
+ log_zone_error(zone_name, "DNSSEC, failed to load keys (%s)",
+ knot_strerror(result));
+ goto done;
+ }
+
+ knot_time_t expire_at = 0;
+ result = knot_zone_sign_update(update, &keyset, &ctx, &expire_at);
+ if (result != KNOT_EOK) {
+ log_zone_error(zone_name, "DNSSEC, failed to sign changeset (%s)",
+ knot_strerror(result));
+ goto done;
+ }
+
+ result = knot_zone_fix_nsec_chain(update, &keyset, &ctx, true);
+ if (result != KNOT_EOK) {
+ log_zone_error(zone_name, "DNSSEC, failed to fix NSEC%s chain (%s)",
+ ctx.policy->nsec3_enabled ? "3" : "",
+ knot_strerror(result));
+ goto done;
+ }
+
+ bool soa_changed = (knot_soa_serial(node_rdataset(update->zone->contents->apex, KNOT_RRTYPE_SOA)->rdata) !=
+ knot_soa_serial(node_rdataset(update->new_cont->apex, KNOT_RRTYPE_SOA)->rdata));
+
+ if (zone_update_no_change(update) && !soa_changed &&
+ !knot_zone_sign_soa_expired(update->new_cont, &keyset, &ctx)) {
+ log_zone_info(zone_name, "DNSSEC, zone is up-to-date");
+ goto done;
+ }
+
+ if (!soa_changed) {
+ // incrementing SOA just of it has not been modified by the update
+ result = zone_update_increment_soa(update, conf());
+ }
+ if (result == KNOT_EOK) {
+ result = knot_zone_sign_soa(update, &keyset, &ctx);
+ }
+ if (result != KNOT_EOK) {
+ log_zone_error(zone_name, "DNSSEC, failed to update SOA record (%s)",
+ knot_strerror(result));
+ goto done;
+ }
+
+ log_zone_info(zone_name, "DNSSEC, successfully signed");
+
+done:
+ if (result == KNOT_EOK) {
+ reschedule->next_sign = schedule_next(&ctx, &keyset, expire_at);
+ }
+
+ free_zone_keys(&keyset);
+ kdnssec_ctx_deinit(&ctx);
+
+ return result;
+}
diff --git a/src/knot/dnssec/zone-events.h b/src/knot/dnssec/zone-events.h
new file mode 100644
index 0000000..3bfd20a
--- /dev/null
+++ b/src/knot/dnssec/zone-events.h
@@ -0,0 +1,95 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <time.h>
+
+#include "knot/zone/zone.h"
+#include "knot/updates/changesets.h"
+#include "knot/updates/zone-update.h"
+#include "knot/dnssec/context.h"
+
+enum zone_sign_flags {
+ ZONE_SIGN_NONE = 0,
+ ZONE_SIGN_DROP_SIGNATURES = (1 << 0),
+ ZONE_SIGN_KEEP_SERIAL = (1 << 1),
+};
+
+typedef enum zone_sign_flags zone_sign_flags_t;
+
+typedef struct {
+ knot_time_t next_sign;
+ knot_time_t next_rollover;
+ knot_time_t next_nsec3resalt;
+ bool keys_changed;
+ bool plan_ds_query;
+ bool allow_rollover; // this one is set by the caller
+ bool allow_nsec3resalt; // this one is set by the caller and modified by the salter
+} zone_sign_reschedule_t;
+
+/*!
+ * \brief Generate/rollover keys in keystore as needed.
+ *
+ * \param kctx Pointers to the keytore, policy, etc.
+ * \param zone_name Zone name.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_dnssec_sign_process_events(const kdnssec_ctx_t *kctx,
+ const knot_dname_t *zone_name);
+
+/*!
+ * \brief DNSSEC re-sign zone, store new records into changeset. Valid signatures
+ * and NSEC(3) records will not be changed.
+ *
+ * \param update Zone Update structure with current zone contents to be updated by signing.
+ * \param flags Zone signing flags.
+ * \param reschedule Signature refresh time of the oldest signature in zone.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_dnssec_zone_sign(zone_update_t *update,
+ zone_sign_flags_t flags,
+ zone_sign_reschedule_t *reschedule);
+
+/*!
+ * \brief Sign changeset (inside incremental Zone Update) created by DDNS or so...
+ *
+ * \param update Zone Update structure with current zone contents, changes to be signed and to be updated with signatures.
+ * \param reschedule Signature refresh time of the new signatures.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_dnssec_sign_update(zone_update_t *update, zone_sign_reschedule_t *reschedule);
+
+/*!
+ * \brief Create new NCES3 salt if the old one is too old, and plan next resalt.
+ *
+ * For given zone, check NSEC3 salt in KASP db and decide if it shall be recreated
+ * and tell the user the next time it shall be called.
+ *
+ * This function is optimized to be called from NSEC3RESALT_EVENT,
+ * but also during zone load so that the zone gets loaded already with
+ * proper DNSSEC chain.
+ *
+ * \param ctx zone signing context
+ * \param salt_changed output if KNOT_EOK: was the salt changed ? (if so, please re-sign)
+ * \param when_resalt output: tmestamp when next resalt takes place
+ *
+ * \return KNOT_E*
+ */
+int knot_dnssec_nsec3resalt(kdnssec_ctx_t *ctx, bool *salt_changed, knot_time_t *when_resalt);
diff --git a/src/knot/dnssec/zone-keys.c b/src/knot/dnssec/zone-keys.c
new file mode 100644
index 0000000..94c0732
--- /dev/null
+++ b/src/knot/dnssec/zone-keys.c
@@ -0,0 +1,529 @@
+/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <limits.h>
+#include <stdio.h>
+
+#include "libdnssec/error.h"
+#include "knot/common/log.h"
+#include "knot/dnssec/zone-keys.h"
+#include "libknot/libknot.h"
+
+#define MAX_KEY_INFO 128
+
+dynarray_define(keyptr, zone_key_t *, DYNARRAY_VISIBILITY_PUBLIC)
+
+void normalize_generate_flags(kdnssec_generate_flags_t *flags)
+{
+ if (!(*flags & DNSKEY_GENERATE_KSK) && !(*flags & DNSKEY_GENERATE_ZSK)) {
+ *flags |= DNSKEY_GENERATE_ZSK;
+ }
+ if (!(*flags & DNSKEY_GENERATE_SEP_SPEC)) {
+ if ((*flags & DNSKEY_GENERATE_KSK)) {
+ *flags |= DNSKEY_GENERATE_SEP_ON;
+ } else {
+ *flags &= ~DNSKEY_GENERATE_SEP_ON;
+ }
+ }
+}
+
+int kdnssec_generate_key(kdnssec_ctx_t *ctx, kdnssec_generate_flags_t flags,
+ knot_kasp_key_t **key_ptr)
+{
+ assert(ctx);
+ assert(ctx->zone);
+ assert(ctx->keystore);
+ assert(ctx->policy);
+
+ normalize_generate_flags(&flags);
+
+ dnssec_key_algorithm_t algorithm = ctx->policy->algorithm;
+ unsigned size = (flags & DNSKEY_GENERATE_KSK) ? ctx->policy->ksk_size : ctx->policy->zsk_size;
+
+ // generate key in the keystore
+
+ char *id = NULL;
+ int r = dnssec_keystore_generate_key(ctx->keystore, algorithm, size, &id);
+ if (r != KNOT_EOK) {
+ return r;
+ }
+
+ // create KASP key
+
+ dnssec_key_t *dnskey = NULL;
+ r = dnssec_key_new(&dnskey);
+ if (r != KNOT_EOK) {
+ free(id);
+ return r;
+ }
+
+ r = dnssec_key_set_dname(dnskey, ctx->zone->dname);
+ if (r != KNOT_EOK) {
+ dnssec_key_free(dnskey);
+ free(id);
+ return r;
+ }
+
+ dnssec_key_set_flags(dnskey, dnskey_flags(flags & DNSKEY_GENERATE_SEP_ON));
+ dnssec_key_set_algorithm(dnskey, algorithm);
+
+ r = dnssec_key_import_keystore(dnskey, ctx->keystore, id);
+ if (r != KNOT_EOK) {
+ dnssec_key_free(dnskey);
+ free(id);
+ return r;
+ }
+
+ knot_kasp_key_t *key = calloc(1, sizeof(*key));
+ if (!key) {
+ dnssec_key_free(dnskey);
+ free(id);
+ return KNOT_ENOMEM;
+ }
+
+ key->id = id;
+ key->key = dnskey;
+ key->is_ksk = (flags & DNSKEY_GENERATE_KSK);
+ key->is_zsk = (flags & DNSKEY_GENERATE_ZSK);
+ key->timing.created = ctx->now;
+
+ r = kasp_zone_append(ctx->zone, key);
+ free(key);
+ if (r != KNOT_EOK) {
+ dnssec_key_free(dnskey);
+ free(id);
+ return r;
+ }
+
+ if (key_ptr) {
+ *key_ptr = &ctx->zone->keys[ctx->zone->num_keys - 1];
+ }
+
+ return KNOT_EOK;
+}
+
+int kdnssec_share_key(kdnssec_ctx_t *ctx, const knot_dname_t *from_zone, const char *key_id)
+{
+ knot_dname_t *to_zone = knot_dname_copy(ctx->zone->dname, NULL);
+ if (to_zone == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ int ret = kdnssec_ctx_commit(ctx);
+ if (ret != KNOT_EOK) {
+ free(to_zone);
+ return ret;
+ }
+
+ ret = kasp_db_share_key(*ctx->kasp_db, from_zone, ctx->zone->dname, key_id);
+ if (ret != KNOT_EOK) {
+ free(to_zone);
+ return ret;
+ }
+
+ kasp_zone_clear(ctx->zone);
+ ret = kasp_zone_load(ctx->zone, to_zone, *ctx->kasp_db);
+ free(to_zone);
+ return ret;
+}
+
+int kdnssec_delete_key(kdnssec_ctx_t *ctx, knot_kasp_key_t *key_ptr)
+{
+ assert(ctx);
+ assert(ctx->zone);
+ assert(ctx->keystore);
+ assert(ctx->policy);
+
+ ssize_t key_index = key_ptr - ctx->zone->keys;
+
+ if (key_index < 0 || key_index >= ctx->zone->num_keys) {
+ return KNOT_EINVAL;
+ }
+
+ bool key_still_used_in_keystore = false;
+ int ret = kasp_db_delete_key(*ctx->kasp_db, ctx->zone->dname, key_ptr->id, &key_still_used_in_keystore);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ if (!key_still_used_in_keystore && !key_ptr->is_pub_only) {
+ ret = dnssec_keystore_remove_key(ctx->keystore, key_ptr->id);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ dnssec_key_free(key_ptr->key);
+ free(key_ptr->id);
+ memmove(key_ptr, key_ptr + 1, (ctx->zone->num_keys - key_index - 1) * sizeof(*key_ptr));
+ ctx->zone->num_keys--;
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Get key feature flags from key parameters.
+ */
+static void set_key(knot_kasp_key_t *kasp_key, knot_time_t now, zone_key_t *zone_key)
+{
+ assert(kasp_key);
+ assert(zone_key);
+
+ knot_kasp_key_timing_t *timing = &kasp_key->timing;
+
+ zone_key->id = kasp_key->id;
+ zone_key->key = kasp_key->key;
+
+ // next event computation
+
+ knot_time_t next = 0;
+ knot_time_t timestamps[] = {
+ timing->pre_active,
+ timing->publish,
+ timing->ready,
+ timing->active,
+ timing->retire_active,
+ timing->retire,
+ timing->post_active,
+ timing->remove,
+ };
+
+ for (int i = 0; i < sizeof(timestamps) / sizeof(knot_time_t); i++) {
+ knot_time_t ts = timestamps[i];
+ if (knot_time_cmp(now, ts) < 0 && knot_time_cmp(ts, next) < 0) {
+ next = ts;
+ }
+ }
+
+ zone_key->next_event = next;
+
+ zone_key->is_ksk = kasp_key->is_ksk;
+ zone_key->is_zsk = kasp_key->is_zsk;
+
+ zone_key->is_public = (knot_time_cmp(timing->publish, now) <= 0 &&
+ knot_time_cmp(timing->post_active, now) > 0 &&
+ knot_time_cmp(timing->remove, now) > 0);
+
+ zone_key->is_active = (((zone_key->is_zsk && knot_time_cmp(timing->pre_active, now) <= 0) ||
+ (knot_time_cmp(timing->pre_active, now) <= 0 && knot_time_cmp(timing->publish, now) <= 0) ||
+ knot_time_cmp(timing->ready, now) <= 0 ||
+ knot_time_cmp(timing->active, now) <= 0) &&
+ knot_time_cmp(timing->retire, now) > 0 &&
+ (zone_key->is_zsk || knot_time_cmp(timing->post_active, now) > 0) &&
+ knot_time_cmp(timing->remove, now) > 0);
+
+ zone_key->cds_priority = (knot_time_cmp(timing->ready, now) <= 0 ? (
+ (knot_time_cmp(timing->active, now) <= 0) ? (
+ (knot_time_cmp(timing->retire_active, now) <= 0 ||
+ knot_time_cmp(timing->retire, now) <= 0) ? 0 : 1) : 2) : 0);
+}
+
+/*!
+ * \brief Check if algorithm is allowed with NSEC3.
+ */
+static bool is_nsec3_allowed(uint8_t algorithm)
+{
+ switch (algorithm) {
+ case DNSSEC_KEY_ALGORITHM_RSA_SHA1:
+ return false;
+ default:
+ return true;
+ }
+}
+
+static void ksk2csk(kdnssec_ctx_t *ctx, zone_keyset_t *keyset, uint8_t alg)
+{
+ for (size_t j = 0; j < keyset->count; j++) {
+ zone_key_t *key = &keyset->keys[j];
+ if (dnssec_key_get_algorithm(key->key) == alg) {
+ assert(key->is_ksk);
+ key->is_zsk = true;
+ }
+ }
+
+ for (size_t i = 0; i < ctx->zone->num_keys; i++) {
+ knot_kasp_key_t *key = &ctx->zone->keys[i];
+ if (dnssec_key_get_algorithm(key->key) == alg) {
+ assert(key->is_ksk);
+ key->is_zsk = true;
+ }
+ }
+
+ log_zone_info(ctx->zone->dname, "DNSSEC, Single-Type Signing "
+ "Scheme enabled");
+}
+
+static int walk_algorithms(kdnssec_ctx_t *ctx, zone_keyset_t *keyset)
+{
+ uint8_t alg_usage[256] = { 0 };
+ bool keys_changed = false, have_active_alg = false;
+
+ for (size_t i = 0; i < keyset->count; i++) {
+ zone_key_t *key = &keyset->keys[i];
+ uint8_t alg = dnssec_key_get_algorithm(key->key);
+
+ if (ctx->policy->nsec3_enabled && !is_nsec3_allowed(alg)) {
+ log_zone_warning(ctx->zone->dname, "DNSSEC, key %d "
+ "cannot be used with NSEC3",
+ dnssec_key_get_keytag(key->key));
+ key->is_public = false;
+ key->is_active = false;
+ key->cds_priority = 0;
+ continue;
+ }
+
+ if (key->is_ksk && key->is_public) { alg_usage[alg] |= 1; }
+ if (key->is_zsk && key->is_public) { alg_usage[alg] |= 2; }
+ if (key->is_ksk && key->is_active) { alg_usage[alg] |= 4; }
+ if (key->is_zsk && key->is_active) { alg_usage[alg] |= 8; }
+ }
+
+ for (size_t i = 0; i < sizeof(alg_usage); i++) {
+ if (!(alg_usage[i] & 3)) {
+ continue; // no public keys, ignore
+ }
+ switch (alg_usage[i]) {
+ case 5: // because migrating from older version OR from manual setup
+ ksk2csk(ctx, keyset, i);
+ alg_usage[i] |= 10;
+ keys_changed = true;
+ // FALLTHROUGH
+ case 15: // all keys ready for signing
+ have_active_alg = true;
+ break;
+ default:
+ return KNOT_DNSSEC_EMISSINGKEYTYPE;
+ }
+ }
+
+ if (!have_active_alg) {
+ return KNOT_DNSSEC_ENOKEY;
+ }
+
+ if (keys_changed) {
+ return kdnssec_ctx_commit(ctx);
+ }
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Load private keys for active keys.
+ */
+static int load_private_keys(dnssec_keystore_t *keystore, zone_keyset_t *keyset)
+{
+ assert(keystore);
+ assert(keyset);
+
+ for (size_t i = 0; i < keyset->count; i++) {
+ if (!keyset->keys[i].is_active) {
+ continue;
+ }
+
+ zone_key_t *key = &keyset->keys[i];
+ int r = dnssec_key_import_keystore(key->key, keystore, key->id);
+ if (r != DNSSEC_EOK && r != DNSSEC_KEY_ALREADY_PRESENT) {
+ return r;
+ }
+ }
+
+ return DNSSEC_EOK;
+}
+
+/*!
+ * \brief Log information about zone keys.
+ */
+static void log_key_info(const zone_key_t *key, char *out, size_t out_len)
+{
+ assert(key);
+ assert(out);
+
+ uint8_t alg_code = dnssec_key_get_algorithm(key->key);
+ const knot_lookup_t *alg = knot_lookup_by_id(knot_dnssec_alg_names, alg_code);
+
+ char alg_code_str[8] = "";
+ if (alg == NULL) {
+ (void)snprintf(alg_code_str, sizeof(alg_code_str), "%d", alg_code);
+ }
+
+ (void)snprintf(out, out_len, "DNSSEC, key, tag %5d, algorithm %s%s%s%s%s",
+ dnssec_key_get_keytag(key->key),
+ (alg != NULL ? alg->name : alg_code_str),
+ (key->is_ksk ? (key->is_zsk ? ", CSK" : ", KSK") : ""),
+ (key->is_public ? ", public" : ""),
+ (key->cds_priority > 1 ? ", ready" : ""),
+ (key->is_active ? ", active" : ""));
+}
+
+int log_key_sort(const void *a, const void *b)
+{
+ const char *alg_a = strstr(a, "alg");
+ const char *alg_b = strstr(b, "alg");
+ assert(alg_a != NULL && alg_b != NULL);
+
+ return strcmp(alg_a, alg_b);
+}
+
+/*!
+ * \brief Load zone keys and init cryptographic context.
+ */
+int load_zone_keys(kdnssec_ctx_t *ctx, zone_keyset_t *keyset_ptr, bool verbose)
+{
+ if (!ctx || !keyset_ptr) {
+ return KNOT_EINVAL;
+ }
+
+ zone_keyset_t keyset = { 0 };
+
+ if (ctx->zone->num_keys < 1) {
+ log_zone_error(ctx->zone->dname, "DNSSEC, no keys are available");
+ return KNOT_DNSSEC_ENOKEY;
+ }
+
+ keyset.count = ctx->zone->num_keys;
+ keyset.keys = calloc(keyset.count, sizeof(zone_key_t));
+ if (!keyset.keys) {
+ free_zone_keys(&keyset);
+ return KNOT_ENOMEM;
+ }
+
+ char key_info[ctx->zone->num_keys][MAX_KEY_INFO];
+ for (size_t i = 0; i < ctx->zone->num_keys; i++) {
+ knot_kasp_key_t *kasp_key = &ctx->zone->keys[i];
+ set_key(kasp_key, ctx->now, &keyset.keys[i]);
+ if (verbose) {
+ log_key_info(&keyset.keys[i], key_info[i], MAX_KEY_INFO);
+ }
+ }
+
+ // Sort the keys by algorithm name.
+ if (verbose) {
+ qsort(key_info, ctx->zone->num_keys, MAX_KEY_INFO, log_key_sort);
+ for (size_t i = 0; i < ctx->zone->num_keys; i++) {
+ log_zone_info(ctx->zone->dname, "%s", key_info[i]);
+ }
+ }
+
+ int ret = walk_algorithms(ctx, &keyset);
+ if (ret != KNOT_EOK) {
+ log_zone_error(ctx->zone->dname, "DNSSEC, keys validation failed (%s)",
+ knot_strerror(ret));
+ free_zone_keys(&keyset);
+ return ret;
+ }
+
+ ret = load_private_keys(ctx->keystore, &keyset);
+ ret = knot_error_from_libdnssec(ret);
+ if (ret != KNOT_EOK) {
+ log_zone_error(ctx->zone->dname, "DNSSEC, failed to load private "
+ "keys (%s)", knot_strerror(ret));
+ free_zone_keys(&keyset);
+ return ret;
+ }
+
+ *keyset_ptr = keyset;
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Free structure with zone keys and associated DNSSEC contexts.
+ */
+void free_zone_keys(zone_keyset_t *keyset)
+{
+ if (!keyset) {
+ return;
+ }
+
+ for (size_t i = 0; i < keyset->count; i++) {
+ dnssec_binary_free(&keyset->keys[i].precomputed_ds);
+ }
+
+ free(keyset->keys);
+
+ memset(keyset, '\0', sizeof(*keyset));
+}
+
+/*!
+ * \brief Get timestamp of next key event.
+ */
+knot_time_t knot_get_next_zone_key_event(const zone_keyset_t *keyset)
+{
+ assert(keyset);
+
+ knot_time_t result = 0;
+
+ for (size_t i = 0; i < keyset->count; i++) {
+ zone_key_t *key = &keyset->keys[i];
+ if (knot_time_cmp(key->next_event, result) < 0) {
+ result = key->next_event;
+ }
+ }
+
+ return result;
+}
+
+/*!
+ * \brief Compute DS record rdata from key + cache it.
+ */
+int zone_key_calculate_ds(zone_key_t *for_key, dnssec_binary_t *out_donotfree)
+{
+ assert(for_key);
+ assert(out_donotfree);
+
+ int ret = KNOT_EOK;
+
+ if (for_key->precomputed_ds.data == NULL) {
+ dnssec_key_digest_t digesttype = DNSSEC_KEY_DIGEST_SHA256; // TODO !
+ ret = dnssec_key_create_ds(for_key->key, digesttype, &for_key->precomputed_ds);
+ ret = knot_error_from_libdnssec(ret);
+ }
+
+ *out_donotfree = for_key->precomputed_ds;
+ return ret;
+}
+
+zone_sign_ctx_t *zone_sign_ctx(const zone_keyset_t *keyset, const kdnssec_ctx_t *dnssec_ctx)
+{
+ zone_sign_ctx_t *ctx = calloc(1, sizeof(*ctx) + keyset->count * sizeof(*ctx->sign_ctxs));
+ if (ctx == NULL) {
+ return NULL;
+ }
+
+ ctx->sign_ctxs = (dnssec_sign_ctx_t **)(ctx + 1);
+ ctx->count = keyset->count;
+ ctx->keys = keyset->keys;
+ ctx->dnssec_ctx = dnssec_ctx;
+ for (size_t i = 0; i < ctx->count; i++) {
+ int ret = dnssec_sign_new(&ctx->sign_ctxs[i], ctx->keys[i].key);
+ if (ret != DNSSEC_EOK) {
+ zone_sign_ctx_free(ctx);
+ return NULL;
+ }
+ }
+
+ return ctx;
+}
+
+void zone_sign_ctx_free(zone_sign_ctx_t *ctx)
+{
+ if (ctx != NULL) {
+ for (size_t i = 0; i < ctx->count; i++) {
+ dnssec_sign_free(ctx->sign_ctxs[i]);
+ }
+ free(ctx);
+ }
+}
diff --git a/src/knot/dnssec/zone-keys.h b/src/knot/dnssec/zone-keys.h
new file mode 100644
index 0000000..a8ee990
--- /dev/null
+++ b/src/knot/dnssec/zone-keys.h
@@ -0,0 +1,176 @@
+/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "contrib/dynarray.h"
+#include "libdnssec/keystore.h"
+#include "libdnssec/sign.h"
+#include "knot/dnssec/kasp/kasp_zone.h"
+#include "knot/dnssec/kasp/policy.h"
+#include "knot/dnssec/context.h"
+
+/*!
+ * \brief Zone key context used during signing.
+ */
+typedef struct {
+ const char *id;
+ dnssec_key_t *key;
+
+ dnssec_binary_t precomputed_ds;
+
+ knot_time_t next_event;
+
+ bool is_ksk;
+ bool is_zsk;
+ bool is_active;
+ bool is_public;
+ int cds_priority;
+} zone_key_t;
+
+dynarray_declare(keyptr, zone_key_t *, DYNARRAY_VISIBILITY_PUBLIC, 1)
+
+typedef struct {
+ size_t count;
+ zone_key_t *keys;
+} zone_keyset_t;
+
+/*!
+ * \brief Signing context used for single signing thread.
+ */
+typedef struct {
+ size_t count; // number of keys in keyset
+ zone_key_t *keys; // keys in keyset
+ dnssec_sign_ctx_t **sign_ctxs; // signing buffers for keys in keyset
+ const kdnssec_ctx_t *dnssec_ctx; // dnssec context
+} zone_sign_ctx_t;
+
+/*!
+ * \brief Flags determining key type
+ */
+enum {
+ DNSKEY_FLAGS_KSK = KNOT_DNSKEY_FLAG_ZONE | KNOT_DNSKEY_FLAG_SEP,
+ DNSKEY_FLAGS_ZSK = KNOT_DNSKEY_FLAG_ZONE,
+};
+
+inline static uint16_t dnskey_flags(bool is_ksk)
+{
+ return is_ksk ? DNSKEY_FLAGS_KSK : DNSKEY_FLAGS_ZSK;
+}
+
+typedef enum {
+ DNSKEY_GENERATE_KSK = (1 << 0), // KSK flag in metadata
+ DNSKEY_GENERATE_ZSK = (1 << 1), // ZSK flag in metadata
+ DNSKEY_GENERATE_SEP_SPEC = (1 << 2), // not (SEP bit set iff KSK)
+ DNSKEY_GENERATE_SEP_ON = (1 << 3), // SEP bit set on
+} kdnssec_generate_flags_t;
+
+void normalize_generate_flags(kdnssec_generate_flags_t *flags);
+
+/*!
+ * \brief Generate new key, store all details in new kasp key structure.
+ *
+ * \param ctx kasp context
+ * \param flags determine if to use the key as KSK and/or ZSK and SEP flag
+ * \param key_ptr output if KNOT_EOK: new pointer to generated key
+ *
+ * \return KNOT_E*
+ */
+int kdnssec_generate_key(kdnssec_ctx_t *ctx, kdnssec_generate_flags_t flags,
+ knot_kasp_key_t **key_ptr);
+
+/*!
+ * \brief Take a key from another zone (copying info, sharing privkey).
+ *
+ * \param ctx kasp context
+ * \param from_zone name of the zone to take from
+ * \param key_id ID of the key to take
+ *
+ * \return KNOT_E*
+ */
+int kdnssec_share_key(kdnssec_ctx_t *ctx, const knot_dname_t *from_zone, const char *key_id);
+
+/*!
+ * \brief Remove key from zone.
+ *
+ * Deletes the key in keystore, unlinks the key from the zone in KASP db,
+ * moreover if no more zones use this key in KASP db, deletes it completely there
+ * and deletes it also from key storage (PKCS8dir/PKCS11).
+ *
+ * \param ctx kasp context (zone, keystore, kaspdb) to be modified
+ * \param key_ptr pointer to key to be removed, must be inside keystore structure, NOT a copy of it!
+ *
+ * \return KNOT_E*
+ */
+int kdnssec_delete_key(kdnssec_ctx_t *ctx, knot_kasp_key_t *key_ptr);
+
+/*!
+ * \brief Load zone keys and init cryptographic context.
+ *
+ * \param ctx Zone signing context.
+ * \param keyset_ptr Resulting zone keyset.
+ * \param verbose Print key summary into log.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int load_zone_keys(kdnssec_ctx_t *ctx, zone_keyset_t *keyset_ptr, bool verbose);
+
+/*!
+ * \brief Free structure with zone keys and associated DNSSEC contexts.
+ *
+ * \param keyset Zone keys.
+ */
+void free_zone_keys(zone_keyset_t *keyset);
+
+/*!
+ * \brief Get timestamp of next key event.
+ *
+ * \param keyset Zone keys.
+ *
+ * \return Timestamp of next key event.
+ */
+knot_time_t knot_get_next_zone_key_event(const zone_keyset_t *keyset);
+
+/*!
+ * \brief Returns DS record rdata for given key.
+ *
+ * This function caches the results, so caaling again with the same key returns immediately.
+ *
+ * \param for_key The key to compute DS for.
+ * \param out_donotfree Output: the DS record rdata. Do not call dnssec_binry_free() on this ever.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int zone_key_calculate_ds(zone_key_t *for_key, dnssec_binary_t *out_donotfree);
+
+/*!
+ * \brief Initialize local signing context.
+ *
+ * \param keyset Key set.
+ * \param dnssec_ctx DNSSEC context.
+ *
+ * \return New local signing context or NULL.
+ */
+zone_sign_ctx_t *zone_sign_ctx(const zone_keyset_t *keyset, const kdnssec_ctx_t *dnssec_ctx);
+
+/*!
+ * \brief Free local signing context.
+ *
+ * \note This doesn't free the underlying keyset.
+ *
+ * \param ctx Local context to be freed.
+ */
+void zone_sign_ctx_free(zone_sign_ctx_t *ctx);
diff --git a/src/knot/dnssec/zone-nsec.c b/src/knot/dnssec/zone-nsec.c
new file mode 100644
index 0000000..95c1056
--- /dev/null
+++ b/src/knot/dnssec/zone-nsec.c
@@ -0,0 +1,409 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "libdnssec/error.h"
+#include "libknot/descriptor.h"
+#include "libknot/rrtype/nsec3.h"
+#include "libknot/rrtype/soa.h"
+#include "knot/common/log.h"
+#include "knot/dnssec/nsec-chain.h"
+#include "knot/dnssec/nsec3-chain.h"
+#include "knot/dnssec/key-events.h"
+#include "knot/dnssec/rrset-sign.h"
+#include "knot/dnssec/zone-nsec.h"
+#include "knot/dnssec/zone-sign.h"
+#include "knot/zone/zone-diff.h"
+#include "contrib/base32hex.h"
+#include "contrib/wire_ctx.h"
+
+/*!
+ * \brief Deletes NSEC3 chain if NSEC should be used.
+ *
+ * \param zone Zone to fix.
+ * \param changeset Changeset to be used.
+ */
+static int delete_nsec3_chain(const zone_contents_t *zone, changeset_t *changeset)
+{
+ assert(zone);
+ assert(changeset);
+
+ if (zone_tree_is_empty(zone->nsec3_nodes)) {
+ return KNOT_EOK;
+ }
+
+ zone_tree_t *empty_tree = zone_tree_create();
+ if (!empty_tree) {
+ return KNOT_ENOMEM;
+ }
+
+ int ret = zone_tree_add_diff(zone->nsec3_nodes, empty_tree, changeset);
+
+ zone_tree_free(&empty_tree);
+
+ return ret;
+}
+
+int knot_nsec3_hash_to_dname(uint8_t *out, size_t out_size, const uint8_t *hash,
+ size_t hash_size, const knot_dname_t *zone_apex)
+
+{
+ if (out == NULL || hash == NULL || zone_apex == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ // Encode raw hash to the first label.
+ uint8_t label[KNOT_DNAME_MAXLEN];
+ int32_t label_size = base32hex_encode(hash, hash_size, label, sizeof(label));
+ if (label_size <= 0) {
+ return label_size;
+ }
+
+ // Write the result, which already is in lower-case.
+ wire_ctx_t wire = wire_ctx_init(out, out_size);
+
+ wire_ctx_write_u8(&wire, label_size);
+ wire_ctx_write(&wire, label, label_size);
+ wire_ctx_write(&wire, zone_apex, knot_dname_size(zone_apex));
+
+ return wire.error;
+}
+
+int knot_create_nsec3_owner(uint8_t *out, size_t out_size,
+ const knot_dname_t *owner, const knot_dname_t *zone_apex,
+ const dnssec_nsec3_params_t *params)
+{
+ if (out == NULL || owner == NULL || zone_apex == NULL || params == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ dnssec_binary_t data = {
+ .data = (uint8_t *)owner,
+ .size = knot_dname_size(owner)
+ };
+
+ dnssec_binary_t hash = { 0 };
+
+ int ret = dnssec_nsec3_hash(&data, params, &hash);
+ if (ret != DNSSEC_EOK) {
+ return knot_error_from_libdnssec(ret);
+ }
+
+ ret = knot_nsec3_hash_to_dname(out, out_size, hash.data, hash.size, zone_apex);
+
+ dnssec_binary_free(&hash);
+
+ return ret;
+}
+
+static bool nsec3param_valid(const knot_rdataset_t *rrs,
+ const dnssec_nsec3_params_t *params)
+{
+ assert(rrs);
+ assert(params);
+
+ // NSEC3 disabled
+ if (params->algorithm == 0) {
+ return false;
+ }
+
+ // multiple NSEC3 records
+ if (rrs->count != 1) {
+ return false;
+ }
+
+ dnssec_binary_t rdata = {
+ .size = rrs->rdata->len,
+ .data = rrs->rdata->data,
+ };
+
+ dnssec_nsec3_params_t parsed = { 0 };
+ int r = dnssec_nsec3_params_from_rdata(&parsed, &rdata);
+ if (r != DNSSEC_EOK) {
+ return false;
+ }
+
+ bool equal = parsed.algorithm == params->algorithm &&
+ parsed.flags == params->flags &&
+ parsed.iterations == params->iterations &&
+ dnssec_binary_cmp(&parsed.salt, &params->salt) == 0;
+
+ dnssec_nsec3_params_free(&parsed);
+
+ return equal;
+}
+
+static int remove_nsec3param(const zone_contents_t *zone, changeset_t *changeset)
+{
+ assert(zone);
+ assert(changeset);
+
+ knot_rrset_t rrset = node_rrset(zone->apex, KNOT_RRTYPE_NSEC3PARAM);
+ int ret = changeset_add_removal(changeset, &rrset, 0);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ rrset = node_rrset(zone->apex, KNOT_RRTYPE_RRSIG);
+ if (!knot_rrset_empty(&rrset)) {
+ knot_rrset_t rrsig;
+ knot_rrset_init(&rrsig, zone->apex->owner, KNOT_RRTYPE_RRSIG,
+ KNOT_CLASS_IN, 0);
+ ret = knot_synth_rrsig(KNOT_RRTYPE_NSEC3PARAM, &rrset.rrs, &rrsig.rrs, NULL);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = changeset_add_removal(changeset, &rrsig, 0);
+ knot_rdataset_clear(&rrsig.rrs, NULL);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+static int set_nsec3param(knot_rrset_t *rrset, const dnssec_nsec3_params_t *params)
+{
+ assert(rrset);
+ assert(params);
+
+ // Prepare wire rdata.
+ size_t rdata_len = 3 * sizeof(uint8_t) + sizeof(uint16_t) + params->salt.size;
+ uint8_t rdata[rdata_len];
+ wire_ctx_t wire = wire_ctx_init(rdata, rdata_len);
+
+ wire_ctx_write_u8(&wire, params->algorithm);
+ wire_ctx_write_u8(&wire, 0); // (RFC 5155 Section 4.1.2)
+ wire_ctx_write_u16(&wire, params->iterations);
+ wire_ctx_write_u8(&wire, params->salt.size);
+ wire_ctx_write(&wire, params->salt.data, params->salt.size);
+
+ if (wire.error != KNOT_EOK) {
+ return wire.error;
+ }
+
+ assert(wire_ctx_available(&wire) == 0);
+
+ return knot_rrset_add_rdata(rrset, rdata, rdata_len, NULL);
+}
+
+static int add_nsec3param(const zone_contents_t *zone, changeset_t *changeset,
+ const dnssec_nsec3_params_t *params)
+{
+ assert(zone);
+ assert(changeset);
+ assert(params);
+
+ knot_rrset_t *rrset = NULL;
+ rrset = knot_rrset_new(zone->apex->owner, KNOT_RRTYPE_NSEC3PARAM,
+ KNOT_CLASS_IN, 0, NULL);
+ if (!rrset) {
+ return KNOT_ENOMEM;
+ }
+
+ int r = set_nsec3param(rrset, params);
+ if (r != KNOT_EOK) {
+ knot_rrset_free(rrset, NULL);
+ return r;
+ }
+
+ r = changeset_add_addition(changeset, rrset, 0);
+ knot_rrset_free(rrset, NULL);
+ return r;
+}
+
+static int update_nsec3param(const zone_contents_t *zone,
+ changeset_t *changeset,
+ const dnssec_nsec3_params_t *params)
+{
+ assert(zone);
+ assert(changeset);
+ assert(params);
+
+ knot_rdataset_t *nsec3param = node_rdataset(zone->apex, KNOT_RRTYPE_NSEC3PARAM);
+ bool valid = nsec3param && nsec3param_valid(nsec3param, params);
+
+ if (nsec3param && !valid) {
+ int r = remove_nsec3param(zone, changeset);
+ if (r != KNOT_EOK) {
+ return r;
+ }
+ }
+
+ if (params->algorithm != 0 && !valid) {
+ return add_nsec3param(zone, changeset, params);
+ }
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Initialize NSEC3PARAM based on the signing policy.
+ *
+ * \note For NSEC, the algorithm number is set to 0.
+ */
+static dnssec_nsec3_params_t nsec3param_init(const knot_kasp_policy_t *policy,
+ const knot_kasp_zone_t *zone)
+{
+ assert(policy);
+ assert(zone);
+
+ dnssec_nsec3_params_t params = { 0 };
+ if (policy->nsec3_enabled) {
+ params.algorithm = DNSSEC_NSEC3_ALGORITHM_SHA1;
+ params.iterations = policy->nsec3_iterations;
+ params.salt = zone->nsec3_salt;
+ params.flags = (policy->nsec3_opt_out ? KNOT_NSEC3_FLAG_OPT_OUT : 0);
+ }
+
+ return params;
+}
+
+int knot_zone_create_nsec_chain(zone_update_t *update,
+ const zone_keyset_t *zone_keys,
+ const kdnssec_ctx_t *ctx,
+ bool sign_nsec_chain)
+{
+ if (update == NULL || ctx == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ const knot_rdataset_t *soa = node_rdataset(update->new_cont->apex, KNOT_RRTYPE_SOA);
+ if (soa == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ uint32_t nsec_ttl = knot_soa_minimum(soa->rdata);
+ dnssec_nsec3_params_t params = nsec3param_init(ctx->policy, ctx->zone);
+
+ changeset_t ch;
+ int ret = changeset_init(&ch, update->new_cont->apex->owner);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = update_nsec3param(update->new_cont, &ch, &params);
+ if (ret != KNOT_EOK) {
+ goto cleanup;
+ }
+
+ if (ctx->policy->nsec3_enabled) {
+ ret = knot_nsec3_create_chain(update->new_cont, &params, nsec_ttl,
+ ctx->policy->nsec3_opt_out, &ch);
+ if (ret != KNOT_EOK) {
+ goto cleanup;
+ }
+ } else {
+ ret = knot_nsec_create_chain(update->new_cont, nsec_ttl, &ch);
+ if (ret != KNOT_EOK) {
+ goto cleanup;
+ }
+
+ ret = delete_nsec3_chain(update->new_cont, &ch);
+ if (ret != KNOT_EOK) {
+ goto cleanup;
+ }
+ }
+
+ if (sign_nsec_chain) {
+ ret = knot_zone_sign_nsecs_in_changeset(zone_keys, ctx, &ch);
+ }
+
+ if (ret == KNOT_EOK) {
+ ret = zone_update_apply_changeset(update, &ch);
+ }
+
+cleanup:
+ changeset_clear(&ch);
+ return ret;
+}
+
+
+int knot_zone_fix_nsec_chain(zone_update_t *update,
+ const zone_keyset_t *zone_keys,
+ const kdnssec_ctx_t *ctx,
+ bool sign_nsec_chain)
+{
+ if (update == NULL || ctx == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ const knot_rdataset_t *soa_old = node_rdataset(update->zone->contents->apex, KNOT_RRTYPE_SOA);
+ const knot_rdataset_t *soa_new = node_rdataset(update->new_cont->apex, KNOT_RRTYPE_SOA);
+ if (soa_old == NULL || soa_new == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ uint32_t nsec_ttl_old = knot_soa_minimum(soa_old->rdata);
+ uint32_t nsec_ttl_new = knot_soa_minimum(soa_new->rdata);
+ dnssec_nsec3_params_t params = nsec3param_init(ctx->policy, ctx->zone);
+
+ changeset_t ch;
+ int ret = changeset_init(&ch, update->new_cont->apex->owner);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ if (nsec_ttl_old != nsec_ttl_new) {
+ ret = KNOT_ENORECORD;
+ } else if (ctx->policy->nsec3_enabled) {
+ ret = knot_nsec3_fix_chain(update, &params, nsec_ttl_new,
+ ctx->policy->nsec3_opt_out, &ch);
+ } else {
+ ret = knot_nsec_fix_chain(update->zone->contents, update->new_cont,
+ nsec_ttl_new, &ch);
+ }
+ if (ret == KNOT_ENORECORD) {
+ log_zone_info(update->zone->name, "DNSSEC, re-creating whole NSEC%s chain",
+ (ctx->policy->nsec3_enabled ? "3" : ""));
+ changeset_clear(&ch);
+ ret = changeset_init(&ch, update->new_cont->apex->owner);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ if (ctx->policy->nsec3_enabled) {
+ ret = knot_nsec3_create_chain(update->new_cont, &params, nsec_ttl_new,
+ ctx->policy->nsec3_opt_out, &ch);
+ } else {
+ ret = knot_nsec_create_chain(update->new_cont, nsec_ttl_new, &ch);
+ }
+ }
+ if (ret != KNOT_EOK) {
+ goto cleanup;
+ }
+
+ if (sign_nsec_chain) {
+ ret = knot_zone_sign_nsecs_in_changeset(zone_keys, ctx, &ch);
+ }
+
+ if (ret == KNOT_EOK) {
+ // Disable strict changeset application momentarily for the NSEC chain fix.
+ // This is important for NSEC3, since some nodes are removed from contents
+ // when fixing individual NSEC3 nodes and then the NSEC3 records from these nodes
+ // are removed again when the chain is fixed, resulting in double removal,
+ // forbidden in the strict changeset application.
+ update->a_ctx->flags &= ~APPLY_STRICT;
+ ret = zone_update_apply_changeset(update, &ch);
+ update->a_ctx->flags |= APPLY_STRICT;
+ }
+
+cleanup:
+ changeset_clear(&ch);
+ return ret;
+}
diff --git a/src/knot/dnssec/zone-nsec.h b/src/knot/dnssec/zone-nsec.h
new file mode 100644
index 0000000..a1e469b
--- /dev/null
+++ b/src/knot/dnssec/zone-nsec.h
@@ -0,0 +1,95 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+
+#include "knot/dnssec/context.h"
+#include "knot/dnssec/zone-keys.h"
+#include "knot/updates/zone-update.h"
+#include "knot/zone/contents.h"
+
+/*!
+ * Check if NSEC3 is enabled for the given zone.
+ *
+ * \param zone Zone to be checked.
+ *
+ * \return NSEC3 is enabled.
+ */
+inline static bool knot_is_nsec3_enabled(const zone_contents_t *zone)
+{
+ return zone != NULL && zone->nsec3_params.algorithm != 0;
+}
+
+/*!
+ * \brief Create NSEC3 owner name from hash and zone apex.
+ *
+ * \param out Output buffer.
+ * \param out_size Size of the output buffer.
+ * \param hash Raw hash.
+ * \param hash_size Size of the hash.
+ * \param zone_apex Zone apex.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_nsec3_hash_to_dname(uint8_t *out, size_t out_size, const uint8_t *hash,
+ size_t hash_size, const knot_dname_t *zone_apex);
+
+/*!
+ * \brief Create NSEC3 owner name from regular owner name.
+ *
+ * \param out Output buffer.
+ * \param out_size Size of the output buffer.
+ * \param owner Node owner name.
+ * \param zone_apex Zone apex name.
+ * \param params Params for NSEC3 hashing function.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_create_nsec3_owner(uint8_t *out, size_t out_size,
+ const knot_dname_t *owner, const knot_dname_t *zone_apex,
+ const dnssec_nsec3_params_t *params);
+
+/*!
+ * \brief Create NSEC or NSEC3 chain in the zone.
+ *
+ * \param update Zone Update with current zone contents and to be updated with NSEC chain.
+ * \param zone_keys Zone keys used for NSEC(3) creation.
+ * \param ctx Signing context.
+ * \param sign_nsec_chain If true, the created NSEC(3) chain is signed at the end.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_zone_create_nsec_chain(zone_update_t *update,
+ const zone_keyset_t *zone_keys,
+ const kdnssec_ctx_t *ctx,
+ bool sign_nsec_chain);
+
+/*!
+ * \brief Fix NSEC or NSEC3 chain after zone was updated.
+ *
+ * \param update Zone Update with the update and to be update with NSEC chain.
+ * \param zone_keys Zone keys used for NSEC(3) creation.
+ * \param ctx Signing context.
+ * \param sign_nsec_chain If true, the created NSEC(3) chain is signed at the end.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_zone_fix_nsec_chain(zone_update_t *update,
+ const zone_keyset_t *zone_keys,
+ const kdnssec_ctx_t *ctx,
+ bool sign_nsec_chain);
diff --git a/src/knot/dnssec/zone-sign.c b/src/knot/dnssec/zone-sign.c
new file mode 100644
index 0000000..fbd8a91
--- /dev/null
+++ b/src/knot/dnssec/zone-sign.c
@@ -0,0 +1,1196 @@
+/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <sys/types.h>
+
+#include "libdnssec/error.h"
+#include "libdnssec/key.h"
+#include "libdnssec/keytag.h"
+#include "libdnssec/sign.h"
+#include "knot/dnssec/key-events.h"
+#include "knot/dnssec/rrset-sign.h"
+#include "knot/dnssec/zone-sign.h"
+#include "libknot/libknot.h"
+#include "contrib/macros.h"
+#include "contrib/wire_ctx.h"
+
+typedef struct {
+ node_t n;
+ uint16_t type;
+} type_node_t;
+
+typedef struct {
+ knot_dname_t *dname;
+ knot_dname_t *hashed_dname;
+ list_t *type_list;
+} signed_info_t;
+
+/*- private API - common functions -------------------------------------------*/
+
+/*!
+ * \brief Initializes RR set and set owner and rclass from template RR set.
+ */
+static knot_rrset_t rrset_init_from(const knot_rrset_t *src, uint16_t type)
+{
+ assert(src);
+ knot_rrset_t rrset;
+ knot_rrset_init(&rrset, src->owner, type, src->rclass, src->ttl);
+ return rrset;
+}
+
+/*!
+ * \brief Create empty RRSIG RR set for a given RR set to be covered.
+ */
+static knot_rrset_t create_empty_rrsigs_for(const knot_rrset_t *covered)
+{
+ assert(!knot_rrset_empty(covered));
+ return rrset_init_from(covered, KNOT_RRTYPE_RRSIG);
+}
+
+static bool apex_rr_changed(const zone_node_t *old_apex,
+ const zone_node_t *new_apex,
+ uint16_t type)
+{
+ assert(old_apex);
+ assert(new_apex);
+ knot_rrset_t old_rr = node_rrset(old_apex, type);
+ knot_rrset_t new_rr = node_rrset(new_apex, type);
+
+ return !knot_rrset_equal(&old_rr, &new_rr, KNOT_RRSET_COMPARE_WHOLE);
+}
+
+static bool apex_dnssec_changed(zone_update_t *update)
+{
+ if (update->zone->contents == NULL || update->new_cont == NULL) {
+ return false;
+ }
+ return apex_rr_changed(update->zone->contents->apex,
+ update->new_cont->apex, KNOT_RRTYPE_DNSKEY) ||
+ apex_rr_changed(update->zone->contents->apex,
+ update->new_cont->apex, KNOT_RRTYPE_NSEC3PARAM);
+}
+
+/*- private API - signing of in-zone nodes -----------------------------------*/
+
+/*!
+ * \brief Check if there is a valid signature for a given RR set and key.
+ *
+ * \param covered RR set with covered records.
+ * \param rrsigs RR set with RRSIGs.
+ * \param key Signing key.
+ * \param ctx Signing context.
+ * \param policy DNSSEC policy.
+ *
+ * \return The signature exists and is valid.
+ */
+static bool valid_signature_exists(const knot_rrset_t *covered,
+ const knot_rrset_t *rrsigs,
+ const dnssec_key_t *key,
+ dnssec_sign_ctx_t *ctx,
+ const kdnssec_ctx_t *dnssec_ctx)
+{
+ assert(key);
+
+ if (knot_rrset_empty(rrsigs)) {
+ return false;
+ }
+
+ uint16_t rrsigs_rdata_count = rrsigs->rrs.count;
+ knot_rdata_t *rdata = rrsigs->rrs.rdata;
+ for (uint16_t i = 0; i < rrsigs_rdata_count; i++) {
+ uint16_t rr_keytag = knot_rrsig_key_tag(rdata);
+ uint16_t rr_covered = knot_rrsig_type_covered(rdata);
+ rdata = knot_rdataset_next(rdata);
+
+ uint16_t keytag = dnssec_key_get_keytag(key);
+ if (rr_keytag != keytag || rr_covered != covered->type) {
+ continue;
+ }
+
+ if (knot_check_signature(covered, rrsigs, i, key, ctx,
+ dnssec_ctx) == KNOT_EOK) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/*!
+ * \brief Check if valid signature exists for all keys for a given RR set.
+ *
+ * \param covered RR set with covered records.
+ * \param rrsigs RR set with RRSIGs.
+ * \param sign_ctx Local zone signing context.
+ *
+ * \return Valid signature exists for every key.
+ */
+static bool all_signatures_exist(const knot_rrset_t *covered,
+ const knot_rrset_t *rrsigs,
+ zone_sign_ctx_t *sign_ctx)
+{
+ assert(sign_ctx);
+
+ for (int i = 0; i < sign_ctx->count; i++) {
+ zone_key_t *key = &sign_ctx->keys[i];
+ if (!knot_zone_sign_use_key(key, covered)) {
+ continue;
+ }
+
+ if (!valid_signature_exists(covered, rrsigs, key->key,
+ sign_ctx->sign_ctxs[i],
+ sign_ctx->dnssec_ctx)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/*!
+ * \brief Note earliest expiration of a signature.
+ *
+ * \param rrsig RRSIG rdata.
+ * \param expires_at Current earliest expiration, will be updated.
+ */
+static void note_earliest_expiration(const knot_rdata_t *rrsig, knot_time_t *expires_at)
+{
+ assert(rrsig);
+ assert(expires_at);
+
+ uint32_t curr_rdata = knot_rrsig_sig_expiration(rrsig);
+ knot_time_t current = knot_time_from_u32(curr_rdata);
+ *expires_at = knot_time_min(current, *expires_at);
+}
+
+/*!
+ * \brief Add expired or invalid RRSIGs into the changeset for removal.
+ *
+ * \param covered RR set with covered records.
+ * \param rrsigs RR set with RRSIGs.
+ * \param sign_ctx Local zone signing context.
+ * \param changeset Changeset to be updated.
+ * \param expires_at Earliest RRSIG expiration.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+static int remove_expired_rrsigs(const knot_rrset_t *covered,
+ const knot_rrset_t *rrsigs,
+ zone_sign_ctx_t *sign_ctx,
+ changeset_t *changeset,
+ knot_time_t *expires_at)
+{
+ assert(changeset);
+
+ if (knot_rrset_empty(rrsigs)) {
+ return KNOT_EOK;
+ }
+
+ assert(rrsigs->type == KNOT_RRTYPE_RRSIG);
+
+ knot_rrset_t to_remove;
+ knot_rrset_init_empty(&to_remove);
+ int result = KNOT_EOK;
+
+ knot_rrset_t synth_rrsig = rrset_init_from(rrsigs, KNOT_RRTYPE_RRSIG);
+ result = knot_synth_rrsig(covered->type, &rrsigs->rrs, &synth_rrsig.rrs, NULL);
+ if (result != KNOT_EOK) {
+ if (result != KNOT_ENOENT) {
+ return result;
+ }
+ return KNOT_EOK;
+ }
+
+ uint16_t rrsig_rdata_count = synth_rrsig.rrs.count;
+ for (uint16_t i = 0; i < rrsig_rdata_count; i++) {
+ knot_rdata_t *rr = knot_rdataset_at(&synth_rrsig.rrs, i);
+ uint16_t keytag = knot_rrsig_key_tag(rr);
+ int endloop = 0; // 1 - continue; 2 - break
+
+ for (size_t j = 0; j < sign_ctx->count; j++) {
+ zone_key_t *key = &sign_ctx->keys[j];
+
+ if (!key->is_active || dnssec_key_get_keytag(key->key) != keytag) {
+ continue;
+ }
+
+ result = knot_check_signature(covered, &synth_rrsig, i, key->key,
+ sign_ctx->sign_ctxs[j], sign_ctx->dnssec_ctx);
+ if (result == KNOT_EOK) {
+ // valid signature
+ note_earliest_expiration(rr, expires_at);
+ endloop = 1;
+ break;
+ } else if (result != DNSSEC_INVALID_SIGNATURE) {
+ endloop = 2;
+ break;
+ }
+ }
+
+ if (endloop == 2) {
+ break;
+ } else if (endloop == 1) {
+ continue;
+ }
+
+ if (knot_rrset_empty(&to_remove)) {
+ to_remove = create_empty_rrsigs_for(&synth_rrsig);
+ }
+
+ result = knot_rdataset_add(&to_remove.rrs, rr, NULL);
+ if (result != KNOT_EOK) {
+ break;
+ }
+ }
+
+ if (!knot_rrset_empty(&to_remove) && result == KNOT_EOK) {
+ result = changeset_add_removal(changeset, &to_remove, 0);
+ }
+
+ knot_rdataset_clear(&synth_rrsig.rrs, NULL);
+ knot_rdataset_clear(&to_remove.rrs, NULL);
+
+ return result;
+}
+
+/*!
+ * \brief Add missing RRSIGs into the changeset for adding.
+ *
+ * \param covered RR set with covered records.
+ * \param rrsigs RR set with RRSIGs.
+ * \param sign_ctx Local zone signing context.
+ * \param changeset Changeset to be updated.
+ * \param expires_at Earliest RRSIG expiration.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+static int add_missing_rrsigs(const knot_rrset_t *covered,
+ const knot_rrset_t *rrsigs,
+ zone_sign_ctx_t *sign_ctx,
+ changeset_t *changeset,
+ knot_time_t *expires_at)
+{
+ assert(!knot_rrset_empty(covered));
+ assert(sign_ctx);
+ assert(changeset);
+
+ int result = KNOT_EOK;
+ knot_rrset_t to_add;
+ knot_rrset_init_empty(&to_add);
+
+ for (size_t i = 0; i < sign_ctx->count; i++) {
+ const zone_key_t *key = &sign_ctx->keys[i];
+ if (!knot_zone_sign_use_key(key, covered)) {
+ continue;
+ }
+
+ if (valid_signature_exists(covered, rrsigs, key->key, sign_ctx->sign_ctxs[i],
+ sign_ctx->dnssec_ctx)) {
+ continue;
+ }
+
+ if (knot_rrset_empty(&to_add)) {
+ to_add = create_empty_rrsigs_for(covered);
+ }
+
+ result = knot_sign_rrset(&to_add, covered, key->key, sign_ctx->sign_ctxs[i],
+ sign_ctx->dnssec_ctx, NULL, expires_at);
+ if (result != KNOT_EOK) {
+ break;
+ }
+ }
+
+ if (!knot_rrset_empty(&to_add) && result == KNOT_EOK) {
+ result = changeset_add_addition(changeset, &to_add, 0);
+ }
+
+ knot_rdataset_clear(&to_add.rrs, NULL);
+
+ return result;
+}
+
+/*!
+ * \brief Add all RRSIGs into the changeset for removal.
+ *
+ * \param covered RR set with covered records.
+ * \param changeset Changeset to be updated.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+static int remove_rrset_rrsigs(const knot_dname_t *owner, uint16_t type,
+ const knot_rrset_t *rrsigs,
+ changeset_t *changeset)
+{
+ assert(owner);
+ assert(changeset);
+ knot_rrset_t synth_rrsig;
+ knot_rrset_init(&synth_rrsig, (knot_dname_t *)owner,
+ KNOT_RRTYPE_RRSIG, rrsigs->rclass, rrsigs->ttl);
+ int ret = knot_synth_rrsig(type, &rrsigs->rrs, &synth_rrsig.rrs, NULL);
+ if (ret != KNOT_EOK) {
+ if (ret != KNOT_ENOENT) {
+ return ret;
+ }
+ return KNOT_EOK;
+ }
+
+ ret = changeset_add_removal(changeset, &synth_rrsig, 0);
+ knot_rdataset_clear(&synth_rrsig.rrs, NULL);
+
+ return ret;
+}
+
+/*!
+ * \brief Drop all existing and create new RRSIGs for covered records.
+ *
+ * \param covered RR set with covered records.
+ * \param rrsigs Existing RRSIGs for covered RR set.
+ * \param sign_ctx Local zone signing context.
+ * \param changeset Changeset to be updated.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+static int force_resign_rrset(const knot_rrset_t *covered,
+ const knot_rrset_t *rrsigs,
+ zone_sign_ctx_t *sign_ctx,
+ changeset_t *changeset)
+{
+ assert(!knot_rrset_empty(covered));
+
+ if (!knot_rrset_empty(rrsigs)) {
+ int result = remove_rrset_rrsigs(covered->owner, covered->type,
+ rrsigs, changeset);
+ if (result != KNOT_EOK) {
+ return result;
+ }
+ }
+
+ return add_missing_rrsigs(covered, NULL, sign_ctx, changeset, NULL);
+}
+
+/*!
+ * \brief Drop all expired and create new RRSIGs for covered records.
+ *
+ * \param covered RR set with covered records.
+ * \param rrsigs Existing RRSIGs for covered RR set.
+ * \param sign_ctx Local zone signing context.
+ * \param changeset Changeset to be updated.
+ * \param expires_at Current earliest expiration, will be updated.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+static int resign_rrset(const knot_rrset_t *covered,
+ const knot_rrset_t *rrsigs,
+ zone_sign_ctx_t *sign_ctx,
+ changeset_t *changeset,
+ knot_time_t *expires_at)
+{
+ assert(!knot_rrset_empty(covered));
+
+ // TODO this function creates some signatures twice (for checking)
+ int result = remove_expired_rrsigs(covered, rrsigs, sign_ctx,
+ changeset, expires_at);
+ if (result != KNOT_EOK) {
+ return result;
+ }
+
+ return add_missing_rrsigs(covered, rrsigs, sign_ctx, changeset, expires_at);
+}
+
+static int remove_standalone_rrsigs(const zone_node_t *node,
+ const knot_rrset_t *rrsigs,
+ changeset_t *changeset)
+{
+ if (rrsigs == NULL) {
+ return KNOT_EOK;
+ }
+
+ uint16_t rrsigs_rdata_count = rrsigs->rrs.count;
+ knot_rdata_t *rdata = rrsigs->rrs.rdata;
+ for (uint16_t i = 0; i < rrsigs_rdata_count; ++i) {
+ uint16_t type_covered = knot_rrsig_type_covered(rdata);
+ if (!node_rrtype_exists(node, type_covered)) {
+ knot_rrset_t to_remove;
+ knot_rrset_init(&to_remove, rrsigs->owner, rrsigs->type,
+ rrsigs->rclass, rrsigs->ttl);
+ int ret = knot_rdataset_add(&to_remove.rrs, rdata, NULL);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ ret = changeset_add_removal(changeset, &to_remove, 0);
+ knot_rdataset_clear(&to_remove.rrs, NULL);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+ rdata = knot_rdataset_next(rdata);
+ }
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Update RRSIGs in a given node by updating changeset.
+ *
+ * \param node Node to be signed.
+ * \param sign_ctx Local zone signing context.
+ * \param changeset Changeset to be updated.
+ * \param expires_at Current earliest expiration, will be updated.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+static int sign_node_rrsets(const zone_node_t *node,
+ zone_sign_ctx_t *sign_ctx,
+ changeset_t *changeset,
+ knot_time_t *expires_at)
+{
+ assert(node);
+ assert(sign_ctx);
+
+ int result = KNOT_EOK;
+ knot_rrset_t rrsigs = node_rrset(node, KNOT_RRTYPE_RRSIG);
+
+ for (int i = 0; i < node->rrset_count; i++) {
+ knot_rrset_t rrset = node_rrset_at(node, i);
+ if (rrset.type == KNOT_RRTYPE_RRSIG) {
+ continue;
+ }
+
+ if (!knot_zone_sign_rr_should_be_signed(node, &rrset)) {
+ continue;
+ }
+
+ if (sign_ctx->dnssec_ctx->rrsig_drop_existing) {
+ result = force_resign_rrset(&rrset, &rrsigs,
+ sign_ctx, changeset);
+ } else {
+ result = resign_rrset(&rrset, &rrsigs, sign_ctx,
+ changeset, expires_at);
+ }
+
+ if (result != KNOT_EOK) {
+ return result;
+ }
+ }
+
+ return remove_standalone_rrsigs(node, &rrsigs, changeset);
+}
+
+/*!
+ * \brief Struct to carry data for 'sign_data' callback function.
+ */
+typedef struct node_sign_args {
+ zone_sign_ctx_t *sign_ctx;
+ changeset_t *changeset;
+ knot_time_t expires_at;
+} node_sign_args_t;
+
+/*!
+ * \brief Sign node (callback function).
+ *
+ * \param node Node to be signed.
+ * \param data Callback data, node_sign_args_t.
+ */
+static int sign_node(zone_node_t **node, void *data)
+{
+ assert(node && *node);
+ assert(data);
+
+ node_sign_args_t *args = (node_sign_args_t *)data;
+
+ if ((*node)->rrset_count == 0) {
+ return KNOT_EOK;
+ }
+
+ if ((*node)->flags & NODE_FLAGS_NONAUTH) {
+ return KNOT_EOK;
+ }
+
+ int result = sign_node_rrsets(*node, args->sign_ctx, args->changeset,
+ &args->expires_at);
+
+ return result;
+}
+
+/*!
+ * \brief Update RRSIGs in a given zone tree by updating changeset.
+ *
+ * \param tree Zone tree to be signed.
+ * \param zone_keys Zone keys.
+ * \param policy DNSSEC policy.
+ * \param changeset Changeset to be updated.
+ * \param expires_at Expiration time of the oldest signature in zone.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+static int zone_tree_sign(zone_tree_t *tree,
+ const zone_keyset_t *zone_keys,
+ const kdnssec_ctx_t *dnssec_ctx,
+ changeset_t *changeset,
+ knot_time_t *expires_at)
+{
+ assert(zone_keys);
+ assert(dnssec_ctx);
+ assert(changeset);
+
+ node_sign_args_t args = {
+ .sign_ctx = zone_sign_ctx(zone_keys, dnssec_ctx),
+ .changeset = changeset,
+ .expires_at = knot_time_add(dnssec_ctx->now, dnssec_ctx->policy->rrsig_lifetime),
+ };
+
+ if (args.sign_ctx == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ int result = zone_tree_apply(tree, sign_node, &args);
+ *expires_at = args.expires_at;
+
+ zone_sign_ctx_free(args.sign_ctx);
+ return result;
+}
+
+/*- private API - signing of NSEC(3) in changeset ----------------------------*/
+
+/*!
+ * \brief Struct to carry data for changeset signing callback functions.
+ */
+typedef struct {
+ const zone_contents_t *zone;
+ zone_sign_ctx_t *sign_ctx;
+ changeset_t *changeset;
+ trie_t *signed_tree;
+} changeset_signing_data_t;
+
+/*- private API - DNSKEY handling --------------------------------------------*/
+
+static int rrset_add_zone_key(knot_rrset_t *rrset, zone_key_t *zone_key)
+{
+ assert(rrset);
+ assert(zone_key);
+
+ dnssec_binary_t dnskey_rdata = { 0 };
+ dnssec_key_get_rdata(zone_key->key, &dnskey_rdata);
+
+ return knot_rrset_add_rdata(rrset, dnskey_rdata.data, dnskey_rdata.size, NULL);
+}
+
+static int rrset_add_zone_ds(knot_rrset_t *rrset, zone_key_t *zone_key)
+{
+ assert(rrset);
+ assert(zone_key);
+
+ dnssec_binary_t cds_rdata = { 0 };
+ zone_key_calculate_ds(zone_key, &cds_rdata);
+
+ return knot_rrset_add_rdata(rrset, cds_rdata.data, cds_rdata.size, NULL);
+}
+
+/*!
+ * \brief Goes through list and looks for RRSet type there.
+ *
+ * \return True if RR type is in the list, false otherwise.
+ */
+static bool rr_type_in_list(const knot_rrset_t *rr, const list_t *l)
+{
+ if (l == NULL || EMPTY_LIST(*l)) {
+ return false;
+ }
+ assert(rr);
+
+ type_node_t *n = NULL;
+ WALK_LIST(n, *l) {
+ type_node_t *type_node = (type_node_t *)n;
+ if (type_node->type == rr->type) {
+ return true;
+ }
+ };
+
+ return false;
+}
+
+static int add_rr_type_to_list(const knot_rrset_t *rr, list_t *l)
+{
+ assert(rr);
+ assert(l);
+
+ type_node_t *n = malloc(sizeof(type_node_t));
+ if (n == NULL) {
+ return KNOT_ENOMEM;
+ }
+ n->type = rr->type;
+
+ add_head(l, (node_t *)n);
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Checks whether RRSet is not already in the hash table, automatically
+ * stores its pointer to the table if not found, but returns false in
+ * that case.
+ *
+ * \param rrset RRSet to be checked for.
+ * \param tree Tree with already signed RRs.
+ * \param rr_signed Set to true if RR is signed already, false otherwise.
+ *
+ * \return KNOT_E*
+ */
+static int rr_already_signed(const knot_rrset_t *rrset, trie_t *t,
+ bool *rr_signed)
+{
+ assert(rrset);
+ assert(t);
+ *rr_signed = false;
+ // Create a key = RRSet owner converted to sortable format
+ knot_dname_storage_t lf_storage;
+ uint8_t *lf = knot_dname_lf(rrset->owner, lf_storage);
+ assert(lf);
+ trie_val_t stored_info = (signed_info_t *)trie_get_try(t, (char *)lf+1,
+ *lf);
+ if (stored_info == NULL) {
+ // Create new info struct
+ signed_info_t *info = malloc(sizeof(signed_info_t));
+ if (info == NULL) {
+ return KNOT_ENOMEM;
+ }
+ memset(info, 0, sizeof(signed_info_t));
+ // Store actual dname repr
+ info->dname = knot_dname_copy(rrset->owner, NULL);
+ if (info->dname == NULL) {
+ free(info);
+ return KNOT_ENOMEM;
+ }
+ // Create new list to insert as a value
+ info->type_list = malloc(sizeof(list_t));
+ if (info->type_list == NULL) {
+ free(info->dname);
+ free(info);
+ return KNOT_ENOMEM;
+ }
+ init_list(info->type_list);
+ // Insert type to list
+ int ret = add_rr_type_to_list(rrset, info->type_list);
+ if (ret != KNOT_EOK) {
+ free(info->type_list);
+ free(info->dname);
+ free(info);
+ return ret;
+ }
+ *trie_get_ins(t, (char *)lf+1, *lf) = info;
+ } else {
+ signed_info_t *info = *((signed_info_t **)stored_info);
+ assert(info->type_list);
+ // Check whether the type is in the list already
+ if (rr_type_in_list(rrset, info->type_list)) {
+ *rr_signed = true;
+ return KNOT_EOK;
+ }
+ // Just update the existing list
+ int ret = add_rr_type_to_list(rrset, info->type_list);
+ if (ret != KNOT_EOK) {
+ *rr_signed = false;
+ return KNOT_EOK;
+ }
+ }
+
+ *rr_signed = false;
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Wrapper function for changeset signing - to be used with changeset
+ * apply functions.
+ *
+ * \param chg_rrset RRSet to be signed (potentially)
+ * \param data Signing data
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+static int sign_changeset_wrap(knot_rrset_t *chg_rrset,
+ changeset_signing_data_t *args,
+ knot_time_t *expire_at)
+{
+ // Find RR's node in zone, find out if we need to sign this RR
+ const zone_node_t *node =
+ zone_contents_find_node(args->zone, chg_rrset->owner);
+
+ // If node is not in zone, all its RRSIGs were dropped - no-op
+ if (node) {
+ knot_rrset_t zone_rrset = node_rrset(node, chg_rrset->type);
+ knot_rrset_t rrsigs = node_rrset(node, KNOT_RRTYPE_RRSIG);
+
+ bool should_sign = knot_zone_sign_rr_should_be_signed(node, &zone_rrset);
+
+ // Check for RRSet in the 'already_signed' table
+ if (args->signed_tree && (should_sign && knot_rrset_empty(&zone_rrset))) {
+ bool already_signed = false;
+
+ int ret = rr_already_signed(chg_rrset, args->signed_tree,
+ &already_signed);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ if (already_signed) {
+ /* Do not sign again. */
+ should_sign = false;
+ }
+ }
+
+ if (should_sign) {
+ return resign_rrset(&zone_rrset, &rrsigs, args->sign_ctx,
+ args->changeset, expire_at);
+ } else {
+ /*
+ * If RRSet in zone DOES have RRSIGs although we
+ * should not sign it, DDNS-caused change to node/rr
+ * occurred and we have to drop all RRSIGs.
+ *
+ * OR
+ *
+ * The whole RRSet was removed, but RRSIGs remained in
+ * the zone. We need to drop them as well.
+ */
+ return remove_rrset_rrsigs(chg_rrset->owner,
+ chg_rrset->type, &rrsigs,
+ args->changeset);
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Frees info node about update signing.
+ *
+ * \param val Node to free.
+ * \param d Unused.
+ */
+static int free_helper_trie_node(trie_val_t *val, void *d)
+{
+ UNUSED(d);
+ signed_info_t *info = (signed_info_t *)*val;
+ if (info->type_list && !EMPTY_LIST(*(info->type_list))) {
+ WALK_LIST_FREE(*(info->type_list));
+ }
+ free(info->type_list);
+ knot_dname_free(info->dname, NULL);
+ knot_dname_free(info->hashed_dname, NULL);
+ free(info);
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Clears trie with info about update signing.
+ *
+ * \param t Trie to clear.
+ */
+static void knot_zone_clear_sorted_changes(trie_t *t)
+{
+ if (t) {
+ trie_apply(t, free_helper_trie_node, NULL);
+ }
+}
+
+/*- public API ---------------------------------------------------------------*/
+
+int knot_zone_sign(zone_update_t *update,
+ zone_keyset_t *zone_keys,
+ const kdnssec_ctx_t *dnssec_ctx,
+ knot_time_t *expire_at)
+{
+ if (!update || !zone_keys || !dnssec_ctx || !expire_at) {
+ return KNOT_EINVAL;
+ }
+
+ int result;
+
+ changeset_t ch;
+ result = changeset_init(&ch, update->new_cont->apex->owner);
+ if (result != KNOT_EOK) {
+ return result;
+ }
+
+ knot_time_t normal_expire = 0;
+ result = zone_tree_sign(update->new_cont->nodes, zone_keys, dnssec_ctx, &ch, &normal_expire);
+ if (result != KNOT_EOK) {
+ changeset_clear(&ch);
+ return result;
+ }
+
+ knot_time_t nsec3_expire = 0;
+ result = zone_tree_sign(update->new_cont->nsec3_nodes, zone_keys, dnssec_ctx,
+ &ch, &nsec3_expire);
+ if (result != KNOT_EOK) {
+ changeset_clear(&ch);
+ return result;
+ }
+
+ *expire_at = knot_time_min(normal_expire, nsec3_expire);
+
+ result = zone_update_apply_changeset(update, &ch); // _fix not needed
+ changeset_clear(&ch);
+
+ return result;
+}
+
+int knot_zone_sign_update_dnskeys(zone_update_t *update,
+ zone_keyset_t *zone_keys,
+ const kdnssec_ctx_t *dnssec_ctx)
+{
+ if (update == NULL || zone_keys == NULL || dnssec_ctx == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ const zone_node_t *apex = update->new_cont->apex;
+ knot_rrset_t dnskeys = node_rrset(apex, KNOT_RRTYPE_DNSKEY);
+ knot_rrset_t cdnskeys = node_rrset(apex, KNOT_RRTYPE_CDNSKEY);
+ knot_rrset_t cdss = node_rrset(apex, KNOT_RRTYPE_CDS);
+ knot_rrset_t *add_dnskeys = NULL;
+ knot_rrset_t *add_cdnskeys = NULL;
+ knot_rrset_t *add_cdss = NULL;
+ uint32_t dnskey_ttl = dnssec_ctx->policy->dnskey_ttl;
+ knot_rrset_t soa = node_rrset(apex, KNOT_RRTYPE_SOA);
+ if (knot_rrset_empty(&soa)) {
+ return KNOT_EINVAL;
+ }
+
+ changeset_t ch;
+ int ret = changeset_init(&ch, apex->owner);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+#define CHECK_RET if (ret != KNOT_EOK) goto cleanup
+
+ // remove all. This will cancel out with additions later
+ ret = changeset_add_removal(&ch, &dnskeys, 0);
+ CHECK_RET;
+ ret = changeset_add_removal(&ch, &cdnskeys, 0);
+ CHECK_RET;
+ ret = changeset_add_removal(&ch, &cdss, 0);
+ CHECK_RET;
+
+ // add DNSKEYs, CDNSKEYs and CDSs
+ add_dnskeys = knot_rrset_new(apex->owner, KNOT_RRTYPE_DNSKEY, soa.rclass,
+ dnskey_ttl, NULL);
+ add_cdnskeys = knot_rrset_new(apex->owner, KNOT_RRTYPE_CDNSKEY, soa.rclass,
+ 0, NULL);
+ add_cdss = knot_rrset_new(apex->owner, KNOT_RRTYPE_CDS, soa.rclass,
+ 0, NULL);
+ if (add_dnskeys == NULL || add_cdnskeys == NULL || add_cdss == NULL) {
+ ret = KNOT_ENOMEM;
+ CHECK_RET;
+ }
+ zone_key_t *ksk_for_cds = NULL;
+ unsigned crp = dnssec_ctx->policy->child_records_publish;
+ int kfc_prio = (crp == CHILD_RECORDS_ALWAYS ? 0 : (crp == CHILD_RECORDS_ROLLOVER ? 1 : 2));
+ for (int i = 0; i < zone_keys->count; i++) {
+ zone_key_t *key = &zone_keys->keys[i];
+ if (key->is_public) {
+ ret = rrset_add_zone_key(add_dnskeys, key);
+ CHECK_RET;
+ }
+
+ // determine which key (if any) will be the one for CDS/CDNSKEY
+ if (key->is_ksk && key->cds_priority > kfc_prio) {
+ ksk_for_cds = key;
+ kfc_prio = key->cds_priority;
+ }
+ }
+
+ if (ksk_for_cds != NULL) {
+ ret = rrset_add_zone_key(add_cdnskeys, ksk_for_cds);
+ CHECK_RET;
+ ret = rrset_add_zone_ds(add_cdss, ksk_for_cds);
+ CHECK_RET;
+ }
+
+ if (crp == CHILD_RECORDS_EMPTY) {
+ const uint8_t cdnskey_empty[5] = { 0, 0, 3, 0, 0 };
+ const uint8_t cds_empty[5] = { 0, 0, 0, 0, 0 };
+ ret = knot_rrset_add_rdata(add_cdnskeys, cdnskey_empty,
+ sizeof(cdnskey_empty), NULL);
+ CHECK_RET;
+ ret = knot_rrset_add_rdata(add_cdss, cds_empty,
+ sizeof(cds_empty), NULL);
+ CHECK_RET;
+ }
+
+ if (!knot_rrset_empty(add_cdnskeys)) {
+ ret = changeset_add_addition(&ch, add_cdnskeys, CHANGESET_CHECK |
+ CHANGESET_CHECK_CANCELOUT);
+ CHECK_RET;
+ }
+
+ if (!knot_rrset_empty(add_cdss)) {
+ ret = changeset_add_addition(&ch, add_cdss, CHANGESET_CHECK |
+ CHANGESET_CHECK_CANCELOUT);
+ CHECK_RET;
+ }
+
+ if (!knot_rrset_empty(add_dnskeys)) {
+ ret = changeset_add_addition(&ch, add_dnskeys, CHANGESET_CHECK |
+ CHANGESET_CHECK_CANCELOUT);
+ CHECK_RET;
+ }
+
+ ret = zone_update_apply_changeset(update, &ch);
+
+#undef CHECK_RET
+
+cleanup:
+ knot_rrset_free(add_dnskeys, NULL);
+ knot_rrset_free(add_cdnskeys, NULL);
+ knot_rrset_free(add_cdss, NULL);
+ changeset_clear(&ch);
+ return ret;
+}
+
+bool knot_zone_sign_use_key(const zone_key_t *key, const knot_rrset_t *covered)
+{
+ if (key == NULL || covered == NULL) {
+ return false;
+ }
+
+ if (!key->is_active) {
+ return false;
+ }
+
+ // this may be a problem with offline KSK
+ bool cds_sign_by_ksk = true;
+
+ assert(key->is_zsk || key->is_ksk);
+ bool is_apex = knot_dname_is_equal(covered->owner,
+ dnssec_key_get_dname(key->key));
+ if (!is_apex) {
+ return key->is_zsk;
+ }
+
+ switch (covered->type) {
+ case KNOT_RRTYPE_DNSKEY:
+ return key->is_ksk;
+ case KNOT_RRTYPE_CDS:
+ case KNOT_RRTYPE_CDNSKEY:
+ return (cds_sign_by_ksk ? key->is_ksk : key->is_zsk);
+ default:
+ return key->is_zsk;
+ }
+}
+
+bool knot_zone_sign_soa_expired(const zone_contents_t *zone,
+ const zone_keyset_t *zone_keys,
+ const kdnssec_ctx_t *dnssec_ctx)
+{
+ if (zone == NULL || zone_keys == NULL || dnssec_ctx == NULL) {
+ return false;
+ }
+
+ knot_rrset_t soa = node_rrset(zone->apex, KNOT_RRTYPE_SOA);
+ assert(!knot_rrset_empty(&soa));
+ knot_rrset_t rrsigs = node_rrset(zone->apex, KNOT_RRTYPE_RRSIG);
+ zone_sign_ctx_t *sign_ctx = zone_sign_ctx(zone_keys, dnssec_ctx);
+ if (sign_ctx == NULL) {
+ return false;
+ }
+ bool exist = all_signatures_exist(&soa, &rrsigs, sign_ctx);
+ zone_sign_ctx_free(sign_ctx);
+ return !exist;
+}
+
+static int sign_changeset(const zone_contents_t *zone,
+ const changeset_t *in_ch,
+ changeset_t *out_ch,
+ const zone_keyset_t *zone_keys,
+ const kdnssec_ctx_t *dnssec_ctx,
+ knot_time_t *expire_at)
+{
+ if (zone == NULL || in_ch == NULL || out_ch == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = KNOT_EOK;
+
+ // Create args for wrapper function - trie for duplicate sigs
+ changeset_signing_data_t args = {
+ .zone = zone,
+ .sign_ctx = zone_sign_ctx(zone_keys, dnssec_ctx),
+ .changeset = out_ch,
+ .signed_tree = trie_create(NULL)
+ };
+
+ if (args.sign_ctx == NULL || args.signed_tree == NULL) {
+ ret = KNOT_ENOMEM;
+ goto cleanup;
+ }
+
+ changeset_iter_t itt;
+ changeset_iter_all(&itt, in_ch);
+
+ knot_rrset_t rr = changeset_iter_next(&itt);
+ while (!knot_rrset_empty(&rr)) {
+ ret = sign_changeset_wrap(&rr, &args, expire_at);
+ if (ret != KNOT_EOK) {
+ changeset_iter_clear(&itt);
+ goto cleanup;
+ }
+ rr = changeset_iter_next(&itt);
+ }
+ changeset_iter_clear(&itt);
+
+ if (!knot_rrset_empty(in_ch->soa_from)) {
+ ret = sign_changeset_wrap(in_ch->soa_from, &args, expire_at);
+ if (ret != KNOT_EOK) {
+ goto cleanup;
+ }
+ }
+ if (!knot_rrset_empty(in_ch->soa_to)) {
+ ret = sign_changeset_wrap(in_ch->soa_to, &args, expire_at);
+ if (ret != KNOT_EOK) {
+ goto cleanup;
+ }
+ }
+
+cleanup:
+ knot_zone_clear_sorted_changes(args.signed_tree);
+ trie_free(args.signed_tree);
+ zone_sign_ctx_free(args.sign_ctx);
+
+ return ret;
+}
+
+int knot_zone_sign_nsecs_in_changeset(const zone_keyset_t *zone_keys,
+ const kdnssec_ctx_t *dnssec_ctx,
+ changeset_t *changeset)
+{
+ if (zone_keys == NULL || dnssec_ctx == NULL || changeset == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ zone_sign_ctx_t *sign_ctx = zone_sign_ctx(zone_keys, dnssec_ctx);
+ if (sign_ctx == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ changeset_iter_t itt;
+ changeset_iter_add(&itt, changeset);
+
+ knot_rrset_t rr = changeset_iter_next(&itt);
+ while (!knot_rrset_empty(&rr)) {
+ if (rr.type == KNOT_RRTYPE_NSEC ||
+ rr.type == KNOT_RRTYPE_NSEC3 ||
+ rr.type == KNOT_RRTYPE_NSEC3PARAM) {
+ int ret = add_missing_rrsigs(&rr, NULL, sign_ctx,
+ changeset, NULL);
+ if (ret != KNOT_EOK) {
+ changeset_iter_clear(&itt);
+ return ret;
+ }
+ }
+ rr = changeset_iter_next(&itt);
+ }
+
+ changeset_iter_clear(&itt);
+ zone_sign_ctx_free(sign_ctx);
+
+ return KNOT_EOK;
+}
+
+bool knot_zone_sign_rr_should_be_signed(const zone_node_t *node,
+ const knot_rrset_t *rrset)
+{
+ if (node == NULL || knot_rrset_empty(rrset)) {
+ return false;
+ }
+
+ // We do not want to sign RRSIGs
+ if (rrset->type == KNOT_RRTYPE_RRSIG) {
+ return false;
+ }
+
+ // At delegation points we only want to sign NSECs and DSs
+ if (node->flags & NODE_FLAGS_DELEG) {
+ if (!(rrset->type == KNOT_RRTYPE_NSEC ||
+ rrset->type == KNOT_RRTYPE_DS)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+int knot_zone_sign_update(zone_update_t *update,
+ zone_keyset_t *zone_keys,
+ const kdnssec_ctx_t *dnssec_ctx,
+ knot_time_t *expire_at)
+{
+ if (update == NULL || zone_keys == NULL || dnssec_ctx == NULL || expire_at == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = KNOT_EOK;
+
+
+ ret = apply_prepare_to_sign(update->a_ctx);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ /* Check if the UPDATE changed DNSKEYs or NSEC3PARAM.
+ * If so, we have to sign the whole zone. */
+ const bool full_sign = apex_dnssec_changed(update);
+ if (full_sign) {
+ ret = knot_zone_sign(update, zone_keys, dnssec_ctx, expire_at);
+ } else {
+ changeset_t sec_ch;
+ ret = changeset_init(&sec_ch, update->zone->name);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ ret = sign_changeset(update->new_cont, &update->change, &sec_ch,
+ zone_keys, dnssec_ctx, expire_at);
+ if (ret == KNOT_EOK) {
+ ret = zone_update_apply_changeset_fix(update, &sec_ch);
+ }
+ changeset_clear(&sec_ch);
+ }
+
+ return ret;
+}
+
+int knot_zone_sign_soa(zone_update_t *update,
+ const zone_keyset_t *zone_keys,
+ const kdnssec_ctx_t *dnssec_ctx)
+{
+ knot_rrset_t soa_to = node_rrset(update->new_cont->apex, KNOT_RRTYPE_SOA);
+ knot_rrset_t soa_rrsig = node_rrset(update->new_cont->apex, KNOT_RRTYPE_RRSIG);
+ changeset_t ch;
+ int ret = changeset_init(&ch, update->zone->name);
+ if (ret == KNOT_EOK) {
+ zone_sign_ctx_t *sign_ctx = zone_sign_ctx(zone_keys, dnssec_ctx);
+ if (sign_ctx == NULL) {
+ changeset_clear(&ch);
+ return KNOT_ENOMEM;
+ }
+ ret = force_resign_rrset(&soa_to, &soa_rrsig, sign_ctx, &ch);
+ if (ret == KNOT_EOK) {
+ ret = zone_update_apply_changeset_fix(update, &ch);
+ }
+ zone_sign_ctx_free(sign_ctx);
+ }
+ changeset_clear(&ch);
+ return ret;
+}
diff --git a/src/knot/dnssec/zone-sign.h b/src/knot/dnssec/zone-sign.h
new file mode 100644
index 0000000..33c0a60
--- /dev/null
+++ b/src/knot/dnssec/zone-sign.h
@@ -0,0 +1,135 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "knot/updates/changesets.h"
+#include "knot/updates/zone-update.h"
+#include "knot/zone/contents.h"
+#include "knot/dnssec/context.h"
+#include "knot/dnssec/zone-keys.h"
+
+/*!
+ * \brief Adds/removes DNSKEY (and CDNSKEY, CDS) records to zone according to zone keyset.
+ *
+ * \param update Structure holding zone contents and to be updated with changes.
+ * \param zone_keys Keyset with private keys.
+ * \param dnssec_ctx KASP context.
+ *
+ * \return KNOT_E*
+ */
+int knot_zone_sign_update_dnskeys(zone_update_t *update,
+ zone_keyset_t *zone_keys,
+ const kdnssec_ctx_t *dnssec_ctx);
+
+/*!
+ * \brief Check if key can be used to sign given RR.
+ *
+ * \param key Zone key.
+ * \param covered RR to be checked.
+ *
+ * \return The RR should be signed.
+ */
+bool knot_zone_sign_use_key(const zone_key_t *key, const knot_rrset_t *covered);
+
+/*!
+ * \brief Update zone signatures and store performed changes in update.
+ *
+ * Updates RRSIGs, NSEC(3)s, and DNSKEYs.
+ *
+ * \param update Zone Update containing the zone and to be updated with new DNSKEYs and RRSIGs.
+ * \param zone_keys Zone keys.
+ * \param dnssec_ctx DNSSEC context.
+ * \param expire_at Time, when the oldest signature in the zone expires.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_zone_sign(zone_update_t *update,
+ zone_keyset_t *zone_keys,
+ const kdnssec_ctx_t *dnssec_ctx,
+ knot_time_t *expire_at);
+
+/*!
+ * \brief Check if zone SOA signatures are expired.
+ *
+ * \param zone Zone to be signed.
+ * \param zone_keys Zone keys.
+ * \param dnssec_ctx DNSSEC context.
+ *
+ * \return True if zone SOA signatures need update, false othewise.
+ */
+bool knot_zone_sign_soa_expired(const zone_contents_t *zone,
+ const zone_keyset_t *zone_keys,
+ const kdnssec_ctx_t *dnssec_ctx);
+
+/*!
+ * \brief Sign NSEC/NSEC3 nodes in changeset and update the changeset.
+ *
+ * \param zone_keys Zone keys.
+ * \param dnssec_ctx DNSSEC context.
+ * \param changeset Changeset to be updated.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_zone_sign_nsecs_in_changeset(const zone_keyset_t *zone_keys,
+ const kdnssec_ctx_t *dnssec_ctx,
+ changeset_t *changeset);
+
+/*!
+ * \brief Checks whether RRSet in a node has to be signed. Will not return
+ * true for all types that should be signed, do not use this as an
+ * universal function, it is implementation specific.
+ *
+ * \param node Node containing the RRSet.
+ * \param rrset RRSet we are checking for.
+ *
+ * \retval true if should be signed.
+ */
+bool knot_zone_sign_rr_should_be_signed(const zone_node_t *node,
+ const knot_rrset_t *rrset);
+
+/*!
+ * \brief Sign updates of the zone, storing new RRSIGs in this update again.
+ *
+ * \param update Zone Update structure.
+ * \param zone_keys Zone keys.
+ * \param dnssec_ctx DNSSEC context.
+ * \param expire_at Time, when the oldest signature in the update expires.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_zone_sign_update(zone_update_t *update,
+ zone_keyset_t *zone_keys,
+ const kdnssec_ctx_t *dnssec_ctx,
+ knot_time_t *expire_at);
+
+/*!
+ * \brief Sign the new SOA record in the Zone Update.
+ *
+ * The reason for having this separate is: not updating
+ * SOA if everything else is unchanged. So, the procedure is
+ * [refresh_DNSKEY_records]->[recreate_nsec]->[sign_zone]->
+ * ->[check_unchanged]->[update_soa]->[sign_soa]
+ *
+ * \param update Zone Update with new SOA and to be updated with SOA RRSIG.
+ * \param zone_keys Zone keys.
+ * \param dnssec_ctx DNSSEC context.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_zone_sign_soa(zone_update_t *update,
+ const zone_keyset_t *zone_keys,
+ const kdnssec_ctx_t *dnssec_ctx);
diff --git a/src/knot/events/events.c b/src/knot/events/events.c
new file mode 100644
index 0000000..954c516
--- /dev/null
+++ b/src/knot/events/events.c
@@ -0,0 +1,475 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <stdarg.h>
+#include <time.h>
+#include <urcu.h>
+
+#include "libknot/libknot.h"
+#include "knot/common/log.h"
+#include "knot/events/events.h"
+#include "knot/events/handlers.h"
+#include "knot/events/replan.h"
+#include "knot/zone/zone.h"
+
+#define ZONE_EVENT_IMMEDIATE 1 /* Fast-track to worker queue. */
+
+typedef int (*zone_event_cb)(conf_t *conf, zone_t *zone);
+
+typedef struct event_info {
+ zone_event_type_t type;
+ const zone_event_cb callback;
+ const char *name;
+} event_info_t;
+
+static const event_info_t EVENT_INFO[] = {
+ { ZONE_EVENT_LOAD, event_load, "load" },
+ { ZONE_EVENT_REFRESH, event_refresh, "refresh" },
+ { ZONE_EVENT_UPDATE, event_update, "update" },
+ { ZONE_EVENT_EXPIRE, event_expire, "expiration" },
+ { ZONE_EVENT_FLUSH, event_flush, "journal flush" },
+ { ZONE_EVENT_NOTIFY, event_notify, "notify" },
+ { ZONE_EVENT_DNSSEC, event_dnssec, "DNSSEC re-sign" },
+ { ZONE_EVENT_UFREEZE, event_ufreeze, "update freeze" },
+ { ZONE_EVENT_UTHAW, event_uthaw, "update thaw" },
+ { ZONE_EVENT_NSEC3RESALT, event_nsec3resalt, "NSEC3 resalt" },
+ { ZONE_EVENT_PARENT_DS_Q, event_parent_ds_q, "parent DS query" },
+ { 0 }
+};
+
+static const event_info_t *get_event_info(zone_event_type_t type)
+{
+ const event_info_t *info;
+ for (info = EVENT_INFO; info->callback != NULL; info++) {
+ if (info->type == type) {
+ return info;
+ }
+ }
+
+ assert(0);
+ return NULL;
+}
+
+static bool valid_event(zone_event_type_t type)
+{
+ return (type > ZONE_EVENT_INVALID && type < ZONE_EVENT_COUNT);
+}
+
+bool ufreeze_applies(zone_event_type_t type)
+{
+ switch (type) {
+ case ZONE_EVENT_LOAD:
+ case ZONE_EVENT_REFRESH:
+ case ZONE_EVENT_UPDATE:
+ case ZONE_EVENT_FLUSH:
+ case ZONE_EVENT_DNSSEC:
+ case ZONE_EVENT_NSEC3RESALT:
+ case ZONE_EVENT_PARENT_DS_Q:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/*! \brief Return remaining time to planned event (seconds). */
+static time_t time_until(time_t planned)
+{
+ time_t now = time(NULL);
+ return now < planned ? (planned - now) : 0;
+}
+
+/*!
+ * \brief Set time of a given event type.
+ */
+static void event_set_time(zone_events_t *events, zone_event_type_t type, time_t time)
+{
+ assert(events);
+ assert(valid_event(type));
+
+ events->time[type] = time;
+}
+
+/*!
+ * \brief Get time of a given event type.
+ */
+static time_t event_get_time(zone_events_t *events, zone_event_type_t type)
+{
+ assert(events);
+ assert(valid_event(type));
+
+ return events->time[type];
+}
+
+/*!
+ * \brief Find next scheduled zone event.
+ *
+ * \note Afer the UTHAW event, get_next_event() is also invoked. In that situation,
+ * all the events are suddenly allowed, and those which were planned into
+ * the ufrozen interval, start to be performed one-by-one sorted by their times.
+ *
+ * \param events Zone events.
+ *
+ * \return Zone event type, or ZONE_EVENT_INVALID if no event is scheduled.
+ */
+static zone_event_type_t get_next_event(zone_events_t *events)
+{
+ if (!events) {
+ return ZONE_EVENT_INVALID;
+ }
+
+ zone_event_type_t next_type = ZONE_EVENT_INVALID;
+ time_t next = 0;
+
+ for (int i = 0; i < ZONE_EVENT_COUNT; i++) {
+ time_t current = events->time[i];
+
+ if ((next == 0 || current < next) && (current != 0) &&
+ (events->forced[i] || !events->ufrozen || !ufreeze_applies(i))) {
+ next = current;
+ next_type = i;
+ }
+ }
+
+ return next_type;
+}
+
+/*!
+ * \brief Fined time of next scheduled event.
+ */
+static time_t get_next_time(zone_events_t *events)
+{
+ zone_event_type_t type = get_next_event(events);
+ return valid_event(type) ? event_get_time(events, type) : 0;
+}
+
+/*!
+ * \brief Cancel scheduled item, schedule first enqueued item.
+ */
+static void reschedule(zone_events_t *events)
+{
+ assert(events);
+
+ pthread_mutex_lock(&events->reschedule_lock);
+ pthread_mutex_lock(&events->mx);
+
+ if (!events->event || events->running || events->frozen) {
+ pthread_mutex_unlock(&events->mx);
+ pthread_mutex_unlock(&events->reschedule_lock);
+ return;
+ }
+
+ zone_event_type_t type = get_next_event(events);
+ if (!valid_event(type)) {
+ pthread_mutex_unlock(&events->mx);
+ pthread_mutex_unlock(&events->reschedule_lock);
+ return;
+ }
+
+ time_t diff = time_until(event_get_time(events, type));
+
+ pthread_mutex_unlock(&events->mx);
+
+ evsched_schedule(events->event, diff * 1000);
+
+ pthread_mutex_unlock(&events->reschedule_lock);
+}
+
+/*!
+ * \brief Zone event wrapper, expected to be called from a worker thread.
+ *
+ * 1. Takes the next planned event.
+ * 2. Resets the event's scheduled time (and forced flag).
+ * 3. Perform the event's callback.
+ * 4. Schedule next event planned event.
+ */
+static void event_wrap(task_t *task)
+{
+ assert(task);
+ assert(task->ctx);
+
+ zone_t *zone = task->ctx;
+ zone_events_t *events = &zone->events;
+
+ pthread_mutex_lock(&events->mx);
+ zone_event_type_t type = get_next_event(events);
+ if (!valid_event(type)) {
+ events->running = false;
+ pthread_mutex_unlock(&events->mx);
+ return;
+ }
+ event_set_time(events, type, 0);
+ events->forced[type] = false;
+ pthread_mutex_unlock(&events->mx);
+
+ const event_info_t *info = get_event_info(type);
+
+ /* Create a configuration copy just for this event. */
+ conf_t *conf;
+ rcu_read_lock();
+ int ret = conf_clone(&conf);
+ rcu_read_unlock();
+ if (ret == KNOT_EOK) {
+ /* Execute the event callback. */
+ ret = info->callback(conf, zone);
+ conf_free(conf);
+ }
+
+ if (ret != KNOT_EOK) {
+ log_zone_error(zone->name, "zone event '%s' failed (%s)",
+ info->name, knot_strerror(ret));
+ }
+
+ pthread_mutex_lock(&events->mx);
+ events->running = false;
+ pthread_mutex_unlock(&events->mx);
+ reschedule(events);
+}
+
+/*!
+ * \brief Called by scheduler thread if the event occurs.
+ */
+static void event_dispatch(event_t *event)
+{
+ assert(event);
+ assert(event->data);
+
+ zone_events_t *events = event->data;
+
+ pthread_mutex_lock(&events->mx);
+ if (!events->running && !events->frozen) {
+ events->running = true;
+ worker_pool_assign(events->pool, &events->task);
+ }
+ pthread_mutex_unlock(&events->mx);
+}
+
+int zone_events_init(zone_t *zone)
+{
+ if (!zone) {
+ return KNOT_EINVAL;
+ }
+
+ zone_events_t *events = &zone->events;
+
+ memset(&zone->events, 0, sizeof(zone->events));
+ pthread_mutex_init(&events->mx, NULL);
+ pthread_mutex_init(&events->reschedule_lock, NULL);
+ events->task.ctx = zone;
+ events->task.run = event_wrap;
+
+ return KNOT_EOK;
+}
+
+int zone_events_setup(struct zone *zone, worker_pool_t *workers,
+ evsched_t *scheduler, knot_db_t *timers_db)
+{
+ if (!zone || !workers || !scheduler) {
+ return KNOT_EINVAL;
+ }
+
+ event_t *event;
+ event = evsched_event_create(scheduler, event_dispatch, &zone->events);
+ if (!event) {
+ return KNOT_ENOMEM;
+ }
+
+ zone->events.event = event;
+ zone->events.pool = workers;
+ zone->events.timers_db = timers_db;
+
+ return KNOT_EOK;
+}
+
+void zone_events_deinit(zone_t *zone)
+{
+ if (!zone) {
+ return;
+ }
+
+ evsched_cancel(zone->events.event);
+ evsched_event_free(zone->events.event);
+
+ pthread_mutex_destroy(&zone->events.mx);
+ pthread_mutex_destroy(&zone->events.reschedule_lock);
+
+ memset(&zone->events, 0, sizeof(zone->events));
+}
+
+void _zone_events_schedule_at(zone_t *zone, ...)
+{
+ zone_events_t *events = &zone->events;
+ va_list args;
+ va_start(args, zone);
+
+ pthread_mutex_lock(&events->mx);
+
+ time_t old_next = get_next_time(events);
+
+ // update timers
+ for (int type = va_arg(args, int); valid_event(type); type = va_arg(args, int)) {
+ time_t planned = va_arg(args, time_t);
+ if (planned < 0) {
+ continue;
+ }
+
+ time_t current = event_get_time(events, type);
+ if (planned == 0 || current == 0 || planned < current) {
+ event_set_time(events, type, planned);
+ }
+ }
+
+ // reschedule if changed
+ time_t next = get_next_time(events);
+ pthread_mutex_unlock(&events->mx);
+ if (old_next != next) {
+ reschedule(events);
+ }
+
+ va_end(args);
+}
+
+void zone_events_schedule_user(zone_t *zone, zone_event_type_t type)
+{
+ if (!zone || !valid_event(type)) {
+ return;
+ }
+
+ zone_events_t *events = &zone->events;
+ pthread_mutex_lock(&events->mx);
+ events->forced[type] = true;
+ pthread_mutex_unlock(&events->mx);
+
+ zone_events_schedule_now(zone, type);
+
+ // reschedule because get_next_event result changed outside of _zone_events_schedule_at
+ reschedule(events);
+}
+
+void zone_events_enqueue(zone_t *zone, zone_event_type_t type)
+{
+ if (!zone || !valid_event(type)) {
+ return;
+ }
+
+ zone_events_t *events = &zone->events;
+
+ pthread_mutex_lock(&events->mx);
+
+ /* Bypass scheduler if no event is running. */
+ if (!events->running && !events->frozen &&
+ (!events->ufrozen || !ufreeze_applies(type))) {
+ events->running = true;
+ event_set_time(events, type, ZONE_EVENT_IMMEDIATE);
+ worker_pool_assign(events->pool, &events->task);
+ pthread_mutex_unlock(&events->mx);
+ return;
+ }
+
+ pthread_mutex_unlock(&events->mx);
+
+ /* Execute as soon as possible. */
+ zone_events_schedule_now(zone, type);
+}
+
+void zone_events_freeze(zone_t *zone)
+{
+ if (!zone) {
+ return;
+ }
+
+ zone_events_t *events = &zone->events;
+
+ /* Prevent new events being enqueued. */
+ pthread_mutex_lock(&events->mx);
+ events->frozen = true;
+ pthread_mutex_unlock(&events->mx);
+
+ /* Cancel current event. */
+ evsched_cancel(events->event);
+}
+
+void zone_events_start(zone_t *zone)
+{
+ if (!zone) {
+ return;
+ }
+
+ zone_events_t *events = &zone->events;
+
+ /* Unlock the events queue. */
+ pthread_mutex_lock(&events->mx);
+ events->frozen = false;
+ pthread_mutex_unlock(&events->mx);
+
+ reschedule(events);
+}
+
+time_t zone_events_get_time(const struct zone *zone, zone_event_type_t type)
+{
+ if (zone == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ time_t event_time = KNOT_ENOENT;
+ zone_events_t *events = (zone_events_t *)&zone->events;
+
+ pthread_mutex_lock(&events->mx);
+
+ /* Get next valid event. */
+ if (valid_event(type)) {
+ event_time = event_get_time(events, type);
+ }
+
+ pthread_mutex_unlock(&events->mx);
+
+ return event_time;
+}
+
+const char *zone_events_get_name(zone_event_type_t type)
+{
+ /* Get information about the event and time. */
+ const event_info_t *info = get_event_info(type);
+ if (info == NULL) {
+ return NULL;
+ }
+
+ return info->name;
+}
+
+time_t zone_events_get_next(const struct zone *zone, zone_event_type_t *type)
+{
+ if (zone == NULL || type == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ time_t next_time = KNOT_ENOENT;
+ zone_events_t *events = (zone_events_t *)&zone->events;
+
+ pthread_mutex_lock(&events->mx);
+
+ /* Get time of next valid event. */
+ *type = get_next_event(events);
+ if (valid_event(*type)) {
+ next_time = event_get_time(events, *type);
+ } else {
+ *type = ZONE_EVENT_INVALID;
+ }
+
+ pthread_mutex_unlock(&events->mx);
+
+ return next_time;
+}
diff --git a/src/knot/events/events.h b/src/knot/events/events.h
new file mode 100644
index 0000000..a95db32
--- /dev/null
+++ b/src/knot/events/events.h
@@ -0,0 +1,190 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <pthread.h>
+#include <stdbool.h>
+#include <sys/time.h>
+
+#include "knot/conf/conf.h"
+#include "knot/common/evsched.h"
+#include "knot/worker/pool.h"
+#include "libknot/db/db.h"
+
+struct zone;
+
+typedef enum zone_event_type {
+ ZONE_EVENT_INVALID = -1,
+ // supported event types
+ ZONE_EVENT_LOAD = 0,
+ ZONE_EVENT_REFRESH,
+ ZONE_EVENT_UPDATE,
+ ZONE_EVENT_EXPIRE,
+ ZONE_EVENT_FLUSH,
+ ZONE_EVENT_NOTIFY,
+ ZONE_EVENT_DNSSEC,
+ ZONE_EVENT_UFREEZE,
+ ZONE_EVENT_UTHAW,
+ ZONE_EVENT_NSEC3RESALT,
+ ZONE_EVENT_PARENT_DS_Q,
+ // terminator
+ ZONE_EVENT_COUNT,
+} zone_event_type_t;
+
+typedef struct zone_events {
+ pthread_mutex_t mx; //!< Mutex protecting the struct.
+ pthread_mutex_t reschedule_lock;//!< Prevent concurrent reschedule() making mess.
+ bool running; //!< Some zone event is being run.
+ bool frozen; //!< Terminated, don't schedule new events.
+ bool ufrozen; //!< Updates to the zone temporarily frozen by user.
+
+ event_t *event; //!< Scheduler event.
+ worker_pool_t *pool; //!< Server worker pool.
+ knot_db_t *timers_db; //!< Persistent zone timers database.
+
+ task_t task; //!< Event execution context.
+ time_t time[ZONE_EVENT_COUNT]; //!< Event execution times.
+ bool forced[ZONE_EVENT_COUNT]; //!< Flag that the event was invoked by user ctl.
+} zone_events_t;
+
+/*!
+ * \brief Initialize zone events.
+ *
+ * The function will not set up the scheduling, use \ref zone_events_setup
+ * to do that.
+ *
+ * \param zone Pointer to zone (context of execution).
+ *
+ * \return KNOT_E*
+ */
+int zone_events_init(struct zone *zone);
+
+/*!
+ * \brief Set up zone events execution.
+ *
+ * \param zone Zone to setup.
+ * \param workers Worker thread pool.
+ * \param scheduler Event scheduler.
+ * \param timers_db Persistent timers database. Can be NULL.
+ *
+ * \return KNOT_E*
+ */
+int zone_events_setup(struct zone *zone, worker_pool_t *workers,
+ evsched_t *scheduler, knot_db_t *timers_db);
+
+/*!
+ * \brief Deinitialize zone events.
+ *
+ * \param zone Zone whose events we want to deinitialize.
+ */
+void zone_events_deinit(struct zone *zone);
+
+/*!
+ * \brief Enqueue event type for asynchronous execution.
+ *
+ * \note This is similar to the scheduling an event for NOW, but it can
+ * bypass the event scheduler if no event is running at the moment.
+ *
+ * \param zone Zone to schedule new event for.
+ * \param type Type of event.
+ */
+void zone_events_enqueue(struct zone *zone, zone_event_type_t type);
+
+/*!
+ * \brief Schedule new zone event.
+ *
+ * The function allows to set multiple events at once.
+ *
+ * The function intreprets time values (t) as follows:
+ *
+ * t > 0: schedule timer for a given time
+ * t = 0: cancel the timer
+ * t < 0: ignore change in the timer
+ *
+ * If the event is already scheduled, the new time will be set only if the
+ * new time is earlier than the currently scheduled one. To override the
+ * check, cancel and schedule the event in a single function call.
+ *
+ * \param zone Zone to schedule new event for.
+ * \param ... Sequence of zone_event_type_t and time_t terminated with
+ * ZONE_EVENT_INVALID.
+ */
+void _zone_events_schedule_at(struct zone *zone, ...);
+
+#define zone_events_schedule_at(zone, events...) \
+ _zone_events_schedule_at(zone, events, ZONE_EVENT_INVALID)
+
+#define zone_events_schedule_now(zone, type) \
+ zone_events_schedule_at(zone, type, time(NULL))
+
+/*!
+ * \brief Schedule zone event to now, with forced flag.
+ */
+void zone_events_schedule_user(struct zone *zone, zone_event_type_t type);
+
+/*!
+ * \brief Freeze all zone events and prevent new events from running.
+ *
+ * \param zone Zone to freeze events for.
+ */
+void zone_events_freeze(struct zone *zone);
+
+/*!
+ * \brief ufreeze_applies
+ * \param type Type of event to be checked
+ * \return true / false if user freeze applies
+ */
+bool ufreeze_applies(zone_event_type_t type);
+
+/*!
+ * \brief Start the events processing.
+ *
+ * \param zone Zone to start processing for.
+ */
+void zone_events_start(struct zone *zone);
+
+/*!
+ * \brief Return time of the occurrence of the given event.
+ *
+ * \param zone Zone to get event time from.
+ * \param type Event type.
+ *
+ * \retval time of the event when event found
+ * \retval 0 when the event is not planned
+ * \retval negative value if event is invalid
+ */
+time_t zone_events_get_time(const struct zone *zone, zone_event_type_t type);
+
+/*!
+ * \brief Return text name of the event.
+ *
+ * \param type Type of event.
+ *
+ * \retval String with event name if it exists.
+ * \retval NULL if the event does not exist.
+ */
+const char *zone_events_get_name(zone_event_type_t type);
+
+/*!
+ * \brief Return time and type of the next event.
+ *
+ * \param zone Zone to get next event from.
+ * \param type [out] Type of the next event will be stored in the parameter.
+ *
+ * \return time of the next event or an error (negative number)
+ */
+time_t zone_events_get_next(const struct zone *zone, zone_event_type_t *type);
diff --git a/src/knot/events/handlers.h b/src/knot/events/handlers.h
new file mode 100644
index 0000000..a103e42
--- /dev/null
+++ b/src/knot/events/handlers.h
@@ -0,0 +1,47 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "knot/conf/conf.h"
+#include "knot/zone/zone.h"
+#include "knot/dnssec/zone-events.h" // zone_sign_reschedule_t
+
+/*! \brief Loads or reloads potentially changed zone. */
+int event_load(conf_t *conf, zone_t *zone);
+/*! \brief Refresh a zone from a master. */
+int event_refresh(conf_t *conf, zone_t *zone);
+/*! \brief Processes DDNS updates in the zone's DDNS queue. */
+int event_update(conf_t *conf, zone_t *zone);
+/*! \brief Empties in-memory zone contents. */
+int event_expire(conf_t *conf, zone_t *zone);
+/*! \brief Flushes zone contents into text file. */
+int event_flush(conf_t *conf, zone_t *zone);
+/*! \brief Sends notify to slaves. */
+int event_notify(conf_t *conf, zone_t *zone);
+/*! \brief Signs the zone using its DNSSEC keys, perform key rollovers. */
+int event_dnssec(conf_t *conf, zone_t *zone);
+/*! \brief NOT A HANDLER, just a helper function to reschedule based on reschedule_t */
+void event_dnssec_reschedule(conf_t *conf, zone_t *zone,
+ const zone_sign_reschedule_t *refresh, bool zone_changed);
+/*! \brief Freeze those events causing zone contents change. */
+int event_ufreeze(conf_t *conf, zone_t *zone);
+/*! \brief Unfreeze zone updates. */
+int event_uthaw(conf_t *conf, zone_t *zone);
+/*! \brief Recreates salt for NSEC3 hashing. */
+int event_nsec3resalt(conf_t *conf, zone_t *zone);
+/*! \brief When CDS/CDNSKEY published, look for matching DS */
+int event_parent_ds_q(conf_t *conf, zone_t *zone);
diff --git a/src/knot/events/handlers/dnssec.c b/src/knot/events/handlers/dnssec.c
new file mode 100644
index 0000000..00d3aef
--- /dev/null
+++ b/src/knot/events/handlers/dnssec.c
@@ -0,0 +1,116 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "knot/common/log.h"
+#include "knot/conf/conf.h"
+#include "knot/dnssec/zone-events.h"
+#include "knot/updates/apply.h"
+#include "knot/zone/zone.h"
+#include "libknot/errcode.h"
+
+static void log_dnssec_next(const knot_dname_t *zone, knot_time_t refresh_at)
+{
+ char time_str[64] = { 0 };
+ struct tm time_gm = { 0 };
+ time_t refresh = refresh_at;
+ localtime_r(&refresh, &time_gm);
+ strftime(time_str, sizeof(time_str), KNOT_LOG_TIME_FORMAT, &time_gm);
+ if (refresh_at == 0) {
+ log_zone_warning(zone, "DNSSEC, next signing not scheduled");
+ } else {
+ log_zone_info(zone, "DNSSEC, next signing at %s", time_str);
+ }
+}
+
+void event_dnssec_reschedule(conf_t *conf, zone_t *zone,
+ const zone_sign_reschedule_t *refresh, bool zone_changed)
+{
+ time_t now = time(NULL);
+ time_t ignore = -1;
+ knot_time_t refresh_at = refresh->next_sign;
+
+ if (knot_time_cmp(refresh->next_rollover, refresh_at) < 0) {
+ refresh_at = refresh->next_rollover;
+ }
+
+ log_dnssec_next(zone->name, (time_t)refresh_at);
+
+ if (refresh->plan_ds_query) {
+ zone->timers.next_parent_ds_q = now;
+ }
+
+ if (refresh->allow_nsec3resalt) {
+ zone->timers.last_resalt = time(NULL);
+ }
+
+ zone_events_schedule_at(zone,
+ ZONE_EVENT_DNSSEC, refresh_at ? (time_t)refresh_at : ignore,
+ ZONE_EVENT_PARENT_DS_Q, refresh->plan_ds_query ? now : ignore,
+ ZONE_EVENT_NSEC3RESALT, refresh->next_nsec3resalt ? refresh->next_nsec3resalt : ignore,
+ ZONE_EVENT_NOTIFY, zone_changed ? now : ignore
+ );
+}
+
+int event_dnssec(conf_t *conf, zone_t *zone)
+{
+ assert(zone);
+
+ zone_sign_reschedule_t resch = { 0 };
+ resch.allow_rollover = true;
+ int sign_flags = 0;
+
+ if (zone->flags & ZONE_FORCE_RESIGN) {
+ log_zone_info(zone->name, "DNSSEC, dropping previous "
+ "signatures, re-signing zone");
+ zone->flags &= ~ZONE_FORCE_RESIGN;
+ sign_flags = ZONE_SIGN_DROP_SIGNATURES;
+ } else {
+ log_zone_info(zone->name, "DNSSEC, signing zone");
+ sign_flags = 0;
+ }
+
+ if (zone_events_get_time(zone, ZONE_EVENT_NSEC3RESALT) <= time(NULL)) {
+ resch.allow_nsec3resalt = true;
+ }
+
+ zone_update_t up;
+ int ret = zone_update_init(&up, zone, UPDATE_INCREMENTAL);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = knot_dnssec_zone_sign(&up, sign_flags, &resch);
+ if (ret != KNOT_EOK) {
+ goto done;
+ }
+
+ bool zone_changed = !zone_update_no_change(&up);
+ if (zone_changed) {
+ ret = zone_update_commit(conf, &up);
+ if (ret != KNOT_EOK) {
+ goto done;
+ }
+ }
+
+ // Schedule dependent events
+ event_dnssec_reschedule(conf, zone, &resch, zone_changed);
+
+done:
+ zone_update_clear(&up);
+ return ret;
+}
diff --git a/src/knot/events/handlers/expire.c b/src/knot/events/handlers/expire.c
new file mode 100644
index 0000000..16e904d
--- /dev/null
+++ b/src/knot/events/handlers/expire.c
@@ -0,0 +1,46 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <urcu.h>
+
+#include "contrib/trim.h"
+#include "knot/common/log.h"
+#include "knot/conf/conf.h"
+#include "knot/events/handlers.h"
+#include "knot/events/replan.h"
+#include "knot/zone/contents.h"
+#include "knot/zone/zone.h"
+
+int event_expire(conf_t *conf, zone_t *zone)
+{
+ assert(zone);
+
+ zone_contents_t *expired = zone_switch_contents(zone, NULL);
+ log_zone_info(zone->name, "zone expired");
+
+ synchronize_rcu();
+ zone_contents_deep_free(expired);
+
+ zone->zonefile.exists = false;
+ mem_trim();
+
+ // NOTE: must preserve zone->timers.soa_expire
+ zone->timers.next_refresh = time(NULL);
+ replan_from_timers(conf, zone);
+
+ return KNOT_EOK;
+}
diff --git a/src/knot/events/handlers/flush.c b/src/knot/events/handlers/flush.c
new file mode 100644
index 0000000..227205d
--- /dev/null
+++ b/src/knot/events/handlers/flush.c
@@ -0,0 +1,38 @@
+/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <time.h>
+
+#include "knot/conf/conf.h"
+#include "knot/zone/zone.h"
+
+int event_flush(conf_t *conf, zone_t *zone)
+{
+ assert(conf);
+ assert(zone);
+
+ if (zone_contents_is_empty(zone->contents)) {
+ return KNOT_EOK;
+ }
+
+ int ret = zone_flush_journal(conf, zone);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ return KNOT_EOK;
+}
diff --git a/src/knot/events/handlers/freeze_thaw.c b/src/knot/events/handlers/freeze_thaw.c
new file mode 100644
index 0000000..1df3adf
--- /dev/null
+++ b/src/knot/events/handlers/freeze_thaw.c
@@ -0,0 +1,49 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "contrib/macros.h"
+#include "knot/events/events.h"
+#include "knot/conf/conf.h"
+#include "knot/zone/zone.h"
+#include "knot/common/log.h"
+
+int event_ufreeze(conf_t *conf, zone_t *zone)
+{
+ UNUSED(conf);
+ assert(zone);
+
+ pthread_mutex_lock(&zone->events.mx);
+ zone->events.ufrozen = true;
+ pthread_mutex_unlock(&zone->events.mx);
+
+ log_zone_info(zone->name, "zone updates frozen");
+
+ return KNOT_EOK;
+}
+
+int event_uthaw(conf_t *conf, zone_t *zone)
+{
+ UNUSED(conf);
+ assert(zone);
+
+ pthread_mutex_lock(&zone->events.mx);
+ zone->events.ufrozen = false;
+ pthread_mutex_unlock(&zone->events.mx);
+
+ log_zone_info(zone->name, "zone updates unfrozen");
+
+ return KNOT_EOK;
+}
diff --git a/src/knot/events/handlers/load.c b/src/knot/events/handlers/load.c
new file mode 100644
index 0000000..7410d30
--- /dev/null
+++ b/src/knot/events/handlers/load.c
@@ -0,0 +1,307 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "knot/common/log.h"
+#include "knot/conf/conf.h"
+#include "knot/dnssec/key-events.h"
+#include "knot/dnssec/zone-events.h"
+#include "knot/events/handlers.h"
+#include "knot/events/replan.h"
+#include "knot/zone/zone-diff.h"
+#include "knot/zone/zone-load.h"
+#include "knot/zone/zone.h"
+#include "knot/zone/zonefile.h"
+#include "knot/updates/acl.h"
+
+static bool dontcare_load_error(conf_t *conf, const zone_t *zone)
+{
+ return (zone->contents == NULL && zone_load_can_bootstrap(conf, zone->name));
+}
+
+static bool allowed_xfr(conf_t *conf, const zone_t *zone)
+{
+ conf_val_t acl = conf_zone_get(conf, C_ACL, zone->name);
+ while (acl.code == KNOT_EOK) {
+ conf_val_t action = conf_id_get(conf, C_ACL, C_ACTION, &acl);
+ while (action.code == KNOT_EOK) {
+ if (conf_opt(&action) == ACL_ACTION_TRANSFER) {
+ return true;
+ }
+ conf_val_next(&action);
+ }
+ conf_val_next(&acl);
+ }
+
+ return false;
+}
+
+int event_load(conf_t *conf, zone_t *zone)
+{
+ zone_contents_t *journal_conts = NULL, *zf_conts = NULL;
+ bool old_contents_exist = (zone->contents != NULL);
+
+ conf_val_t val = conf_zone_get(conf, C_JOURNAL_CONTENT, zone->name);
+ unsigned load_from = conf_opt(&val);
+
+ val = conf_zone_get(conf, C_ZONEFILE_LOAD, zone->name);
+ unsigned zf_from = conf_opt(&val);
+
+ int ret = KNOT_EOK;
+
+ // If configured, load journal contents.
+ if (load_from == JOURNAL_CONTENT_ALL && !old_contents_exist && zf_from != ZONEFILE_LOAD_WHOLE) {
+ ret = zone_load_from_journal(conf, zone, &journal_conts);
+ if (ret != KNOT_EOK) {
+ journal_conts = NULL;
+ }
+ }
+
+ // If configured, attempt to load zonefile.
+ if (zf_from != ZONEFILE_LOAD_NONE) {
+ time_t mtime;
+ char *filename = conf_zonefile(conf, zone->name);
+ ret = zonefile_exists(filename, &mtime);
+ bool zonefile_unchanged = (zone->zonefile.exists && zone->zonefile.mtime == mtime);
+ free(filename);
+ if (ret == KNOT_EOK) {
+ ret = zone_load_contents(conf, zone->name, &zf_conts);
+ }
+ if (ret != KNOT_EOK) {
+ zf_conts = NULL;
+ if (dontcare_load_error(conf, zone)) {
+ log_zone_info(zone->name, "failed to parse zone file (%s)",
+ knot_strerror(ret));
+ } else {
+ log_zone_error(zone->name, "failed to parse zone file (%s)",
+ knot_strerror(ret));
+ }
+ goto cleanup;
+ }
+
+ // Save zonefile information.
+ zone->zonefile.serial = zone_contents_serial(zf_conts);
+ zone->zonefile.exists = (zf_conts != NULL);
+ zone->zonefile.mtime = mtime;
+
+ // If configured and possible, fix the SOA serial of zonefile.
+ zone_contents_t *relevant = (zone->contents != NULL ? zone->contents : journal_conts);
+ if (zf_conts != NULL && zf_from == ZONEFILE_LOAD_DIFSE && relevant != NULL) {
+ uint32_t serial = zone_contents_serial(relevant);
+ conf_val_t policy = conf_zone_get(conf, C_SERIAL_POLICY, zone->name);
+ uint32_t set = serial_next(serial, conf_opt(&policy));
+ zone_contents_set_soa_serial(zf_conts, set);
+ log_zone_info(zone->name, "zone file parsed, serial corrected %u -> %u",
+ zone->zonefile.serial, set);
+ zone->zonefile.serial = set;
+ } else {
+ log_zone_info(zone->name, "zone file parsed, serial %u",
+ zone->zonefile.serial);
+ }
+
+ // If configured and appliable to zonefile, load journal changes.
+ bool journal_load_configured1 = (load_from == JOURNAL_CONTENT_CHANGES);
+ bool journal_load_configured2 = (load_from == JOURNAL_CONTENT_ALL);
+
+ if ((journal_load_configured1 || journal_load_configured2) &&
+ (!old_contents_exist || zonefile_unchanged)) {
+ ret = zone_load_journal(conf, zone, zf_conts);
+ if (ret != KNOT_EOK) {
+ zone_contents_deep_free(zf_conts);
+ zf_conts = NULL;
+ log_zone_warning(zone->name, "failed to load journal (%s)",
+ knot_strerror(ret));
+ }
+ }
+ }
+
+ // If configured contents=all, but not present, store zonefile.
+ if (load_from == JOURNAL_CONTENT_ALL &&
+ journal_conts == NULL && zf_conts != NULL && !old_contents_exist) {
+ ret = zone_in_journal_store(conf, zone, zf_conts);
+ if (ret != KNOT_EOK) {
+ log_zone_warning(zone->name, "failed to write zone-in-journal (%s)",
+ knot_strerror(ret));
+ }
+ }
+
+ val = conf_zone_get(conf, C_DNSSEC_SIGNING, zone->name);
+ bool dnssec_enable = conf_bool(&val), zu_from_zf_conts = false;
+ zone_update_t up = { 0 };
+ bool ignore_dnssec = ((zf_from == ZONEFILE_LOAD_DIFF || zf_from == ZONEFILE_LOAD_DIFSE)
+ && dnssec_enable);
+
+ // Create zone_update structure according to current state.
+ if (old_contents_exist) {
+ if (zf_conts == NULL) {
+ // nothing to be re-loaded
+ ret = KNOT_EOK;
+ goto cleanup;
+ } else if (zf_from == ZONEFILE_LOAD_WHOLE) {
+ // throw old zone contents and load new from ZF
+ ret = zone_update_from_contents(&up, zone, zf_conts,
+ (load_from == JOURNAL_CONTENT_NONE ?
+ UPDATE_FULL : UPDATE_INCREMENTAL));
+ zu_from_zf_conts = true;
+ } else {
+ // compute ZF diff and if success, apply it
+ ret = zone_update_from_differences(&up, zone, zone->contents, zf_conts, UPDATE_INCREMENTAL, ignore_dnssec);
+ zone_contents_deep_free(zf_conts);
+ zf_conts = NULL;
+ }
+ } else {
+ if (journal_conts != NULL && zf_from != ZONEFILE_LOAD_WHOLE) {
+ if (zf_conts == NULL) {
+ // load zone-in-journal
+ ret = zone_update_from_contents(&up, zone, journal_conts, UPDATE_INCREMENTAL);
+ } else {
+ // load zone-in-journal, compute ZF diff and if success, apply it
+ ret = zone_update_from_differences(&up, zone, journal_conts, zf_conts,
+ UPDATE_INCREMENTAL | UPDATE_JOURNAL, ignore_dnssec);
+ zone_contents_deep_free(zf_conts);
+ zf_conts = NULL;
+ if (ret == KNOT_ESEMCHECK || ret == KNOT_ERANGE) {
+ log_zone_warning(zone->name,
+ "zone file changed with SOA serial %s, "
+ "ignoring zone file and loading from journal",
+ (ret == KNOT_ESEMCHECK ? "unupdated" : "decreased"));
+ ret = zone_update_from_contents(&up, zone, journal_conts, UPDATE_INCREMENTAL);
+ }
+ }
+ } else {
+ if (zf_conts == NULL) {
+ // nothing to be loaded
+ ret = KNOT_ENOENT;
+ } else {
+ // load from ZF
+ ret = zone_update_from_contents(&up, zone, zf_conts,
+ (load_from == JOURNAL_CONTENT_NONE ?
+ UPDATE_FULL : UPDATE_INCREMENTAL));
+ if (zf_from == ZONEFILE_LOAD_WHOLE) {
+ zu_from_zf_conts = true;
+ }
+ }
+ }
+ }
+ if (ret != KNOT_EOK) {
+ switch (ret) {
+ case KNOT_ENOENT:
+ if (zone_load_can_bootstrap(conf, zone->name)) {
+ log_zone_info(zone->name, "zone will be bootstrapped");
+ } else {
+ log_zone_info(zone->name, "zone not found");
+ }
+ break;
+ case KNOT_ESEMCHECK:
+ log_zone_warning(zone->name, "zone file changed without SOA serial update");
+ break;
+ case KNOT_ERANGE:
+ log_zone_warning(zone->name, "zone file changed, but SOA serial decreased");
+ break;
+ }
+ goto cleanup;
+ }
+
+ // The contents are already part of zone_update.
+ zf_conts = NULL;
+ journal_conts = NULL;
+
+ // Sign zone using DNSSEC if configured.
+ zone_sign_reschedule_t dnssec_refresh = { .allow_rollover = true, .allow_nsec3resalt = true, };
+ if (dnssec_enable) {
+ ret = knot_dnssec_zone_sign(&up, 0, &dnssec_refresh);
+ if (ret != KNOT_EOK) {
+ zone_update_clear(&up);
+ goto cleanup;
+ }
+ if (zu_from_zf_conts && (up.flags & UPDATE_INCREMENTAL) && allowed_xfr(conf, zone)) {
+ log_zone_warning(zone->name,
+ "with automatic DNSSEC signing and outgoing transfers enabled, "
+ "'zonefile-load: difference' should be set to avoid malformed "
+ "IXFR after manual zone file update");
+ }
+ }
+
+ // If the change is only automatically incremented SOA serial, make it no change.
+ if (zf_from == ZONEFILE_LOAD_DIFSE && (up.flags & UPDATE_INCREMENTAL) &&
+ changeset_differs_just_serial(&up.change)) {
+ changeset_t *cpy = changeset_clone(&up.change);
+ if (cpy == NULL) {
+ ret = KNOT_ENOMEM;
+ goto cleanup;
+ }
+ ret = zone_update_apply_changeset_reverse(&up, cpy);
+ changeset_free(cpy);
+ if (ret == KNOT_EOK) {
+ ret = changeset_remove_addition(&up.change, up.change.soa_to);
+ }
+ if (ret != KNOT_EOK) {
+ goto cleanup;
+ }
+ }
+
+ bool incremental = ((up.flags & UPDATE_INCREMENTAL) && !zone_update_no_change(&up));
+ uint32_t old_serial = (!incremental ? 0 :
+ (up.zone->contents ? zone_contents_serial(up.zone->contents) : zone->zonefile.serial)
+ );
+ uint32_t new_serial = zone_contents_serial(up.new_cont);
+
+ // Commit zone_update back to zone (including journal update, rcu,...).
+ ret = zone_update_commit(conf, &up);
+ zone_update_clear(&up);
+ if (ret != KNOT_EOK) {
+ goto cleanup;
+ }
+
+ if (incremental) {
+ log_zone_info(zone->name, "loaded, serial %u -> %u, %zu bytes",
+ old_serial, new_serial, zone->contents->size);
+ } else {
+ log_zone_info(zone->name, "loaded, serial %u, %zu bytes",
+ new_serial, zone->contents->size);
+ }
+
+ if (zone->control_update != NULL) {
+ log_zone_warning(zone->name, "control transaction aborted");
+ zone_control_clear(zone);
+ }
+
+ // Schedule depedent events.
+ const knot_rdataset_t *soa = zone_soa(zone);
+ zone->timers.soa_expire = knot_soa_expire(soa->rdata);
+
+ if (dnssec_enable) {
+ event_dnssec_reschedule(conf, zone, &dnssec_refresh, false); // false since we handle NOTIFY below
+ }
+
+ replan_from_timers(conf, zone);
+
+ if (old_serial != new_serial) {
+ zone_events_schedule_now(zone, ZONE_EVENT_NOTIFY);
+ }
+
+ return KNOT_EOK;
+
+cleanup:
+ // Try to bootstrap the zone if local error.
+ replan_from_timers(conf, zone);
+
+ zone_contents_deep_free(zf_conts);
+ zone_contents_deep_free(journal_conts);
+
+ return (dontcare_load_error(conf, zone) ? KNOT_EOK : ret);
+}
diff --git a/src/knot/events/handlers/notify.c b/src/knot/events/handlers/notify.c
new file mode 100644
index 0000000..bcd81bf
--- /dev/null
+++ b/src/knot/events/handlers/notify.c
@@ -0,0 +1,158 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "knot/common/log.h"
+#include "knot/conf/conf.h"
+#include "knot/query/query.h"
+#include "knot/query/requestor.h"
+#include "knot/zone/zone.h"
+#include "libknot/errcode.h"
+
+/*!
+ * \brief NOTIFY message processing data.
+ */
+struct notify_data {
+ const knot_dname_t *zone;
+ const knot_rrset_t *soa;
+ const struct sockaddr *remote;
+ struct query_edns_data edns;
+};
+
+static int notify_begin(knot_layer_t *layer, void *params)
+{
+ layer->data = params;
+
+ return KNOT_STATE_PRODUCE;
+}
+
+static int notify_produce(knot_layer_t *layer, knot_pkt_t *pkt)
+{
+ struct notify_data *data = layer->data;
+
+ // mandatory: NOTIFY opcode, AA flag, SOA qtype
+ query_init_pkt(pkt);
+ knot_wire_set_opcode(pkt->wire, KNOT_OPCODE_NOTIFY);
+ knot_wire_set_aa(pkt->wire);
+ knot_pkt_put_question(pkt, data->zone, KNOT_CLASS_IN, KNOT_RRTYPE_SOA);
+
+ // unsecure hint: new SOA
+ if (data->soa) {
+ knot_pkt_begin(pkt, KNOT_ANSWER);
+ knot_pkt_put(pkt, KNOT_COMPR_HINT_QNAME, data->soa, 0);
+ }
+
+ query_put_edns(pkt, &data->edns);
+
+ return KNOT_STATE_CONSUME;
+}
+
+static int notify_consume(knot_layer_t *layer, knot_pkt_t *pkt)
+{
+ return KNOT_STATE_DONE;
+}
+
+static const knot_layer_api_t NOTIFY_API = {
+ .begin = notify_begin,
+ .produce = notify_produce,
+ .consume = notify_consume,
+};
+
+#define NOTIFY_LOG(priority, zone, remote, fmt, ...) \
+ ns_log(priority, zone, LOG_OPERATION_NOTIFY, LOG_DIRECTION_OUT, remote, \
+ fmt, ## __VA_ARGS__)
+
+static int send_notify(conf_t *conf, zone_t *zone, const knot_rrset_t *soa,
+ const conf_remote_t *slave, int timeout)
+{
+ struct notify_data data = {
+ .zone = zone->name,
+ .soa = soa,
+ .remote = (struct sockaddr *)&slave->addr,
+ };
+
+ query_edns_data_init(&data.edns, conf, zone->name, slave->addr.ss_family);
+
+ struct knot_requestor requestor = { 0 };
+ knot_requestor_init(&requestor, &NOTIFY_API, &data, NULL);
+
+ knot_pkt_t *pkt = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, NULL);
+ if (!pkt) {
+ knot_requestor_clear(&requestor);
+ return KNOT_ENOMEM;
+ }
+
+ const struct sockaddr *dst = (struct sockaddr *)&slave->addr;
+ const struct sockaddr *src = (struct sockaddr *)&slave->via;
+ struct knot_request *req = knot_request_make(NULL, dst, src, pkt, &slave->key, 0);
+ if (!req) {
+ knot_request_free(req, NULL);
+ knot_requestor_clear(&requestor);
+ return KNOT_ENOMEM;
+ }
+
+ int ret = knot_requestor_exec(&requestor, req, timeout);
+
+ if (ret == KNOT_EOK) {
+ NOTIFY_LOG(LOG_INFO, zone->name, dst,
+ "serial %u", knot_soa_serial(soa->rrs.rdata));
+ } else if (knot_pkt_ext_rcode(req->resp) == 0) {
+ NOTIFY_LOG(LOG_WARNING, zone->name, dst,
+ "failed (%s)", knot_strerror(ret));
+ } else {
+ NOTIFY_LOG(LOG_WARNING, zone->name, dst,
+ "server responded with error '%s'",
+ knot_pkt_ext_rcode_name(req->resp));
+ }
+
+ knot_request_free(req, NULL);
+ knot_requestor_clear(&requestor);
+
+ return ret;
+}
+
+int event_notify(conf_t *conf, zone_t *zone)
+{
+ assert(zone);
+
+ if (zone_contents_is_empty(zone->contents)) {
+ return KNOT_EOK;
+ }
+
+ // NOTIFY content
+ int timeout = conf->cache.srv_tcp_reply_timeout * 1000;
+ knot_rrset_t soa = node_rrset(zone->contents->apex, KNOT_RRTYPE_SOA);
+
+ // send NOTIFY to each remote, use working address
+ conf_val_t notify = conf_zone_get(conf, C_NOTIFY, zone->name);
+ while (notify.code == KNOT_EOK) {
+ conf_val_t addr = conf_id_get(conf, C_RMT, C_ADDR, &notify);
+ size_t addr_count = conf_val_count(&addr);
+
+ for (int i = 0; i < addr_count; i++) {
+ conf_remote_t slave = conf_remote(conf, &notify, i);
+ int ret = send_notify(conf, zone, &soa, &slave, timeout);
+ if (ret == KNOT_EOK) {
+ break;
+ }
+ }
+
+ conf_val_next(&notify);
+ }
+
+ return KNOT_EOK;
+}
diff --git a/src/knot/events/handlers/nsec3resalt.c b/src/knot/events/handlers/nsec3resalt.c
new file mode 100644
index 0000000..479e0b1
--- /dev/null
+++ b/src/knot/events/handlers/nsec3resalt.c
@@ -0,0 +1,46 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "knot/dnssec/context.h"
+#include "knot/dnssec/zone-events.h"
+
+int event_nsec3resalt(conf_t *conf, zone_t *zone)
+{
+ bool salt_changed = false;
+ knot_time_t next_resalt = 0;
+
+ kdnssec_ctx_t kctx = { 0 };
+
+ int ret = kdnssec_ctx_init(conf, &kctx, zone->name, NULL);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = knot_dnssec_nsec3resalt(&kctx, &salt_changed, &next_resalt);
+
+ if (ret == KNOT_EOK && salt_changed) {
+ zone_events_schedule_now(zone, ZONE_EVENT_DNSSEC);
+ zone->timers.last_resalt = kctx.now;
+ }
+
+ kdnssec_ctx_deinit(&kctx);
+
+ if (next_resalt) {
+ zone_events_schedule_at(zone, ZONE_EVENT_NSEC3RESALT, next_resalt);
+ }
+
+ return ret;
+}
diff --git a/src/knot/events/handlers/parent_ds_query.c b/src/knot/events/handlers/parent_ds_query.c
new file mode 100644
index 0000000..b16440c
--- /dev/null
+++ b/src/knot/events/handlers/parent_ds_query.c
@@ -0,0 +1,53 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "knot/dnssec/ds_query.h"
+#include "knot/zone/zone.h"
+
+int event_parent_ds_q(conf_t *conf, zone_t *zone)
+{
+ kdnssec_ctx_t ctx = { 0 };
+
+ int ret = kdnssec_ctx_init(conf, &ctx, zone->name, NULL);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ zone_keyset_t keyset = { 0 };
+ ret = load_zone_keys(&ctx, &keyset, false);
+ if (ret != KNOT_EOK) {
+ kdnssec_ctx_deinit(&ctx);
+ return ret;
+ }
+
+ ret = knot_parent_ds_query(&ctx, &keyset, conf->cache.srv_tcp_reply_timeout * 1000);
+
+ zone->timers.next_parent_ds_q = 0;
+ if (ret != KNOT_EOK) {
+ if (ctx.policy->ksk_sbm_check_interval > 0) {
+ time_t next_check = time(NULL) + ctx.policy->ksk_sbm_check_interval;
+ zone->timers.next_parent_ds_q = next_check;
+ zone_events_schedule_at(zone, ZONE_EVENT_PARENT_DS_Q, next_check);
+ }
+ } else {
+ zone_events_schedule_now(zone, ZONE_EVENT_DNSSEC);
+ }
+
+ free_zone_keys(&keyset);
+ kdnssec_ctx_deinit(&ctx);
+
+ return KNOT_EOK; // allways ok, if failure it has been rescheduled
+}
diff --git a/src/knot/events/handlers/refresh.c b/src/knot/events/handlers/refresh.c
new file mode 100644
index 0000000..27aa2c4
--- /dev/null
+++ b/src/knot/events/handlers/refresh.c
@@ -0,0 +1,1169 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include "contrib/mempattern.h"
+#include "libdnssec/random.h"
+#include "knot/common/log.h"
+#include "knot/conf/conf.h"
+#include "knot/dnssec/zone-events.h"
+#include "knot/events/handlers.h"
+#include "knot/events/replan.h"
+#include "knot/nameserver/ixfr.h"
+#include "knot/query/layer.h"
+#include "knot/query/query.h"
+#include "knot/query/requestor.h"
+#include "knot/updates/changesets.h"
+#include "knot/zone/serial.h"
+#include "knot/zone/zone.h"
+#include "knot/zone/zonefile.h"
+#include "libknot/errcode.h"
+
+/*!
+ * \brief Refresh event processing.
+ *
+ * The following diagram represents refresh event processing.
+ *
+ * \verbatim
+ * O
+ * |
+ * +-----v-----+
+ * | BEGIN |
+ * +---+---+---+
+ * has SOA | | no SOA
+ * +-------------------+ +------------------------------+
+ * | |
+ * +------v------+ outdated +--------------+ error +-------v------+
+ * | SOA query +------------> IXFR query +-----------> AXFR query |
+ * +-----+---+---+ +------+-------+ +----+----+----+
+ * error | | current | success success | | error
+ * | +-----+ +---------------+ | |
+ * | | | +--------------------------------------+ |
+ * | | | | +----------+ +--------------+
+ * | | | | | | |
+ * | +--v-v-v--+ | +--v--v--+
+ * | | DONE | | | FAIL |
+ * | +---------+ | +--------+
+ * +----------------------------+
+ *
+ * \endverbatim
+ */
+
+#define REFRESH_LOG(priority, zone, remote, msg...) \
+ ns_log(priority, zone, LOG_OPERATION_REFRESH, LOG_DIRECTION_OUT, remote, msg)
+
+#define _XFRIN_LOG(priority, operation, zone, remote, msg...) \
+ ns_log(priority, zone, operation, LOG_DIRECTION_IN, remote, msg)
+
+#define AXFRIN_LOG(priority, zone, remote, msg...) \
+ _XFRIN_LOG(priority, LOG_OPERATION_AXFR, zone, remote, msg)
+
+#define IXFRIN_LOG(priority, zone, remote, msg...) \
+ _XFRIN_LOG(priority, LOG_OPERATION_IXFR, zone, remote, msg)
+
+#define BOOTSTRAP_MAXTIME (24*60*60)
+#define BOOTSTRAP_JITTER (30)
+
+enum state {
+ REFRESH_STATE_INVALID = 0,
+ STATE_SOA_QUERY,
+ STATE_TRANSFER,
+};
+
+enum xfr_type {
+ XFR_TYPE_ERROR = -1,
+ XFR_TYPE_UNDETERMINED = 0,
+ XFR_TYPE_UPTODATE,
+ XFR_TYPE_AXFR,
+ XFR_TYPE_IXFR,
+};
+
+struct refresh_data {
+ // transfer configuration, initialize appropriately:
+
+ zone_t *zone; //!< Zone to eventually updated.
+ conf_t *conf; //!< Server configuration.
+ const struct sockaddr *remote; //!< Remote endpoint.
+ const knot_rrset_t *soa; //!< Local SOA (NULL for AXFR).
+ const size_t max_zone_size; //!< Maximal zone size.
+ struct query_edns_data edns; //!< EDNS data to be used in queries.
+
+ // internal state, initialize with zeroes:
+
+ enum state state; //!< Event processing state.
+ enum xfr_type xfr_type; //!< Transer type (mostly IXFR versus AXFR).
+ knot_rrset_t *initial_soa_copy; //!< Copy of the received initial SOA.
+ struct xfr_stats stats; //!< Transfer statistics.
+ size_t change_size; //!< Size of added and removed RRs.
+
+ struct {
+ zone_contents_t *zone; //!< AXFR result, new zone.
+ } axfr;
+
+ struct {
+ struct ixfr_proc *proc; //!< IXFR processing context.
+ knot_rrset_t *final_soa; //!< SOA denoting end of transfer.
+ list_t changesets; //!< IXFR result, zone updates.
+ } ixfr;
+
+ bool updated; // TODO: Can we fid a better way to check if zone was updated?
+ knot_mm_t *mm; // TODO: This used to be used in IXFR. Remove or reuse.
+};
+
+static bool serial_is_current(uint32_t local_serial, uint32_t remote_serial)
+{
+ return (serial_compare(local_serial, remote_serial) & SERIAL_MASK_GEQ);
+}
+
+static time_t bootstrap_next(const zone_timers_t *timers)
+{
+ time_t expired_at = timers->last_refresh + timers->soa_expire;
+
+ // previous interval
+ time_t interval = timers->next_refresh - expired_at;
+ if (interval < 0) {
+ interval = 0;
+ }
+
+ // exponential backoff
+ interval *= 2;
+ if (interval > BOOTSTRAP_MAXTIME) {
+ interval = BOOTSTRAP_MAXTIME;
+ }
+
+ // prevent burst refresh
+ interval += dnssec_random_uint16_t() % BOOTSTRAP_JITTER;
+
+ return interval;
+}
+
+static int xfr_validate(zone_contents_t *zone, struct refresh_data *data)
+{
+ sem_handler_t handler = {
+ .cb = err_handler_logger
+ };
+
+ int ret = sem_checks_process(zone, false, &handler, time(NULL));
+ if (ret != KNOT_EOK) {
+ // error is logged by the error handler
+ return ret;
+ }
+
+ if (zone->size > data->max_zone_size) {
+ ns_log(LOG_WARNING, data->zone->name,
+ data->xfr_type == XFR_TYPE_IXFR ? LOG_OPERATION_IXFR : LOG_OPERATION_AXFR,
+ LOG_DIRECTION_IN, data->remote, "zone size exceeded");
+ return KNOT_EZONESIZE;
+ }
+
+ return KNOT_EOK;
+}
+
+static void xfr_log_publish(const knot_dname_t *zone_name,
+ const struct sockaddr *remote,
+ const uint32_t old_serial,
+ const uint32_t new_serial,
+ bool axfr_bootstrap)
+{
+ if (!axfr_bootstrap) {
+ REFRESH_LOG(LOG_INFO, zone_name, remote,
+ "zone updated, serial %u -> %u",
+ old_serial, new_serial);
+ } else {
+ REFRESH_LOG(LOG_INFO, zone_name, remote,
+ "zone updated, serial none -> %u",
+ new_serial);
+ }
+}
+
+static int axfr_init(struct refresh_data *data)
+{
+ zone_contents_t *new_zone = zone_contents_new(data->zone->name);
+ if (new_zone == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ data->axfr.zone = new_zone;
+ return KNOT_EOK;
+}
+
+static void axfr_cleanup(struct refresh_data *data)
+{
+ zone_contents_deep_free(data->axfr.zone);
+ data->axfr.zone = NULL;
+}
+
+static int axfr_finalize(struct refresh_data *data)
+{
+ zone_contents_t *new_zone = data->axfr.zone;
+
+ int ret = zone_contents_adjust_full(new_zone);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = xfr_validate(new_zone, data);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ uint32_t master_serial = zone_contents_serial(new_zone);
+ uint32_t local_serial = zone_contents_serial(data->zone->contents);
+ bool have_lastsigned = zone_get_lastsigned_serial(data->zone, &local_serial);
+ uint32_t old_serial = local_serial;
+ bool bootstrap = (data->soa == NULL);
+ if ((!bootstrap || have_lastsigned) &&
+ (serial_compare(master_serial, local_serial) != SERIAL_GREATER)) {
+ conf_val_t val = conf_zone_get(data->conf, C_SERIAL_POLICY, data->zone->name);
+ local_serial = serial_next(local_serial, conf_opt(&val));
+ zone_contents_set_soa_serial(new_zone, local_serial);
+ }
+
+ zone_update_t up = { 0 };
+ ret = zone_update_from_contents(&up, data->zone, new_zone, UPDATE_FULL);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Seized by zone_update. Don't free the contents again in axfr_cleanup.
+ data->axfr.zone = NULL;
+
+ conf_val_t val = conf_zone_get(data->conf, C_DNSSEC_SIGNING, data->zone->name);
+ bool dnssec_enable = conf_bool(&val);
+ if (dnssec_enable) {
+ zone_sign_reschedule_t resch = { .allow_rollover = true };
+ ret = knot_dnssec_zone_sign(&up, ZONE_SIGN_KEEP_SERIAL, &resch);
+ if (ret != KNOT_EOK) {
+ zone_update_clear(&up);
+ return ret;
+ }
+ event_dnssec_reschedule(data->conf, data->zone, &resch, true);
+ }
+
+ ret = zone_update_commit(data->conf, &up);
+ zone_update_clear(&up);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ if (dnssec_enable) {
+ ret = zone_set_master_serial(data->zone, master_serial);
+ if (ret == KNOT_EOK) {
+ ret = zone_set_lastsigned_serial(data->zone, zone_contents_serial(new_zone));
+ }
+ if (ret != KNOT_EOK) {
+ log_zone_warning(data->zone->name,
+ "unable to save master serial, future transfers might be broken");
+ }
+ }
+
+ xfr_log_publish(data->zone->name, data->remote, old_serial,
+ zone_contents_serial(new_zone), bootstrap);
+
+ return KNOT_EOK;
+}
+
+static int axfr_consume_rr(const knot_rrset_t *rr, struct refresh_data *data)
+{
+ assert(rr);
+ assert(data);
+ assert(data->axfr.zone);
+
+ // zc is stateless structure which can be initialized for each rr
+ // the changes are stored only in data->axfr.zone (aka zc.z)
+ zcreator_t zc = {
+ .z = data->axfr.zone,
+ .master = false,
+ .ret = KNOT_EOK
+ };
+
+ if (rr->type == KNOT_RRTYPE_SOA &&
+ node_rrtype_exists(zc.z->apex, KNOT_RRTYPE_SOA)) {
+ return KNOT_STATE_DONE;
+ }
+
+ int ret = zcreator_step(&zc, rr);
+ if (ret != KNOT_EOK) {
+ return KNOT_STATE_FAIL;
+ }
+
+ data->change_size += knot_rrset_size(rr);
+ if (data->change_size > data->max_zone_size) {
+ AXFRIN_LOG(LOG_WARNING, data->zone->name, data->remote,
+ "zone size exceeded");
+ return KNOT_STATE_FAIL;
+ }
+
+ return KNOT_STATE_CONSUME;
+}
+
+static int axfr_consume_packet(knot_pkt_t *pkt, struct refresh_data *data)
+{
+ assert(pkt);
+ assert(data);
+
+ const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER);
+ int ret = KNOT_STATE_CONSUME;
+ for (uint16_t i = 0; i < answer->count && ret == KNOT_STATE_CONSUME; ++i) {
+ ret = axfr_consume_rr(knot_pkt_rr(answer, i), data);
+ }
+ return ret;
+}
+
+static int axfr_consume(knot_pkt_t *pkt, struct refresh_data *data)
+{
+ assert(pkt);
+ assert(data);
+
+ // Check RCODE
+ if (knot_pkt_ext_rcode(pkt) != KNOT_RCODE_NOERROR) {
+ AXFRIN_LOG(LOG_WARNING, data->zone->name, data->remote,
+ "server responded with error '%s'",
+ knot_pkt_ext_rcode_name(pkt));
+ return KNOT_STATE_FAIL;
+ }
+
+ // Initialize with first packet
+ if (data->axfr.zone == NULL) {
+ int ret = axfr_init(data);
+ if (ret != KNOT_EOK) {
+ AXFRIN_LOG(LOG_WARNING, data->zone->name, data->remote,
+ "failed to initialize (%s)",
+ knot_strerror(ret));
+ return KNOT_STATE_FAIL;
+ }
+
+ AXFRIN_LOG(LOG_INFO, data->zone->name, data->remote, "starting");
+ xfr_stats_begin(&data->stats);
+ data->change_size = 0;
+ }
+
+ int next;
+ // Process saved SOA if fallback from IXFR
+ if (data->initial_soa_copy != NULL) {
+ next = axfr_consume_rr(data->initial_soa_copy, data);
+ knot_rrset_free(data->initial_soa_copy, data->mm);
+ data->initial_soa_copy = NULL;
+ if (next != KNOT_STATE_CONSUME) {
+ return next;
+ }
+ }
+
+ // Process answer packet
+ xfr_stats_add(&data->stats, pkt->size);
+ next = axfr_consume_packet(pkt, data);
+
+ // Finalize
+ if (next == KNOT_STATE_DONE) {
+ xfr_stats_end(&data->stats);
+ }
+
+ return next;
+}
+
+/*! \brief Initialize IXFR-in processing context. */
+static int ixfr_init(struct refresh_data *data)
+{
+ struct ixfr_proc *proc = mm_alloc(data->mm, sizeof(*proc));
+ if (proc == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ memset(proc, 0, sizeof(struct ixfr_proc));
+ proc->state = IXFR_START;
+ proc->mm = data->mm;
+
+ data->ixfr.proc = proc;
+ data->ixfr.final_soa = NULL;
+
+ init_list(&data->ixfr.changesets);
+
+ return KNOT_EOK;
+}
+
+/*! \brief Clean up data allocated by IXFR-in processing. */
+static void ixfr_cleanup(struct refresh_data *data)
+{
+ if (data->ixfr.proc == NULL) {
+ return;
+ }
+
+ knot_rrset_free(data->ixfr.final_soa, data->mm);
+ data->ixfr.final_soa = NULL;
+ mm_free(data->mm, data->ixfr.proc);
+ data->ixfr.proc = NULL;
+
+ changesets_free(&data->ixfr.changesets);
+}
+
+static int ixfr_finalize(struct refresh_data *data)
+{
+ uint32_t master_serial;
+ int ret = zone_get_master_serial(data->zone, &master_serial);
+ if (ret != KNOT_EOK) {
+ log_zone_error(data->zone->name, "Failed reading master's serial"
+ "from KASP DB (%s)", knot_strerror(ret));
+ return ret;
+ }
+ uint32_t local_serial = zone_contents_serial(data->zone->contents);
+ uint32_t lastsigned_serial = local_serial;
+ bool have_lastsigned = zone_get_lastsigned_serial(data->zone, &lastsigned_serial);
+ uint32_t old_serial = local_serial;
+ changeset_t *chs = NULL;
+ WALK_LIST(chs, data->ixfr.changesets) {
+ master_serial = knot_soa_serial(chs->soa_to->rrs.rdata);
+ knot_soa_serial_set(chs->soa_from->rrs.rdata, local_serial);
+ if (have_lastsigned && (serial_compare(lastsigned_serial, local_serial) & SERIAL_MASK_GEQ)) {
+ local_serial = lastsigned_serial;
+ }
+ if (serial_compare(master_serial, local_serial) != SERIAL_GREATER) {
+ conf_val_t val = conf_zone_get(data->conf, C_SERIAL_POLICY, data->zone->name);
+ local_serial = serial_next(local_serial, conf_opt(&val));
+ knot_soa_serial_set(chs->soa_to->rrs.rdata, local_serial);
+ } else {
+ local_serial = master_serial;
+ }
+ }
+
+ zone_update_t up = { 0 };
+ ret = zone_update_init(&up, data->zone, UPDATE_INCREMENTAL | UPDATE_STRICT);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ changeset_t *set = NULL;
+ WALK_LIST(set, data->ixfr.changesets) {
+ ret = zone_update_apply_changeset(&up, set);
+ if (ret != KNOT_EOK) {
+ zone_update_clear(&up);
+ IXFRIN_LOG(LOG_WARNING, data->zone->name, data->remote,
+ "failed to apply changes to zone (%s)",
+ knot_strerror(ret));
+ return ret;
+ }
+ }
+
+ ret = xfr_validate(up.new_cont, data);
+ if (ret != KNOT_EOK) {
+ zone_update_clear(&up);
+ return ret;
+ }
+
+ conf_val_t val = conf_zone_get(data->conf, C_DNSSEC_SIGNING, data->zone->name);
+ bool dnssec_enable = conf_bool(&val);
+ if (dnssec_enable) {
+ zone_sign_reschedule_t resch = { .allow_rollover = true };
+ ret = knot_dnssec_sign_update(&up, &resch);
+ if (ret != KNOT_EOK) {
+ zone_update_clear(&up);
+ return ret;
+ }
+ event_dnssec_reschedule(data->conf, data->zone, &resch, true);
+ }
+
+ ret = zone_update_commit(data->conf, &up);
+
+ if (ret == KNOT_EOK) {
+ if (dnssec_enable && !EMPTY_LIST(data->ixfr.changesets)) {
+ ret = zone_set_master_serial(data->zone, master_serial);
+ if (ret == KNOT_EOK) {
+ ret = zone_set_lastsigned_serial(data->zone,
+ zone_contents_serial(up.zone->contents));
+ }
+ if (ret != KNOT_EOK) {
+ log_zone_warning(data->zone->name,
+ "unable to save master serial, future transfers might be broken");
+ }
+ }
+ xfr_log_publish(data->zone->name, data->remote, old_serial,
+ zone_contents_serial(up.zone->contents), false);
+ } else {
+ IXFRIN_LOG(LOG_WARNING, data->zone->name, data->remote,
+ "failed to store changes (%s)", knot_strerror(ret));
+ }
+
+ zone_update_clear(&up);
+ return ret;
+}
+
+/*! \brief Stores starting SOA into changesets structure. */
+static int ixfr_solve_start(const knot_rrset_t *rr, struct refresh_data *data)
+{
+ assert(data->ixfr.final_soa == NULL);
+ if (rr->type != KNOT_RRTYPE_SOA) {
+ return KNOT_EMALF;
+ }
+
+ // Store terminal SOA
+ data->ixfr.final_soa = knot_rrset_copy(rr, data->mm);
+ if (data->ixfr.final_soa == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ // Initialize list for changes
+ init_list(&data->ixfr.changesets);
+
+ return KNOT_EOK;
+}
+
+/*! \brief Decides what to do with a starting SOA (deletions). */
+static int ixfr_solve_soa_del(const knot_rrset_t *rr, struct refresh_data *data)
+{
+ if (rr->type != KNOT_RRTYPE_SOA) {
+ return KNOT_EMALF;
+ }
+
+ // Create new changeset.
+ changeset_t *change = changeset_new(data->zone->name);
+ if (change == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ // Store SOA into changeset.
+ change->soa_from = knot_rrset_copy(rr, NULL);
+ if (change->soa_from == NULL) {
+ changeset_free(change);
+ return KNOT_ENOMEM;
+ }
+
+ // Add changeset.
+ add_tail(&data->ixfr.changesets, &change->n);
+
+ return KNOT_EOK;
+}
+
+/*! \brief Stores ending SOA into changeset. */
+static int ixfr_solve_soa_add(const knot_rrset_t *rr, changeset_t *change, knot_mm_t *mm)
+{
+ if (rr->type != KNOT_RRTYPE_SOA) {
+ return KNOT_EMALF;
+ }
+
+ change->soa_to = knot_rrset_copy(rr, NULL);
+ if (change->soa_to == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ return KNOT_EOK;
+}
+
+/*! \brief Adds single RR into remove section of changeset. */
+static int ixfr_solve_del(const knot_rrset_t *rr, changeset_t *change, knot_mm_t *mm)
+{
+ return changeset_add_removal(change, rr, 0);
+}
+
+/*! \brief Adds single RR into add section of changeset. */
+static int ixfr_solve_add(const knot_rrset_t *rr, changeset_t *change, knot_mm_t *mm)
+{
+ return changeset_add_addition(change, rr, 0);
+}
+
+/*! \brief Decides what the next IXFR-in state should be. */
+static int ixfr_next_state(struct refresh_data *data, const knot_rrset_t *rr)
+{
+ const bool soa = (rr->type == KNOT_RRTYPE_SOA);
+ enum ixfr_state state = data->ixfr.proc->state;
+
+ if ((state == IXFR_SOA_ADD || state == IXFR_ADD) &&
+ knot_rrset_equal(rr, data->ixfr.final_soa, KNOT_RRSET_COMPARE_WHOLE)) {
+ return IXFR_DONE;
+ }
+
+ switch (state) {
+ case IXFR_START:
+ // Final SOA already stored or transfer start.
+ return data->ixfr.final_soa ? IXFR_SOA_DEL : IXFR_START;
+ case IXFR_SOA_DEL:
+ // Empty delete section or start of delete section.
+ return soa ? IXFR_SOA_ADD : IXFR_DEL;
+ case IXFR_SOA_ADD:
+ // Empty add section or start of add section.
+ return soa ? IXFR_SOA_DEL : IXFR_ADD;
+ case IXFR_DEL:
+ // End of delete section or continue.
+ return soa ? IXFR_SOA_ADD : IXFR_DEL;
+ case IXFR_ADD:
+ // End of add section or continue.
+ return soa ? IXFR_SOA_DEL : IXFR_ADD;
+ default:
+ assert(0);
+ return IXFR_INVALID;
+ }
+}
+
+/*!
+ * \brief Processes single RR according to current IXFR-in state. The states
+ * correspond with IXFR-in message structure, in the order they are
+ * mentioned in the code.
+ *
+ * \param rr RR to process.
+ * \param proc Processing context.
+ *
+ * \return KNOT_E*
+ */
+static int ixfr_step(const knot_rrset_t *rr, struct refresh_data *data)
+{
+ data->ixfr.proc->state = ixfr_next_state(data, rr);
+ changeset_t *change = TAIL(data->ixfr.changesets);
+
+ switch (data->ixfr.proc->state) {
+ case IXFR_START:
+ return ixfr_solve_start(rr, data);
+ case IXFR_SOA_DEL:
+ return ixfr_solve_soa_del(rr, data);
+ case IXFR_DEL:
+ return ixfr_solve_del(rr, change, data->mm);
+ case IXFR_SOA_ADD:
+ return ixfr_solve_soa_add(rr, change, data->mm);
+ case IXFR_ADD:
+ return ixfr_solve_add(rr, change, data->mm);
+ case IXFR_DONE:
+ return KNOT_EOK;
+ default:
+ return KNOT_ERROR;
+ }
+}
+
+static int ixfr_consume_rr(const knot_rrset_t *rr, struct refresh_data *data)
+{
+ if (knot_dname_in_bailiwick(rr->owner, data->zone->name) < 0) {
+ return KNOT_STATE_CONSUME;
+ }
+
+ int ret = ixfr_step(rr, data);
+ if (ret != KNOT_EOK) {
+ IXFRIN_LOG(LOG_WARNING, data->zone->name, data->remote,
+ "failed (%s)", knot_strerror(ret));
+ return KNOT_STATE_FAIL;
+ }
+
+ data->change_size += knot_rrset_size(rr);
+ if (data->change_size / 2 > data->max_zone_size) {
+ IXFRIN_LOG(LOG_WARNING, data->zone->name, data->remote,
+ "transfer size exceeded");
+ return KNOT_STATE_FAIL;
+ }
+
+ if (data->ixfr.proc->state == IXFR_DONE) {
+ return KNOT_STATE_DONE;
+ }
+
+ return KNOT_STATE_CONSUME;
+}
+
+/*!
+ * \brief Processes IXFR reply packet and fills in the changesets structure.
+ *
+ * \param pkt Packet containing the IXFR reply in wire format.
+ * \param adata Answer data, including processing context.
+ *
+ * \return KNOT_STATE_CONSUME, KNOT_STATE_DONE, KNOT_STATE_FAIL
+ */
+static int ixfr_consume_packet(knot_pkt_t *pkt, struct refresh_data *data)
+{
+ // Process RRs in the message.
+ const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER);
+ int ret = KNOT_STATE_CONSUME;
+ for (uint16_t i = 0; i < answer->count && ret == KNOT_STATE_CONSUME; ++i) {
+ ret = ixfr_consume_rr(knot_pkt_rr(answer, i), data);
+ }
+ return ret;
+}
+
+static enum xfr_type determine_xfr_type(const knot_pktsection_t *answer,
+ uint32_t zone_serial, const knot_rrset_t *initial_soa)
+{
+ if (answer->count < 1) {
+ return XFR_TYPE_ERROR;
+ }
+
+ const knot_rrset_t *rr_one = knot_pkt_rr(answer, 0);
+ if (initial_soa != NULL) {
+ if (rr_one->type == KNOT_RRTYPE_SOA) {
+ return knot_rrset_equal(initial_soa, rr_one, KNOT_RRSET_COMPARE_WHOLE) ?
+ XFR_TYPE_AXFR : XFR_TYPE_IXFR;
+ }
+ return XFR_TYPE_AXFR;
+ }
+
+ if (answer->count == 1) {
+ if (rr_one->type == KNOT_RRTYPE_SOA) {
+ return serial_is_current(zone_serial, knot_soa_serial(rr_one->rrs.rdata)) ?
+ XFR_TYPE_UPTODATE : XFR_TYPE_UNDETERMINED;
+ }
+ return XFR_TYPE_ERROR;
+ }
+
+ const knot_rrset_t *rr_two = knot_pkt_rr(answer, 1);
+ if (answer->count == 2 && rr_one->type == KNOT_RRTYPE_SOA &&
+ knot_rrset_equal(rr_one, rr_two, KNOT_RRSET_COMPARE_WHOLE)) {
+ return XFR_TYPE_AXFR;
+ }
+
+ return (rr_one->type == KNOT_RRTYPE_SOA && rr_two->type != KNOT_RRTYPE_SOA) ?
+ XFR_TYPE_AXFR : XFR_TYPE_IXFR;
+}
+
+static int ixfr_consume(knot_pkt_t *pkt, struct refresh_data *data)
+{
+ assert(pkt);
+ assert(data);
+
+ // Check RCODE
+ if (knot_pkt_ext_rcode(pkt) != KNOT_RCODE_NOERROR) {
+ IXFRIN_LOG(LOG_WARNING, data->zone->name, data->remote,
+ "server responded with error '%s'",
+ knot_pkt_ext_rcode_name(pkt));
+ return KNOT_STATE_FAIL;
+ }
+
+ // Initialize with first packet
+ if (data->ixfr.proc == NULL) {
+ const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER);
+
+ uint32_t master_serial;
+ int ret = zone_get_master_serial(data->zone, &master_serial);
+ if (ret != KNOT_EOK) {
+ log_zone_error(data->zone->name, "Failed reading master's serial"
+ "from KASP DB (%s)", knot_strerror(ret));
+ return KNOT_STATE_FAIL;
+ }
+ data->xfr_type = determine_xfr_type(answer, master_serial,
+ data->initial_soa_copy);
+ switch (data->xfr_type) {
+ case XFR_TYPE_ERROR:
+ IXFRIN_LOG(LOG_WARNING, data->zone->name, data->remote,
+ "malformed response SOA");
+ return KNOT_STATE_FAIL;
+ case XFR_TYPE_UNDETERMINED:
+ // Store the SOA and check with next packet
+ data->initial_soa_copy = knot_rrset_copy(knot_pkt_rr(answer, 0), data->mm);
+ if (data->initial_soa_copy == NULL) {
+ return KNOT_STATE_FAIL;
+ }
+ xfr_stats_add(&data->stats, pkt->size);
+ return KNOT_STATE_CONSUME;
+ case XFR_TYPE_AXFR:
+ IXFRIN_LOG(LOG_INFO, data->zone->name, data->remote,
+ "receiving AXFR-style IXFR");
+ return axfr_consume(pkt, data);
+ case XFR_TYPE_UPTODATE:
+ IXFRIN_LOG(LOG_INFO, data->zone->name, data->remote,
+ "zone is up-to-date");
+ xfr_stats_begin(&data->stats);
+ xfr_stats_add(&data->stats, pkt->size);
+ xfr_stats_end(&data->stats);
+ return KNOT_STATE_DONE;
+ case XFR_TYPE_IXFR:
+ break;
+ default:
+ assert(0);
+ return KNOT_STATE_FAIL;
+ }
+
+ ret = ixfr_init(data);
+ if (ret != KNOT_EOK) {
+ IXFRIN_LOG(LOG_WARNING, data->zone->name, data->remote,
+ "failed to initialize (%s)", knot_strerror(ret));
+ return KNOT_STATE_FAIL;
+ }
+
+ IXFRIN_LOG(LOG_INFO, data->zone->name, data->remote, "starting");
+ xfr_stats_begin(&data->stats);
+ data->change_size = 0;
+ }
+
+ int next;
+ // Process saved SOA if existing
+ if (data->initial_soa_copy != NULL) {
+ next = ixfr_consume_rr(data->initial_soa_copy, data);
+ knot_rrset_free(data->initial_soa_copy, data->mm);
+ data->initial_soa_copy = NULL;
+ if (next != KNOT_STATE_CONSUME) {
+ return next;
+ }
+ }
+
+ // Process answer packet
+ xfr_stats_add(&data->stats, pkt->size);
+ next = ixfr_consume_packet(pkt, data);
+
+ // Finalize
+ if (next == KNOT_STATE_DONE) {
+ xfr_stats_end(&data->stats);
+ }
+
+ return next;
+}
+
+static int soa_query_produce(knot_layer_t *layer, knot_pkt_t *pkt)
+{
+ struct refresh_data *data = layer->data;
+
+ query_init_pkt(pkt);
+
+ int r = knot_pkt_put_question(pkt, data->zone->name, KNOT_CLASS_IN, KNOT_RRTYPE_SOA);
+ if (r != KNOT_EOK) {
+ return KNOT_STATE_FAIL;
+ }
+
+ r = query_put_edns(pkt, &data->edns);
+ if (r != KNOT_EOK) {
+ return KNOT_STATE_FAIL;
+ }
+
+ return KNOT_STATE_CONSUME;
+}
+
+static int soa_query_consume(knot_layer_t *layer, knot_pkt_t *pkt)
+{
+ struct refresh_data *data = layer->data;
+
+ if (knot_pkt_ext_rcode(pkt) != KNOT_RCODE_NOERROR) {
+ REFRESH_LOG(LOG_WARNING, data->zone->name, data->remote,
+ "server responded with error '%s'",
+ knot_pkt_ext_rcode_name(pkt));
+ return KNOT_STATE_FAIL;
+ }
+
+ const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER);
+ const knot_rrset_t *rr = answer->count == 1 ? knot_pkt_rr(answer, 0) : NULL;
+ if (!rr || rr->type != KNOT_RRTYPE_SOA || rr->rrs.count != 1) {
+ REFRESH_LOG(LOG_WARNING, data->zone->name, data->remote,
+ "malformed message");
+ return KNOT_STATE_FAIL;
+ }
+
+ uint32_t local_serial;
+ int ret = zone_get_master_serial(data->zone, &local_serial);
+ if (ret != KNOT_EOK) {
+ log_zone_error(data->zone->name, "Failed reading master's serial"
+ "from KASP DB (%s)", knot_strerror(ret));
+ return KNOT_STATE_FAIL;
+ }
+ uint32_t remote_serial = knot_soa_serial(rr->rrs.rdata);
+ bool current = serial_is_current(local_serial, remote_serial);
+ bool master_uptodate = serial_is_current(remote_serial, local_serial);
+
+ REFRESH_LOG(LOG_INFO, data->zone->name, data->remote,
+ "remote serial %u, %s", remote_serial,
+ current ? (master_uptodate ? "zone is up-to-date" :
+ "master is outdated") : "zone is outdated");
+
+ if (current) {
+ return master_uptodate ? KNOT_STATE_DONE : KNOT_STATE_FAIL;
+ } else {
+ data->state = STATE_TRANSFER;
+ return KNOT_STATE_RESET;
+ }
+}
+
+static int transfer_produce(knot_layer_t *layer, knot_pkt_t *pkt)
+{
+ struct refresh_data *data = layer->data;
+
+ bool ixfr = (data->xfr_type == XFR_TYPE_IXFR);
+
+ query_init_pkt(pkt);
+ knot_pkt_put_question(pkt, data->zone->name, KNOT_CLASS_IN,
+ ixfr ? KNOT_RRTYPE_IXFR : KNOT_RRTYPE_AXFR);
+
+ if (ixfr) {
+ assert(data->soa);
+ knot_rrset_t *sending_soa = knot_rrset_copy(data->soa, data->mm);
+ uint32_t master_serial;
+ int ret = zone_get_master_serial(data->zone, &master_serial);
+ if (ret != KNOT_EOK) {
+ log_zone_error(data->zone->name, "Failed reading master's serial"
+ "from KASP DB (%s)", knot_strerror(ret));
+ }
+ if (sending_soa == NULL || ret != KNOT_EOK) {
+ knot_rrset_free(sending_soa, data->mm);
+ return KNOT_STATE_FAIL;
+ }
+ knot_soa_serial_set(sending_soa->rrs.rdata, master_serial);
+ knot_pkt_begin(pkt, KNOT_AUTHORITY);
+ knot_pkt_put(pkt, KNOT_COMPR_HINT_QNAME, sending_soa, 0);
+ knot_rrset_free(sending_soa, data->mm);
+ }
+
+ query_put_edns(pkt, &data->edns);
+
+ return KNOT_STATE_CONSUME;
+}
+
+static int transfer_consume(knot_layer_t *layer, knot_pkt_t *pkt)
+{
+ struct refresh_data *data = layer->data;
+
+ int next = (data->xfr_type == XFR_TYPE_AXFR) ? axfr_consume(pkt, data) :
+ ixfr_consume(pkt, data);
+
+ // Transfer completed
+ if (next == KNOT_STATE_DONE) {
+ // Log transfer even if we still can fail
+ xfr_log_finished(data->zone->name,
+ data->xfr_type == XFR_TYPE_IXFR ||
+ data->xfr_type == XFR_TYPE_UPTODATE ?
+ LOG_OPERATION_IXFR : LOG_OPERATION_AXFR,
+ LOG_DIRECTION_IN, data->remote, &data->stats);
+
+ /*
+ * TODO: Move finialization into finish
+ * callback. And update requestor to allow reset from fallback
+ * as we need IXFR to AXFR failover.
+ */
+ if (tsig_unsigned_count(layer->tsig) != 0) {
+ return KNOT_STATE_FAIL;
+ }
+
+ // Finalize and publish the zone
+ int ret;
+ switch (data->xfr_type) {
+ case XFR_TYPE_IXFR:
+ ret = ixfr_finalize(data);
+ break;
+ case XFR_TYPE_AXFR:
+ ret = axfr_finalize(data);
+ break;
+ default:
+ return next;
+ }
+ if (ret == KNOT_EOK) {
+ data->updated = true;
+ } else {
+ next = KNOT_STATE_FAIL;
+ }
+ }
+
+ return next;
+}
+
+static int refresh_begin(knot_layer_t *layer, void *_data)
+{
+ layer->data = _data;
+ struct refresh_data *data = _data;
+
+ if (data->soa) {
+ data->state = STATE_SOA_QUERY;
+ data->xfr_type = XFR_TYPE_IXFR;
+ data->initial_soa_copy = NULL;
+ } else {
+ data->state = STATE_TRANSFER;
+ data->xfr_type = XFR_TYPE_AXFR;
+ data->initial_soa_copy = NULL;
+ }
+
+ return KNOT_STATE_PRODUCE;
+}
+
+static int refresh_produce(knot_layer_t *layer, knot_pkt_t *pkt)
+{
+ struct refresh_data *data = layer->data;
+
+ switch (data->state) {
+ case STATE_SOA_QUERY: return soa_query_produce(layer, pkt);
+ case STATE_TRANSFER: return transfer_produce(layer, pkt);
+ default:
+ return KNOT_STATE_FAIL;
+ }
+}
+
+static int refresh_consume(knot_layer_t *layer, knot_pkt_t *pkt)
+{
+ struct refresh_data *data = layer->data;
+
+ switch (data->state) {
+ case STATE_SOA_QUERY: return soa_query_consume(layer, pkt);
+ case STATE_TRANSFER: return transfer_consume(layer, pkt);
+ default:
+ return KNOT_STATE_FAIL;
+ }
+}
+
+static int refresh_reset(knot_layer_t *layer)
+{
+ return KNOT_STATE_PRODUCE;
+}
+
+static int refresh_finish(knot_layer_t *layer)
+{
+ struct refresh_data *data = layer->data;
+
+ // clean processing context
+ axfr_cleanup(data);
+ ixfr_cleanup(data);
+
+ return KNOT_STATE_NOOP;
+}
+
+static const knot_layer_api_t REFRESH_API = {
+ .begin = refresh_begin,
+ .produce = refresh_produce,
+ .consume = refresh_consume,
+ .reset = refresh_reset,
+ .finish = refresh_finish,
+};
+
+static size_t max_zone_size(conf_t *conf, const knot_dname_t *zone)
+{
+ conf_val_t val = conf_zone_get(conf, C_MAX_ZONE_SIZE, zone);
+ return conf_int(&val);
+}
+
+typedef struct {
+ bool force_axfr;
+ bool send_notify;
+} try_refresh_ctx_t;
+
+static int try_refresh(conf_t *conf, zone_t *zone, const conf_remote_t *master, void *ctx)
+{
+ // TODO: Abstract interface to issue DNS queries. This is almost copy-pasted.
+
+ assert(zone);
+ assert(master);
+ assert(ctx);
+
+ try_refresh_ctx_t *trctx = ctx;
+
+ knot_rrset_t soa = { 0 };
+ if (zone->contents) {
+ soa = node_rrset(zone->contents->apex, KNOT_RRTYPE_SOA);
+ }
+
+ struct refresh_data data = {
+ .zone = zone,
+ .conf = conf,
+ .remote = (struct sockaddr *)&master->addr,
+ .soa = zone->contents && !trctx->force_axfr ? &soa : NULL,
+ .max_zone_size = max_zone_size(conf, zone->name),
+ };
+
+ query_edns_data_init(&data.edns, conf, zone->name, master->addr.ss_family);
+
+ struct knot_requestor requestor;
+ knot_requestor_init(&requestor, &REFRESH_API, &data, NULL);
+
+ knot_pkt_t *pkt = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, NULL);
+ if (!pkt) {
+ knot_requestor_clear(&requestor);
+ return KNOT_ENOMEM;
+ }
+
+ const struct sockaddr *dst = (struct sockaddr *)&master->addr;
+ const struct sockaddr *src = (struct sockaddr *)&master->via;
+ struct knot_request *req = knot_request_make(NULL, dst, src, pkt, &master->key, 0);
+ if (!req) {
+ knot_request_free(req, NULL);
+ knot_requestor_clear(&requestor);
+ return KNOT_ENOMEM;
+ }
+
+ int timeout = conf->cache.srv_tcp_reply_timeout * 1000;
+
+ int ret;
+
+ // while loop runs 0x or 1x; IXFR to AXFR failover
+ while ((ret = knot_requestor_exec(&requestor, req, timeout)) != KNOT_EOK &&
+ data.xfr_type == XFR_TYPE_IXFR) {
+ REFRESH_LOG(LOG_WARNING, data.zone->name, data.remote,
+ "fallback to AXFR");
+ ixfr_cleanup(&data);
+ data.xfr_type = XFR_TYPE_AXFR;
+ requestor.layer.state = KNOT_STATE_RESET;
+ requestor.layer.flags |= KNOT_RQ_LAYER_CLOSE;
+ }
+ knot_request_free(req, NULL);
+ knot_requestor_clear(&requestor);
+
+ if (ret == KNOT_EOK) {
+ trctx->send_notify = data.updated;
+ }
+
+ return ret;
+}
+
+static int64_t min_refresh_interval(conf_t *conf, const knot_dname_t *zone)
+{
+ conf_val_t val = conf_zone_get(conf, C_MIN_REFRESH_INTERVAL, zone);
+ return conf_int(&val);
+}
+
+static int64_t max_refresh_interval(conf_t *conf, const knot_dname_t *zone)
+{
+ conf_val_t val = conf_zone_get(conf, C_MAX_REFRESH_INTERVAL, zone);
+ return conf_int(&val);
+}
+
+int event_refresh(conf_t *conf, zone_t *zone)
+{
+ assert(zone);
+
+ if (!zone_is_slave(conf, zone)) {
+ return KNOT_EOK;
+ }
+
+ try_refresh_ctx_t trctx = { 0 };
+
+ // TODO: Flag on zone is ugly. Event specific parameters would be nice.
+ if (zone->flags & ZONE_FORCE_AXFR) {
+ zone->flags &= ~ZONE_FORCE_AXFR;
+ trctx.force_axfr = true;
+ }
+
+ int ret = zone_master_try(conf, zone, try_refresh, &trctx, "refresh");
+ if (ret != KNOT_EOK) {
+ log_zone_error(zone->name, "refresh, failed (%s)", knot_strerror(ret));
+ }
+
+ time_t now = time(NULL);
+ const knot_rdataset_t *soa = zone_soa(zone);
+
+ if (ret == KNOT_EOK) {
+ zone->timers.soa_expire = knot_soa_expire(soa->rdata);
+ zone->timers.last_refresh = now;
+ zone->timers.next_refresh = now + knot_soa_refresh(soa->rdata);
+ } else {
+ time_t next = 0;
+ if (soa) {
+ next = knot_soa_retry(soa->rdata);
+ } else {
+ next = bootstrap_next(&zone->timers);
+ }
+ zone->timers.next_refresh = now + next;
+ }
+
+ /* Check for allowed refresh interval limits. */
+ int64_t min_refresh = min_refresh_interval(conf, zone->name);
+ if(zone->timers.next_refresh < now + min_refresh) {
+ zone->timers.next_refresh = now + min_refresh;
+ }
+ int64_t max_refresh = max_refresh_interval(conf, zone->name);
+ if(zone->timers.next_refresh > now + max_refresh) {
+ zone->timers.next_refresh = now + max_refresh;
+ }
+
+ /* Rechedule events. */
+ replan_from_timers(conf, zone);
+ if (trctx.send_notify) {
+ zone_events_schedule_at(zone, ZONE_EVENT_NOTIFY, time(NULL) + 1);
+ }
+
+ return KNOT_EOK;
+}
diff --git a/src/knot/events/handlers/update.c b/src/knot/events/handlers/update.c
new file mode 100644
index 0000000..6478364
--- /dev/null
+++ b/src/knot/events/handlers/update.c
@@ -0,0 +1,33 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include "knot/conf/conf.h"
+#include "knot/nameserver/update.h"
+#include "knot/zone/zone.h"
+#include "libknot/errcode.h"
+
+int event_update(conf_t *conf, zone_t *zone)
+{
+ assert(zone);
+
+ /* Process update list - forward if zone has master, or execute. */
+ updates_execute(conf, zone);
+
+ return KNOT_EOK;
+}
diff --git a/src/knot/events/replan.c b/src/knot/events/replan.c
new file mode 100644
index 0000000..a3f6fcd
--- /dev/null
+++ b/src/knot/events/replan.c
@@ -0,0 +1,175 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+
+#include "knot/events/replan.h"
+
+#define TIME_CANCEL 0
+#define TIME_IGNORE (-1)
+
+/*!
+ * \brief Move DDNS queue from old zone to new zone and replan if necessary.
+ *
+ * New zone will contain references from the old zone. New zone will free
+ * the data.
+ */
+static void replan_ddns(zone_t *zone, zone_t *old_zone)
+{
+ assert(zone);
+ assert(old_zone);
+
+ if (old_zone->ddns_queue_size == 0) {
+ return;
+ }
+
+ ptrnode_t *node = NULL;
+ WALK_LIST(node, old_zone->ddns_queue) {
+ ptrlist_add(&zone->ddns_queue, node->d, NULL);
+ }
+ zone->ddns_queue_size = old_zone->ddns_queue_size;
+
+ ptrlist_free(&old_zone->ddns_queue, NULL);
+
+ zone_events_schedule_now(zone, ZONE_EVENT_UPDATE);
+}
+
+/*!
+ * \brief Replan NOTIFY event if it was queued for the old zone.
+ */
+static void replan_notify(zone_t *zone, const zone_t *old_zone)
+{
+ assert(zone);
+ assert(old_zone);
+
+ time_t notify = zone_events_get_time(old_zone, ZONE_EVENT_NOTIFY);
+ if (notify > 0) {
+ zone_events_schedule_at(zone, notify);
+ }
+}
+
+/*!
+ * \brief Replan DNSSEC if automatic signing enabled.
+ *
+ * This is required as the configuration could have changed.
+ */
+static void replan_dnssec(conf_t *conf, zone_t *zone)
+{
+ assert(conf);
+ assert(zone);
+
+ conf_val_t val = conf_zone_get(conf, C_DNSSEC_SIGNING, zone->name);
+ if (conf_bool(&val)) {
+ zone_events_schedule_now(zone, ZONE_EVENT_DNSSEC);
+ }
+}
+
+static bool can_expire(const zone_t *zone)
+{
+ return zone->timers.soa_expire > 0 && !zone_expired(zone);
+}
+
+/*!
+ * \brief Replan events that depend on zone timers (REFRESH, EXPIRE, FLUSH, RESALT, PARENT DS QUERY).
+ */
+void replan_from_timers(conf_t *conf, zone_t *zone)
+{
+ assert(conf);
+ assert(zone);
+
+ time_t now = time(NULL);
+
+ time_t refresh = TIME_CANCEL;
+ if (zone_is_slave(conf, zone)) {
+ refresh = zone->timers.next_refresh;
+ assert(refresh > 0);
+ }
+
+ time_t expire_pre = TIME_IGNORE;
+ time_t expire = TIME_IGNORE;
+ if (zone_is_slave(conf, zone) && can_expire(zone)) {
+ expire_pre = TIME_CANCEL;
+ expire = zone->timers.last_refresh + zone->timers.soa_expire;
+ }
+
+ time_t flush = TIME_IGNORE;
+ if (!zone_is_slave(conf, zone) || can_expire(zone)) {
+ conf_val_t val = conf_zone_get(conf, C_ZONEFILE_SYNC, zone->name);
+ int64_t sync_timeout = conf_int(&val);
+ if (sync_timeout > 0) {
+ flush = zone->timers.last_flush + sync_timeout;
+ }
+ }
+
+ time_t resalt = TIME_CANCEL;
+ conf_val_t val = conf_zone_get(conf, C_DNSSEC_SIGNING, zone->name);
+ if (conf_bool(&val)) {
+ conf_val_t policy = conf_zone_get(conf, C_DNSSEC_POLICY, zone->name);
+ conf_id_fix_default(&policy);
+ val = conf_id_get(conf, C_POLICY, C_NSEC3, &policy);
+ if (conf_bool(&val)) {
+ if (zone->timers.last_resalt == 0) {
+ resalt = now;
+ } else {
+ val = conf_id_get(conf, C_POLICY, C_NSEC3_SALT_LIFETIME, &policy);
+ resalt = zone->timers.last_resalt + conf_int(&val);
+ }
+ }
+ }
+
+ time_t ds = zone->timers.next_parent_ds_q;
+ if (ds == 0) {
+ ds = TIME_IGNORE;
+ }
+
+ zone_events_schedule_at(zone,
+ ZONE_EVENT_REFRESH, refresh,
+ ZONE_EVENT_EXPIRE, expire_pre,
+ ZONE_EVENT_EXPIRE, expire,
+ ZONE_EVENT_FLUSH, flush,
+ ZONE_EVENT_NSEC3RESALT, resalt,
+ ZONE_EVENT_PARENT_DS_Q, ds);
+}
+
+void replan_load_new(zone_t *zone)
+{
+ // enqueue directly, make first load waitable
+ // other events will cascade from load
+ zone_events_enqueue(zone, ZONE_EVENT_LOAD);
+}
+
+void replan_load_bootstrap(conf_t *conf, zone_t *zone)
+{
+ replan_from_timers(conf, zone);
+}
+
+void replan_load_current(conf_t *conf, zone_t *zone, zone_t *old_zone)
+{
+ replan_ddns(zone, old_zone);
+ replan_notify(zone, old_zone);
+
+ replan_from_timers(conf, zone);
+ replan_dnssec(conf, zone);
+}
+
+void replan_load_updated(zone_t *zone, zone_t *old_zone)
+{
+ replan_ddns(zone, old_zone);
+ replan_notify(zone, old_zone);
+
+ // other events will cascade from load
+ zone_events_schedule_now(zone, ZONE_EVENT_LOAD);
+}
diff --git a/src/knot/events/replan.h b/src/knot/events/replan.h
new file mode 100644
index 0000000..05e3112
--- /dev/null
+++ b/src/knot/events/replan.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 2014 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include "knot/conf/conf.h"
+#include "knot/zone/zone.h"
+
+/*!
+ * \brief Replan timer dependent refresh, expire, and flush.
+ */
+void replan_from_timers(conf_t *conf, zone_t *zone);
+
+/*!
+ * \defgroup replan_load Replan timers after zone load or reload.
+ * @{
+ */
+void replan_load_new(zone_t *zone);
+void replan_load_bootstrap(conf_t *conf, zone_t *zone);
+void replan_load_current(conf_t *conf, zone_t *zone, zone_t *old_zone);
+void replan_load_updated(zone_t *zone, zone_t *old_zone);
+/*! @} */
diff --git a/src/knot/include/module.h b/src/knot/include/module.h
new file mode 100644
index 0000000..b3ca878
--- /dev/null
+++ b/src/knot/include/module.h
@@ -0,0 +1,549 @@
+/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief Knot DNS module interface.
+ *
+ * \addtogroup module
+ * @{
+ */
+
+#pragma once
+
+#include <stdarg.h>
+#include <stdint.h>
+#include <syslog.h>
+#include <sys/socket.h>
+
+#include <libknot/libknot.h>
+#include <libknot/yparser/ypschema.h>
+
+/*** Query module API. ***/
+
+/*! Current module ABI version. */
+#define KNOTD_MOD_ABI_VERSION 200
+/*! Module configuration name prefix. */
+#define KNOTD_MOD_NAME_PREFIX "mod-"
+
+/*! Configuration check function context. */
+typedef struct {
+ const yp_item_t *item; /*!< Current item descriptor. */
+ const uint8_t *id; /*!< Current section identifier. */
+ size_t id_len; /*!< Current section identifier length. */
+ const uint8_t *data; /*!< Current item data. */
+ size_t data_len; /*!< Current item data length. */
+ const char *err_str; /*!< Output error message. */
+ struct knotd_conf_check_extra *extra; /*!< Private items (conf/tools.h). */
+} knotd_conf_check_args_t;
+
+/*! Module context. */
+typedef struct knotd_mod knotd_mod_t;
+
+/*!
+ * Module load callback.
+ *
+ * Responsibilities:
+ * - Query processing hooks registration
+ * - Optional module specific context initialization
+ * - Module configuration processing
+ * - Query statistics counters registration
+ *
+ * \param[in] mod Module context.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+typedef int (*knotd_mod_load_f)(knotd_mod_t *mod);
+
+/*!
+ * Module unload callback.
+ *
+ * Responsibilities:
+ * - Optional module specific context deinitialization
+ *
+ * \param[in] mod Module context.
+ */
+typedef void (*knotd_mod_unload_f)(knotd_mod_t *mod);
+
+/*!
+ * Module configuration section check callback.
+ *
+ * Responsibilities:
+ * - Optional module configuration section items checks.
+ *
+ * \note Set args.err_str to proper error message if error.
+ *
+ * \param[in] args Configuration check arguments.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+typedef int (*knotd_conf_check_f)(knotd_conf_check_args_t *args);
+
+/*! Module flags. */
+typedef enum {
+ KNOTD_MOD_FLAG_NONE = 0, /*!< Unspecified. */
+ KNOTD_MOD_FLAG_OPT_CONF = 1 << 0, /*!< Optional module configuration. */
+ KNOTD_MOD_FLAG_SCOPE_GLOBAL = 1 << 1, /*!< Can be specified as global module. */
+ KNOTD_MOD_FLAG_SCOPE_ZONE = 1 << 2, /*!< Can be specified as zone module. */
+ KNOTD_MOD_FLAG_SCOPE_ANY = KNOTD_MOD_FLAG_SCOPE_GLOBAL |
+ KNOTD_MOD_FLAG_SCOPE_ZONE,
+} knotd_mod_flag_t;
+
+/*! Module API. */
+typedef struct {
+ uint32_t version; /*!< Embedded version of the module ABI. */
+ const char *name; /*!< Module name. */
+ knotd_mod_flag_t flags; /*!< Module flags. */
+ knotd_mod_load_f load; /*!< Module load callback. */
+ knotd_mod_unload_f unload; /*!< Module unload callback. */
+ const yp_item_t *config; /*!< Module configuration schema. */
+ knotd_conf_check_f config_check; /*!< Module configuration check callback. */
+} knotd_mod_api_t;
+
+/*! Static module API symbol must have a unique name. */
+#ifdef KNOTD_MOD_STATIC
+ #define KNOTD_MOD_API_NAME(mod_name) knotd_mod_api_##mod_name
+#else
+ #define KNOTD_MOD_API_NAME(mod_name) knotd_mod_api
+#endif
+
+/*! Module API instance initialization helper macro. */
+#define KNOTD_MOD_API(mod_name, mod_flags, mod_load, mod_unload, mod_conf, mod_conf_check) \
+ __attribute__((visibility("default"))) \
+ const knotd_mod_api_t KNOTD_MOD_API_NAME(mod_name) = { \
+ .version = KNOTD_MOD_ABI_VERSION, \
+ .name = KNOTD_MOD_NAME_PREFIX #mod_name, \
+ .flags = mod_flags, \
+ .load = mod_load, \
+ .unload = mod_unload, \
+ .config = mod_conf, \
+ .config_check = mod_conf_check, \
+ }
+
+/*** Configuration, statistics, logging,... API. ***/
+
+/*!
+ * Checks reference item (YP_TREF) value if the destination exists.
+ *
+ * \note This function is intended to be used in module schema.
+ *
+ * \param[in] args Configuration check arguments.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int knotd_conf_check_ref(knotd_conf_check_args_t *args);
+
+/*!
+ * Gets optional module context.
+ *
+ * \param[in] mod Module context.
+ *
+ * \return Pointer to optional module context.
+ */
+void *knotd_mod_ctx(knotd_mod_t *mod);
+
+/*!
+ * Sets optional module context.
+ *
+ * \param[in] mod Module context.
+ * \param[in] ctx Optional module context.
+ */
+void knotd_mod_ctx_set(knotd_mod_t *mod, void *ctx);
+
+/*!
+ * Gets the zone name the module is configured for.
+ *
+ * \param[in] mod Module context.
+ *
+ * \return Zone name.
+ */
+const knot_dname_t *knotd_mod_zone(knotd_mod_t *mod);
+
+/*!
+ * Emits a module specific log message.
+ *
+ * \param[in] mod Module context.
+ * \param[in] priority Message priority (LOG_DEBUG...LOG_CRIT).
+ * \param[in] fmt Content of the message.
+ */
+void knotd_mod_log(knotd_mod_t *mod, int priority, const char *fmt, ...);
+
+/*!
+ * Emits a module specific log message (va_list variant).
+ *
+ * \param[in] mod Module context.
+ * \param[in] priority Message priority (LOG_DEBUG...LOG_CRIT).
+ * \param[in] fmt Content of the message.
+ * \param[in] args Variable argument list.
+ */
+void knotd_mod_vlog(knotd_mod_t *mod, int priority, const char *fmt, va_list args);
+
+/*!
+ * Statistics multi-counter index to name transformation callback.
+ *
+ * \param[in] idx Multi-counter index.
+ * \param[in] idx_count Number of subcounters.
+ *
+ * \return Index name string.
+ */
+typedef char* (*knotd_mod_idx_to_str_f)(uint32_t idx, uint32_t idx_count);
+
+/*!
+ * Registers a statistics counter.
+ *
+ * \param[in] mod Module context.
+ * \param[in] ctr_name Counter name
+ * \param[in] idx_count Number of subcounters (set 1 for single-counter).
+ * \param[in] idx_to_str Subcounter index to name transformation callback
+ * (set NULL for single-counter).
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int knotd_mod_stats_add(knotd_mod_t *mod, const char *ctr_name, uint32_t idx_count,
+ knotd_mod_idx_to_str_f idx_to_str);
+
+/*!
+ * Increments a statistics counter.
+ *
+ * \param[in] mod Module context.
+ * \param[in] ctr_id Counter id (counted in the order the counters were registered).
+ * \param[in] idx Subcounter index (set 0 for single-counter).
+ * \param[in] val Value increment.
+ */
+void knotd_mod_stats_incr(knotd_mod_t *mod, uint32_t ctr_id, uint32_t idx, uint64_t val);
+
+/*!
+ * Decrements a statistics counter.
+ *
+ * \param[in] mod Module context.
+ * \param[in] ctr_id Counter id (counted in the order the counters were registered).
+ * \param[in] idx Subcounter index (set 0 for single-counter).
+ * \param[in] val Value decrement.
+ */
+void knotd_mod_stats_decr(knotd_mod_t *mod, uint32_t ctr_id, uint32_t idx, uint64_t val);
+
+/*!
+ * Sets a statistics counter value.
+ *
+ * \param[in] mod Module context.
+ * \param[in] ctr_id Counter id (counted in the order the counters were registered).
+ * \param[in] idx Subcounter index (set 0 for single-counter).
+ * \param[in] val Value.
+ */
+void knotd_mod_stats_store(knotd_mod_t *mod, uint32_t ctr_id, uint32_t idx, uint64_t val);
+
+/*! Configuration single-value abstraction. */
+typedef union {
+ int64_t integer;
+ unsigned option;
+ bool boolean;
+ const char *string;
+ const knot_dname_t *dname;
+ struct {
+ struct sockaddr_storage addr;
+ struct sockaddr_storage addr_max;
+ int addr_mask;
+ };
+ struct {
+ const uint8_t *data;
+ size_t data_len;
+ };
+} knotd_conf_val_t;
+
+/*! Configuration value. */
+typedef struct {
+ knotd_conf_val_t single; /*!< Single-valued item data. */
+ knotd_conf_val_t *multi; /*!< Multi-valued item data. */
+ size_t count; /*!< Number of items (0 if default single value). */
+} knotd_conf_t;
+
+/*! Environment items. */
+typedef enum {
+ KNOTD_CONF_ENV_VERSION = 0, /*!< Software version. */
+ KNOTD_CONF_ENV_HOSTNAME = 1, /*!< Current hostname. */
+ KNOTD_CONF_ENV_WORKERS_UDP = 2, /*!< Current number of UDP workers. */
+ KNOTD_CONF_ENV_WORKERS_TCP = 3, /*!< Current number of TCP workers. */
+} knotd_conf_env_t;
+
+/*!
+ * Gets general configuration value.
+ *
+ * \param[in] mod Module context.
+ * \param[in] section_name Section name.
+ * \param[in] item_name Section item name.
+ * \param[in] id Section identifier (NULL for simple section).
+ *
+ * \return Configuration value.
+ */
+knotd_conf_t knotd_conf(knotd_mod_t *mod, const yp_name_t *section_name,
+ const yp_name_t *item_name, const knotd_conf_t *id);
+
+/*!
+ * Gets environment value.
+ *
+ * \param[in] mod Module context.
+ * \param[in] env Environment item.
+ *
+ * \return Configuration value.
+ */
+knotd_conf_t knotd_conf_env(knotd_mod_t *mod, knotd_conf_env_t env);
+
+/*!
+ * Gets module configuration value.
+ *
+ * \param[in] mod Module context.
+ * \param[in] item_name Module section item name.
+ *
+ * \return Configuration value.
+ */
+knotd_conf_t knotd_conf_mod(knotd_mod_t *mod, const yp_name_t *item_name);
+
+/*!
+ * Gets zone configuration value.
+ *
+ * \param[in] mod Module context.
+ * \param[in] item_name Zone section item name.
+ * \param[in] zone Zone name.
+ *
+ * \return Configuration value.
+ */
+knotd_conf_t knotd_conf_zone(knotd_mod_t *mod, const yp_name_t *item_name,
+ const knot_dname_t *zone);
+
+/*!
+ * Gets module configuration value during the checking phase.
+ *
+ * \note This function is intended to be used in 'knotd_conf_check_f' callbacks.
+ *
+ * \param[in] args
+ * \param[in] item_name
+ *
+ * \return Configuration value.
+ */
+knotd_conf_t knotd_conf_check_item(knotd_conf_check_args_t *args,
+ const yp_name_t *item_name);
+
+/*!
+ * \brief Checks if address is in at least one of given ranges.
+ *
+ * \param[in] range
+ * \param[in] addr
+ *
+ * \return true if addr is in at least one range, false otherwise.
+ */
+bool knotd_conf_addr_range_match(const knotd_conf_t *range,
+ const struct sockaddr_storage *addr);
+
+/*!
+ * Deallocates multi-valued configuration values.
+ *
+ * \param[in] conf Configuration value.
+ */
+void knotd_conf_free(knotd_conf_t *conf);
+
+/*** Query processing API. ***/
+
+/*!
+ * DNS query type.
+ *
+ * This type encompasses the different query types distinguished by both the
+ * OPCODE and the QTYPE.
+ */
+typedef enum {
+ KNOTD_QUERY_TYPE_INVALID, /*!< Invalid query. */
+ KNOTD_QUERY_TYPE_NORMAL, /*!< Normal query. */
+ KNOTD_QUERY_TYPE_AXFR, /*!< Request for AXFR transfer. */
+ KNOTD_QUERY_TYPE_IXFR, /*!< Request for IXFR transfer. */
+ KNOTD_QUERY_TYPE_NOTIFY, /*!< NOTIFY query. */
+ KNOTD_QUERY_TYPE_UPDATE, /*!< Dynamic update. */
+} knotd_query_type_t;
+
+/*! Query processing specific flags. */
+typedef enum {
+ KNOTD_QUERY_FLAG_NO_AXFR = 1 << 0, /*!< Don't process AXFR. */
+ KNOTD_QUERY_FLAG_NO_IXFR = 1 << 1, /*!< Don't process IXFR. */
+ KNOTD_QUERY_FLAG_LIMIT_ANY = 1 << 2, /*!< Limit ANY QTYPE (respond with TC=1). */
+ KNOTD_QUERY_FLAG_LIMIT_SIZE = 1 << 3, /*!< Apply UDP size limit. */
+ KNOTD_QUERY_FLAG_COOKIE = 1 << 4, /*!< Valid DNS Cookie indication. */
+} knotd_query_flag_t;
+
+/*! Query processing data context parameters. */
+typedef struct {
+ knotd_query_flag_t flags; /*!< Current query flgas. */
+ const struct sockaddr_storage *remote; /*!< Current remote address. */
+ int socket; /*!< Current network socket. */
+ unsigned thread_id; /*!< Current thread id. */
+ void *server; /*!< Server object private item. */
+} knotd_qdata_params_t;
+
+/*! Query processing data context. */
+typedef struct {
+ knot_pkt_t *query; /*!< Query to be solved. */
+ knotd_query_type_t type; /*!< Query packet type. */
+ const knot_dname_t *name; /*!< Currently processed name. */
+ uint16_t rcode; /*!< Resulting RCODE (Whole extended RCODE). */
+ uint16_t rcode_tsig; /*!< Resulting TSIG RCODE. */
+ knot_rrset_t opt_rr; /*!< OPT record. */
+ knot_sign_context_t sign; /*!< Signing context. */
+ knot_edns_client_subnet_t *ecs; /*!< EDNS Client Subnet option. */
+ bool err_truncated; /*!< Set TC bit if error reply. */
+
+ /*! Persistent items on processing reset. */
+ knot_mm_t *mm; /*!< Memory context. */
+ knotd_qdata_params_t *params; /*!< Low-level processing parameters. */
+
+ struct knotd_qdata_extra *extra; /*!< Private items (process_query.h). */
+} knotd_qdata_t;
+
+/*!
+ * Gets the current zone name.
+ *
+ * \param[in] qdata Query data.
+ *
+ * \return Zone name.
+ */
+const knot_dname_t *knotd_qdata_zone_name(knotd_qdata_t *qdata);
+
+/*!
+ * Gets the current zone apex rrset of the given type.
+ *
+ * \param[in] qdata Query data.
+ * \param[in] type Rrset type.
+ *
+ * \return A copy of the zone apex rrset.
+ */
+knot_rrset_t knotd_qdata_zone_apex_rrset(knotd_qdata_t *qdata, uint16_t type);
+
+/*! General query processing states. */
+typedef enum {
+ KNOTD_STATE_NOOP = 0, /*!< No response. */
+ KNOTD_STATE_DONE = 4, /*!< Finished. */
+ KNOTD_STATE_FAIL = 5, /*!< Error. */
+ KNOTD_STATE_FINAL = 6, /*!< Finished and finalized (QNAME, EDNS, TSIG). */
+} knotd_state_t;
+
+/*! brief Internet query processing states. */
+typedef enum {
+ KNOTD_IN_STATE_BEGIN, /*!< Begin name resolution. */
+ KNOTD_IN_STATE_NODATA, /*!< Positive result with NO data. */
+ KNOTD_IN_STATE_HIT, /*!< Positive result. */
+ KNOTD_IN_STATE_MISS, /*!< Negative result. */
+ KNOTD_IN_STATE_DELEG, /*!< Result is delegation. */
+ KNOTD_IN_STATE_FOLLOW, /*!< Resolution not complete (CNAME/DNAME chain). */
+ KNOTD_IN_STATE_TRUNC, /*!< Finished, packet size limit encountered. */
+ KNOTD_IN_STATE_ERROR, /*!< Resolution failed. */
+} knotd_in_state_t;
+
+/*! Query module processing stages. */
+typedef enum {
+ KNOTD_STAGE_BEGIN = 0, /*!< Before query processing. */
+ KNOTD_STAGE_PREANSWER, /*!< Before section processing. */
+ KNOTD_STAGE_ANSWER, /*!< Answer section processing. */
+ KNOTD_STAGE_AUTHORITY, /*!< Authority section processing. */
+ KNOTD_STAGE_ADDITIONAL, /*!< Additional section processing. */
+ KNOTD_STAGE_END, /*!< After query processing. */
+} knotd_stage_t;
+
+/*!
+ * General processing hook.
+ *
+ * \param[in] state Current processing state.
+ * \param[in,out] pkt Response packet.
+ * \param[in] qdata Query data.
+ * \param[in] mod Module context.
+ *
+ * \return Next processing state.
+ */
+typedef knotd_state_t (*knotd_mod_hook_f)
+ (knotd_state_t state, knot_pkt_t *pkt, knotd_qdata_t *qdata, knotd_mod_t *mod);
+
+/*!
+ * Internet class processing hook.
+ *
+ * \param[in] state Current processing state.
+ * \param[in,out] pkt Response packet.
+ * \param[in] qdata Query data.
+ * \param[in] mod Module context.
+ *
+ * \return Next processing state.
+ */
+typedef knotd_in_state_t (*knotd_mod_in_hook_f)
+ (knotd_in_state_t state, knot_pkt_t *pkt, knotd_qdata_t *qdata, knotd_mod_t *mod);
+
+/*!
+ * Registers general processing module hook.
+ *
+ * \param[in] mod Module context.
+ * \param[in] stage Processing stage (KNOTD_STAGE_BEGIN or KNOTD_STAGE_END).
+ * \param[in] hook Module hook.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int knotd_mod_hook(knotd_mod_t *mod, knotd_stage_t stage, knotd_mod_hook_f hook);
+
+/*!
+ * Registers Internet class module hook.
+ *
+ * \param[in] mod Module context.
+ * \param[in] stage Processing stage (KNOTD_STAGE_ANSWER..KNOTD_STAGE_ADDITIONAL).
+ * \param[in] hook Module hook.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int knotd_mod_in_hook(knotd_mod_t *mod, knotd_stage_t stage, knotd_mod_in_hook_f hook);
+
+/*** DNSSEC API. ***/
+
+/*!
+ * Initializes DNSSEC signing context.
+ *
+ * \param[in] mod Module context.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int knotd_mod_dnssec_init(knotd_mod_t *mod);
+
+/*!
+ * Loads available DNSSEC signing keys.
+ *
+ * \param[in] mod Module context.
+ * \param[in] verbose Print key summary into log indication.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int knotd_mod_dnssec_load_keyset(knotd_mod_t *mod, bool verbose);
+
+/*!
+ * Frees up resources before re-loading DNSSEC signing keys.
+ *
+ * \param[in] mod Module context.
+ */
+void knotd_mod_dnssec_unload_keyset(knotd_mod_t *mod);
+
+/*!
+ * Generates RRSIGs for given RRSet.
+ *
+ * \param[in] mod Module context.
+ * \param[out] rrsigs Output RRSIG RRSet.
+ * \param[in] rrset Input RRSet to generate RRSIGs for.
+ * \param[in] mm Memory context.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int knotd_mod_dnssec_sign_rrset(knotd_mod_t *mod, knot_rrset_t *rrsigs,
+ const knot_rrset_t *rrset, knot_mm_t *mm);
+
+/*! @} */
diff --git a/src/knot/journal/chgset_ctx.c b/src/knot/journal/chgset_ctx.c
new file mode 100644
index 0000000..092bacf
--- /dev/null
+++ b/src/knot/journal/chgset_ctx.c
@@ -0,0 +1,88 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "chgset_ctx.h"
+
+#include "knot/journal/journal.h"
+#include "knot/journal/serialization.h"
+
+chgset_ctx_t *chgset_ctx_create(size_t chunk_count)
+{
+ chgset_ctx_t *ch = calloc(1, sizeof(*ch));
+ if (ch != NULL) {
+ ch->chunk_count = chunk_count;
+ ch->src_chunks = calloc(chunk_count, sizeof(*ch->src_chunks));
+ ch->chunk_sizes = calloc(chunk_count, sizeof(*ch->chunk_sizes));
+ if (ch->src_chunks == NULL || ch->chunk_sizes == NULL) {
+ chgset_ctx_free(ch);
+ ch = NULL;
+ }
+ }
+ return ch;
+}
+
+void chgset_ctx_free(chgset_ctx_t *ch)
+{
+ free(ch->src_chunks);
+ free(ch->chunk_sizes);
+ free(ch);
+}
+
+void chgset_ctx_list_close(chgset_ctx_list_t *l)
+{
+ chgset_ctx_t *ch = NULL, *nxt = NULL;
+ WALK_LIST_DELSAFE(ch, nxt, l->l) {
+ chgset_ctx_free(ch);
+ }
+ journal_txn_commit(l->txn);
+ free(l->txn);
+ memset(l, 0, sizeof(*l));
+}
+
+void chgset_ctx_iterate(chgset_ctx_t *ch)
+{
+ assert(ch->chunk_count > 0);
+
+ ch->curr_chunk = 0;
+ ch->wire = wire_ctx_init(ch->src_chunks[0], ch->chunk_sizes[0]);
+ ch->phase = CHGSET_CTX_START;
+}
+
+int chgset_ctx_next(chgset_ctx_t *ch, knot_rrset_t *rrset)
+{
+ int ret = deserialize_rrset_chunks(&ch->wire, rrset, ch->src_chunks,
+ ch->chunk_sizes, ch->chunk_count, &ch->curr_chunk);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ if (ch->phase == CHGSET_CTX_START && rrset->type != KNOT_RRTYPE_SOA) {
+ return KNOT_EMALF;
+ }
+
+ if (ch->phase == CHGSET_CTX_SOA_FROM || ch->phase == CHGSET_CTX_SOA_TO ||
+ rrset->type == KNOT_RRTYPE_SOA) {
+ ch->phase++;
+ }
+
+ if (ch->curr_chunk == ch->chunk_count - 1 && wire_ctx_available(&ch->wire) == 0) {
+ ch->phase = CHGSET_CTX_DONE;
+ } else if (ch->phase == CHGSET_CTX_DONE) {
+ return KNOT_EMALF;
+ }
+
+ return ret;
+}
diff --git a/src/knot/journal/chgset_ctx.h b/src/knot/journal/chgset_ctx.h
new file mode 100644
index 0000000..22e1903
--- /dev/null
+++ b/src/knot/journal/chgset_ctx.h
@@ -0,0 +1,63 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "contrib/ucw/lists.h"
+#include "contrib/wire_ctx.h"
+#include "libknot/rrset.h"
+
+typedef enum {
+ CHGSET_CTX_NOITER = 0,
+ CHGSET_CTX_START,
+ CHGSET_CTX_SOA_FROM,
+ CHGSET_CTX_REM,
+ CHGSET_CTX_SOA_TO,
+ CHGSET_CTX_ADD,
+ CHGSET_CTX_DONE,
+} chgset_ctx_phase_t;
+
+struct journal_txn; // journal.c
+
+typedef struct {
+ node_t n;
+
+ uint8_t **src_chunks;
+ size_t *chunk_sizes;
+ size_t chunk_count;
+ size_t curr_chunk;
+ wire_ctx_t wire;
+ chgset_ctx_phase_t phase;
+
+ uint32_t serial_from;
+ uint32_t serial_to;
+} chgset_ctx_t;
+
+typedef struct {
+ list_t l;
+ struct journal_txn *txn;
+} chgset_ctx_list_t;
+
+chgset_ctx_t *chgset_ctx_create(size_t chunk_count);
+
+void chgset_ctx_free(chgset_ctx_t *ch);
+
+void chgset_ctx_list_close(chgset_ctx_list_t *l);
+
+void chgset_ctx_iterate(chgset_ctx_t *ch);
+
+int chgset_ctx_next(chgset_ctx_t *ch, knot_rrset_t *rrset);
+
diff --git a/src/knot/journal/journal.c b/src/knot/journal/journal.c
new file mode 100644
index 0000000..c3ab541
--- /dev/null
+++ b/src/knot/journal/journal.c
@@ -0,0 +1,2197 @@
+/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <inttypes.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <stdarg.h>
+
+#include "knot/journal/journal.h"
+#include "knot/common/log.h"
+#include "contrib/files.h"
+#include "contrib/ctype.h"
+#include "libknot/endian.h"
+#include "contrib/dynarray.h"
+
+/*! \brief Journal version. */
+#define JOURNAL_VERSION "1.0"
+/*! \brief Changeset chunk size. */
+#define CHUNK_MAX (70 * 1024)
+/*! \brief Max number of concurrent DB readers. */
+#define JOURNAL_MAX_READERS 630
+
+/*! \brief Various metadata DB key strings. Also hardcoded in macro txn_commit()! */
+#define MDKEY_GLOBAL_VERSION "version"
+#define MDKEY_GLOBAL_JOURNAL_COUNT "journal_count"
+#define MDKEY_GLOBAL_LAST_TOTAL_OCCUPIED "last_total_occupied"
+#define MDKEY_GLOBAL_LAST_INSERTER_ZONE "last_inserter_zone"
+#define MDKEY_PERZONE_OCCUPIED "occupied"
+#define MDKEY_PERZONE_FLAGS "flags"
+#define KEY_BOOTSTRAP_CHANGESET "bootstrap"
+
+/*! \brief The number of unused bytes in DB key. */
+#define DB_KEY_UNUSED_ZERO (4)
+
+/*! \brief Metadata inserted on the beginning of each chunk:
+ * uint32_t serial_to + uint32_t chunk_count + 24B unused */
+#define JOURNAL_HEADER_SIZE (32)
+
+// eventually move to contrib and reuse as needed
+#define local_array_max_static_size (100)
+#define local_array(type, name, size) \
+ type name ## _static__[local_array_max_static_size] = { 0 }; \
+ type *name ## _dynamic__ = ((size) > local_array_max_static_size ? calloc((size), sizeof(type)) : NULL); \
+ type *name = ((size) > local_array_max_static_size ? name ## _dynamic__ : name ## _static__);
+#define local_array_free(name) { free(name ## _dynamic__); }
+
+enum {
+ LAST_FLUSHED_VALID = 1 << 0, /* "last flush is valid" flag. */
+ SERIAL_TO_VALID = 1 << 1, /* "last serial_to is valid" flag. */
+ MERGED_SERIAL_VALID = 1 << 2, /* "serial_from" of merged changeset. */
+ DIRTY_SERIAL_VALID = 1 << 3, /* "dirty_serial" is present in the DB. */
+ FIRST_SERIAL_INVALID = 1 << 4, /* "first_serial" is not valid. */
+};
+
+static bool journal_flush_allowed(journal_t *j) {
+ conf_val_t val = conf_zone_get(conf(), C_ZONEFILE_SYNC, j->zone);
+ return conf_int(&val) >= 0;
+}
+
+static bool journal_merge_allowed(journal_t *j) {
+ return !journal_flush_allowed(j); // TODO think of other behaviour, e.g. setting
+}
+
+static size_t journal_max_usage(journal_t *j)
+{
+ conf_val_t val = conf_zone_get(conf(), C_MAX_JOURNAL_USAGE, j->zone);
+ return conf_int(&val);
+}
+
+static size_t journal_max_changesets(journal_t *j)
+{
+ conf_val_t val = conf_zone_get(conf(), C_MAX_JOURNAL_DEPTH, j->zone);
+ return conf_int(&val);
+}
+
+static float journal_tofree_factor(journal_t *j)
+{
+ return 2.0f;
+}
+
+static float journal_minfree_factor(journal_t *j)
+{
+ return 0.33f;
+}
+
+/*
+ * ***************************** PART I *******************************
+ *
+ * Transaction manipulation functions
+ *
+ * ********************************************************************
+ */
+
+typedef struct {
+ uint32_t first_serial; // Serial_from of the first changeset.
+ uint32_t last_serial; // Serial_from of the last changeset.
+ uint32_t last_serial_to; // Serial_to of the last changeset.
+ uint32_t last_flushed; // Serial_from of the last flushed (or merged) chengeset.
+ uint32_t merged_serial; // "serial_from" of merged changeset.
+ uint32_t dirty_serial; // Serial_from of an incompletely inserted changeset which shall be deleted (see DB_MAX_INSERT_TXN).
+ uint32_t changeset_count; // Number of changesets in this journal.
+ uint32_t flags; // LAST_FLUSHED_VALID, SERIAL_TO_VALID, MERGED_SERIAL_VALID.
+} metadata_t;
+
+typedef struct journal_txn {
+ journal_t *j;
+ knot_db_txn_t *txn;
+ int ret;
+ bool opened;
+
+ bool is_rw;
+
+ knot_db_iter_t *iter;
+
+ knot_db_val_t key;
+ knot_db_val_t val;
+ uint8_t key_raw[512];
+
+ metadata_t shadow_md;
+} txn_t;
+
+static void md_get(txn_t *txn, const knot_dname_t *zone, const char *mdkey, uint64_t *res);
+static void md_get32(txn_t *txn, const knot_dname_t *zone, const char *mdkey, uint32_t *res);
+static void md_set(txn_t *txn, const knot_dname_t *zone, const char *mdkey, uint64_t val);
+static void md_set32(txn_t *txn, const knot_dname_t *zone, const char *mdkey, uint32_t val);
+
+static void txn_init(txn_t *txn, knot_db_txn_t *db_txn, journal_t *j)
+{
+ memset(txn, 0, sizeof(*txn));
+ txn->j = j;
+ txn->txn = db_txn;
+ txn->key.data = &txn->key_raw;
+}
+
+#define local_txn_t(txn_name, journal) \
+ knot_db_txn_t __db_txn_ ## txn_name; \
+ txn_t __local_txn_ ## txn_name; \
+ txn_t *txn_name = &__local_txn_ ## txn_name; \
+ txn_init(txn_name, &__db_txn_ ## txn_name, (journal))
+
+/*
+ * Structure of the DB key:
+ * Metadata:
+ * | [ zone_name | \0 ] | unused zero 4B | metadata_key | \0 |
+ *
+ * Changeset:
+ * | zone_name | \0 | unused zero 4B | (be32)serial_from | (be32)chunk_index |
+ * or
+ * | zone_name | \0 | unused zero 4B | metadata_key | \0 | (be32)serial_from |
+ *
+ * Structure of the changeset:
+ * | (be32)serial_to | (be32)#of_chunks | unused zero 24B | serialized_changeset...
+ *
+ */
+
+static bool key_is_ok(const knot_db_val_t *key, bool zone_related)
+{
+ const uint8_t *it = key->data;
+ ssize_t it_len = key->len;
+ if (zone_related) {
+ size_t dname_len = knot_dname_size(it);
+ it += dname_len;
+ it_len -= dname_len;
+ }
+ it += 4;
+ it_len -= 4;
+
+ return ((zone_related && it_len == 8) || // normal changeset
+ (is_lower(*it) && !is_lower(*(it-1)))); // metadata
+}
+
+static void txn_key_str(txn_t *txn, const knot_dname_t *zone, const char *key)
+{
+ size_t zone_size = knot_dname_size(zone);
+ txn->key.len = zone_size + DB_KEY_UNUSED_ZERO + strlen(key) + 1;
+ if (txn->key.len > 512) {
+ txn->ret = KNOT_ERROR;
+ return;
+ }
+ if (zone != NULL) memcpy(txn->key.data, zone, zone_size);
+ memset(txn->key.data + zone_size, 0, DB_KEY_UNUSED_ZERO);
+ strcpy(txn->key.data + zone_size + DB_KEY_UNUSED_ZERO, key);
+ assert(key_is_ok(&txn->key, zone != NULL));
+}
+
+static void txn_key_2u32(txn_t *txn, const knot_dname_t *zone, uint32_t key1, uint32_t key2)
+{
+ size_t zone_size = knot_dname_size(zone);
+ txn->key.len = zone_size + DB_KEY_UNUSED_ZERO + 2*sizeof(uint32_t);
+ if (txn->key.len > 512) {
+ txn->ret = KNOT_ERROR;
+ return;
+ }
+ if (zone != NULL) memcpy(txn->key.data, zone, zone_size);
+ memset(txn->key.data + zone_size, 0, DB_KEY_UNUSED_ZERO);
+ uint32_t key_be1 = htobe32(key1);
+ uint32_t key_be2 = htobe32(key2);
+ memcpy(txn->key.data + zone_size + DB_KEY_UNUSED_ZERO, &key_be1, sizeof(uint32_t));
+ memcpy(txn->key.data + zone_size + DB_KEY_UNUSED_ZERO + sizeof(uint32_t),
+ &key_be2, sizeof(uint32_t));
+ assert(key_is_ok(&txn->key, zone != NULL));
+}
+
+static void txn_key_str_u32(txn_t *txn, const knot_dname_t *zone, const char *key1, uint32_t key2)
+{
+ size_t zone_size = knot_dname_size(zone);
+ txn->key.len = zone_size + DB_KEY_UNUSED_ZERO + strlen(key1) + 1 + sizeof(uint32_t);
+ if (txn->key.len > 512) {
+ txn->ret = KNOT_ERROR;
+ return;
+ }
+ if (zone != NULL) memcpy(txn->key.data, zone, zone_size);
+ memset(txn->key.data + zone_size, 0, DB_KEY_UNUSED_ZERO);
+ strcpy(txn->key.data + zone_size + DB_KEY_UNUSED_ZERO, key1);
+ uint32_t key_be2 = htobe32(key2);
+ memcpy(txn->key.data + zone_size + DB_KEY_UNUSED_ZERO + strlen(key1) + 1,
+ &key_be2, sizeof(uint32_t));
+ assert(key_is_ok(&txn->key, zone != NULL));
+}
+
+static int txn_cmpkey(txn_t *txn, knot_db_val_t *key2)
+{
+ if (txn->key.len != key2->len) {
+ return (txn->key.len < key2->len ? -1 : 1);
+ }
+ if (key2->len == 0) {
+ return 0;
+ }
+ return memcmp(txn->key.data, key2->data, key2->len);
+}
+
+static void txn_val_u64(txn_t *txn, uint64_t *res)
+{
+ if (txn->ret != KNOT_EOK) {
+ return;
+ }
+ uint32_t beval32;
+ uint64_t beval;
+ switch (txn->val.len) {
+ case sizeof(uint32_t):
+ memcpy(&beval32, (uint32_t *)txn->val.data, sizeof(beval32));
+ *res = (uint64_t)be32toh(beval32);
+ break;
+ case sizeof(uint64_t):
+ memcpy(&beval, (uint64_t *)txn->val.data, sizeof(beval));
+ *res = be64toh(beval);
+ break;
+ default:
+ txn->ret = KNOT_EMALF;
+ }
+}
+
+#define txn_begin_md(md) md_get32(txn, txn->j->zone, #md, &txn->shadow_md.md)
+#define txn_commit_md(md) md_set32(txn, txn->j->zone, #md, txn->shadow_md.md)
+
+#define txn_check_open(txn) if (((txn)->ret = ((txn)->opened ? (txn)->ret : KNOT_EINVAL)) != KNOT_EOK) return
+#define txn_check_ret(txn) if (((txn)->ret = ((txn)->opened ? (txn)->ret : KNOT_EINVAL)) != KNOT_EOK) return ((txn)->ret)
+
+static void txn_begin(txn_t *txn, bool write_allowed)
+{
+ if (txn->ret == KNOT_EOK && txn->opened) {
+ txn->ret = KNOT_EINVAL;
+ }
+ if (txn->ret != KNOT_EOK) {
+ return;
+ }
+
+ txn->ret = txn->j->db->db_api->txn_begin(txn->j->db->db, txn->txn,
+ (write_allowed ? 0 : KNOT_DB_RDONLY));
+
+ txn->is_rw = write_allowed;
+ txn->opened = true;
+
+ txn_begin_md(first_serial);
+ txn_begin_md(last_serial);
+ txn_begin_md(last_serial_to);
+ txn_begin_md(last_flushed);
+ txn_begin_md(merged_serial);
+ txn_begin_md(dirty_serial);
+ txn_begin_md(changeset_count);
+ txn_begin_md(flags);
+}
+
+static void txn_find_force(txn_t *txn)
+{
+ txn_check_open(txn);
+ txn->ret = txn->j->db->db_api->find(txn->txn, &txn->key, &txn->val, 0);
+}
+
+static bool txn_find(txn_t *txn)
+{
+ if (txn->ret != KNOT_EOK || !txn->opened) {
+ return false;
+ }
+ txn_find_force(txn);
+ if (txn->ret == KNOT_ENOENT) {
+ txn->ret = KNOT_EOK;
+ return false;
+ }
+ return (txn->ret == KNOT_EOK);
+}
+
+static void txn_insert(txn_t *txn)
+{
+ txn_check_open(txn);
+ txn->ret = txn->j->db->db_api->insert(txn->txn, &txn->key, &txn->val, 0);
+}
+
+static void txn_del(txn_t *txn)
+{
+ txn_check_open(txn);
+ txn->ret = txn->j->db->db_api->del(txn->txn, &txn->key);
+}
+
+static void txn_iter_begin(txn_t *txn)
+{
+ txn_check_open(txn);
+ txn->iter = txn->j->db->db_api->iter_begin(txn->txn, KNOT_DB_FIRST);
+ if (txn->iter == NULL) {
+ txn->ret = KNOT_ENOMEM;
+ }
+}
+
+#define txn_check_iter if (txn->iter == NULL && txn->ret == KNOT_EOK) txn->ret = KNOT_EINVAL; \
+ if (txn->ret != KNOT_EOK) return;
+
+static void txn_iter_seek(txn_t *txn)
+{
+ txn_check_iter
+ txn->iter = txn->j->db->db_api->iter_seek(txn->iter, &txn->key, 0);
+ if (txn->iter == NULL) {
+ txn->ret = KNOT_ENOENT;
+ }
+}
+
+static void txn_iter_key(txn_t *txn, knot_db_val_t *at_key)
+{
+ txn_check_iter
+ txn->ret = txn->j->db->db_api->iter_key(txn->iter, at_key);
+}
+
+static void txn_iter_val(txn_t *txn)
+{
+ txn_check_iter
+ txn->ret = txn->j->db->db_api->iter_val(txn->iter, &txn->val);
+}
+
+static void txn_iter_next(txn_t *txn)
+{
+ txn_check_iter
+ txn->iter = txn->j->db->db_api->iter_next(txn->iter);
+ if (txn->iter == NULL) {
+ txn->ret = KNOT_ENOENT;
+ }
+}
+
+static void txn_iter_finish(txn_t *txn)
+{
+ if (txn->iter != NULL) {
+ txn->j->db->db_api->iter_finish(txn->iter);
+ }
+ txn->iter = NULL;
+}
+
+static void txn_abort(txn_t *txn)
+{
+ if (txn->opened) {
+ txn_iter_finish(txn);
+ txn->j->db->db_api->txn_abort(txn->txn);
+ txn->opened = false;
+ }
+}
+
+static void txn_commit(txn_t *txn)
+{
+ if (txn->is_rw) {
+ txn_commit_md(first_serial);
+ txn_commit_md(last_serial);
+ txn_commit_md(last_serial_to);
+ txn_commit_md(last_flushed);
+ txn_commit_md(merged_serial);
+ txn_commit_md(dirty_serial);
+ txn_commit_md(changeset_count);
+ txn_commit_md(flags);
+ }
+
+ if (txn->ret != KNOT_EOK) {
+ txn_abort(txn);
+ return;
+ }
+
+ txn_iter_finish(txn);
+ txn->ret = txn->j->db->db_api->txn_commit(txn->txn);
+
+ if (txn->ret == KNOT_EOK) {
+ txn->opened = false;
+ }
+ txn_abort(txn); // no effect if all ok
+}
+
+void journal_txn_commit(struct journal_txn *txn)
+{
+ if (txn != NULL) {
+ txn_commit(txn);
+ }
+}
+
+static void txn_restart(txn_t *txn)
+{
+ txn_commit(txn);
+ assert(!txn->opened);
+ if (txn->ret == KNOT_EOK) {
+ txn_begin(txn, txn->is_rw);
+ }
+}
+
+static void txn_reuse(txn_t **txn, txn_t *to_reuse, bool write_allowed)
+{
+ if (to_reuse == NULL) {
+ txn_begin(*txn, write_allowed);
+ } else {
+ *txn = to_reuse;
+ }
+}
+
+static void txn_unreuse(txn_t **txn, txn_t *reused)
+{
+ if (reused == NULL) {
+ txn_commit(*txn);
+ }
+}
+
+#define reuse_txn(name, journal, to_reuse, wa) local_txn_t(name, journal); txn_reuse(&name, to_reuse, wa)
+#define unreuse_txn(name, reused) txn_unreuse(&name, reused)
+
+/*
+ * ***************************** PART II ******************************
+ *
+ * DB metadata manip. and Chunk metadata headers
+ *
+ * ********************************************************************
+ */
+
+static void md_get(txn_t *txn, const knot_dname_t *zone, const char *mdkey, uint64_t *res)
+{
+ txn_check_open(txn);
+ txn_key_str(txn, zone, mdkey);
+ uint64_t res1 = 0;
+ if (txn_find(txn)) {
+ txn_val_u64(txn, &res1);
+ }
+ *res = res1;
+}
+
+static void md_get32(txn_t *txn, const knot_dname_t *zone, const char *mdkey, uint32_t *res)
+{
+ uint64_t res1 = 0;
+ md_get(txn, zone, mdkey, &res1);
+ if (res1 > UINT32_MAX) {
+ txn->ret = KNOT_EMALF;
+ } else {
+ *res = (uint32_t)res1;
+ }
+}
+
+// allocates res
+static void md_get_common_last_inserter_zone(txn_t *txn, knot_dname_t **res)
+{
+ txn_check_open(txn);
+ txn_key_str(txn, NULL, MDKEY_GLOBAL_LAST_INSERTER_ZONE);
+ if (txn_find(txn)) {
+ *res = knot_dname_copy(txn->val.data, NULL);
+ } else {
+ *res = NULL;
+ }
+}
+
+static int md_set_common_last_inserter_zone(txn_t *txn, knot_dname_t *zone)
+{
+ txn_check_ret(txn);
+ txn_key_str(txn, NULL, MDKEY_GLOBAL_LAST_INSERTER_ZONE);
+ txn->val.len = knot_dname_size(zone);
+ txn->val.data = zone;
+ txn_insert(txn);
+ return txn->ret;
+}
+
+static void md_del_last_inserter_zone(txn_t *txn, knot_dname_t *if_equals)
+{
+ txn_check_open(txn);
+ txn_key_str(txn, NULL, MDKEY_GLOBAL_LAST_INSERTER_ZONE);
+ if (txn_find(txn)) {
+ if (if_equals == NULL || knot_dname_is_equal(txn->val.data, if_equals)) {
+ txn_del(txn);
+ }
+ }
+}
+
+static void md_get_common_last_occupied(txn_t *txn, size_t *res)
+{
+ uint64_t sres = 0;
+ md_get(txn, NULL, MDKEY_GLOBAL_LAST_TOTAL_OCCUPIED, &sres);
+ *res = (size_t) sres;
+}
+
+static void md_set(txn_t *txn, const knot_dname_t *zone, const char *mdkey, uint64_t val)
+{
+ txn_key_str(txn, zone, mdkey);
+ uint64_t val1 = htobe64(val);
+ txn->val.len = sizeof(uint64_t);
+ txn->val.data = &val1;
+ txn_insert(txn);
+}
+
+static void md_set32(txn_t *txn, const knot_dname_t *zone, const char *mdkey, uint32_t val)
+{
+ txn_key_str(txn, zone, mdkey);
+ uint32_t val1 = htobe32(val);
+ txn->val.len = sizeof(uint32_t);
+ txn->val.data = &val1;
+ txn_insert(txn);
+}
+
+static bool md_flag(txn_t *txn, int flag)
+{
+ return (txn->shadow_md.flags & flag);
+}
+
+/*! \brief Marks metadata as flushed */
+static void md_flush(txn_t *txn)
+{
+ if (md_flag(txn, SERIAL_TO_VALID) && !md_flag(txn, FIRST_SERIAL_INVALID)) {
+ txn->shadow_md.last_flushed = txn->shadow_md.last_serial;
+ txn->shadow_md.flags |= LAST_FLUSHED_VALID;
+ }
+}
+
+static int md_flushed(txn_t *txn)
+{
+ return (!md_flag(txn, SERIAL_TO_VALID) ||
+ (md_flag(txn, LAST_FLUSHED_VALID) &&
+ serial_equal(txn->shadow_md.last_flushed, txn->shadow_md.last_serial)));
+}
+
+static void make_header(knot_db_val_t *to, uint32_t serial_to, int chunk_count)
+{
+ assert(to->len >= JOURNAL_HEADER_SIZE);
+ assert(chunk_count > 0);
+
+ uint32_t be_serial_to = htobe32(serial_to);
+ uint32_t be_chunk_count = htobe32((uint32_t)chunk_count);
+
+ memcpy(to->data, &be_serial_to, sizeof(be_serial_to));
+ memcpy(to->data + sizeof(be_serial_to), &be_chunk_count, sizeof(be_chunk_count));
+ memset(to->data + sizeof(be_serial_to) + sizeof(be_chunk_count), 0,
+ JOURNAL_HEADER_SIZE - sizeof(be_serial_to) - sizeof(be_chunk_count));
+}
+
+/*! \brief read properties from chunk header "from". All the output params are optional */
+static void unmake_header(const knot_db_val_t *from, uint32_t *serial_to,
+ int *chunk_count, size_t *header_size)
+{
+ assert(from->len >= JOURNAL_HEADER_SIZE);
+
+ uint32_t be_serial_to, be_chunk_count;
+ if (serial_to != NULL) {
+ memcpy(&be_serial_to, from->data, sizeof(be_serial_to));
+ *serial_to = be32toh(be_serial_to);
+ }
+ if (chunk_count != NULL) {
+ memcpy(&be_chunk_count, from->data + sizeof(be_serial_to), sizeof(be_chunk_count));
+ assert(be32toh(be_chunk_count) <= INT_MAX);
+ *chunk_count = (int)be32toh(be_chunk_count);
+ }
+ if (header_size != NULL) {
+ *header_size = JOURNAL_HEADER_SIZE;
+ }
+}
+
+static int first_digit(char * of)
+{
+ return atoi(of);
+}
+
+static void md_update_journal_count(txn_t * txn, int change_amount)
+{
+ uint64_t jcnt = 0;
+ md_get(txn, NULL, MDKEY_GLOBAL_JOURNAL_COUNT, &jcnt);
+ md_set(txn, NULL, MDKEY_GLOBAL_JOURNAL_COUNT, jcnt + change_amount);
+}
+
+static int initial_md_check(journal_t *j, bool *dirty_present)
+{
+ *dirty_present = 0;
+
+ bool something_updated = false;
+
+ local_txn_t(txn, j);
+ txn_begin(txn, true);
+ txn_key_str(txn, NULL, MDKEY_GLOBAL_VERSION);
+ if (!txn_find(txn)) {
+ txn->val.len = strlen(JOURNAL_VERSION) + 1;
+ txn->val.data = JOURNAL_VERSION;
+ txn_insert(txn);
+ something_updated = true;
+ } else {
+ char * jver = txn->val.data;
+ if (first_digit(jver) != first_digit(JOURNAL_VERSION)) {
+ txn_abort(txn);
+ return KNOT_ENOTSUP;
+ }
+ }
+ txn_key_str(txn, j->zone, MDKEY_PERZONE_FLAGS);
+ if (!txn_find(txn)) {
+ md_update_journal_count(txn, +1);
+ something_updated = true;
+ }
+ *dirty_present = md_flag(txn, DIRTY_SERIAL_VALID);
+
+ if (something_updated) {
+ txn_commit(txn);
+ } else { // abort to gain up speed when opening a lot of zones
+ txn_abort(txn);
+ }
+
+ return txn->ret;
+}
+
+/*
+ * **************************** PART III ******************************
+ *
+ * DB iteration
+ *
+ * ********************************************************************
+ */
+
+enum {
+ JOURNAL_ITERATION_CHUNKS, // call the iteration callback for each chunk read, with just the chunk in ctx->val
+ JOURNAL_ITERATION_CHANGESETS // call the iteration callback after the last chunk of a changeset read, with all its chunks in ctx->val
+};
+
+typedef struct {
+ txn_t *txn; // DB txn not to be touched by callback, just contains journal pointer
+ uint32_t serial; // serial-from of current changeset
+ uint32_t serial_to; // serial-to of current changeset
+ const int method; // JOURNAL_ITERATION_CHUNKS or JOURNAL_ITERATION_CHANGESETS, to be set by the caller of iterate()
+ int chunk_index; // index of current chunk
+ int chunk_count; // # of chunks of current changeset
+ knot_db_val_t *val; // one val if JOURNAL_ITERATION_CHUNKS; chunk_count vals if JOURNAL_ITERATION_CHANGESETS
+ knot_db_iter_t *iter; // DB iteration context, not to be touched by callback
+ void *iter_context; // anything to send to the callback by the caller of iterate(), untouched by iterate()
+} iteration_ctx_t;
+
+typedef int (*iteration_cb_t)(iteration_ctx_t *ctx);
+
+/*!
+ * \brief Move iter to next changeset chunk.
+ *
+ * Try optimisticly fast move to next DB item. But the changeset can be out of order,
+ * so if we don't succeed (different serial or end of DB), we lookup next serial slowly.
+ */
+
+static void get_iter_next(iteration_ctx_t *ctx, iteration_cb_t key_cb)
+{
+ knot_db_val_t other_key = { 0 };
+
+ txn_check_open(ctx->txn);
+ txn_iter_next(ctx->txn);
+ txn_iter_key(ctx->txn, &other_key);
+ key_cb(ctx);
+ if (ctx->txn->ret == KNOT_ENOENT ||
+ (ctx->txn->ret == KNOT_EOK && txn_cmpkey(ctx->txn, &other_key) != 0)) {
+ ctx->txn->ret = KNOT_EOK;
+ if (ctx->txn->iter != NULL) {
+ txn_iter_finish(ctx->txn);
+ }
+ txn_iter_begin(ctx->txn);
+ txn_iter_seek(ctx->txn);
+ }
+}
+
+static int iterate(journal_t *j, txn_t *_txn, iteration_cb_t cb, int method,
+ void *iter_context, uint32_t first, uint32_t last, iteration_cb_t key_cb)
+{
+ reuse_txn(txn, j, _txn, true);
+
+ iteration_ctx_t ctx = {
+ .method = method,
+ .iter_context = iter_context,
+ .txn = txn,
+ .serial = first,
+ .chunk_index = 0
+ };
+
+ knot_db_val_t *vals = NULL;
+
+ txn_iter_begin(txn);
+
+ key_cb(&ctx);
+ txn_iter_seek(txn);
+
+ ctx.val = &txn->val;
+
+ while (true) {
+ txn_iter_val(txn);
+ if (txn->ret != KNOT_EOK) {
+ break;
+ }
+
+ unmake_header(&txn->val, &ctx.serial_to, &ctx.chunk_count, NULL);
+
+ if (method == JOURNAL_ITERATION_CHANGESETS) {
+ if (ctx.chunk_index == 0) {
+ if (vals != NULL) free(vals);
+ vals = malloc(ctx.chunk_count * sizeof(knot_db_val_t));
+ if (vals == NULL) {
+ txn->ret = KNOT_ENOMEM;
+ break;
+ }
+ ctx.val = vals;
+ }
+ memcpy(vals + ctx.chunk_index, &txn->val, sizeof(knot_db_val_t));
+ }
+
+ if (method == JOURNAL_ITERATION_CHUNKS) {
+ txn->ret = cb(&ctx);
+ }
+
+ if (ctx.chunk_index == ctx.chunk_count - 1) { // hit last chunk of current changeset
+ if (method == JOURNAL_ITERATION_CHANGESETS) {
+ txn->ret = cb(&ctx);
+ }
+
+ if (ctx.serial == last) {
+ break; // standard loop exit here
+ }
+
+ ctx.serial = ctx.serial_to;
+ ctx.chunk_index = 0;
+ } else {
+ ctx.chunk_index++;
+ }
+
+ get_iter_next(&ctx, key_cb);
+ }
+
+ if (vals != NULL) {
+ free(vals);
+ }
+ txn_iter_finish(txn);
+
+ unreuse_txn(txn, _txn);
+
+ return txn->ret;
+}
+
+static int normal_iterkeycb(iteration_ctx_t *ctx)
+{
+ txn_key_2u32(ctx->txn, ctx->txn->j->zone, ctx->serial, ctx->chunk_index);
+ return KNOT_EOK;
+}
+
+/*
+ * ***************************** PART IV ******************************
+ *
+ * Reading changesets
+ *
+ * ********************************************************************
+ */
+
+/*! \brief Deserialize changeset from chunks (in vals) */
+static int vals_to_changeset(knot_db_val_t *vals, int nvals,
+ const knot_dname_t *zone_name, changeset_t **ch)
+{
+ local_array(uint8_t *, valps, nvals)
+ local_array(size_t, vallens, nvals)
+ if (valps == NULL || vallens == NULL) {
+ local_array_free(valps)
+ local_array_free(vallens)
+ return KNOT_ENOMEM;
+ }
+
+ for (size_t i = 0; i < nvals; i++) {
+ valps[i] = vals[i].data + JOURNAL_HEADER_SIZE;
+ vallens[i] = vals[i].len - JOURNAL_HEADER_SIZE;
+ }
+
+ changeset_t *t_ch = changeset_new(zone_name);
+ if (t_ch == NULL) {
+ local_array_free(valps)
+ local_array_free(vallens)
+ return KNOT_ENOMEM;
+ }
+
+ int ret = changeset_deserialize(t_ch, valps, vallens, nvals);
+
+ local_array_free(valps)
+ local_array_free(vallens)
+ if (ret != KNOT_EOK) {
+ changeset_free(t_ch);
+ return ret;
+ }
+ *ch = t_ch;
+ return KNOT_EOK;
+}
+
+static int vals_to_chgset_ctx(knot_db_val_t *vals, int nvals, uint32_t serial_from,
+ uint32_t serial_to, chgset_ctx_t **ch)
+{
+ if (nvals < 1) {
+ return KNOT_EINVAL;
+ }
+
+ chgset_ctx_t *t_ch = chgset_ctx_create(nvals);
+ if (t_ch == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ for (size_t i = 0; i < nvals; i++) {
+ t_ch->src_chunks[i] = vals[i].data + JOURNAL_HEADER_SIZE;
+ t_ch->chunk_sizes[i] = vals[i].len - JOURNAL_HEADER_SIZE;
+ }
+
+ t_ch->serial_from = serial_from;
+ t_ch->serial_to = serial_to;
+
+ *ch = t_ch;
+ return KNOT_EOK;
+}
+
+static int load_one_itercb(iteration_ctx_t *ctx)
+{
+ changeset_t *ch = NULL, **targ = ctx->iter_context;
+ if (*targ != NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = vals_to_changeset(ctx->val, ctx->chunk_count, ctx->txn->j->zone, &ch);
+ if (ret == KNOT_EOK) *targ = ch;
+ return ret;
+}
+
+static int load_list_itercb(iteration_ctx_t *ctx)
+{
+ changeset_t *ch = NULL;
+ list_t *chlist = *(list_t **) ctx->iter_context;
+
+ int ret = vals_to_changeset(ctx->val, ctx->chunk_count, ctx->txn->j->zone, &ch);
+
+ if (ret == KNOT_EOK) {
+ add_tail(chlist, &ch->n);
+ }
+ return ret;
+}
+
+static int load_list_ctx_itercb(iteration_ctx_t *ctx)
+{
+ chgset_ctx_t *ch = NULL;
+ list_t *chlist = *(list_t **) ctx->iter_context;
+
+ int ret = vals_to_chgset_ctx(ctx->val, ctx->chunk_count, ctx->serial, ctx->serial_to, &ch);
+
+ if (ret == KNOT_EOK) {
+ add_tail(chlist, &ch->n);
+ }
+ return ret;
+}
+
+/*! \brief Load one changeset (with serial) from DB */
+static int load_one(journal_t *j, txn_t *_txn, uint32_t serial, changeset_t **ch)
+{
+ reuse_txn(txn, j, _txn, false);
+ changeset_t *rch = NULL;
+ iterate(j, txn, load_one_itercb, JOURNAL_ITERATION_CHANGESETS, &rch, serial, serial, normal_iterkeycb);
+ unreuse_txn(txn, _txn);
+ if (txn->ret == KNOT_EOK) {
+ if (rch == NULL) txn->ret = KNOT_ENOENT;
+ else *ch = rch;
+ }
+ return txn->ret;
+}
+
+static int load_merged_changeset(journal_t *j, txn_t *_txn, changeset_t **mch,
+ const uint32_t *only_if_serial)
+{
+ assert(*mch == NULL);
+
+ reuse_txn(txn, j, _txn, false);
+ txn_check_ret(txn);
+ uint32_t ms = txn->shadow_md.merged_serial, fl = txn->shadow_md.flags;
+
+ if ((fl & MERGED_SERIAL_VALID) &&
+ (only_if_serial == NULL || serial_equal(ms, *only_if_serial))) {
+ load_one(j, txn, ms, mch);
+ }
+ unreuse_txn(txn, _txn);
+
+ return txn->ret;
+}
+
+int journal_load_changesets(journal_t *j, list_t *dst, uint32_t from)
+{
+ if (j == NULL || j->db == NULL || dst == NULL) return KNOT_EINVAL;
+
+ local_txn_t(txn, j);
+ txn_begin(txn, false);
+
+ uint32_t ls = txn->shadow_md.last_serial;
+ iterate(j, txn, load_list_itercb, JOURNAL_ITERATION_CHANGESETS, &dst, from,
+ ls, normal_iterkeycb);
+ txn_commit(txn);
+
+ return txn->ret;
+}
+
+int journal_load_chgset_ctx(journal_t *j, chgset_ctx_list_t *dst, uint32_t from)
+{
+ if (j == NULL || j->db == NULL || dst == NULL) return KNOT_EINVAL;
+
+ txn_t *txn = calloc(1, sizeof(*txn) + sizeof(*txn->txn));
+ if (txn == NULL) {
+ return KNOT_ENOMEM;
+ }
+ txn_init(txn, ((void *)txn) + sizeof(*txn), j);
+ txn_begin(txn, false);
+
+ init_list(&dst->l);
+ dst->txn = txn;
+ list_t *dstl = &dst->l;
+
+ uint32_t ls = txn->shadow_md.last_serial;
+ iterate(j, txn, load_list_ctx_itercb, JOURNAL_ITERATION_CHANGESETS, &dstl, from,
+ ls, normal_iterkeycb);
+
+ if (txn->ret != KNOT_EOK) {
+ int ret = txn->ret;
+ txn_commit(txn);
+ free(txn);
+ return ret;
+ }
+
+ return txn->ret;
+}
+
+int load_bootstrap_iterkeycb(iteration_ctx_t *ctx)
+{
+ txn_key_str_u32(ctx->txn, ctx->txn->j->zone, KEY_BOOTSTRAP_CHANGESET, ctx->chunk_index);
+ return KNOT_EOK;
+}
+
+static int load_bootstrap_changeset(journal_t *j, txn_t *_txn, changeset_t **ch)
+{
+ reuse_txn(txn, j, _txn, false);
+ changeset_t *rch = NULL;
+ iterate(j, txn, load_one_itercb, JOURNAL_ITERATION_CHANGESETS, &rch,
+ 0, 0, load_bootstrap_iterkeycb);
+ unreuse_txn(txn, _txn);
+ if (txn->ret == KNOT_EOK) {
+ if (rch == NULL) txn->ret = KNOT_ENOENT;
+ else *ch = rch;
+ }
+ return txn->ret;
+}
+
+static bool has_bootstrap_changeset(journal_t *j, txn_t *_txn)
+{
+ reuse_txn(txn, j, _txn, false);
+ txn_key_str_u32(txn, j->zone, KEY_BOOTSTRAP_CHANGESET, 0);
+ bool res = txn_find(txn);
+ unreuse_txn(txn, _txn);
+ return res;
+}
+
+int journal_load_bootstrap(journal_t *j, list_t *dst)
+{
+ if (j == NULL || j->db == NULL || dst == NULL) return KNOT_EINVAL;
+
+ local_txn_t(txn, j);
+ txn_begin(txn, false);
+
+ changeset_t *bch = NULL;
+ load_bootstrap_changeset(j, txn, &bch);
+ if (bch == NULL) {
+ txn->ret = KNOT_ENOENT;
+ goto jlb_end;
+ }
+ add_tail(dst, &bch->n);
+ uint32_t from = knot_soa_serial(bch->soa_to->rrs.rdata);
+
+ uint32_t ls = txn->shadow_md.last_serial;
+ iterate(j, txn, load_list_itercb, JOURNAL_ITERATION_CHANGESETS, &dst,
+ from, ls, normal_iterkeycb);
+ if (txn->ret == KNOT_ENOENT) {
+ txn->ret = KNOT_EOK;
+ }
+jlb_end:
+ txn_commit(txn);
+ return txn->ret;
+}
+
+/*
+ * ***************************** PART V *******************************
+ *
+ * Deleting changesets
+ *
+ * ********************************************************************
+ */
+
+typedef struct {
+ size_t freed_approx;
+ size_t to_be_freed;
+} delete_status_t;
+
+static int del_upto_itercb(iteration_ctx_t *ctx)
+{
+ txn_key_2u32(ctx->txn, ctx->txn->j->zone, ctx->serial, ctx->chunk_index);
+ txn_del(ctx->txn);
+ txn_check_ret(ctx->txn);
+
+ // one whole changeset has been deleted => update metadata.
+ // We are sure that the deleted changeset is first at this time.
+ // If it's not merged changeset, point first_serial to next one
+ if (ctx->chunk_index == ctx->chunk_count - 1) {
+ if (!md_flag(ctx->txn, MERGED_SERIAL_VALID) ||
+ !serial_equal(ctx->txn->shadow_md.merged_serial,ctx->serial)) {
+ ctx->txn->shadow_md.first_serial = ctx->serial_to;
+ ctx->txn->shadow_md.changeset_count--;
+ }
+ if (serial_equal(ctx->txn->shadow_md.last_flushed, ctx->serial)) {
+ ctx->txn->shadow_md.flags &= ~LAST_FLUSHED_VALID;
+ }
+ if (serial_equal(ctx->txn->shadow_md.last_serial, ctx->serial)) {
+ ctx->txn->shadow_md.flags &= ~SERIAL_TO_VALID;
+ }
+ if (serial_equal(ctx->txn->shadow_md.merged_serial,ctx->serial)) {
+ ctx->txn->shadow_md.flags &= ~MERGED_SERIAL_VALID;
+ }
+ }
+ return KNOT_EOK;
+}
+
+/*! \brief Delete from beginning of DB up to "last" changeset including.
+ * Please ensure (dbfirst == j->metadata.first_serial) */
+static int delete_upto(journal_t *j, txn_t *txn, uint32_t dbfirst, uint32_t last)
+{
+ return iterate(j, txn, del_upto_itercb, JOURNAL_ITERATION_CHUNKS, NULL,
+ dbfirst, last, normal_iterkeycb);
+}
+
+static int delete_merged_changeset(journal_t *j, txn_t *t)
+{
+ reuse_txn(txn, j, t, true);
+ txn_check_ret(txn);
+ if (!md_flag(txn, MERGED_SERIAL_VALID)) {
+ txn->ret = KNOT_ENOENT;
+ } else {
+ delete_upto(j, txn, txn->shadow_md.merged_serial, txn->shadow_md.merged_serial);
+ }
+ unreuse_txn(txn, t);
+ return txn->ret;
+}
+
+static int delete_bootstrap_changeset(journal_t *j, txn_t *_txn);
+
+static int drop_journal(journal_t *j, txn_t *_txn)
+{
+ reuse_txn(txn, j, _txn, true);
+ txn_check_ret(txn);
+ if (md_flag(txn, MERGED_SERIAL_VALID)) {
+ delete_merged_changeset(j, txn);
+ }
+ if (md_flag(txn, SERIAL_TO_VALID) && !md_flag(txn, FIRST_SERIAL_INVALID)) {
+ delete_upto(j, txn, txn->shadow_md.first_serial, txn->shadow_md.last_serial);
+ }
+ delete_bootstrap_changeset(j, txn);
+ md_del_last_inserter_zone(txn, j->zone);
+ md_set(txn, j->zone, MDKEY_PERZONE_OCCUPIED, 0);
+ unreuse_txn(txn, _txn);
+ return txn->ret;
+}
+
+static int del_tofree_itercb(iteration_ctx_t *ctx)
+{
+ delete_status_t *ds = ctx->iter_context;
+
+ if (ds->to_be_freed == 0) {
+ return KNOT_EOK; // all done, just running through the rest of records w/o change
+ }
+
+ txn_key_2u32(ctx->txn, ctx->txn->j->zone, ctx->serial, ctx->chunk_index);
+ txn_del(ctx->txn);
+ txn_check_ret(ctx->txn);
+
+ ds->freed_approx += /*4096 + */ctx->val->len;
+
+ // when whole changeset deleted, check target and update metadata
+ if (ctx->chunk_index == ctx->chunk_count - 1) {
+ ctx->txn->shadow_md.first_serial = ctx->serial_to;
+ ctx->txn->shadow_md.changeset_count--;
+ if (serial_equal(ctx->txn->shadow_md.last_flushed, ctx->serial)) {
+ ctx->txn->shadow_md.flags &= ~LAST_FLUSHED_VALID;
+ ds->to_be_freed = 0; // prevents deleting unflushed changesets
+ }
+ if (serial_equal(ctx->txn->shadow_md.last_serial, ctx->serial)) {
+ ctx->txn->shadow_md.flags &= ~SERIAL_TO_VALID;
+ }
+ if (ds->freed_approx >= ds->to_be_freed) {
+ ds->to_be_freed = 0;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Deletes from j->db oldest changesets to free up space
+ *
+ * It tries deleting olny flushed changesets, preserves all unflushed ones.
+ *
+ * \retval KNOT_EOK if no error, even if too little or nothing deleted (check really_freed for result); KNOT_E* if error
+ */
+static int delete_tofree(journal_t *j, txn_t *_txn, size_t to_be_freed, size_t *really_freed)
+{
+ reuse_txn(txn, j, _txn, true);
+ txn_check_ret(txn);
+
+ if (!md_flag(txn, LAST_FLUSHED_VALID)) {
+ *really_freed = 0;
+ return KNOT_EOK;
+ }
+ delete_status_t ds = { .freed_approx = 0, .to_be_freed = to_be_freed };
+ iterate(j, txn, del_tofree_itercb, JOURNAL_ITERATION_CHUNKS, &ds,
+ txn->shadow_md.first_serial, txn->shadow_md.last_serial, normal_iterkeycb);
+ unreuse_txn(txn, _txn);
+
+ if (txn->ret == KNOT_EOK) {
+ *really_freed = ds.freed_approx;
+ }
+ return txn->ret;
+}
+
+static int del_count_itercb(iteration_ctx_t *ctx)
+{
+ delete_status_t *ds = ctx->iter_context;
+ if (ds->freed_approx >= ds->to_be_freed) {
+ return KNOT_EOK;
+ }
+ txn_key_2u32(ctx->txn, ctx->txn->j->zone, ctx->serial, ctx->chunk_index);
+ txn_del(ctx->txn);
+ txn_check_ret(ctx->txn);
+
+ // when whole changeset deleted, check target and update metadata
+ if (ctx->chunk_index == ctx->chunk_count - 1) {
+ ctx->txn->shadow_md.first_serial = ctx->serial_to;
+ ctx->txn->shadow_md.changeset_count--;
+ if (serial_equal(ctx->txn->shadow_md.last_flushed, ctx->serial)) {
+ ctx->txn->shadow_md.flags &= ~LAST_FLUSHED_VALID;
+ ds->to_be_freed = ds->freed_approx; // prevents deleting unflushed changesets
+ }
+ if (serial_equal(ctx->txn->shadow_md.last_serial, ctx->serial)) {
+ ctx->txn->shadow_md.flags &= ~SERIAL_TO_VALID;
+ }
+ ds->freed_approx++;
+ }
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Deletes specified number of changesets
+ *
+ * It tries deleting olny flushed changesets, preserves all unflushed ones.
+ *
+ * \retval KNOT_EOK if no error, even if too little or nothing deleted (check really_deleted for result)
+ * \return KNOT_E* if error
+ */
+static int delete_count(journal_t *j, txn_t *_txn, size_t to_be_deleted, size_t *really_deleted)
+{
+ reuse_txn(txn, j, _txn, true);
+ txn_check_ret(txn);
+
+ if (!md_flag(txn, LAST_FLUSHED_VALID)) {
+ *really_deleted = 0;
+ return KNOT_EOK;
+ }
+ delete_status_t ds = { .freed_approx = 0, .to_be_freed = to_be_deleted };
+ iterate(j, txn, del_count_itercb, JOURNAL_ITERATION_CHUNKS, &ds,
+ txn->shadow_md.first_serial, txn->shadow_md.last_serial, normal_iterkeycb);
+ unreuse_txn(txn, _txn);
+
+ if (txn->ret == KNOT_EOK) {
+ *really_deleted = ds.freed_approx;
+ }
+ return txn->ret;
+}
+
+static int delete_dirty_serial(journal_t *j, txn_t *_txn)
+{
+ reuse_txn(txn, j, _txn, true);
+ txn_check_ret(txn);
+
+ if (!md_flag(txn, DIRTY_SERIAL_VALID)) return KNOT_EOK;
+
+ uint32_t ds = txn->shadow_md.dirty_serial, chunk = 0;
+
+ txn_key_2u32(txn, j->zone, ds, chunk);
+ while (txn_find(txn)) {
+ txn_del(txn);
+ txn_key_2u32(txn, j->zone, ds, ++chunk);
+ }
+ unreuse_txn(txn, _txn);
+ if (txn->ret == KNOT_EOK) {
+ txn->shadow_md.flags &= ~DIRTY_SERIAL_VALID;
+ }
+ return txn->ret;
+}
+
+static int delete_bootstrap_changeset(journal_t *j, txn_t *_txn)
+{
+ reuse_txn(txn, j, _txn, false);
+ uint32_t chunk = 0;
+ txn_key_str_u32(txn, j->zone, KEY_BOOTSTRAP_CHANGESET, chunk);
+ while (txn_find(txn)) {
+ txn_del(txn);
+ txn_key_str_u32(txn, j->zone, KEY_BOOTSTRAP_CHANGESET, ++chunk);
+ }
+ unreuse_txn(txn, _txn);
+ return txn->ret;
+}
+
+/*
+ * ***************************** PART VI ******************************
+ *
+ * Writing changesets
+ *
+ * ********************************************************************
+ */
+
+static int merge_itercb(iteration_ctx_t *ctx)
+{
+ changeset_t *ch = NULL, *mch = *(changeset_t **)ctx->iter_context;
+
+ int ret = vals_to_changeset(ctx->val, ctx->chunk_count, ctx->txn->j->zone, &ch);
+ if (ret == KNOT_EOK) {
+ ret = changeset_merge(mch, ch, 0);
+ changeset_free(ch);
+ }
+ return ret;
+}
+
+static int merge_unflushed_changesets(journal_t *j, txn_t *_txn, changeset_t **mch, bool *merged_bootstrap)
+{
+ reuse_txn(txn, j, _txn, false);
+ txn_check_ret(txn);
+ *mch = NULL;
+ if (md_flushed(txn)) {
+ goto m_u_ch_end;
+ }
+ uint32_t from;
+ txn->ret = load_bootstrap_changeset(j, txn, mch);
+ *merged_bootstrap = (txn->ret == KNOT_EOK);
+ if (txn->ret == KNOT_ENOENT) { // no bootstrap changeset (normal operation)
+ bool was_merged = md_flag(txn, MERGED_SERIAL_VALID);
+ bool was_flushed = md_flag(txn, LAST_FLUSHED_VALID);
+ txn->ret = KNOT_EOK;
+ from = was_merged ? txn->shadow_md.merged_serial :
+ (was_flushed ? txn->shadow_md.last_flushed :
+ txn->shadow_md.first_serial);
+ txn->ret = load_one(j, txn, from, mch);
+ if (!was_merged && was_flushed && txn->ret == KNOT_EOK) {
+ // we have to jump to ONE AFTER last_flushed
+ from = knot_soa_serial((*mch)->soa_to->rrs.rdata);
+ changeset_free(*mch);
+ *mch = NULL;
+ txn->ret = load_one(j, txn, from, mch);
+ }
+ }
+ if (txn->ret != KNOT_EOK) {
+ goto m_u_ch_end;
+ }
+ from = knot_soa_serial((*mch)->soa_to->rrs.rdata);
+
+ if (!serial_equal(from, txn->shadow_md.last_serial_to)) {
+ txn->ret = iterate(j, txn, merge_itercb, JOURNAL_ITERATION_CHANGESETS,
+ mch, from, txn->shadow_md.last_serial, normal_iterkeycb);
+ }
+
+m_u_ch_end:
+ unreuse_txn(txn, _txn);
+ if (txn->ret != KNOT_EOK && *mch != NULL) {
+ changeset_free(*mch);
+ *mch = NULL;
+ }
+ return txn->ret;
+}
+
+dynarray_declare(chunk, knot_db_val_t, DYNARRAY_VISIBILITY_STATIC, 32)
+dynarray_define(chunk, knot_db_val_t, DYNARRAY_VISIBILITY_STATIC)
+
+// uses local context, e.g.: j, txn, changesets, nchs, serialized_size_total, store_changeset_cleanup, inserting_merged
+#define try_flush \
+ if (!md_flushed(txn)) { \
+ if (journal_merge_allowed(j)) { \
+ changeset_t *merged; \
+ merge_unflushed_changesets(j, txn, &merged, &merged_into_bootstrap); \
+ if (txn->ret != KNOT_EOK) { \
+ goto store_changeset_cleanup; \
+ } \
+ add_tail(changesets, &merged->n); \
+ nchs++; \
+ serialized_size_merged += changeset_serialized_size(merged); \
+ md_flush(txn); \
+ inserting_merged = true; \
+ } \
+ else { \
+ txn->ret = KNOT_EBUSY; \
+ goto store_changeset_cleanup; \
+ } \
+ }
+
+static int store_changesets(journal_t *j, list_t *changesets)
+{
+ // PART 1 : initializers, compute serialized_sizes, transaction start
+ changeset_t *ch;
+
+ size_t nchs = 0, inserted_size = 0;
+ size_t serialized_size_changes = 0, serialized_size_merged = 0;
+
+ size_t chunks = 0;
+
+ bool inserting_merged = false;
+ bool merged_into_bootstrap = false;
+ bool inserting_bootstrap = false;
+
+ size_t occupied_last, occupied_now = knot_db_lmdb_get_usage(j->db->db);
+
+ WALK_LIST(ch, *changesets) {
+ nchs++;
+ serialized_size_changes += changeset_serialized_size(ch);
+ if (ch->soa_from == NULL) {
+ inserting_bootstrap = true;
+ }
+ }
+
+ local_txn_t(txn, j);
+ txn_begin(txn, true);
+
+ bool zone_in_journal = has_bootstrap_changeset(j, txn);
+ bool merge_allowed = journal_merge_allowed(j);
+
+ // if you're tempted to add dirty_serial deletion somewhere here, you're wrong. Don't do it.
+
+ // PART 2 : recalculating the previous insert's occupy change
+ md_get_common_last_occupied(txn, &occupied_last);
+ md_set(txn, NULL, MDKEY_GLOBAL_LAST_TOTAL_OCCUPIED, occupied_now);
+ if (occupied_now != occupied_last) {
+ knot_dname_t *last_zone = NULL;
+ uint64_t lz_occupied;
+ md_get_common_last_inserter_zone(txn, &last_zone);
+ if (last_zone != NULL) {
+ md_get(txn, last_zone, MDKEY_PERZONE_OCCUPIED, &lz_occupied);
+ lz_occupied = (lz_occupied + occupied_now > occupied_last ?
+ lz_occupied + occupied_now - occupied_last : 0);
+ md_set(txn, last_zone, MDKEY_PERZONE_OCCUPIED, lz_occupied);
+ free(last_zone);
+ }
+ }
+ md_set_common_last_inserter_zone(txn, j->zone);
+
+ // PART 3a : delete all if inserting bootstrap changeset
+ if (inserting_bootstrap) {
+ drop_journal(j, txn);
+ txn_restart(txn);
+ }
+
+ // PART 3b : check if we exceeded designed occupation and delete some
+ uint64_t occupied = 0, occupied_max;
+ md_get(txn, j->zone, MDKEY_PERZONE_OCCUPIED, &occupied);
+ occupied_max = journal_max_usage(j);
+ occupied += serialized_size_changes;
+ if (occupied > occupied_max) {
+ size_t freed;
+ size_t tofree = (occupied - occupied_max) * journal_tofree_factor(j);
+ size_t free_min = tofree * journal_minfree_factor(j);
+ delete_tofree(j, txn, tofree, &freed);
+ if (freed < free_min) {
+ tofree -= freed;
+ free_min -= freed;
+ try_flush
+ tofree += serialized_size_merged;
+ delete_tofree(j, txn, tofree, &freed);
+ if (freed < free_min) {
+ txn->ret = KNOT_ESPACE;
+ log_zone_warning(j->zone, "journal, unable to make free space for insert, "
+ "required: %"PRIu64", max: %"PRIu64,
+ occupied, occupied_max);
+ goto store_changeset_cleanup;
+ }
+ }
+ }
+
+ // PART 3c : check if we exceeded history depth
+ long over_limit = (long)txn->shadow_md.changeset_count - journal_max_changesets(j) +
+ list_size(changesets) - (inserting_merged ? 1 : 0);
+ if (zone_in_journal && over_limit > 0 && !merge_allowed) {
+ txn->ret = KNOT_ESPACE;
+ log_zone_warning(j->zone, "journal, unable to make free slot for insert");
+ goto store_changeset_cleanup;
+ } else if (over_limit > 0) {
+ size_t deled;
+ delete_count(j, txn, over_limit, &deled);
+ over_limit -= deled;
+ if (over_limit > 0) {
+ try_flush
+ delete_count(j, txn, over_limit, &deled);
+ // ignore further errors here, the limit is not so important
+ }
+ }
+
+ // PART 4: continuity and duplicity check
+ changeset_t * chs_head = (HEAD(*changesets));
+ bool is_first_bootstrap = (chs_head->soa_from == NULL);
+ uint32_t serial = is_first_bootstrap ? 0 : knot_soa_serial(chs_head->soa_from->rrs.rdata);
+ if (md_flag(txn, SERIAL_TO_VALID) && (is_first_bootstrap ||
+ !serial_equal(txn->shadow_md.last_serial_to, serial)) &&
+ !inserting_bootstrap /* if inserting bootstrap, drop_journal() was called, so no discontinuity */) {
+ log_zone_warning(j->zone, "journal, discontinuity in changes history (%u -> %u), dropping older changesets",
+ txn->shadow_md.last_serial_to, serial);
+ if (zone_in_journal) {
+ txn->ret = KNOT_ERANGE; // we can't drop history if zone-in-journal, so this is forbidden
+ goto store_changeset_cleanup;
+ } else if (merge_allowed) {
+ // flush would only merge and drop would delete the merge, so skip it
+ } else {
+ try_flush
+ }
+ drop_journal(j, txn);
+ txn_restart(txn);
+ }
+ WALK_LIST(ch, *changesets) {
+ uint32_t serial_to = knot_soa_serial(ch->soa_to->rrs.rdata);
+ bool is_this_bootstrap = (ch->soa_from == NULL);
+ bool is_this_merged = (inserting_merged && ch == TAIL(*changesets));
+ if (is_this_bootstrap || is_this_merged) {
+ continue;
+ }
+ txn_key_2u32(txn, j->zone, serial_to, 0);
+ if (txn_find(txn)) {
+ log_zone_warning(j->zone, "journal, duplicate changeset serial (%u), dropping older changesets",
+ serial_to);
+ if (zone_in_journal) {
+ if (merge_allowed) {
+ try_flush // merge will get rid of the duplicity => OK
+ } else {
+ txn->ret = KNOT_EEXIST; // we can't fix it in this case, refuse to do it
+ goto store_changeset_cleanup;
+ }
+ } else {
+ try_flush
+ }
+ delete_upto(j, txn, txn->shadow_md.first_serial, serial_to);
+ txn_restart(txn);
+ }
+ }
+
+ // PART 5: serializing into lmdb
+ WALK_LIST(ch, *changesets) {
+ if (txn->ret != KNOT_EOK) {
+ break;
+ }
+
+ chunk_dynarray_t dchunks = { 0 };
+ chunks = 0;
+
+ serialize_ctx_t *sctx = serialize_init(ch);
+ if (sctx == NULL) {
+ txn->ret = KNOT_ENOMEM;
+ break;
+ }
+
+ bool is_this_merged = (inserting_merged && ch == TAIL(*changesets));
+ bool is_this_bootstrap = (ch->soa_from == NULL);
+ uint32_t serial = is_this_bootstrap ? 0 : knot_soa_serial(ch->soa_from->rrs.rdata);
+ uint32_t serial_to = knot_soa_serial(ch->soa_to->rrs.rdata);
+
+ while (serialize_unfinished(sctx)) {
+ size_t chunk_size;
+ serialize_prepare(sctx, CHUNK_MAX - JOURNAL_HEADER_SIZE, &chunk_size);
+ if (chunk_size == 0) {
+ break;
+ }
+
+ inserted_size += chunk_size;
+
+ if (is_this_bootstrap) {
+ txn_key_str_u32(txn, j->zone, KEY_BOOTSTRAP_CHANGESET, chunks);
+ } else {
+ txn_key_2u32(txn, j->zone, serial, chunks);
+ }
+
+ txn->val.data = NULL;
+ txn->val.len = chunk_size + JOURNAL_HEADER_SIZE;
+
+ txn_insert(txn);
+ if (txn->ret != KNOT_EOK) break;
+
+ chunk_dynarray_add(&dchunks, &txn->val);
+
+ chunks++;
+
+ serialize_chunk(sctx, txn->val.data + JOURNAL_HEADER_SIZE, chunk_size);
+ }
+
+ serialize_deinit(sctx);
+
+ dynarray_foreach(chunk, knot_db_val_t, val, dchunks) {
+ make_header(val, serial_to, chunks);
+ }
+ chunk_dynarray_free(&dchunks);
+
+ // PART 7: metadata update
+ if (txn->ret != KNOT_EOK) {
+ break;
+ }
+ if (is_this_merged && !merged_into_bootstrap) {
+ txn->shadow_md.flags |= MERGED_SERIAL_VALID;
+ txn->shadow_md.merged_serial = serial;
+ }
+ else if (is_this_bootstrap) {
+ if (!md_flag(txn, SERIAL_TO_VALID) || !is_this_merged) {
+ txn->shadow_md.flags |= FIRST_SERIAL_INVALID;
+ txn->shadow_md.last_serial_to = serial_to;
+ }
+ txn->shadow_md.flags |= SERIAL_TO_VALID;
+ } else {
+ if (!md_flag(txn, SERIAL_TO_VALID) || md_flag(txn, FIRST_SERIAL_INVALID)) {
+ txn->shadow_md.first_serial = serial;
+ }
+ txn->shadow_md.flags &= ~FIRST_SERIAL_INVALID;
+ txn->shadow_md.flags |= SERIAL_TO_VALID;
+ txn->shadow_md.last_serial = serial;
+ txn->shadow_md.last_serial_to = serial_to;
+ txn->shadow_md.changeset_count++;
+ }
+ }
+
+ // PART X : finalization and cleanup
+
+store_changeset_cleanup:
+
+ txn_commit(txn);
+
+ if (txn->ret != KNOT_EOK) {
+ local_txn_t(ddtxn, j);
+ txn_begin(ddtxn, true);
+ if (md_flag(ddtxn, DIRTY_SERIAL_VALID)) {
+ delete_dirty_serial(j, ddtxn);
+ }
+ txn_commit(ddtxn);
+ }
+
+ changeset_t *dbgchst = TAIL(*changesets);
+
+ if (inserting_merged) {
+ // free the merged changeset
+ rem_node(&dbgchst->n);
+ changeset_free(dbgchst);
+ }
+
+ return txn->ret;
+}
+#undef try_flush
+
+int journal_store_changeset(journal_t *journal, changeset_t *ch)
+{
+ if (journal == NULL || journal->db == NULL || ch == NULL) return KNOT_EINVAL;
+
+ changeset_t *ch_shallowcopy = malloc(sizeof(changeset_t));
+ if (ch_shallowcopy == NULL) {
+ return KNOT_ENOMEM;
+ }
+ memcpy(ch_shallowcopy, ch, sizeof(changeset_t)); // we need to copy the changeset_t structure not to break ch->n
+
+ list_t list;
+ init_list(&list);
+ add_tail(&list, &ch_shallowcopy->n);
+ int ret = store_changesets(journal, &list);
+
+ free(ch_shallowcopy);
+ return ret;
+}
+
+int journal_store_changesets(journal_t *journal, list_t *src)
+{
+ if (journal == NULL || journal->db == NULL || src == NULL) return KNOT_EINVAL;
+ return store_changesets(journal, src);
+}
+
+/*
+ * **************************** PART VII ******************************
+ *
+ * Journal initialization and global manipulation
+ *
+ * ********************************************************************
+ */
+
+journal_t *journal_new()
+{
+ return calloc(1, sizeof(journal_t));
+}
+
+void journal_free(journal_t **journal)
+{
+ if (journal == NULL || *journal == NULL) return;
+
+ if ((*journal)->zone != NULL) {
+ free((knot_dname_t *)(*journal)->zone);
+ }
+ free(*journal);
+ *journal = NULL;
+}
+
+static int open_journal_db_unsafe(journal_db_t **db)
+{
+ if ((*db)->db != NULL) return KNOT_EOK;
+
+ struct knot_db_lmdb_opts opts = KNOT_DB_LMDB_OPTS_INITIALIZER;
+ opts.path = (*db)->path;
+ opts.mapsize = (*db)->fslimit;
+ opts.maxdbs = 1;
+ opts.maxreaders = JOURNAL_MAX_READERS;
+ opts.flags.env = ((*db)->mode == JOURNAL_MODE_ASYNC ?
+ KNOT_DB_LMDB_WRITEMAP | KNOT_DB_LMDB_MAPASYNC : 0);
+ opts.flags.env |= KNOT_DB_LMDB_NOTLS;
+
+ int ret = (*db)->db_api->init(&(*db)->db, NULL, &opts);
+ if (ret != KNOT_EOK) {
+ (*db)->db = NULL;
+ return ret;
+ }
+
+ size_t real_fslimit = knot_db_lmdb_get_mapsize((*db)->db);
+ (*db)->fslimit = real_fslimit;
+
+ return KNOT_EOK;
+}
+
+int journal_open_db(journal_db_t **db)
+{
+ if (*db == NULL) return KNOT_EINVAL;
+ pthread_mutex_lock(&(*db)->db_mutex);
+ int ret = open_journal_db_unsafe(db);
+ pthread_mutex_unlock(&(*db)->db_mutex);
+ return ret;
+}
+
+int journal_open(journal_t *journal, journal_db_t **db, const knot_dname_t *zone_name)
+{
+ int ret = KNOT_EOK;
+
+ if (journal == NULL || (*db) == NULL) return KNOT_EINVAL;
+ if (journal->db != NULL) {
+ return KNOT_EOK;
+ }
+
+ // open shared journal DB if not already
+ if ((*db)->db == NULL) {
+ ret = journal_open_db(db);
+ }
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ journal->db = *db;
+
+ journal->zone = knot_dname_copy(zone_name, NULL);
+ if (journal->zone == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ bool dirty_serial_valid;
+ ret = initial_md_check(journal, &dirty_serial_valid);
+
+ if (ret == KNOT_EOK && dirty_serial_valid) {
+ delete_dirty_serial(journal, NULL);
+ }
+
+ return ret;
+}
+
+void journal_close(journal_t *journal)
+{
+ journal->db = NULL;
+ free(journal->zone);
+ journal->zone = NULL;
+}
+
+int journal_db_init(journal_db_t **db, const char *lmdb_dir_path, size_t lmdb_fslimit,
+ journal_mode_t mode)
+{
+ if (*db != NULL) {
+ return KNOT_EOK;
+ }
+ *db = malloc(sizeof(journal_db_t));
+ if (*db == NULL) {
+ return KNOT_ENOMEM;
+ }
+ journal_db_t dbinit = {
+ .db = NULL,
+ .db_api = knot_db_lmdb_api(),
+ .path = strdup(lmdb_dir_path),
+ .fslimit = ((lmdb_fslimit < JOURNAL_MIN_FSLIMIT) ? JOURNAL_MIN_FSLIMIT : lmdb_fslimit),
+ .mode = mode,
+ };
+ memcpy(*db, &dbinit, sizeof(journal_db_t));
+ pthread_mutex_init(&(*db)->db_mutex, NULL);
+ return KNOT_EOK;
+}
+
+static void destroy_journal_db(journal_db_t **db)
+{
+ assert((*db)->db == NULL);
+
+ pthread_mutex_destroy(&(*db)->db_mutex);
+ free((*db)->path);
+ free((*db));
+ *db = NULL;
+}
+
+void journal_db_close(journal_db_t **db)
+{
+ if (db == NULL || *db == NULL) {
+ return;
+ }
+
+ pthread_mutex_lock(&(*db)->db_mutex);
+ if ((*db)->db != NULL) {
+ (*db)->db_api->deinit((*db)->db);
+ (*db)->db = NULL;
+ }
+ pthread_mutex_unlock(&(*db)->db_mutex);
+
+ destroy_journal_db(db);
+}
+
+int journal_flush(journal_t *journal)
+{
+ if (journal == NULL || journal->db == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ local_txn_t(txn, journal);
+ txn_begin(txn, true);
+ md_flush(txn);
+ txn_commit(txn);
+ return txn->ret;
+}
+
+bool journal_exists(journal_db_t **db, knot_dname_t *zone_name)
+{
+ if (db == NULL || *db == NULL || zone_name == NULL) {
+ return false;
+ }
+
+ if ((*db)->db == NULL) {
+ struct stat st;
+ if (stat((*db)->path, &st) != 0 || st.st_size == 0) {
+ return false;
+ }
+ int ret = journal_open_db(db);
+ if (ret != KNOT_EOK) {
+ return false;
+ }
+ }
+
+ journal_t fake_journal = { .db = *db, .zone = zone_name };
+ local_txn_t(txn, &fake_journal);
+ txn_begin(txn, false);
+ txn_key_str(txn, zone_name, MDKEY_PERZONE_FLAGS);
+ bool res = txn_find(txn);
+ txn_abort(txn);
+
+ return res;
+}
+
+static knot_db_val_t *dbval_copy(const knot_db_val_t *from)
+{
+ knot_db_val_t *to = malloc(sizeof(knot_db_val_t) + from->len);
+ if (to != NULL) {
+ memcpy(to, from, sizeof(knot_db_val_t));
+ to->data = to + 1; // == ((uit8_t *)to) + sizeof(knot_db_val_t)
+ memcpy(to->data, from->data, from->len);
+ }
+ return to;
+} // TODO think of moving this fun into different place/lib
+
+int journal_scrape(journal_t *j)
+{
+ if (j->db == NULL) return KNOT_EINVAL;
+ local_txn_t(txn, j);
+ txn_begin(txn, true);
+ txn_check_ret(txn);
+
+ knot_db_val_t key = { .len = 0, .data = "" };
+
+ list_t to_del;
+ init_list(&to_del);
+
+ txn_iter_begin(txn);
+ while (txn->ret == KNOT_EOK && txn->iter != NULL) {
+ txn_iter_key(txn, &key);
+ if (knot_dname_is_equal((const knot_dname_t *) key.data, j->zone)
+ && key_is_ok(&key, true)) {
+ knot_db_val_t * inskey = dbval_copy(&key);
+ if (inskey == NULL) {
+ txn->ret = KNOT_ENOMEM;
+ goto scrape_end;
+ }
+ ptrlist_add(&to_del, inskey, NULL);
+ }
+ txn_iter_next(txn);
+ }
+ if (txn->ret == KNOT_ENOENT) {
+ txn->ret = KNOT_EOK;
+ }
+ txn_iter_finish(txn);
+
+ ptrnode_t *del_one;
+ if (txn->ret == KNOT_EOK) {
+ WALK_LIST(del_one, to_del) {
+ txn->ret = j->db->db_api->del(txn->txn, (knot_db_val_t *)del_one->d);
+ }
+ if (!EMPTY_LIST(to_del)) {
+ md_update_journal_count(txn, -1);
+ }
+
+ md_del_last_inserter_zone(txn, j->zone);
+
+ txn->ret = j->db->db_api->txn_commit(txn->txn);
+ }
+scrape_end:
+ ptrlist_deep_free(&to_del, NULL);
+
+ return txn->ret;
+}
+
+void journal_metadata_info(journal_t *j, bool *has_bootstrap, kserial_t *merged_serial,
+ kserial_t *first_serial, kserial_t *last_flushed, kserial_t *serial_to,
+ uint64_t *occupied, uint64_t *occupied_all_zones)
+{
+ // NOTE: there is NEVER the situation that only merged changeset would be present and no common changeset in db.
+
+ if (j == NULL || j->db == NULL) {
+ if (has_bootstrap != NULL) {
+ *has_bootstrap = false;
+ }
+ if (merged_serial != NULL) {
+ merged_serial->valid = false;
+ }
+ if (first_serial != NULL) {
+ first_serial->valid = false;
+ }
+ if (last_flushed != NULL) {
+ last_flushed->valid = false;
+ }
+ if (serial_to != NULL) {
+ serial_to->valid = false;
+ }
+ if (occupied != NULL) {
+ *occupied = 0;
+ }
+ return;
+ }
+
+ uint64_t occupied_total = knot_db_lmdb_get_usage(j->db->db);
+
+ local_txn_t(txn, j);
+ txn_begin(txn, false);
+ txn_check_open(txn);
+
+ if (has_bootstrap != NULL) {
+ *has_bootstrap = has_bootstrap_changeset(j, txn);
+ }
+ if (merged_serial != NULL) {
+ merged_serial->valid = md_flag(txn, MERGED_SERIAL_VALID);
+ merged_serial->serial = txn->shadow_md.merged_serial;
+ }
+ if (first_serial != NULL) {
+ first_serial->valid = !md_flag(txn, FIRST_SERIAL_INVALID);
+ first_serial->serial = txn->shadow_md.first_serial;
+ }
+ if (last_flushed != NULL) {
+ last_flushed->valid = md_flag(txn, LAST_FLUSHED_VALID);
+ last_flushed->serial = txn->shadow_md.last_flushed;
+ }
+ if (serial_to != NULL) {
+ serial_to->valid = md_flag(txn, SERIAL_TO_VALID);
+ serial_to->serial = txn->shadow_md.last_serial_to;
+ }
+ if (occupied != NULL) {
+ md_get(txn, j->zone, MDKEY_PERZONE_OCCUPIED, occupied);
+ knot_dname_t *last_inserter = NULL;
+ md_get_common_last_inserter_zone(txn, &last_inserter);
+ if (last_inserter != NULL && knot_dname_is_equal(last_inserter, j->zone)) {
+ size_t lz_occupied;
+ md_get_common_last_occupied(txn, &lz_occupied);
+ *occupied += occupied_total - lz_occupied;
+ }
+ free(last_inserter);
+ }
+ if (occupied_all_zones != NULL) {
+ *occupied_all_zones = occupied_total;
+ }
+
+ txn_abort(txn);
+}
+
+int journal_drop_changesets(journal_t *journal)
+{
+ return drop_journal(journal, NULL);
+}
+
+int journal_db_list_zones(journal_db_t **db, list_t *zones)
+{
+ uint64_t expected_count;
+
+ if (list_size(zones) > 0) {
+ return KNOT_EINVAL;
+ }
+
+ if ((*db)->db == NULL) {
+ int ret = journal_open_db(db);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ journal_t fake_journal = { .db = *db, .zone = (knot_dname_t *)"" };
+ local_txn_t(txn, &fake_journal);
+ txn_begin(txn, false);
+ md_get(txn, NULL, MDKEY_GLOBAL_JOURNAL_COUNT, &expected_count);
+ txn_check_ret(txn);
+
+ knot_db_val_t key;
+ txn_iter_begin(txn);
+ while (txn->ret == KNOT_EOK && txn->iter != NULL) {
+ txn_iter_key(txn, &key);
+
+ int metaflag_len = strlen(MDKEY_PERZONE_FLAGS);
+ char *compare_metaflag = key.data;
+ compare_metaflag += key.len - 1;
+ if (txn->ret == KNOT_EOK && *compare_metaflag == '\0') {
+ compare_metaflag -= metaflag_len;
+ if (strcmp(compare_metaflag, MDKEY_PERZONE_FLAGS) == 0) {
+ knot_dname_t *found_zone = knot_dname_copy((const knot_dname_t *)key.data, NULL);
+ if (found_zone == NULL) {
+ txn->ret = KNOT_ENOMEM;
+ break;
+ }
+ ptrlist_add(zones, found_zone, NULL);
+ }
+ }
+ txn_iter_next(txn);
+ }
+ if (txn->ret == KNOT_ENOENT) {
+ txn->ret = KNOT_EOK;
+ }
+ txn_iter_finish(txn);
+ txn_abort(txn);
+ if (list_size(zones) < 1) {
+ txn->ret = KNOT_ENOENT;
+ }
+ return txn->ret;
+}
+
+/*
+ * *************************** PART VIII ******************************
+ *
+ * Journal check
+ *
+ * ********************************************************************
+ */
+
+static void _jch_print(const knot_dname_t *zname, int warn_level, const char *format, ...)
+{
+ char buf[512] = "journal check: ";
+ char *zname_ch = NULL;
+
+ va_list args;
+ va_start(args, format);
+ vsprintf(buf + strlen(buf), format, args);
+ va_end(args);
+
+ switch (warn_level) {
+ case JOURNAL_CHECK_STDERR:
+ zname_ch = knot_dname_to_str_alloc(zname);
+ fprintf(stderr, "[%s] %s\n", zname_ch, buf);
+ free(zname_ch);
+ break;
+ case JOURNAL_CHECK_INFO:
+ log_zone_info(zname, "%s", buf);
+ break;
+ case JOURNAL_CHECK_WARN:
+ log_zone_error(zname, "%s", buf);
+ break;
+ default:
+ break;
+ }
+}
+
+#define jch_print(wl, fmt_args...) if ((wl) <= warn_level) _jch_print(j->zone, warn_level, fmt_args)
+#define jch_info(fmt_args...) jch_print(JOURNAL_CHECK_INFO, fmt_args)
+#define jch_warn(fmt_args...) jch_print((allok = 0, JOURNAL_CHECK_WARN), fmt_args)
+#define jch_txn(comment, fatal) do { if (txn->ret != KNOT_EOK) { \
+ jch_warn("failed transaction: %s (%s)", (comment), knot_strerror(txn->ret)); \
+ if (fatal) return txn->ret; } } while (0)
+
+int journal_check(journal_t *j, journal_check_level_t warn_level)
+{
+ int ret, allok = 1;
+ changeset_t *ch = NULL;
+ uint32_t sfrom, sto;
+ uint32_t first_unflushed;
+ uint32_t chcount;
+
+ jch_info("started");
+
+ if (j->db == NULL) {
+ jch_warn("is not open");
+ return KNOT_ESEMCHECK;
+ }
+
+ local_txn_t(txn, j);
+ txn_begin(txn, true);
+ jch_txn("begin", true);
+
+ jch_info("metadata: flags >> %d << fs %u ls %u lst %u lf %u ms %u ds %u cnt %u",
+ txn->shadow_md.flags, txn->shadow_md.first_serial, txn->shadow_md.last_serial,
+ txn->shadow_md.last_serial_to, txn->shadow_md.last_flushed, txn->shadow_md.merged_serial,
+ txn->shadow_md.dirty_serial, txn->shadow_md.changeset_count);
+
+ chcount = txn->shadow_md.changeset_count;
+ first_unflushed = txn->shadow_md.first_serial;
+
+ if (md_flag(txn, DIRTY_SERIAL_VALID)) {
+ jch_warn("there is some post-crash mess in the DB");
+ }
+
+ if (!md_flag(txn, SERIAL_TO_VALID)) {
+ if (md_flag(txn, LAST_FLUSHED_VALID)) {
+ jch_warn("journal flagged empty but last_flushed valid");
+ }
+ if (md_flag(txn, MERGED_SERIAL_VALID)) {
+ jch_warn("no other than merged changeset present, this should not happen");
+ }
+ goto check_merged;
+ }
+
+ if (md_flag(txn, FIRST_SERIAL_INVALID)) {
+ jch_info("there is just the bootstrap changeset in journal");
+ ret = load_bootstrap_changeset(j, txn, &ch);
+ if (ret != KNOT_EOK) {
+ jch_warn("can't read bootstrap changeset (%s)", knot_strerror(ret));
+ } else {
+ changeset_free(ch);
+ }
+ goto check_merged;
+ } else {
+ ret = load_bootstrap_changeset(j, txn, &ch);
+ switch (ret) {
+ case KNOT_EOK:
+ sto = knot_soa_serial(ch->soa_to->rrs.rdata);
+ jch_info("bootstrap changeset loaded, sto %u", sto);
+ changeset_free(ch);
+ break;
+ case KNOT_ENOENT:
+ txn->ret = KNOT_EOK;
+ break;
+ default:
+ jch_info("failed to read bootstrap changeset (%s)", knot_strerror(ret));
+ break;
+ }
+ }
+
+ ret = load_one(j, txn, txn->shadow_md.first_serial, &ch);
+ if (ret != KNOT_EOK) {
+ jch_warn("can't read first changeset %u (%s)",
+ txn->shadow_md.first_serial, knot_strerror(ret));
+ goto check_merged;
+ }
+
+ sfrom = knot_soa_serial(ch->soa_from->rrs.rdata), sto = knot_soa_serial(ch->soa_to->rrs.rdata);
+ if (!serial_equal(txn->shadow_md.first_serial, sfrom)) {
+ jch_warn("first changeset's serial 'from' %u is not ok", sfrom);
+ }
+
+ if (md_flag(txn, LAST_FLUSHED_VALID)) {
+ changeset_free(ch);
+ ret = load_one(j, txn, txn->shadow_md.last_flushed, &ch);
+ if (ret != KNOT_EOK) {
+ jch_warn("can't read last flushed changeset %u (%s)",
+ txn->shadow_md.last_flushed, knot_strerror(ret));
+ } else {
+ first_unflushed = knot_soa_serial(ch->soa_to->rrs.rdata);
+ }
+ }
+ if (ret == KNOT_EOK) {
+ changeset_free(ch);
+ }
+
+ if (serial_equal(txn->shadow_md.last_serial_to, sto)) {
+ jch_info("there is just one changeset in the journal");
+ goto check_merged;
+ }
+ ret = load_one(j, txn, sto, &ch);
+ if (ret != KNOT_EOK) {
+ jch_warn("can't read second changeset %u (%s)", sto, knot_strerror(ret));
+ } else {
+ sfrom = knot_soa_serial(ch->soa_from->rrs.rdata);
+ if (!serial_equal(sfrom, sto)) {
+ jch_warn("second changeset's serial 'from' %u is not ok", sfrom);
+ }
+ changeset_free(ch);
+ }
+
+ sfrom = txn->shadow_md.first_serial;
+ sto = txn->shadow_md.last_serial_to;
+ txn_commit(txn);
+ jch_txn("commit", true);
+
+ list_t l;
+ init_list(&l);
+ ret = journal_load_changesets(j, &l, sfrom);
+ if (ret != KNOT_EOK) {
+ jch_warn("can't read all changesets %u -> %u (%s)", sfrom, sto, knot_strerror(ret));
+ goto check_merged;
+ }
+ jch_info("listed %zu changesets", list_size(&l));
+ if (list_size(&l) != chcount) {
+ jch_warn("expected %u changesets but found %zu", chcount, list_size(&l));
+ }
+
+ ch = HEAD(l);
+ if (!serial_equal(sfrom, knot_soa_serial(ch->soa_from->rrs.rdata))) {
+ jch_warn("first listed changeset's serial 'from' %u is not ok",
+ knot_soa_serial(ch->soa_from->rrs.rdata));
+ }
+ ch = TAIL(l);
+ if (!serial_equal(sto, knot_soa_serial(ch->soa_to->rrs.rdata))) {
+ jch_warn("last listed changeset's serial 'to' %u is not ok",
+ knot_soa_serial(ch->soa_to->rrs.rdata));
+ }
+ changesets_free(&l);
+
+check_merged:
+ if (txn->opened) txn_abort(txn);
+ txn_begin(txn, false);
+ jch_txn("begin2", true);
+ if (md_flag(txn, MERGED_SERIAL_VALID)) {
+ ch = NULL;
+ ret = load_merged_changeset(j, txn, &ch, NULL);
+ if (ret != KNOT_EOK) {
+ jch_warn("can't read merged changeset (%s)", knot_strerror(ret));
+ } else {
+ sfrom = knot_soa_serial(ch->soa_from->rrs.rdata);
+ sto = knot_soa_serial(ch->soa_to->rrs.rdata);
+ jch_info("merged changeset %u -> %u (size %zu)", sfrom, sto,
+ changeset_serialized_size(ch));
+ if (!serial_equal(sfrom, txn->shadow_md.merged_serial)) {
+ jch_warn("merged changeset's serial 'from' is not ok");
+ }
+ if (!serial_equal(sto, first_unflushed)) {
+ jch_warn("merged changeset's serial 'to' is not ok");
+ }
+ changeset_free(ch);
+ }
+ }
+ txn_commit(txn);
+ jch_txn("commit2", true);
+
+ if (allok) {
+ jch_info("passed without errors");
+ }
+
+ return (allok ? KNOT_EOK : KNOT_ERROR);
+}
diff --git a/src/knot/journal/journal.h b/src/knot/journal/journal.h
new file mode 100644
index 0000000..113fd71
--- /dev/null
+++ b/src/knot/journal/journal.h
@@ -0,0 +1,244 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <pthread.h>
+
+#include "libknot/db/db.h"
+#include "contrib/ucw/lists.h"
+#include "knot/updates/changesets.h"
+#include "knot/journal/serialization.h"
+#include "knot/journal/chgset_ctx.h"
+#include "knot/zone/serial.h"
+
+/*! \brief Minimum journal size. */
+#define JOURNAL_MIN_FSLIMIT (1 * 1024 * 1024)
+
+typedef enum {
+ JOURNAL_MODE_ROBUST = 0, // Robust journal DB disk synchronization.
+ JOURNAL_MODE_ASYNC = 1, // Asynchronous journal DB disk synchronization.
+} journal_mode_t;
+
+typedef struct {
+ knot_db_t *db;
+ const knot_db_api_t *db_api;
+ char *path;
+ size_t fslimit;
+ journal_mode_t mode;
+ pthread_mutex_t db_mutex; // please delete this once you move DB opening from journal_open to db_init
+} journal_db_t;
+
+typedef struct {
+ journal_db_t *db;
+ knot_dname_t *zone;
+} journal_t;
+
+typedef enum {
+ JOURNAL_CHECK_SILENT = 0, // No logging, just curious for return value.
+ JOURNAL_CHECK_WARN = 1, // Log journal inconsistencies.
+ JOURNAL_CHECK_INFO = 2, // Log journal state.
+ JOURNAL_CHECK_STDERR = 3, // Log everything and redirect to stderr.
+} journal_check_level_t;
+
+struct journal_txn;
+
+/*!
+ * \brief Initialize shared journal DB file. The DB will be open on first use.
+ *
+ * \param db Database to be initialized. Must be (*db == NULL) before!
+ * \param lmdb_dir_path Path to the directory with DB
+ * \param lmdb_fslimit Maximum size of DB data file
+ * \param mode Journal DB synchronization mode.
+ *
+ * \return KNOT_E*
+ */
+int journal_db_init(journal_db_t **db, const char *lmdb_dir_path, size_t lmdb_fslimit,
+ journal_mode_t mode);
+
+/*!
+ * \brief Close shared journal DB file.
+ *
+ * \param db DB to close.
+ */
+void journal_db_close(journal_db_t **db);
+
+/*!
+ * \brief List the zones contained in journal DB.
+ *
+ * \param[in] db Shared journal DB
+ * \param[out] zones List of strings (char *) of zone names
+ *
+ * \return KNOT_EOK ok
+ * \retval KNOT_ENOMEM no zones found
+ * \retval KNOT_EMALF different # of zones found than expected
+ * \retval KNOT_E* other error
+ */
+int journal_db_list_zones(journal_db_t **db, list_t *zones);
+
+/*!
+ * \brief Allocate a new journal structure.
+ *
+ * \retval new journal instance if successful.
+ * \retval NULL on error.
+ */
+journal_t *journal_new(void);
+
+/*!
+ * \brief Free a journal structure.
+ *
+ * \param journal A journal structure to free.
+ */
+void journal_free(journal_t **journal);
+
+/*!
+ * \brief Open/create the journal based on the filesystem path to LMDB directory
+ *
+ * \param journal Journal struct to use.
+ * \param db Shared journal database.
+ * \param zone_name Name of the zone this journal belongs to.
+ *
+ * \retval KNOT_EOK on success.
+ * \return < KNOT_EOK on other errors.
+ */
+int journal_open(journal_t *journal, journal_db_t **db,
+ const knot_dname_t *zone_name);
+
+/*!
+ * \brief Close journal.
+ *
+ * \param journal Journal to close.
+ */
+void journal_close(journal_t *journal);
+
+/*!
+ * \brief Load changesets from journal since "from" serial.
+ *
+ * \param journal Journal to load from.
+ * \param dst Store changesets here.
+ * \param from Start serial.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_ENOENT when the lookup of the first entry fails.
+ * \return < KNOT_EOK on other error.
+ */
+int journal_load_changesets(journal_t *journal, list_t *dst, uint32_t from);
+
+int journal_load_chgset_ctx(journal_t *j, chgset_ctx_list_t *dst, uint32_t from);
+
+/*!
+ * \brief Load changesets from journal, starting with bootstrap changeset.
+ *
+ * \param journal Journal to load from.
+ * \param dst Store changesets here, starting with bootstrap changeset.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_ENOENT when there is no bootstrap changeset.
+ * \return < KNOT_EOK on other error.
+ */
+int journal_load_bootstrap(journal_t *journal, list_t *dst);
+
+/*!
+ * \brief Store changesets in journal.
+ *
+ * \param journal Journal to store in.
+ * \param src Changesets to store.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_EBUSY when full, asking zone to flush itself to zonefile
+ * to allow cleaning up history and freeing up space
+ * \retval KNOT_ESPACE when full and not able to free up any space
+ * \return < KNOT_EOK on other errors.
+ */
+int journal_store_changesets(journal_t *journal, list_t *src);
+
+/*!
+ * \brief Store changesets in journal.
+ *
+ * \param journal Journal to store in.
+ * \param change Changeset to store.
+ *
+ * \retval (same as for journal_store_changesets())
+ */
+int journal_store_changeset(journal_t *journal, changeset_t *change);
+
+/*!
+ * \brief Open the journal database.
+ *
+ * This is an "almost static" function, which is mostly called by other journal
+ * methods like journal_open() and journal_exists(). However it can be called
+ * separately just for more precise error resolution.
+ *
+ * \param db Journal to be opened.
+ * \return KNOT_E*
+ */
+int journal_open_db(journal_db_t **db);
+
+/*!
+ * \brief Check if this (zone's) journal is present in shared journal DB.
+ *
+ * \param db Shared journal DB
+ * \param zone_name Name of the zone of the journal in question
+ *
+ * \return true or false
+ */
+bool journal_exists(journal_db_t **db, knot_dname_t *zone_name);
+
+/*! \brief Tell the journal that zone has been flushed.
+ *
+ * \param journal Journal to flush.
+ *
+ * \return KNOT_E*
+ */
+int journal_flush(journal_t *journal);
+
+/*! \brief Remove completely this (zone's) journal from shared journal DB.
+ *
+ * This must be called with opened journal.
+ *
+ * \param journal Journal to be deleted
+ *
+ * \return KNOT_E*
+ */
+int journal_scrape(journal_t *journal);
+
+/*! \brief Obtain public information from journal metadata
+ */
+void journal_metadata_info(journal_t *journal, bool *is_empty, kserial_t *merged_serial,
+ kserial_t *first_serial, kserial_t *last_flushed,
+ kserial_t *serial_to, uint64_t *occupied, uint64_t *occupied_all_zones);
+
+/*!
+ * \brief Delete all changesets in zone's journal, keeping metadata.
+ *
+ * \param journal Journal to clear.
+ *
+ * \return KNOT_E*
+ */
+int journal_drop_changesets(journal_t *journal);
+
+/*! \brief Check the journal consistency, errors to stderr.
+ *
+ * \param journal Journal to check.
+ * \param warn_level Journal check level.
+ *
+ * \return KNOT_E*
+ */
+int journal_check(journal_t *journal, journal_check_level_t warn_level);
+
+void journal_txn_commit(struct journal_txn *txn);
+
+/*! @} */
diff --git a/src/knot/journal/serialization.c b/src/knot/journal/serialization.c
new file mode 100644
index 0000000..75e18a2
--- /dev/null
+++ b/src/knot/journal/serialization.c
@@ -0,0 +1,380 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "knot/journal/serialization.h"
+#include "libknot/libknot.h"
+
+#define SERIALIZE_RRSET_INIT (-1)
+#define SERIALIZE_RRSET_DONE ((1L<<16)+1)
+
+typedef enum {
+ PHASE_SOA_1,
+ PHASE_REM,
+ PHASE_SOA_2,
+ PHASE_ADD,
+ PHASE_END,
+} serialize_phase_t;
+
+#define RRSET_BUF_MAXSIZE 256
+
+struct serialize_ctx {
+ const changeset_t *ch;
+ changeset_iter_t it;
+ serialize_phase_t changeset_phase;
+ long rrset_phase;
+ knot_rrset_t rrset_buf[RRSET_BUF_MAXSIZE];
+ size_t rrset_buf_size;
+};
+
+serialize_ctx_t *serialize_init(const changeset_t *ch)
+{
+ serialize_ctx_t *ctx = calloc(1, sizeof(*ctx));
+ if (ctx == NULL) {
+ return NULL;
+ }
+
+ ctx->ch = ch;
+ ctx->changeset_phase = ch->soa_from != NULL ? PHASE_SOA_1 : PHASE_SOA_2;
+ ctx->rrset_phase = SERIALIZE_RRSET_INIT;
+ ctx->rrset_buf_size = 0;
+
+ return ctx;
+}
+
+static knot_rrset_t get_next_rrset(serialize_ctx_t *ctx)
+{
+ knot_rrset_t res;
+ knot_rrset_init_empty(&res);
+ switch (ctx->changeset_phase) {
+ case PHASE_SOA_1:
+ changeset_iter_rem(&ctx->it, ctx->ch);
+ ctx->changeset_phase = PHASE_REM;
+ return *ctx->ch->soa_from;
+ case PHASE_REM:
+ res = changeset_iter_next(&ctx->it);
+ if (knot_rrset_empty(&res)) {
+ changeset_iter_clear(&ctx->it);
+ changeset_iter_add(&ctx->it, ctx->ch);
+ ctx->changeset_phase = PHASE_ADD;
+ return *ctx->ch->soa_to;
+ }
+ return res;
+ case PHASE_SOA_2:
+ if (ctx->it.node != NULL) {
+ changeset_iter_clear(&ctx->it);
+ }
+ changeset_iter_add(&ctx->it, ctx->ch);
+ ctx->changeset_phase = PHASE_ADD;
+ return *ctx->ch->soa_to;
+ case PHASE_ADD:
+ res = changeset_iter_next(&ctx->it);
+ if (knot_rrset_empty(&res)) {
+ changeset_iter_clear(&ctx->it);
+ ctx->changeset_phase = PHASE_END;
+ }
+ return res;
+ default:
+ return res;
+ }
+}
+
+void serialize_prepare(serialize_ctx_t *ctx, size_t max_size, size_t *realsize)
+{
+ *realsize = 0;
+
+ // check if we are in middle of a rrset
+ if (ctx->rrset_buf_size > 0) {
+ ctx->rrset_buf[0] = ctx->rrset_buf[ctx->rrset_buf_size - 1];
+ ctx->rrset_buf_size = 1;
+ } else {
+ ctx->rrset_buf[0] = get_next_rrset(ctx);
+ if (ctx->changeset_phase == PHASE_END) {
+ ctx->rrset_buf_size = 0;
+ return;
+ }
+ ctx->rrset_buf_size = 1;
+ }
+
+ size_t candidate = 0;
+ long tmp_phase = ctx->rrset_phase;
+ while (1) {
+ if (tmp_phase >= ctx->rrset_buf[ctx->rrset_buf_size - 1].rrs.count) {
+ if (ctx->rrset_buf_size >= RRSET_BUF_MAXSIZE) {
+ return;
+ }
+ ctx->rrset_buf[ctx->rrset_buf_size++] = get_next_rrset(ctx);
+ if (ctx->changeset_phase == PHASE_END) {
+ ctx->rrset_buf_size--;
+ return;
+ }
+ tmp_phase = SERIALIZE_RRSET_INIT;
+ }
+ if (tmp_phase == SERIALIZE_RRSET_INIT) {
+ candidate += 3 * sizeof(uint16_t) +
+ knot_dname_size(ctx->rrset_buf[ctx->rrset_buf_size - 1].owner);
+ } else {
+ candidate += sizeof(uint32_t) + sizeof(uint16_t) +
+ knot_rdataset_at(&ctx->rrset_buf[ctx->rrset_buf_size - 1].rrs, tmp_phase)->len;
+ }
+ if (candidate > max_size) {
+ return;
+ }
+ *realsize = candidate;
+ tmp_phase++;
+ }
+}
+
+void serialize_chunk(serialize_ctx_t *ctx, uint8_t *dst_chunk, size_t chunk_size)
+{
+ wire_ctx_t wire = wire_ctx_init(dst_chunk, chunk_size);
+
+ for (size_t i = 0; ; ) {
+ if (ctx->rrset_phase >= ctx->rrset_buf[i].rrs.count) {
+ if (++i >= ctx->rrset_buf_size) {
+ break;
+ }
+ ctx->rrset_phase = SERIALIZE_RRSET_INIT;
+ }
+ if (ctx->rrset_phase == SERIALIZE_RRSET_INIT) {
+ int size = knot_dname_to_wire(wire.position, ctx->rrset_buf[i].owner,
+ wire_ctx_available(&wire));
+ if (size < 0 || wire_ctx_available(&wire) < size + 3 * sizeof(uint16_t)) {
+ break;
+ }
+ wire_ctx_skip(&wire, size);
+ wire_ctx_write_u16(&wire, ctx->rrset_buf[i].type);
+ wire_ctx_write_u16(&wire, ctx->rrset_buf[i].rclass);
+ wire_ctx_write_u16(&wire, ctx->rrset_buf[i].rrs.count);
+ } else {
+ const knot_rdata_t *rr = knot_rdataset_at(&ctx->rrset_buf[i].rrs,
+ ctx->rrset_phase);
+ assert(rr);
+ uint16_t rdlen = rr->len;
+ if (wire_ctx_available(&wire) < sizeof(uint32_t) + sizeof(uint16_t) + rdlen) {
+ break;
+ }
+ // Compatibility, but one TTL per rrset would be enough.
+ wire_ctx_write_u32(&wire, ctx->rrset_buf[i].ttl);
+ wire_ctx_write_u16(&wire, rdlen);
+ wire_ctx_write(&wire, rr->data, rdlen);
+ }
+ ctx->rrset_phase++;
+ }
+}
+
+bool serialize_unfinished(serialize_ctx_t *ctx)
+{
+ return ctx->changeset_phase < PHASE_END;
+}
+
+void serialize_deinit(serialize_ctx_t *ctx)
+{
+ if (ctx->it.node != NULL) {
+ changeset_iter_clear(&ctx->it);
+ }
+ free(ctx);
+}
+
+static int deserialize_rrset(wire_ctx_t *wire, knot_rrset_t *rrset, long *phase)
+{
+ assert(wire != NULL && rrset != NULL && phase != NULL);
+ assert(*phase >= SERIALIZE_RRSET_INIT && *phase < SERIALIZE_RRSET_DONE);
+
+ if (*phase == SERIALIZE_RRSET_INIT && wire_ctx_available(wire) > 0) {
+ // Read owner, rtype, rclass and RR count.
+ size_t size = knot_dname_size(wire->position);
+ knot_dname_t *owner = knot_dname_copy(wire->position, NULL);
+ if (owner == NULL || wire_ctx_available(wire) < size + 3 * sizeof(uint16_t)) {
+ knot_dname_free(owner, NULL);
+ return KNOT_EMALF;
+ }
+ wire_ctx_skip(wire, size);
+ uint16_t type = wire_ctx_read_u16(wire);
+ uint16_t rclass = wire_ctx_read_u16(wire);
+ uint16_t rrcount = wire_ctx_read_u16(wire);
+ (*phase) = rrcount;
+ if (wire->error != KNOT_EOK) {
+ knot_dname_free(owner, NULL);
+ return wire->error;
+ }
+ knot_rrset_init(rrset, owner, type, rclass, 0);
+ }
+
+ bool first = true;
+ for ( ; *phase > 0 && wire_ctx_available(wire) > 0; (*phase)--) {
+ uint32_t ttl = wire_ctx_read_u32(wire);
+ if (first) {
+ rrset->ttl = ttl;
+ first = false;
+ }
+ uint32_t rdata_size = wire_ctx_read_u16(wire);
+ if (wire->error != KNOT_EOK ||
+ wire_ctx_available(wire) < rdata_size ||
+ knot_rrset_add_rdata(rrset, wire->position, rdata_size,
+ NULL) != KNOT_EOK) {
+ knot_rrset_clear(rrset, NULL);
+ return KNOT_EMALF;
+ }
+ wire_ctx_skip(wire, rdata_size);
+ }
+
+ if (*phase == 0) {
+ *phase = SERIALIZE_RRSET_DONE;
+ }
+ return KNOT_EOK;
+}
+
+int deserialize_rrset_chunks(wire_ctx_t *wire, knot_rrset_t *rrset,
+ uint8_t *src_chunks[], const size_t *chunk_sizes,
+ size_t chunks_count, size_t *cur_chunk)
+{
+ long phase = SERIALIZE_RRSET_INIT;
+ while (1) {
+ int ret = deserialize_rrset(wire, rrset, &phase);
+ if (ret != KNOT_EOK || phase == SERIALIZE_RRSET_DONE) {
+ return ret;
+ }
+ // now the rrset wasn't whole on this chunk
+ if (*cur_chunk >= chunks_count - 1) {
+ return KNOT_EMALF;
+ }
+ if (wire->error != KNOT_EOK) {
+ return wire->error;
+ }
+ (*cur_chunk)++;
+ assert(chunk_sizes[*cur_chunk] > 0);
+ *wire = wire_ctx_init(src_chunks[*cur_chunk], chunk_sizes[*cur_chunk]);
+ }
+}
+
+static uint64_t rrset_binary_size(const knot_rrset_t *rrset)
+{
+ if (rrset == NULL || rrset->rrs.count == 0) {
+ return 0;
+ }
+
+ // Owner size + type + class + RR count.
+ uint64_t size = knot_dname_size(rrset->owner) + 3 * sizeof(uint16_t);
+
+ // RRs.
+ knot_rdata_t *rr = rrset->rrs.rdata;
+ for (uint16_t i = 0; i < rrset->rrs.count; i++) {
+ // TTL + RR size + RR.
+ size += sizeof(uint32_t) + sizeof(uint16_t) + rr->len;
+ rr = knot_rdataset_next(rr);
+ }
+
+ return size;
+}
+
+size_t changeset_serialized_size(const changeset_t *ch)
+{
+ if (ch == NULL) {
+ return 0;
+ }
+
+ size_t soa_from_size = rrset_binary_size(ch->soa_from);
+ size_t soa_to_size = rrset_binary_size(ch->soa_to);
+
+ changeset_iter_t it;
+ changeset_iter_all(&it, ch);
+
+ size_t change_size = 0;
+ knot_rrset_t rrset = changeset_iter_next(&it);
+ while (!knot_rrset_empty(&rrset)) {
+ change_size += rrset_binary_size(&rrset);
+ rrset = changeset_iter_next(&it);
+ }
+
+ changeset_iter_clear(&it);
+
+ return soa_from_size + soa_to_size + change_size;
+}
+
+int changeset_deserialize(changeset_t *ch, uint8_t *src_chunks[],
+ const size_t *chunks_sizes, size_t chunks_count)
+{
+ if (ch == NULL || src_chunks == NULL || chunks_sizes == NULL ||
+ chunks_count == 0) {
+ return KNOT_EINVAL;
+ }
+
+ size_t cur_chunk = 0;
+ wire_ctx_t wire = wire_ctx_init_const(src_chunks[0], chunks_sizes[0]);
+
+ // Deserialize SOA 'from'.
+ knot_rrset_t rrset;
+ int ret = deserialize_rrset_chunks(&wire, &rrset, src_chunks, chunks_sizes,
+ chunks_count, &cur_chunk);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ assert(rrset.type == KNOT_RRTYPE_SOA);
+
+ ch->soa_from = knot_rrset_copy(&rrset, NULL);
+ knot_rrset_clear(&rrset, NULL);
+ if (ch->soa_from == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ // Read remaining RRSets.
+ bool in_remove_section = true;
+ while (cur_chunk < chunks_count - 1 || wire_ctx_available(&wire) > 0) {
+ // Parse next RRSet.
+ ret = deserialize_rrset_chunks(&wire, &rrset, src_chunks, chunks_sizes,
+ chunks_count, &cur_chunk);
+ if (ret != KNOT_EOK) {
+ break;
+ }
+
+ // Check for next (and also last) SOA.
+ if (rrset.type == KNOT_RRTYPE_SOA) {
+ // Move to ADD section if in REMOVE.
+ assert(in_remove_section);
+ in_remove_section = false;
+
+ ch->soa_to = knot_rrset_copy(&rrset, NULL);
+ if (ch->soa_to == NULL) {
+ ret = KNOT_ENOMEM;
+ }
+ } else {
+ if (in_remove_section) {
+ ret = changeset_add_removal(ch, &rrset, 0);
+ } else {
+ ret = changeset_add_addition(ch, &rrset, 0);
+ }
+ }
+
+ knot_rrset_clear(&rrset, NULL);
+
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ // If there was only one SOA record, we are in the bootstrap changeset.
+ if (in_remove_section) {
+ ch->soa_to = ch->soa_from;
+ ch->soa_from = NULL;
+ zone_contents_t *tmp = ch->add;
+ ch->add = ch->remove;
+ ch->remove = tmp;
+ }
+
+ return wire.error;
+}
diff --git a/src/knot/journal/serialization.h b/src/knot/journal/serialization.h
new file mode 100644
index 0000000..550bd1c
--- /dev/null
+++ b/src/knot/journal/serialization.h
@@ -0,0 +1,98 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include "libknot/rrset.h"
+#include "knot/updates/changesets.h"
+#include "contrib/wire_ctx.h"
+
+typedef struct serialize_ctx serialize_ctx_t;
+
+/*!
+ * \brief Init serialization context.
+ *
+ * \param ch Changeset to be serialized.
+ *
+ * \return Context.
+ */
+serialize_ctx_t *serialize_init(const changeset_t *ch);
+
+/*!
+ * \brief Pre-check and space computation before serializing a chunk.
+ *
+ * \note This MUST be called before each serialize_chunk() !
+ *
+ * \param ctx Serializing context.
+ * \param max_size Maximum size of next chunk.
+ * \param realsize Output: real exact size of next chunk.
+ */
+void serialize_prepare(serialize_ctx_t *ctx, size_t max_size, size_t *realsize);
+
+/*!
+ * \brief Perform one step of serializiation: fill one chunk.
+ *
+ * \param ctx Serializing context.
+ * \param chunk Pointer on allocated memory to be serialized into.
+ * \param chunk_size Its size. It MUST be the same as returned from serialize_prepare().
+ */
+void serialize_chunk(serialize_ctx_t *ctx, uint8_t *chunk, size_t chunk_size);
+
+/*! \brief Tells if there remains something of the changeset
+ * to be serialized into next chunk(s) yet. */
+bool serialize_unfinished(serialize_ctx_t *ctx);
+
+/*! \brief Free serialization context. */
+void serialize_deinit(serialize_ctx_t *ctx);
+
+/*!
+ * \brief Returns size of changeset in serialized form.
+ *
+ * \param[in] ch Changeset whose size we want to compute.
+ *
+ * \return Size of the changeset.
+ */
+size_t changeset_serialized_size(const changeset_t *ch);
+
+/*!
+ * \brief Deserializes chunked area into ch
+ *
+ * \param[out] ch The changeset.
+ * \param[in] src_chunks The chunks to deserialize.
+ * \param[in] chunks_sizes The size of each chunk.
+ * \param[in] chunks_count The number of chunks.
+ *
+ * \retval KNOT_E*
+ */
+int changeset_deserialize(changeset_t *ch, uint8_t *src_chunks[],
+ const size_t *chunks_sizes, size_t chunks_count);
+
+/*!
+ * \brief Deserializes single RRSet being part of a changeset serialized in chunks.
+ *
+ * \param wire[in] Current chunk ready to be parsed.
+ * \param rrset[out] RRSet to be deserialized (empty before).
+ * \param src_chunks[in] All chunks of the serialized changeset.
+ * \param chunk_sizes[in] Their sizes.
+ * \param chunks_count[in] Their count.
+ * \param cur_chunk[in+out] Index of current chunk.
+ *
+ * \return KNOT_E*
+ */
+int deserialize_rrset_chunks(wire_ctx_t *wire, knot_rrset_t *rrset,
+ uint8_t *src_chunks[], const size_t *chunk_sizes,
+ size_t chunks_count, size_t *cur_chunk);
diff --git a/src/knot/modules/cookies/Makefile.inc b/src/knot/modules/cookies/Makefile.inc
new file mode 100644
index 0000000..c40abed
--- /dev/null
+++ b/src/knot/modules/cookies/Makefile.inc
@@ -0,0 +1,13 @@
+knot_modules_cookies_la_SOURCES = knot/modules/cookies/cookies.c
+EXTRA_DIST += knot/modules/cookies/cookies.rst
+
+if STATIC_MODULE_cookies
+libknotd_la_SOURCES += $(knot_modules_cookies_la_SOURCES)
+endif
+
+if SHARED_MODULE_cookies
+knot_modules_cookies_la_LDFLAGS = $(KNOTD_MOD_LDFLAGS)
+knot_modules_cookies_la_CPPFLAGS = $(KNOTD_MOD_CPPFLAGS)
+knot_modules_cookies_la_LIBADD = libcontrib.la
+pkglib_LTLIBRARIES += knot/modules/cookies.la
+endif
diff --git a/src/knot/modules/cookies/cookies.c b/src/knot/modules/cookies/cookies.c
new file mode 100644
index 0000000..996c80d
--- /dev/null
+++ b/src/knot/modules/cookies/cookies.c
@@ -0,0 +1,269 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <pthread.h>
+#include <unistd.h>
+
+#include "knot/include/module.h"
+#include "libknot/libknot.h"
+#include "contrib/string.h"
+#include "libdnssec/random.h"
+
+#ifdef HAVE_ATOMIC
+#define ATOMIC_SET(dst, val) __atomic_store_n(&(dst), (val), __ATOMIC_RELAXED)
+#define ATOMIC_GET(src) __atomic_load_n(&(src), __ATOMIC_RELAXED)
+#define ATOMIC_ADD(dst, val) __atomic_add_fetch(&(dst), (val), __ATOMIC_RELAXED)
+#else
+#define ATOMIC_SET(dst, val) ((dst) = (val))
+#define ATOMIC_GET(src) (src)
+#define ATOMIC_ADD(dst, val) ((dst) += (val))
+#endif
+
+#define BADCOOKIE_CTR_INIT 1
+
+#define MOD_SECRET_LIFETIME "\x0F""secret-lifetime"
+#define MOD_BADCOOKIE_SLIP "\x0E""badcookie-slip"
+
+const yp_item_t cookies_conf[] = {
+ { MOD_SECRET_LIFETIME, YP_TINT, YP_VINT = { 1, 36*24*3600, 26*3600, YP_STIME } },
+ { MOD_BADCOOKIE_SLIP, YP_TINT, YP_VINT = { 1, INT32_MAX, 1 } },
+ { NULL }
+};
+
+typedef struct {
+ struct {
+ uint64_t variable;
+ uint64_t constant;
+ } secret;
+ pthread_t update_secret;
+ uint32_t secret_lifetime;
+ uint32_t badcookie_slip;
+ uint16_t badcookie_ctr; // Counter for BADCOOKIE answers.
+} cookies_ctx_t;
+
+static void update_ctr(cookies_ctx_t *ctx)
+{
+ assert(ctx);
+
+ if (ATOMIC_GET(ctx->badcookie_ctr) < ctx->badcookie_slip) {
+ ATOMIC_ADD(ctx->badcookie_ctr, 1);
+ } else {
+ ATOMIC_SET(ctx->badcookie_ctr, BADCOOKIE_CTR_INIT);
+ }
+}
+
+static int generate_secret(cookies_ctx_t *ctx)
+{
+ assert(ctx);
+
+ // Generate a new variable part of the server secret.
+ uint64_t new_secret;
+ int ret = dnssec_random_buffer((uint8_t *)&new_secret, sizeof(new_secret));
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ATOMIC_SET(ctx->secret.variable, new_secret);
+
+ return KNOT_EOK;
+}
+
+static void *update_secret(void *data)
+{
+ knotd_mod_t *mod = (knotd_mod_t *)data;
+ cookies_ctx_t *ctx = knotd_mod_ctx(mod);
+
+ while (true) {
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+ int ret = generate_secret(ctx);
+ if (ret != KNOT_EOK) {
+ knotd_mod_log(mod, LOG_ERR, "failed to generate a secret (%s)",
+ knot_strerror(ret));
+ }
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+ sleep(ctx->secret_lifetime);
+ }
+
+ return NULL;
+}
+
+// Inserts the current cookie option into the answer's OPT RR.
+static int put_cookie(knotd_qdata_t *qdata, knot_pkt_t *pkt,
+ const knot_edns_cookie_t *cc, const knot_edns_cookie_t *sc)
+{
+ assert(qdata && pkt && cc && sc);
+
+ uint8_t *option = NULL;
+ uint16_t option_size = knot_edns_cookie_size(cc, sc);
+ int ret = knot_edns_reserve_option(&qdata->opt_rr, KNOT_EDNS_OPTION_COOKIE,
+ option_size, &option, qdata->mm);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = knot_edns_cookie_write(option, option_size, cc, sc);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Reserve extra space for the cookie option.
+ ret = knot_pkt_reserve(pkt, KNOT_EDNS_OPTION_HDRLEN + option_size);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ return KNOT_EOK;
+}
+
+static knotd_state_t cookies_process(knotd_state_t state, knot_pkt_t *pkt,
+ knotd_qdata_t *qdata, knotd_mod_t *mod)
+{
+ assert(pkt && qdata && mod);
+
+ cookies_ctx_t *ctx = knotd_mod_ctx(mod);
+
+ // DNS cookies are ignored in the case of the TCP connection.
+ if (!(qdata->params->flags & KNOTD_QUERY_FLAG_LIMIT_SIZE)) {
+ return state;
+ }
+
+ // Check if the cookie option is present.
+ uint8_t *cookie_opt = knot_pkt_edns_option(qdata->query,
+ KNOT_EDNS_OPTION_COOKIE);
+ if (cookie_opt == NULL) {
+ return state;
+ }
+
+ // Increment the statistics counter.
+ knotd_mod_stats_incr(mod, 0, 0, 1);
+
+ knot_edns_cookie_t cc;
+ knot_edns_cookie_t sc;
+
+ // Parse the cookie from wireformat.
+ const uint8_t *data = knot_edns_opt_get_data(cookie_opt);
+ uint16_t data_len = knot_edns_opt_get_length(cookie_opt);
+ int ret = knot_edns_cookie_parse(&cc, &sc, data, data_len);
+ if (ret != KNOT_EOK) {
+ qdata->rcode = KNOT_RCODE_FORMERR;
+ return KNOTD_STATE_FAIL;
+ }
+
+ // Prepare data for server cookie computation.
+ knot_edns_cookie_params_t params;
+ params.client_addr = (struct sockaddr *)qdata->params->remote;
+ uint64_t current_secret = ATOMIC_GET(ctx->secret.variable);
+ memcpy(params.secret, &current_secret, sizeof(current_secret));
+ memcpy(params.secret + sizeof(current_secret), &ctx->secret.constant,
+ sizeof(ctx->secret.constant));
+
+ // Compare server cookie.
+ ret = knot_edns_cookie_server_check(&sc, &cc, &params);
+ if (ret != KNOT_EOK) {
+ if (ATOMIC_GET(ctx->badcookie_ctr) > BADCOOKIE_CTR_INIT) {
+ // Silently drop the response.
+ update_ctr(ctx);
+ return KNOTD_STATE_NOOP;
+ } else {
+ if (ctx->badcookie_slip > 1) {
+ update_ctr(ctx);
+ }
+
+ ret = knot_edns_cookie_server_generate(&sc, &cc, &params);
+ if (ret != KNOT_EOK) {
+ return KNOTD_STATE_FAIL;
+ }
+
+ ret = put_cookie(qdata, pkt, &cc, &sc);
+ if (ret != KNOT_EOK) {
+ return KNOTD_STATE_FAIL;
+ }
+
+ qdata->rcode = KNOT_RCODE_BADCOOKIE;
+ return KNOTD_STATE_FAIL;
+ }
+ }
+
+ // Reuse valid server cookie.
+ ret = put_cookie(qdata, pkt, &cc, &sc);
+ if (ret != KNOT_EOK) {
+ return KNOTD_STATE_FAIL;
+ }
+
+ // Set the valid cookie flag.
+ qdata->params->flags |= KNOTD_QUERY_FLAG_COOKIE;
+
+ return state;
+}
+
+int cookies_load(knotd_mod_t *mod)
+{
+ // Create module context.
+ cookies_ctx_t *ctx = calloc(1, sizeof(cookies_ctx_t));
+ if (ctx == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ // Initialize BADCOOKIE counter.
+ ctx->badcookie_ctr = BADCOOKIE_CTR_INIT;
+
+ // Set up configurable items.
+ knotd_conf_t conf = knotd_conf_mod(mod, MOD_SECRET_LIFETIME);
+ ctx->secret_lifetime = conf.single.integer;
+
+ conf = knotd_conf_mod(mod, MOD_BADCOOKIE_SLIP);
+ ctx->badcookie_slip = conf.single.integer;
+
+ // Set up statistics counters.
+ int ret = knotd_mod_stats_add(mod, "presence", 1, NULL);
+ if (ret != KNOT_EOK) {
+ free(ctx);
+ return ret;
+ }
+
+ // Initialize the server secret.
+ ret = dnssec_random_buffer((uint8_t *)&ctx->secret, sizeof(ctx->secret));
+ if (ret != KNOT_EOK) {
+ free(ctx);
+ return ret;
+ }
+
+ knotd_mod_ctx_set(mod, ctx);
+
+ // Start the secret rollover thread.
+ if (pthread_create(&ctx->update_secret, NULL, update_secret, (void *)mod)) {
+ knotd_mod_log(mod, LOG_ERR, "failed to create the secret rollover thread");
+ }
+
+#ifndef HAVE_ATOMIC
+ knotd_mod_log(mod, LOG_WARNING, "the module might work slightly wrong on this platform");
+ ctx->badcookie_slip = 1;
+#endif
+
+ return knotd_mod_hook(mod, KNOTD_STAGE_BEGIN, cookies_process);
+}
+
+void cookies_unload(knotd_mod_t *mod)
+{
+ cookies_ctx_t *ctx = knotd_mod_ctx(mod);
+ memzero(&ctx->secret, sizeof(ctx->secret));
+ (void)pthread_cancel(ctx->update_secret);
+ (void)pthread_join(ctx->update_secret, NULL);
+ free(ctx);
+}
+
+KNOTD_MOD_API(cookies, KNOTD_MOD_FLAG_SCOPE_ANY | KNOTD_MOD_FLAG_OPT_CONF,
+ cookies_load, cookies_unload, cookies_conf, NULL);
diff --git a/src/knot/modules/cookies/cookies.rst b/src/knot/modules/cookies/cookies.rst
new file mode 100644
index 0000000..2feb270
--- /dev/null
+++ b/src/knot/modules/cookies/cookies.rst
@@ -0,0 +1,78 @@
+.. _mod-cookies:
+
+``cookies`` — DNS Cookies
+=========================
+
+DNS Cookies (:rfc:`7873`) is a lightweight security mechanism against
+denial-of-service and amplification attacks. The server keeps a secret value
+(the server secret), which is used to generate a cookie, which is sent to
+the client in the OPT RR. The server then verifies the authenticity of the client
+by the presence of a correct cookie. Both the server and the client have to
+support DNS Cookies, otherwise they are not used.
+
+.. NOTE::
+ This module introduces a statistics counter: the number of queries
+ containing the COOKIE option.
+
+.. WARNING::
+ For effective module operation the :ref:`RRL<mod-rrl>` module must also
+ be enabled.
+
+Example
+-------
+
+It is recommended to enable DNS Cookies globally, not per zone.
+
+::
+
+ mod-cookies:
+ - id: default
+ secret-lifetime: 30h # The server secret is regenerated every 30 hours
+ badcookie-slip: 3 # The server replies only to every third query with a wrong cookie
+
+ template:
+ - id: default
+ global-module: mod-cookies/default # Enable DNS Cookies globally
+
+Module reference
+----------------
+
+::
+
+ mod-cookies:
+ - id: STR
+ secret-lifetime: TIME
+ badcookie-slip: INT
+
+.. _mod-cookies_id:
+
+id
+..
+
+A module identifier.
+
+.. _mod-cookies_secret-lifetime:
+
+secret-lifetime
+...............
+
+This option configures how often the server secret is regenerated.
+The maximum allowed value is 36 days (:rfc:`7873#section-7.1`).
+
+*Default:* 26 hours
+
+.. _mod-cookies_badcookie-slip:
+
+badcookie-slip
+..............
+
+This option configures how often the server responds to queries containing
+an invalid cookie by sending them the correct cookie.
+
+- The value **1** means that the server responds to every query.
+- The value **2** means that the server responds to every second query with
+ an invalid cookie, the rest of the queries is dropped.
+- The value **N > 2** means that the server responds to every N\ :sup:`th`
+ query with an invalid cookie, the rest of the queries is dropped.
+
+*Default:* 1
diff --git a/src/knot/modules/dnsproxy/Makefile.inc b/src/knot/modules/dnsproxy/Makefile.inc
new file mode 100644
index 0000000..cda2a43
--- /dev/null
+++ b/src/knot/modules/dnsproxy/Makefile.inc
@@ -0,0 +1,13 @@
+knot_modules_dnsproxy_la_SOURCES = knot/modules/dnsproxy/dnsproxy.c
+EXTRA_DIST += knot/modules/dnsproxy/dnsproxy.rst
+
+if STATIC_MODULE_dnsproxy
+libknotd_la_SOURCES += $(knot_modules_dnsproxy_la_SOURCES)
+endif
+
+if SHARED_MODULE_dnsproxy
+knot_modules_dnsproxy_la_LDFLAGS = $(KNOTD_MOD_LDFLAGS)
+knot_modules_dnsproxy_la_CPPFLAGS = $(KNOTD_MOD_CPPFLAGS)
+knot_modules_dnsproxy_la_LIBADD = libcontrib.la
+pkglib_LTLIBRARIES += knot/modules/dnsproxy.la
+endif
diff --git a/src/knot/modules/dnsproxy/dnsproxy.c b/src/knot/modules/dnsproxy/dnsproxy.c
new file mode 100644
index 0000000..7d378a3
--- /dev/null
+++ b/src/knot/modules/dnsproxy/dnsproxy.c
@@ -0,0 +1,165 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "contrib/net.h"
+#include "knot/include/module.h"
+#include "knot/conf/schema.h"
+#include "knot/query/capture.h" // Forces static module!
+#include "knot/query/requestor.h" // Forces static module!
+#include "knot/nameserver/process_query.h" // Forces static module!
+
+#define MOD_REMOTE "\x06""remote"
+#define MOD_TIMEOUT "\x07""timeout"
+#define MOD_FALLBACK "\x08""fallback"
+#define MOD_CATCH_NXDOMAIN "\x0E""catch-nxdomain"
+
+const yp_item_t dnsproxy_conf[] = {
+ { MOD_REMOTE, YP_TREF, YP_VREF = { C_RMT }, YP_FNONE,
+ { knotd_conf_check_ref } },
+ { MOD_TIMEOUT, YP_TINT, YP_VINT = { 0, INT32_MAX, 500 } },
+ { MOD_FALLBACK, YP_TBOOL, YP_VBOOL = { true } },
+ { MOD_CATCH_NXDOMAIN, YP_TBOOL, YP_VNONE },
+ { NULL }
+};
+
+int dnsproxy_conf_check(knotd_conf_check_args_t *args)
+{
+ knotd_conf_t rmt = knotd_conf_check_item(args, MOD_REMOTE);
+ if (rmt.count == 0) {
+ args->err_str = "no remote server specified";
+ return KNOT_EINVAL;
+ }
+
+ return KNOT_EOK;
+}
+
+typedef struct {
+ struct sockaddr_storage remote;
+ struct sockaddr_storage via;
+ bool fallback;
+ bool catch_nxdomain;
+ int timeout;
+} dnsproxy_t;
+
+static knotd_state_t dnsproxy_fwd(knotd_state_t state, knot_pkt_t *pkt,
+ knotd_qdata_t *qdata, knotd_mod_t *mod)
+{
+ assert(pkt && qdata && mod);
+
+ dnsproxy_t *proxy = knotd_mod_ctx(mod);
+
+ /* Forward only queries ending with REFUSED (no zone) or NXDOMAIN (if configured) */
+ if (proxy->fallback && !(qdata->rcode == KNOT_RCODE_REFUSED ||
+ (qdata->rcode == KNOT_RCODE_NXDOMAIN && proxy->catch_nxdomain))) {
+ return state;
+ }
+
+ /* Forward also original TSIG. */
+ if (qdata->query->tsig_rr != NULL && !proxy->fallback) {
+ knot_tsig_append(qdata->query->wire, &qdata->query->size,
+ qdata->query->max_size, qdata->query->tsig_rr);
+ }
+
+ /* Capture layer context. */
+ const knot_layer_api_t *capture = query_capture_api();
+ struct capture_param capture_param = {
+ .sink = pkt,
+ .orig_qname = qdata->extra->orig_qname
+ };
+
+ /* Create a forwarding request. */
+ struct knot_requestor re;
+ int ret = knot_requestor_init(&re, capture, &capture_param, qdata->mm);
+ if (ret != KNOT_EOK) {
+ return state; /* Ignore, not enough memory. */
+ }
+
+ bool is_tcp = net_is_stream(qdata->params->socket);
+ const struct sockaddr *dst = (const struct sockaddr *)&proxy->remote;
+ const struct sockaddr *src = (const struct sockaddr *)&proxy->via;
+ struct knot_request *req = knot_request_make(re.mm, dst, src, qdata->query, NULL,
+ is_tcp ? 0 : KNOT_RQ_UDP);
+ if (req == NULL) {
+ knot_requestor_clear(&re);
+ return state; /* Ignore, not enough memory. */
+ }
+
+ /* Forward request. */
+ ret = knot_requestor_exec(&re, req, proxy->timeout);
+
+ knot_request_free(req, re.mm);
+ knot_requestor_clear(&re);
+
+ /* Check result. */
+ if (ret != KNOT_EOK) {
+ qdata->rcode = KNOT_RCODE_SERVFAIL;
+ return KNOTD_STATE_FAIL; /* Forwarding failed, SERVFAIL. */
+ } else {
+ qdata->rcode = knot_pkt_ext_rcode(pkt);
+ }
+
+ /* Respond also with TSIG. */
+ if (pkt->tsig_rr != NULL && !proxy->fallback) {
+ knot_tsig_append(pkt->wire, &pkt->size, pkt->max_size, pkt->tsig_rr);
+ }
+
+ return (proxy->fallback ? KNOTD_STATE_DONE : KNOTD_STATE_FINAL);
+}
+
+int dnsproxy_load(knotd_mod_t *mod)
+{
+ dnsproxy_t *proxy = calloc(1, sizeof(*proxy));
+ if (proxy == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ knotd_conf_t remote = knotd_conf_mod(mod, MOD_REMOTE);
+ knotd_conf_t conf = knotd_conf(mod, C_RMT, C_ADDR, &remote);
+ if (conf.count > 0) {
+ proxy->remote = conf.multi[0].addr;
+ knotd_conf_free(&conf);
+ }
+ conf = knotd_conf(mod, C_RMT, C_VIA, &remote);
+ if (conf.count > 0) {
+ proxy->via = conf.multi[0].addr;
+ knotd_conf_free(&conf);
+ }
+
+ conf = knotd_conf_mod(mod, MOD_TIMEOUT);
+ proxy->timeout = conf.single.integer;
+
+ conf = knotd_conf_mod(mod, MOD_FALLBACK);
+ proxy->fallback = conf.single.boolean;
+
+ conf = knotd_conf_mod(mod, MOD_CATCH_NXDOMAIN);
+ proxy->catch_nxdomain = conf.single.boolean;
+
+ knotd_mod_ctx_set(mod, proxy);
+
+ if (proxy->fallback) {
+ return knotd_mod_hook(mod, KNOTD_STAGE_END, dnsproxy_fwd);
+ } else {
+ return knotd_mod_hook(mod, KNOTD_STAGE_BEGIN, dnsproxy_fwd);
+ }
+}
+
+void dnsproxy_unload(knotd_mod_t *mod)
+{
+ free(knotd_mod_ctx(mod));
+}
+
+KNOTD_MOD_API(dnsproxy, KNOTD_MOD_FLAG_SCOPE_ANY,
+ dnsproxy_load, dnsproxy_unload, dnsproxy_conf, dnsproxy_conf_check);
diff --git a/src/knot/modules/dnsproxy/dnsproxy.rst b/src/knot/modules/dnsproxy/dnsproxy.rst
new file mode 100644
index 0000000..92057de
--- /dev/null
+++ b/src/knot/modules/dnsproxy/dnsproxy.rst
@@ -0,0 +1,102 @@
+.. _mod-dnsproxy:
+
+``dnsproxy`` – Tiny DNS proxy
+=============================
+
+The module forwards all queries, or all specific zone queries if configured
+per zone, to the indicated server for resolution. If configured in the fallback
+mode, only localy unsatisfied queries are forwarded. I.e. a tiny DNS proxy.
+There are several uses of this feature:
+
+* A substitute public-facing server in front of the real one
+* Local zones (poor man's "views"), rest is forwarded to the public-facing server
+* etc.
+
+.. NOTE::
+ The module does not alter the query/response as the resolver would,
+ and the original transport protocol is kept as well.
+
+Example
+-------
+
+The configuration is straightforward and just a single remote server is
+required::
+
+ remote:
+ - id: hidden
+ address: 10.0.1.1
+
+ mod-dnsproxy:
+ - id: default
+ remote: hidden
+ fallback: on
+
+ template:
+ - id: default
+ global-module: mod-dnsproxy/default
+
+ zone:
+ - domain: local.zone
+
+When clients query for anything in the ``local.zone``, they will be
+responded to locally. The rest of the requests will be forwarded to the
+specified server (``10.0.1.1`` in this case).
+
+Module reference
+----------------
+
+::
+
+ mod-dnsproxy:
+ - id: STR
+ remote: remote_id
+ timeout: INT
+ fallback: BOOL
+ catch-nxdomain: BOOL
+
+.. _mod-dnsproxy_id:
+
+id
+..
+
+A module identifier.
+
+.. _mod-dnsproxy_remote:
+
+remote
+......
+
+A :ref:`reference<remote_id>` to a remote server where the queries are
+forwarded to.
+
+*Required*
+
+.. _mod-dnsproxy_timeout:
+
+timeout
+.......
+
+A remote response timeout in milliseconds.
+
+*Default:* 500
+
+.. _mod-dnsproxy_fallback:
+
+fallback
+........
+
+If enabled, localy unsatisfied queries leading to REFUSED (no zone) are forwarded.
+If disabled, all queries are directly forwarded without any local attempts
+to resolve them.
+
+*Default:* on
+
+.. _mod-dnsproxy_catch-nxdomain:
+
+catch-nxdomain
+..............
+
+If enabled, localy unsatisfied queries leading to NXDOMAIN are forwarded.
+This option is only relevant in the fallback mode.
+
+*Default:* off
diff --git a/src/knot/modules/dnstap/Makefile.inc b/src/knot/modules/dnstap/Makefile.inc
new file mode 100644
index 0000000..19f6043
--- /dev/null
+++ b/src/knot/modules/dnstap/Makefile.inc
@@ -0,0 +1,15 @@
+knot_modules_dnstap_la_SOURCES = knot/modules/dnstap/dnstap.c
+EXTRA_DIST += knot/modules/dnstap/dnstap.rst
+
+if STATIC_MODULE_dnstap
+libknotd_la_SOURCES += $(knot_modules_dnstap_la_SOURCES)
+libknotd_la_CPPFLAGS += $(DNSTAP_CFLAGS)
+libknotd_la_LIBADD += $(DNSTAP_LIBS) libdnstap.la
+endif
+
+if SHARED_MODULE_dnstap
+knot_modules_dnstap_la_LDFLAGS = $(KNOTD_MOD_LDFLAGS)
+knot_modules_dnstap_la_CPPFLAGS = $(KNOTD_MOD_CPPFLAGS) $(DNSTAP_CFLAGS)
+knot_modules_dnstap_la_LIBADD = $(DNSTAP_LIBS) libdnstap.la
+pkglib_LTLIBRARIES += knot/modules/dnstap.la
+endif
diff --git a/src/knot/modules/dnstap/dnstap.c b/src/knot/modules/dnstap/dnstap.c
new file mode 100644
index 0000000..976f43f
--- /dev/null
+++ b/src/knot/modules/dnstap/dnstap.c
@@ -0,0 +1,320 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <netinet/in.h>
+
+#include "contrib/dnstap/dnstap.h"
+#include "contrib/dnstap/dnstap.pb-c.h"
+#include "contrib/dnstap/message.h"
+#include "contrib/dnstap/writer.h"
+#include "contrib/time.h"
+#include "knot/include/module.h"
+
+#define MOD_SINK "\x04""sink"
+#define MOD_IDENTITY "\x08""identity"
+#define MOD_VERSION "\x07""version"
+#define MOD_QUERIES "\x0B""log-queries"
+#define MOD_RESPONSES "\x0D""log-responses"
+
+const yp_item_t dnstap_conf[] = {
+ { MOD_SINK, YP_TSTR, YP_VNONE },
+ { MOD_IDENTITY, YP_TSTR, YP_VNONE },
+ { MOD_VERSION, YP_TSTR, YP_VNONE },
+ { MOD_QUERIES, YP_TBOOL, YP_VBOOL = { true } },
+ { MOD_RESPONSES, YP_TBOOL, YP_VBOOL = { true } },
+ { NULL }
+};
+
+int dnstap_conf_check(knotd_conf_check_args_t *args)
+{
+ knotd_conf_t sink = knotd_conf_check_item(args, MOD_SINK);
+ if (sink.count == 0 || sink.single.string[0] == '\0') {
+ args->err_str = "no sink specified";
+ return KNOT_EINVAL;
+ }
+
+ return KNOT_EOK;
+}
+
+typedef struct {
+ struct fstrm_iothr *iothread;
+ char *identity;
+ size_t identity_len;
+ char *version;
+ size_t version_len;
+} dnstap_ctx_t;
+
+static knotd_state_t log_message(knotd_state_t state, const knot_pkt_t *pkt,
+ knotd_qdata_t *qdata, knotd_mod_t *mod)
+{
+ assert(pkt && qdata && mod);
+
+ /* Skip empty packet. */
+ if (state == KNOTD_STATE_NOOP) {
+ return state;
+ }
+
+ dnstap_ctx_t *ctx = knotd_mod_ctx(mod);
+
+ struct fstrm_iothr_queue *ioq =
+ fstrm_iothr_get_input_queue_idx(ctx->iothread, qdata->params->thread_id);
+
+ /* Unless we want to measure the time it takes to process each query,
+ * we can treat Q/R times the same. */
+ struct timespec tv = { .tv_sec = time(NULL) };
+
+ /* Determine query / response. */
+ Dnstap__Message__Type msgtype = DNSTAP__MESSAGE__TYPE__AUTH_QUERY;
+ if (knot_wire_get_qr(pkt->wire)) {
+ msgtype = DNSTAP__MESSAGE__TYPE__AUTH_RESPONSE;
+ }
+
+ /* Determine whether we run on UDP/TCP. */
+ int protocol = IPPROTO_TCP;
+ if (qdata->params->flags & KNOTD_QUERY_FLAG_LIMIT_SIZE) {
+ protocol = IPPROTO_UDP;
+ }
+
+ /* Create a dnstap message. */
+ Dnstap__Message msg;
+ int ret = dt_message_fill(&msg, msgtype,
+ (const struct sockaddr *)qdata->params->remote,
+ NULL, /* todo: fill me! */
+ protocol, pkt->wire, pkt->size, &tv);
+ if (ret != KNOT_EOK) {
+ return state;
+ }
+
+ Dnstap__Dnstap dnstap = DNSTAP__DNSTAP__INIT;
+ dnstap.type = DNSTAP__DNSTAP__TYPE__MESSAGE;
+ dnstap.message = &msg;
+
+ /* Set message version and identity. */
+ if (ctx->identity_len > 0) {
+ dnstap.identity.data = (uint8_t *)ctx->identity;
+ dnstap.identity.len = ctx->identity_len;
+ dnstap.has_identity = 1;
+ }
+ if (ctx->version_len > 0) {
+ dnstap.version.data = (uint8_t *)ctx->version;
+ dnstap.version.len = ctx->version_len;
+ dnstap.has_version = 1;
+ }
+
+ /* Pack the message. */
+ uint8_t *frame = NULL;
+ size_t size = 0;
+ dt_pack(&dnstap, &frame, &size);
+ if (frame == NULL) {
+ return state;
+ }
+
+ /* Submit a request. */
+ fstrm_res res = fstrm_iothr_submit(ctx->iothread, ioq, frame, size,
+ fstrm_free_wrapper, NULL);
+ if (res != fstrm_res_success) {
+ free(frame);
+ return state;
+ }
+
+ return state;
+}
+
+/*! \brief Submit message - query. */
+static knotd_state_t dnstap_message_log_query(knotd_state_t state, knot_pkt_t *pkt,
+ knotd_qdata_t *qdata, knotd_mod_t *mod)
+{
+ assert(qdata);
+
+ return log_message(state, qdata->query, qdata, mod);
+}
+
+/*! \brief Submit message - response. */
+static knotd_state_t dnstap_message_log_response(knotd_state_t state, knot_pkt_t *pkt,
+ knotd_qdata_t *qdata, knotd_mod_t *mod)
+{
+ return log_message(state, pkt, qdata, mod);
+}
+
+/*! \brief Create a UNIX socket sink. */
+static struct fstrm_writer* dnstap_unix_writer(const char *path)
+{
+ struct fstrm_unix_writer_options *opt = NULL;
+ struct fstrm_writer_options *wopt = NULL;
+ struct fstrm_writer *writer = NULL;
+
+ opt = fstrm_unix_writer_options_init();
+ if (opt == NULL) {
+ goto finish;
+ }
+ fstrm_unix_writer_options_set_socket_path(opt, path);
+
+ wopt = fstrm_writer_options_init();
+ if (wopt == NULL) {
+ goto finish;
+ }
+ fstrm_writer_options_add_content_type(wopt, DNSTAP_CONTENT_TYPE,
+ strlen(DNSTAP_CONTENT_TYPE));
+ writer = fstrm_unix_writer_init(opt, wopt);
+
+finish:
+ fstrm_unix_writer_options_destroy(&opt);
+ fstrm_writer_options_destroy(&wopt);
+ return writer;
+}
+
+/*! \brief Create a basic file writer sink. */
+static struct fstrm_writer* dnstap_file_writer(const char *path)
+{
+ struct fstrm_file_options *fopt = NULL;
+ struct fstrm_writer_options *wopt = NULL;
+ struct fstrm_writer *writer = NULL;
+
+ fopt = fstrm_file_options_init();
+ if (fopt == NULL) {
+ goto finish;
+ }
+ fstrm_file_options_set_file_path(fopt, path);
+
+ wopt = fstrm_writer_options_init();
+ if (wopt == NULL) {
+ goto finish;
+ }
+ fstrm_writer_options_add_content_type(wopt, DNSTAP_CONTENT_TYPE,
+ strlen(DNSTAP_CONTENT_TYPE));
+ writer = fstrm_file_writer_init(fopt, wopt);
+
+finish:
+ fstrm_file_options_destroy(&fopt);
+ fstrm_writer_options_destroy(&wopt);
+ return writer;
+}
+
+/*! \brief Create a log sink according to the path string. */
+static struct fstrm_writer* dnstap_writer(const char *path)
+{
+ const char *prefix = "unix:";
+ const size_t prefix_len = strlen(prefix);
+
+ /* UNIX socket prefix. */
+ if (strlen(path) > prefix_len && strncmp(path, prefix, prefix_len) == 0) {
+ return dnstap_unix_writer(path + prefix_len);
+ }
+
+ return dnstap_file_writer(path);
+}
+
+int dnstap_load(knotd_mod_t *mod)
+{
+ /* Create dnstap context. */
+ dnstap_ctx_t *ctx = calloc(1, sizeof(*ctx));
+ if (ctx == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ /* Set identity. */
+ knotd_conf_t conf = knotd_conf_mod(mod, MOD_IDENTITY);
+ if (conf.count == 1) {
+ ctx->identity = (conf.single.string != NULL) ?
+ strdup(conf.single.string) : NULL;
+ } else {
+ knotd_conf_t host = knotd_conf_env(mod, KNOTD_CONF_ENV_HOSTNAME);
+ ctx->identity = strdup(host.single.string);
+ }
+ ctx->identity_len = (ctx->identity != NULL) ? strlen(ctx->identity) : 0;
+
+ /* Set version. */
+ conf = knotd_conf_mod(mod, MOD_VERSION);
+ if (conf.count == 1) {
+ ctx->version = (conf.single.string != NULL) ?
+ strdup(conf.single.string) : NULL;
+ } else {
+ knotd_conf_t version = knotd_conf_env(mod, KNOTD_CONF_ENV_VERSION);
+ ctx->version = strdup(version.single.string);
+ }
+ ctx->version_len = (ctx->version != NULL) ? strlen(ctx->version) : 0;
+
+ /* Set sink. */
+ conf = knotd_conf_mod(mod, MOD_SINK);
+ const char *sink = conf.single.string;
+
+ /* Set log_queries. */
+ conf = knotd_conf_mod(mod, MOD_QUERIES);
+ const bool log_queries = conf.single.boolean;
+
+ /* Set log_responses. */
+ conf = knotd_conf_mod(mod, MOD_RESPONSES);
+ const bool log_responses = conf.single.boolean;
+
+ /* Initialize the writer and the options. */
+ struct fstrm_writer *writer = dnstap_writer(sink);
+ if (writer == NULL) {
+ goto fail;
+ }
+
+ struct fstrm_iothr_options *opt = fstrm_iothr_options_init();
+ if (opt == NULL) {
+ fstrm_writer_destroy(&writer);
+ goto fail;
+ }
+
+ /* Initialize queues. */
+ knotd_conf_t udp = knotd_conf_env(mod, KNOTD_CONF_ENV_WORKERS_UDP);
+ knotd_conf_t tcp = knotd_conf_env(mod, KNOTD_CONF_ENV_WORKERS_TCP);
+ size_t qcount = udp.single.integer + tcp.single.integer;
+ fstrm_iothr_options_set_num_input_queues(opt, qcount);
+
+ /* Create the I/O thread. */
+ ctx->iothread = fstrm_iothr_init(opt, &writer);
+ fstrm_iothr_options_destroy(&opt);
+ if (ctx->iothread == NULL) {
+ fstrm_writer_destroy(&writer);
+ goto fail;
+ }
+
+ knotd_mod_ctx_set(mod, ctx);
+
+ /* Hook to the query plan. */
+ if (log_queries) {
+ knotd_mod_hook(mod, KNOTD_STAGE_BEGIN, dnstap_message_log_query);
+ }
+ if (log_responses) {
+ knotd_mod_hook(mod, KNOTD_STAGE_END, dnstap_message_log_response);
+ }
+
+ return KNOT_EOK;
+fail:
+ knotd_mod_log(mod, LOG_ERR, "failed to init sink '%s'", sink);
+
+ free(ctx->identity);
+ free(ctx->version);
+ free(ctx);
+
+ return KNOT_ENOMEM;
+}
+
+void dnstap_unload(knotd_mod_t *mod)
+{
+ dnstap_ctx_t *ctx = knotd_mod_ctx(mod);
+
+ fstrm_iothr_destroy(&ctx->iothread);
+ free(ctx->identity);
+ free(ctx->version);
+ free(ctx);
+}
+
+KNOTD_MOD_API(dnstap, KNOTD_MOD_FLAG_SCOPE_ANY,
+ dnstap_load, dnstap_unload, dnstap_conf, dnstap_conf_check);
diff --git a/src/knot/modules/dnstap/dnstap.rst b/src/knot/modules/dnstap/dnstap.rst
new file mode 100644
index 0000000..d37f69a
--- /dev/null
+++ b/src/knot/modules/dnstap/dnstap.rst
@@ -0,0 +1,106 @@
+.. _mod-dnstap:
+
+``dnstap`` – Dnstap traffic logging
+===================================
+
+A module for query and response logging based on the dnstap_ library.
+You can capture either all or zone-specific queries and responses; usually
+you want to do the former.
+
+Example
+-------
+
+The configuration comprises only a :ref:`mod-dnstap_sink` path parameter,
+which can be either a file or a UNIX socket::
+
+ mod-dnstap:
+ - id: capture_all
+ sink: /tmp/capture.tap
+
+ template:
+ - id: default
+ global-module: mod-dnstap/capture_all
+
+.. NOTE::
+ To be able to use a Unix socket you need an external program to create it.
+ Knot DNS connects to it as a client using the libfstrm library. It operates
+ exactly like syslog. See `here
+ <https://www.nlnetlabs.nl/bugs-script/show_bug.cgi?id=741#c10>`_ for
+ more details.
+
+.. NOTE::
+ Dnstap log files can also be created or read using ``kdig``.
+
+.. _dnstap: http://dnstap.info/
+
+Module reference
+----------------
+
+For all queries logging, use this module in the *default* template. For
+zone-specific logging, use this module in the proper zone configuration.
+
+::
+
+ mod-dnstap:
+ - id: STR
+ sink: STR
+ identity: STR
+ version: STR
+ log-queries: BOOL
+ log-responses: BOOL
+
+.. _mod-dnstap_id:
+
+id
+..
+
+A module identifier.
+
+.. _mod-dnstap_sink:
+
+sink
+....
+
+A sink path, which can be either a file or a UNIX socket when prefixed with
+``unix:``.
+
+*Required*
+
+.. WARNING::
+ File is overwritten on server startup or reload.
+
+.. _mod-dnstap_identity:
+
+identity
+........
+
+A DNS server identity. Set empty value to disable.
+
+*Default:* FQDN hostname
+
+.. _mod-dnstap_version:
+
+version
+.......
+
+A DNS server version. Set empty value to disable.
+
+*Default:* server version
+
+.. _mod-dnstap_log-queries:
+
+log-queries
+...........
+
+If enabled, query messages will be logged.
+
+*Default:* on
+
+.. _mod-dnstap_log-responses:
+
+log-responses
+.............
+
+If enabled, response messages will be logged.
+
+*Default:* on
diff --git a/src/knot/modules/geoip/Makefile.inc b/src/knot/modules/geoip/Makefile.inc
new file mode 100644
index 0000000..395cf9f
--- /dev/null
+++ b/src/knot/modules/geoip/Makefile.inc
@@ -0,0 +1,16 @@
+knot_modules_geoip_la_SOURCES = knot/modules/geoip/geoip.c \
+ knot/modules/geoip/geodb.c \
+ knot/modules/geoip/geodb.h
+EXTRA_DIST += knot/modules/geoip/geoip.rst
+
+if STATIC_MODULE_geoip
+libknotd_la_SOURCES += $(knot_modules_geoip_la_SOURCES)
+libknotd_la_CPPFLAGS += $(libmaxminddb_CFLAGS)
+libknotd_la_LIBADD += $(libmaxminddb_LIBS)
+endif
+
+if SHARED_MODULE_geoip
+knot_modules_geoip_la_LDFLAGS = $(KNOTD_MOD_LDFLAGS)
+knot_modules_geoip_la_CPPFLAGS = $(KNOTD_MOD_CPPFLAGS)
+pkglib_LTLIBRARIES += knot/modules/geoip.la
+endif
diff --git a/src/knot/modules/geoip/geodb.c b/src/knot/modules/geoip/geodb.c
new file mode 100644
index 0000000..899c4d1
--- /dev/null
+++ b/src/knot/modules/geoip/geodb.c
@@ -0,0 +1,222 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "knot/modules/geoip/geodb.h"
+#include "contrib/strtonum.h"
+#include "contrib/string.h"
+
+#if HAVE_MAXMINDDB
+static const uint16_t type_map[] = {
+ [GEODB_KEY_ID] = MMDB_DATA_TYPE_UINT32,
+ [GEODB_KEY_TXT] = MMDB_DATA_TYPE_UTF8_STRING
+};
+#endif
+
+int parse_geodb_path(geodb_path_t *path, const char *input)
+{
+ if (path == NULL || input == NULL) {
+ return -1;
+ }
+
+ // Parse optional type of key.
+ path->type = GEODB_KEY_TXT;
+ const char *delim = input;
+ if (input[0] == '(') {
+ delim = strchr(input, ')');
+ if (delim == NULL) {
+ return -1;
+ }
+ input++;
+ char *type = sprintf_alloc("%.*s", delim - input, input);
+ const knot_lookup_t *table = knot_lookup_by_name(geodb_key_types, type);
+ free(type);
+ if (table == NULL) {
+ return -1;
+ }
+ path->type = table->id;
+ input = delim + 1;
+ }
+
+ // Parse the path.
+ uint16_t len = 0;
+ while (1) {
+ delim = strchr(input, '/');
+ if (delim == NULL) {
+ delim = input + strlen(input);
+ }
+ path->path[len] = malloc(delim - input + 1);
+ if (path->path[len] == NULL) {
+ return -1;
+ }
+ memcpy(path->path[len], input, delim - input);
+ path->path[len][delim - input] = '\0';
+ len++;
+ if (*delim == 0 || len == GEODB_MAX_PATH_LEN) {
+ break;
+ }
+ input = delim + 1;
+ }
+
+ return 0;
+}
+
+int parse_geodb_data(const char *input, void **geodata, uint32_t *geodata_len,
+ uint8_t *geodepth, geodb_path_t *path, uint16_t path_cnt)
+{
+ for (uint16_t i = 0; i < path_cnt; i++) {
+ const char *delim = strchr(input, ';');
+ if (delim == NULL) {
+ delim = input + strlen(input);
+ }
+ uint16_t key_len = delim - input;
+ if (key_len > 0 && !(key_len == 1 && *input == '*')) {
+ *geodepth = i + 1;
+ switch (path[i].type) {
+ case GEODB_KEY_TXT:
+ geodata[i] = malloc(key_len + 1);
+ if (geodata[i] == NULL) {
+ return -1;
+ }
+ memcpy(geodata[i], input, key_len);
+ ((char *)geodata[i])[key_len] = '\0';
+ geodata_len[i] = key_len;
+ break;
+ case GEODB_KEY_ID:
+ geodata[i] = malloc(sizeof(uint32_t));
+ if (geodata[i] == NULL) {
+ return -1;
+ }
+ if (str_to_u32(input, (uint32_t *)geodata[i]) != KNOT_EOK) {
+ return -1;
+ }
+ geodata_len[i] = sizeof(uint32_t);
+ break;
+ default:
+ assert(0);
+ return -1;
+ }
+ }
+ if (*delim == '\0') {
+ break;
+ }
+ input = delim + 1;
+ }
+
+ return 0;
+}
+
+bool geodb_available(void)
+{
+#if HAVE_MAXMINDDB
+ return true;
+#else
+ return false;
+#endif
+}
+
+geodb_t *geodb_open(const char *filename)
+{
+#if HAVE_MAXMINDDB
+ MMDB_s *db = calloc(1, sizeof(MMDB_s));
+ if (db == NULL) {
+ return NULL;
+ }
+ int mmdb_error = MMDB_open(filename, MMDB_MODE_MMAP, db);
+ if (mmdb_error != MMDB_SUCCESS) {
+ free(db);
+ return NULL;
+ }
+ return db;
+#else
+ return NULL;
+#endif
+}
+
+void geodb_close(geodb_t *geodb)
+{
+#if HAVE_MAXMINDDB
+ MMDB_close(geodb);
+#endif
+}
+
+int geodb_query(geodb_t *geodb, geodb_data_t *entries, struct sockaddr *remote,
+ geodb_path_t *paths, uint16_t path_cnt, uint16_t *netmask)
+{
+#if HAVE_MAXMINDDB
+ int mmdb_error = 0;
+ MMDB_lookup_result_s res;
+ res = MMDB_lookup_sockaddr(geodb, remote, &mmdb_error);
+ if (mmdb_error != MMDB_SUCCESS || !res.found_entry) {
+ return -1;
+ }
+
+ // Save netmask.
+ *netmask = res.netmask;
+
+ for (uint16_t i = 0; i < path_cnt; i++) {
+ // Get the value of the next key.
+ mmdb_error = MMDB_aget_value(&res.entry, &entries[i], (const char *const*)paths[i].path);
+ if (mmdb_error != MMDB_SUCCESS && mmdb_error != MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR) {
+ return -1;
+ }
+ if (mmdb_error == MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR || !entries[i].has_data) {
+ entries[i].has_data = false;
+ continue;
+ }
+ // Check the type.
+ if (entries[i].type != type_map[paths[i].type]) {
+ entries[i].has_data = false;
+ continue;
+ }
+ }
+ return 0;
+#else
+ return -1;
+#endif
+}
+
+bool remote_in_geo(void **geodata, uint32_t *geodata_len, uint16_t geodepth, geodb_data_t *entries)
+{
+#if HAVE_MAXMINDDB
+ for (int i = 0; i < geodepth; i++) {
+ // Nothing to do if current geodata do not specify this key.
+ if (geodata[i] == NULL) {
+ continue;
+ }
+ if (!entries[i].has_data) {
+ return false;
+ }
+ switch (entries[i].type) {
+ case MMDB_DATA_TYPE_UTF8_STRING:
+ if (geodata_len[i] != entries[i].data_size ||
+ memcmp(geodata[i], entries[i].utf8_string, geodata_len[i]) != 0) {
+ return false;
+ }
+ break;
+ case MMDB_DATA_TYPE_UINT32:
+ if (*((uint32_t *)geodata[i]) != entries[i].uint32) {
+ return false;
+ }
+ break;
+ default:
+ return false;
+ }
+ }
+ return true;
+#else
+ return false;
+#endif
+}
diff --git a/src/knot/modules/geoip/geodb.h b/src/knot/modules/geoip/geodb.h
new file mode 100644
index 0000000..6995883
--- /dev/null
+++ b/src/knot/modules/geoip/geodb.h
@@ -0,0 +1,65 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <libknot/libknot.h>
+#if HAVE_MAXMINDDB
+#include <maxminddb.h>
+#endif
+
+#if HAVE_MAXMINDDB
+#define geodb_t MMDB_s
+#define geodb_data_t MMDB_entry_data_s
+#else
+#define geodb_t void
+#define geodb_data_t char
+#endif
+
+// MaxMind DB related constants.
+#define GEODB_MAX_PATH_LEN 8
+#define GEODB_MAX_DEPTH 8
+
+typedef enum {
+ GEODB_KEY_ID,
+ GEODB_KEY_TXT
+} geodb_key_type_t;
+
+static const knot_lookup_t geodb_key_types[] = {
+ { GEODB_KEY_ID, "id" },
+ { GEODB_KEY_TXT, "" }
+};
+
+typedef struct {
+ geodb_key_type_t type;
+ char *path[GEODB_MAX_PATH_LEN + 1]; // MMDB_aget_value() requires last member to be NULL.
+} geodb_path_t;
+
+int parse_geodb_path(geodb_path_t *path, const char *input);
+
+int parse_geodb_data(const char *input, void **geodata, uint32_t *geodata_len,
+ uint8_t *geodepth, geodb_path_t *path, uint16_t path_cnt);
+
+bool geodb_available(void);
+
+geodb_t *geodb_open(const char *filename);
+
+void geodb_close(geodb_t *geodb);
+
+int geodb_query(geodb_t *geodb, geodb_data_t *entries, struct sockaddr *remote,
+ geodb_path_t *paths, uint16_t path_cnt, uint16_t *netmask);
+
+bool remote_in_geo(void **geodata, uint32_t *geodata_len, uint16_t geodepth, geodb_data_t *entries);
diff --git a/src/knot/modules/geoip/geoip.c b/src/knot/modules/geoip/geoip.c
new file mode 100644
index 0000000..01e73e7
--- /dev/null
+++ b/src/knot/modules/geoip/geoip.c
@@ -0,0 +1,779 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+#include "knot/conf/schema.h"
+#include "knot/include/module.h"
+#include "knot/modules/geoip/geodb.h"
+#include "libknot/libknot.h"
+#include "contrib/qp-trie/trie.h"
+#include "contrib/ucw/lists.h"
+#include "contrib/sockaddr.h"
+#include "contrib/string.h"
+#include "contrib/strtonum.h"
+#include "libzscanner/scanner.h"
+
+#define MOD_CONFIG_FILE "\x0B""config-file"
+#define MOD_TTL "\x03""ttl"
+#define MOD_MODE "\x04""mode"
+#define MOD_GEODB_FILE "\x0A""geodb-file"
+#define MOD_GEODB_KEY "\x09""geodb-key"
+
+enum operation_mode {
+ MODE_SUBNET,
+ MODE_GEODB
+};
+
+static const knot_lookup_t modes[] = {
+ { MODE_SUBNET, "subnet" },
+ { MODE_GEODB, "geodb" },
+ { 0, NULL }
+};
+
+static const char* mode_key[] = {
+ [MODE_SUBNET] = "net",
+ [MODE_GEODB] = "geo"
+};
+
+const yp_item_t geoip_conf[] = {
+ { MOD_CONFIG_FILE, YP_TSTR, YP_VNONE },
+ { MOD_TTL, YP_TINT, YP_VINT = { 0, UINT32_MAX, 60, YP_STIME } },
+ { MOD_MODE, YP_TOPT, YP_VOPT = { modes, MODE_SUBNET} },
+ { MOD_GEODB_FILE, YP_TSTR, YP_VNONE },
+ { MOD_GEODB_KEY, YP_TSTR, YP_VSTR = { "country/iso_code" }, YP_FMULTI },
+ { NULL }
+};
+
+int geoip_conf_check(knotd_conf_check_args_t *args)
+{
+ knotd_conf_t conf = knotd_conf_check_item(args, MOD_CONFIG_FILE);
+ if (conf.count == 0) {
+ args->err_str = "no configuration file specified";
+ return KNOT_EINVAL;
+ }
+ conf = knotd_conf_check_item(args, MOD_MODE);
+ if (conf.count == 1 && conf.single.option == MODE_GEODB) {
+ if (!geodb_available()) {
+ args->err_str = "geodb mode not available";
+ return KNOT_EINVAL;
+ }
+ conf = knotd_conf_check_item(args, MOD_GEODB_FILE);
+ if (conf.count == 0) {
+ args->err_str = "no geodb file specified while in geodb mode";
+ return KNOT_EINVAL;
+ }
+ }
+ return KNOT_EOK;
+}
+
+typedef struct {
+ enum operation_mode mode;
+ uint32_t ttl;
+ trie_t *geo_trie;
+ bool dnssec;
+
+ geodb_t *geodb;
+ geodb_path_t paths[GEODB_MAX_DEPTH];
+ uint16_t path_count;
+} geoip_ctx_t;
+
+typedef struct {
+ struct sockaddr_storage *subnet;
+ uint8_t subnet_prefix;
+
+ void *geodata[GEODB_MAX_DEPTH];
+ uint32_t geodata_len[GEODB_MAX_DEPTH];
+ uint8_t geodepth;
+
+ size_t count, avail;
+ knot_rrset_t *rrsets;
+ knot_rrset_t *rrsigs;
+} geo_view_t;
+
+typedef struct {
+ size_t count, avail;
+ geo_view_t *views;
+} geo_trie_val_t;
+
+static int add_view_to_trie(knot_dname_t *owner, geo_view_t *view, geoip_ctx_t *ctx)
+{
+ int ret = KNOT_EOK;
+
+ // Find the node belonging to the owner.
+ knot_dname_storage_t lf_storage;
+ uint8_t *lf = knot_dname_lf(owner, lf_storage);
+ assert(lf);
+ trie_val_t *val = trie_get_ins(ctx->geo_trie, (char *)lf + 1, *lf);
+ geo_trie_val_t *cur_val = *val;
+
+ if (cur_val == NULL) {
+ // Create new node value.
+ geo_trie_val_t *new_val = calloc(1, sizeof(geo_trie_val_t));
+ new_val->avail = 1;
+ new_val->count = 1;
+ new_val->views = malloc(sizeof(geo_view_t));
+ new_val->views[0] = *view;
+
+ // Add new value to trie.
+ *val = new_val;
+ } else {
+ // Double the views array in size if necessary.
+ if (cur_val->avail == cur_val->count) {
+ void *alloc_ret = realloc(cur_val->views,
+ 2 * cur_val->avail * sizeof(geo_view_t));
+ if (alloc_ret == NULL) {
+ return KNOT_ENOMEM;
+ }
+ cur_val->views = alloc_ret;
+ cur_val->avail *= 2;
+ }
+
+ // Insert new element.
+ cur_val->views[cur_val->count++] = *view;
+ }
+
+ return ret;
+}
+
+static bool remote_in_subnet(const struct sockaddr_storage *remote, geo_view_t *view)
+{
+ if (view->subnet->ss_family != remote->ss_family) {
+ return false;
+ }
+ uint8_t *raw_addr = NULL;
+ uint8_t *raw_subnet = NULL;
+ switch(remote->ss_family) {
+ case AF_INET:
+ raw_addr = (uint8_t *)&((const struct sockaddr_in *)remote)->sin_addr;
+ raw_subnet = (uint8_t *)&((const struct sockaddr_in *)view->subnet)->sin_addr;
+ break;
+ case AF_INET6:
+ raw_addr = (uint8_t *)&((const struct sockaddr_in6 *)remote)->sin6_addr;
+ raw_subnet = (uint8_t *)&((const struct sockaddr_in6 *)view->subnet)->sin6_addr;
+ break;
+ default:
+ return false;
+ }
+ uint8_t nbytes = view->subnet_prefix / 8;
+ uint8_t nbits = view->subnet_prefix % 8;
+ for (int i = 0; i < nbytes; i++) {
+ if (raw_addr[i] != raw_subnet[i]) {
+ return false;
+ }
+ }
+ if (nbits != 0) {
+ uint8_t mask = ((1 << nbits) - 1) << (8 - nbits);
+ if ((raw_addr[nbytes] & mask) != raw_subnet[nbytes]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static int finalize_geo_view(knotd_mod_t *mod, geo_view_t *view, knot_dname_t *owner,
+ geoip_ctx_t *ctx)
+{
+ if (view == NULL || view->count == 0) {
+ return KNOT_EOK;
+ }
+
+ int ret = KNOT_EOK;
+ if (ctx->dnssec) {
+ view->rrsigs = malloc(sizeof(knot_rrset_t) * view->count);
+ if (view->rrsigs == NULL) {
+ return KNOT_ENOMEM;
+ }
+ for (size_t i = 0; i < view->count; i++) {
+ knot_dname_t *owner_cpy = knot_dname_copy(owner, NULL);
+ if (owner_cpy == NULL) {
+ return KNOT_ENOMEM;
+ }
+ knot_rrset_init(&view->rrsigs[i], owner_cpy, KNOT_RRTYPE_RRSIG,
+ KNOT_CLASS_IN, ctx->ttl);
+ ret = knotd_mod_dnssec_sign_rrset(mod, &view->rrsigs[i],
+ &view->rrsets[i], NULL);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+ }
+
+ ret = add_view_to_trie(owner, view, ctx);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ memset(view, 0, sizeof(*view));
+ return ret;
+}
+
+static int init_geo_view(geo_view_t *view)
+{
+ if (view == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ view->count = 0;
+ view->avail = 1;
+ view->rrsigs = NULL;
+ view->rrsets = malloc(sizeof(knot_rrset_t));
+ if (view->rrsets == NULL) {
+ return KNOT_ENOMEM;
+ }
+ return KNOT_EOK;
+}
+
+static void clear_geo_view(geo_view_t *view)
+{
+ if (view == NULL) {
+ return;
+ }
+ for (int i = 0; i < GEODB_MAX_DEPTH; i++) {
+ free(view->geodata[i]);
+ }
+ free(view->subnet);
+ for (int j = 0; j < view->count; j++) {
+ knot_rrset_clear(&view->rrsets[j], NULL);
+ if (view->rrsigs != NULL) {
+ knot_rrset_clear(&view->rrsigs[j], NULL);
+ }
+ }
+ free(view->rrsets);
+ view->rrsets = NULL;
+ free(view->rrsigs);
+ view->rrsigs = NULL;
+}
+
+static int parse_origin(yp_parser_t *yp, zs_scanner_t *scanner)
+{
+ char *set_origin = sprintf_alloc("$ORIGIN %s%s\n", yp->key,
+ (yp->key[yp->key_len - 1] == '.') ? "" : ".");
+ if (set_origin == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ // Set owner as origin for future record parses.
+ if (zs_set_input_string(scanner, set_origin, strlen(set_origin)) != 0 ||
+ zs_parse_record(scanner) != 0) {
+ free(set_origin);
+ return KNOT_EPARSEFAIL;
+ }
+ free(set_origin);
+ return KNOT_EOK;
+}
+
+static int parse_view(knotd_mod_t *mod, geoip_ctx_t *ctx, yp_parser_t *yp, geo_view_t *view)
+{
+ // Initialize new geo view.
+ memset(view, 0, sizeof(*view));
+ int ret = init_geo_view(view);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Check view type syntax.
+ int key_len = strlen(mode_key[ctx->mode]);
+ if (yp->key_len != key_len || memcmp(yp->key, mode_key[ctx->mode], key_len) != 0) {
+ knotd_mod_log(mod, LOG_ERR, "invalid key type (%s) on line %zu",
+ yp->key, yp->line_count);
+ return KNOT_EINVAL;
+ }
+
+ // Parse geodata/subnet.
+ if (ctx->mode == MODE_GEODB) {
+ if (parse_geodb_data((char *)yp->data, view->geodata, view->geodata_len,
+ &view->geodepth, ctx->paths, ctx->path_count) != 0) {
+ knotd_mod_log(mod, LOG_ERR, "invalid geo format (%s) on line %zu",
+ yp->data, yp->line_count);
+ return KNOT_EINVAL;
+ }
+ } else if (ctx->mode == MODE_SUBNET) {
+ // Locate the optional slash in the subnet string.
+ char *slash = strchr(yp->data, '/');
+ if (slash == NULL) {
+ slash = yp->data + yp->data_len;
+ }
+ *slash = '\0';
+
+ // Parse address.
+ view->subnet = calloc(1, sizeof(struct sockaddr_storage));
+ if (view->subnet == NULL) {
+ return KNOT_ENOMEM;
+ }
+ void *write_addr = &((struct sockaddr_in *)view->subnet)->sin_addr;
+ // Try to parse as IPv4 address.
+ ret = inet_pton(AF_INET, yp->data, write_addr);
+ if (ret == 1) {
+ view->subnet->ss_family = AF_INET;
+ view->subnet_prefix = 32;
+ } else { // Try to parse as IPv6 address.
+ write_addr = &((struct sockaddr_in6 *)view->subnet)->sin6_addr;
+ ret = inet_pton(AF_INET6, yp->data, write_addr);
+ if (ret != 1) {
+ knotd_mod_log(mod, LOG_ERR, "invalid address format (%s) on line %zu",
+ yp->data, yp->line_count);
+ return KNOT_EINVAL;
+ }
+ view->subnet->ss_family = AF_INET6;
+ view->subnet_prefix = 128;
+ }
+
+ // Parse subnet prefix.
+ if (slash < yp->data + yp->data_len - 1) {
+ ret = str_to_u8(slash + 1, &view->subnet_prefix);
+ if (ret != KNOT_EOK) {
+ knotd_mod_log(mod, LOG_ERR, "invalid prefix (%s) on line %zu",
+ slash + 1, yp->line_count);
+ return ret;
+ }
+ if (view->subnet->ss_family == AF_INET && view->subnet_prefix > 32) {
+ view->subnet_prefix = 32;
+ knotd_mod_log(mod, LOG_WARNING, "IPv4 prefix too large on line %zu, set to 32",
+ yp->line_count);
+ }
+ if (view->subnet->ss_family == AF_INET6 && view->subnet_prefix > 128) {
+ view->subnet_prefix = 128;
+ knotd_mod_log(mod, LOG_WARNING, "IPv6 prefix too large on line %zu, set to 128",
+ yp->line_count);
+ }
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+static int parse_rr(knotd_mod_t *mod, yp_parser_t *yp, zs_scanner_t *scanner,
+ knot_dname_t *owner, geo_view_t *view, uint32_t ttl)
+{
+ uint16_t rr_type = KNOT_RRTYPE_A;
+ if (knot_rrtype_from_string(yp->key, &rr_type) != 0) {
+ knotd_mod_log(mod, LOG_ERR, "invalid RR type (%s) on line %zu",
+ yp->key, yp->line_count);
+ return KNOT_EINVAL;
+ }
+
+ if (knot_rrtype_is_dnssec(rr_type)) {
+ knotd_mod_log(mod, LOG_ERR, "DNSSEC record (%s) not allowed on line %zu",
+ yp->key, yp->line_count);
+ return KNOT_EINVAL;
+ }
+
+ knot_rrset_t *add_rr = NULL;
+ for (size_t i = 0; i < view->count; i++) {
+ if (view->rrsets[i].type == rr_type) {
+ add_rr = &view->rrsets[i];
+ break;
+ }
+ }
+
+ if (add_rr == NULL) {
+ if (view->count == view->avail) {
+ void *alloc_ret = realloc(view->rrsets,
+ 2 * view->avail * sizeof(knot_rrset_t));
+ if (alloc_ret == NULL) {
+ return KNOT_ENOMEM;
+ }
+ view->rrsets = alloc_ret;
+ view->avail *= 2;
+ }
+ add_rr = &view->rrsets[view->count++];
+ knot_dname_t *owner_cpy = knot_dname_copy(owner, NULL);
+ if (owner_cpy == NULL) {
+ return KNOT_ENOMEM;
+ }
+ knot_rrset_init(add_rr, owner_cpy, rr_type, KNOT_CLASS_IN, ttl);
+ }
+
+ // Parse record.
+ char *input_string = sprintf_alloc("@ %s %s\n", yp->key, yp->data);
+ if (input_string == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ if (zs_set_input_string(scanner, input_string, strlen(input_string)) != 0 ||
+ zs_parse_record(scanner) != 0 ||
+ scanner->state != ZS_STATE_DATA) {
+ free(input_string);
+ return KNOT_EPARSEFAIL;
+ }
+ free(input_string);
+
+ // Add new rdata to current rrset.
+ return knot_rrset_add_rdata(add_rr, scanner->r_data, scanner->r_data_length, NULL);
+}
+
+static int geo_conf_yparse(knotd_mod_t *mod, geoip_ctx_t *ctx)
+{
+ int ret = KNOT_EOK;
+ yp_parser_t *yp = NULL;
+ zs_scanner_t *scanner = NULL;
+ knot_dname_t owner_buff[KNOT_DNAME_MAXLEN];
+ knot_dname_t *owner = NULL;
+ geo_view_t *view = calloc(1, sizeof(geo_view_t));
+ if (view == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ // Initialize yparser.
+ yp = malloc(sizeof(yp_parser_t));
+ if (yp == NULL) {
+ ret = KNOT_ENOMEM;
+ goto cleanup;
+ }
+ yp_init(yp);
+ knotd_conf_t conf = knotd_conf_mod(mod, MOD_CONFIG_FILE);
+ ret = yp_set_input_file(yp, conf.single.string);
+ if (ret != KNOT_EOK) {
+ knotd_mod_log(mod, LOG_ERR, "failed to load configuration file");
+ goto cleanup;
+ }
+
+ // Initialize zscanner.
+ scanner = malloc(sizeof(zs_scanner_t));
+ if (scanner == NULL) {
+ ret = KNOT_ENOMEM;
+ goto cleanup;
+ }
+ if (zs_init(scanner, NULL, KNOT_CLASS_IN, ctx->ttl) != 0) {
+ ret = KNOT_EPARSEFAIL;
+ goto cleanup;
+ }
+
+ // Main loop.
+ while (1) {
+ // Get the next item in config.
+ ret = yp_parse(yp);
+ if (ret == KNOT_EOF) {
+ ret = finalize_geo_view(mod, view, owner, ctx);
+ goto cleanup;
+ }
+ if (ret != KNOT_EOK) {
+ knotd_mod_log(mod, LOG_ERR, "failed to parse configuration file (%s)",
+ knot_strerror(ret));
+ goto cleanup;
+ }
+
+ // If the next item is not a rrset, the current view is finished.
+ if (yp->event != YP_EKEY1) {
+ ret = finalize_geo_view(mod, view, owner, ctx);
+ if (ret != KNOT_EOK) {
+ goto cleanup;
+ }
+ }
+
+ // Next domain.
+ if (yp->event == YP_EKEY0) {
+ owner = knot_dname_from_str(owner_buff, yp->key, sizeof(owner_buff));
+ if (owner == NULL) {
+ knotd_mod_log(mod, LOG_ERR, "invalid domain name in config on line %zu",
+ yp->line_count);
+ ret = KNOT_EINVAL;
+ goto cleanup;
+ }
+ ret = parse_origin(yp, scanner);
+ if (ret != KNOT_EOK) {
+ goto cleanup;
+ }
+ }
+
+ // Next view.
+ if (yp->event == YP_EID) {
+ ret = parse_view(mod, ctx, yp, view);
+ if (ret != KNOT_EOK) {
+ goto cleanup;
+ }
+ }
+
+ // Next RR of the current view.
+ if (yp->event == YP_EKEY1) {
+ // Check whether we really are in a view.
+ if (view->avail <= 0) {
+ knotd_mod_log(mod, LOG_ERR, "missing '%s' in config before line %zu",
+ (ctx->mode == MODE_SUBNET) ? "- net: SUBNET" : "- geo: LOCATION",
+ yp->line_count);
+ ret = KNOT_EINVAL;
+ goto cleanup;
+ }
+ ret = parse_rr(mod, yp, scanner, owner, view, ctx->ttl);
+ if (ret != KNOT_EOK) {
+ goto cleanup;
+ }
+ }
+ }
+
+cleanup:
+ if (ret != KNOT_EOK) {
+ clear_geo_view(view);
+ }
+ free(view);
+ zs_deinit(scanner);
+ free(scanner);
+ yp_deinit(yp);
+ free(yp);
+ return ret;
+}
+
+static void clear_geo_trie(trie_t *trie)
+{
+ trie_it_t *it = trie_it_begin(trie);
+ while (!trie_it_finished(it)) {
+ geo_trie_val_t *val = (geo_trie_val_t *) (*trie_it_val(it));
+ for (int i = 0; i < val->count; i++) {
+ clear_geo_view(&val->views[i]);
+ }
+ free(val->views);
+ free(val);
+ trie_it_next(it);
+ }
+ trie_it_free(it);
+ trie_clear(trie);
+}
+
+static void free_geoip_ctx(geoip_ctx_t *ctx)
+{
+ geodb_close(ctx->geodb);
+ free(ctx->geodb);
+ clear_geo_trie(ctx->geo_trie);
+ trie_free(ctx->geo_trie);
+ for (int i = 0; i < ctx->path_count; i++) {
+ for (int j = 0; j < GEODB_MAX_PATH_LEN; j++) {
+ free(ctx->paths[i].path[j]);
+ }
+ }
+ free(ctx);
+}
+
+static knotd_in_state_t geoip_process(knotd_in_state_t state, knot_pkt_t *pkt,
+ knotd_qdata_t *qdata, knotd_mod_t *mod)
+{
+ assert(pkt && qdata && mod);
+
+ // Nothing to do if the query was already resolved by a previous module.
+ if (state == KNOTD_IN_STATE_HIT) {
+ return state;
+ }
+
+ geoip_ctx_t *ctx = (geoip_ctx_t *)knotd_mod_ctx(mod);
+
+ // Save the query type.
+ uint16_t qtype = knot_pkt_qtype(qdata->query);
+
+ // Check if geolocation is available for given query.
+ knot_dname_storage_t lf_storage;
+ uint8_t *lf = knot_dname_lf(knot_pkt_qname(qdata->query), lf_storage);
+ // Exit if no qname.
+ if (lf == NULL) {
+ return state;
+ }
+ trie_val_t *val = trie_get_try(ctx->geo_trie, (char *)lf + 1, *lf);
+ if (val == NULL) {
+ // Nothing to do in this module.
+ return state;
+ }
+
+ geo_trie_val_t *data = *val;
+
+ // Check if EDNS Client Subnet is available.
+ struct sockaddr_storage ecs_addr = { 0 };
+ const struct sockaddr_storage *remote = qdata->params->remote;
+ if (knot_edns_client_subnet_get_addr(&ecs_addr, qdata->ecs) == KNOT_EOK) {
+ remote = &ecs_addr;
+ }
+
+ knot_rrset_t *rr = NULL;
+ knot_rrset_t *rrsig = NULL;
+ knot_rrset_t *cname = NULL;
+ knot_rrset_t *cnamesig = NULL;
+ uint16_t netmask = 0;
+ if (ctx->mode == MODE_SUBNET) {
+ // Find the best subnet containing the remote and queried rrset.
+ uint8_t best_prefix = 0;
+ for (int i = 0; i < data->count; i++) {
+ geo_view_t *view = &data->views[i];
+ if ((rr == NULL || view->subnet_prefix > best_prefix) && remote_in_subnet(remote, view)) {
+ for (int j = 0; j < view->count; j++) {
+ if (view->rrsets[j].type == qtype) {
+ best_prefix = view->subnet_prefix;
+ rr = &view->rrsets[j];
+ rrsig = (view->rrsigs) ? &view->rrsigs[j] : NULL;
+ break;
+ } else if (view->rrsets[j].type == KNOT_RRTYPE_CNAME) {
+ best_prefix = view->subnet_prefix;
+ cname = &view->rrsets[j];
+ cnamesig = (view->rrsigs) ? &view->rrsigs[j] : NULL;
+ }
+ }
+ }
+ }
+ netmask = best_prefix;
+ } else if (ctx->mode == MODE_GEODB) {
+ geodb_data_t entries[ctx->path_count];
+
+ int ret = geodb_query(ctx->geodb, entries, (struct sockaddr *)remote,
+ ctx->paths, ctx->path_count, &netmask);
+ // MMDB may supply IPv6 prefixes even for IPv4 address, see man libmaxminddb.
+ if (remote->ss_family == AF_INET && netmask > 32) {
+ netmask -= 96;
+ }
+
+ if (ret != 0) {
+ return state;
+ }
+
+ uint8_t best_depth = 0;
+ // Find the best geo view containing the remote and queried rrset.
+ for (int i = 0; i < data->count; i++) {
+ geo_view_t *view = &data->views[i];
+ if ((rr == NULL || view->geodepth > best_depth) &&
+ remote_in_geo(view->geodata, view->geodata_len, view->geodepth, entries)) {
+ for (int j = 0; j < view->count; j++) {
+ if (view->rrsets[j].type == qtype) {
+ best_depth = view->geodepth;
+ rr = &view->rrsets[j];
+ rrsig = (view->rrsigs) ? &view->rrsigs[j] : NULL;
+ break;
+ } else if (view->rrsets[j].type == KNOT_RRTYPE_CNAME) {
+ best_depth = view->geodepth;
+ cname = &view->rrsets[j];
+ cnamesig = (view->rrsigs) ? &view->rrsigs[j] : NULL;
+ }
+ }
+ }
+ }
+ }
+
+ // Return CNAME if only CNAME is found.
+ if (rr == NULL && cname != NULL) {
+ rr = cname;
+ rrsig = cnamesig;
+ }
+
+ // Answer the query if possible.
+ if (rr != NULL) {
+ // Update ECS if used.
+ if (qdata->ecs != NULL && netmask > 0) {
+ qdata->ecs->scope_len = netmask;
+ }
+
+ knot_pkt_put(pkt, KNOT_COMPR_HINT_QNAME, rr, 0);
+ if (ctx->dnssec && knot_pkt_has_dnssec(qdata->query) && rrsig != NULL) {
+ knot_pkt_put(pkt, KNOT_COMPR_HINT_QNAME, rrsig, 0);
+ }
+
+ // We've got an answer, set the AA bit.
+ knot_wire_set_aa(pkt->wire);
+
+ return KNOTD_IN_STATE_HIT;
+ }
+
+ return state;
+}
+
+int geoip_load(knotd_mod_t *mod)
+{
+ // Create module context.
+ geoip_ctx_t *ctx = calloc(1, sizeof(geoip_ctx_t));
+ if (ctx == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ knotd_conf_t conf = knotd_conf_mod(mod, MOD_TTL);
+ ctx->ttl = conf.single.integer;
+ conf = knotd_conf_mod(mod, MOD_MODE);
+ ctx->mode = conf.single.option;
+
+ // Initialize the dname trie.
+ ctx->geo_trie = trie_create(NULL);
+ if (ctx->geo_trie == NULL) {
+ free_geoip_ctx(ctx);
+ return KNOT_ENOMEM;
+ }
+
+ if (ctx->mode == MODE_GEODB) {
+ // Initialize geodb.
+ conf = knotd_conf_mod(mod, MOD_GEODB_FILE);
+ ctx->geodb = geodb_open(conf.single.string);
+ if (ctx->geodb == NULL) {
+ knotd_mod_log(mod, LOG_ERR, "failed to open geo DB");
+ free_geoip_ctx(ctx);
+ return KNOT_EINVAL;
+ }
+
+ // Load configured geodb keys.
+ conf = knotd_conf_mod(mod, MOD_GEODB_KEY);
+ ctx->path_count = conf.count;
+ if (ctx->path_count > GEODB_MAX_DEPTH) {
+ knotd_mod_log(mod, LOG_ERR, "maximal number of geodb-key items (%d) exceeded",
+ GEODB_MAX_DEPTH);
+ knotd_conf_free(&conf);
+ free_geoip_ctx(ctx);
+ return KNOT_EINVAL;
+ }
+ for (size_t i = 0; i < conf.count; i++) {
+ if (parse_geodb_path(&ctx->paths[i], (char *)conf.multi[i].string) != 0) {
+ knotd_mod_log(mod, LOG_ERR, "unrecognized geodb-key format");
+ knotd_conf_free(&conf);
+ free_geoip_ctx(ctx);
+ return KNOT_EINVAL;
+ }
+ }
+ knotd_conf_free(&conf);
+ }
+
+ // Is DNSSEC used on this zone?
+ conf = knotd_conf_zone(mod, C_DNSSEC_SIGNING, knotd_mod_zone(mod));
+ ctx->dnssec = conf.single.boolean;
+ if (ctx->dnssec) {
+ int ret = knotd_mod_dnssec_init(mod);
+ if (ret != KNOT_EOK) {
+ knotd_mod_log(mod, LOG_ERR, "failed to initialize DNSSEC");
+ free_geoip_ctx(ctx);
+ return ret;
+ }
+ ret = knotd_mod_dnssec_load_keyset(mod, false);
+ if (ret != KNOT_EOK) {
+ knotd_mod_log(mod, LOG_ERR, "failed to load DNSSEC keys");
+ free_geoip_ctx(ctx);
+ return ret;
+ }
+ }
+
+ // Parse geo configuration file.
+ int ret = geo_conf_yparse(mod, ctx);
+ if (ret != KNOT_EOK) {
+ knotd_mod_log(mod, LOG_ERR, "failed to load geo configuration");
+ free_geoip_ctx(ctx);
+ return ret;
+ }
+
+ knotd_mod_ctx_set(mod, ctx);
+
+ return knotd_mod_in_hook(mod, KNOTD_STAGE_PREANSWER, geoip_process);
+}
+
+void geoip_unload(knotd_mod_t *mod)
+{
+ geoip_ctx_t *ctx = knotd_mod_ctx(mod);
+ if (ctx != NULL) {
+ free_geoip_ctx(ctx);
+ }
+}
+
+KNOTD_MOD_API(geoip, KNOTD_MOD_FLAG_SCOPE_ZONE,
+ geoip_load, geoip_unload, geoip_conf, geoip_conf_check);
diff --git a/src/knot/modules/geoip/geoip.rst b/src/knot/modules/geoip/geoip.rst
new file mode 100644
index 0000000..745a6ed
--- /dev/null
+++ b/src/knot/modules/geoip/geoip.rst
@@ -0,0 +1,211 @@
+.. _mod-geoip:
+
+``geoip`` — Geography-based responses
+=====================================
+
+This module offers response tailoring based on client's
+subnet or geographic location. It supports GeoIP databases
+in the MaxMind DB format, such as `GeoIP2 <https://dev.maxmind.com/geoip/geoip2/downloadable/>`_
+or the free version `GeoLite2 <https://dev.maxmind.com/geoip/geoip2/geolite2/>`_.
+
+The module can be enabled only per zone.
+
+.. NOTE::
+ If :ref:`EDNS Client Subnet<server_edns-client-subnet>` support is enabled
+ and if a query contains this option, the module takes advantage of this
+ information to provide a more accurate response.
+
+DNSSEC support
+--------------
+
+There are two ways to enable DNSSEC signing of tailored responses.
+If automatic DNSSEC signing is enabled, record signatures are precomputed when the module is loaded.
+This has a speed benefit, however note that every RRset configured in the module should
+have a **default** RRset of the same type contained in the zone, so that the NSEC(3)
+chain can be built correctly. Also, it is STRONGLY RECOMMENDED to use
+:ref:`manual key management <dnssec-manual-key-management>` in this setting,
+as the corresponding zone has to be reloaded when the signing key changes and to
+have better control over key synchronization to all instances of the server.
+
+.. NOTE::
+ If the GeoIP module is used with automatic DNSSEC signing, the keys for computing record signatures
+ MUST exist or be generated before the server is launched, otherwise the module fails to
+ compute the signatures and does not load.
+
+Alternatively, the :ref:`geoip<mod-geoip>` module may be combined with the
+:ref:`onlinesign<mod-onlinesign>` module and the tailored responses can be signed
+on the fly. This approach is much more computationally demanding for the server.
+
+.. NOTE::
+ If the GeoIP module is used with online signing, it is recommended to set the :ref:`nsec-bitmap<mod-onlinesign_nsec-bitmap>`
+ option of the onlinesign module to contain all Resource Record types potentially generated by the module.
+
+Example
+-------
+* An example configuration.::
+
+ mod-geoip:
+ - id: default
+ config-file: /path/to/geo.conf
+ ttl: 20
+ mode: geodb
+ geodb-file: /path/to/GeoLite2-City.mmdb
+ geodb-key: [ country/iso_code, city/names/en ]
+
+ zone:
+ - domain: example.com.
+ module: mod-geoip/default
+
+
+Configuration file
+------------------
+
+Every instance of the module requires an additional :ref:`mod-geoip_config-file`
+in which the desired responses to queries from various locations are configured.
+This file has the following simple format:
+
+::
+
+ domain-name1:
+ - geo|net: location1
+ RR-Type1: RDATA
+ RR-Type2: RDATA
+ ...
+ - geo|net: location2
+ RR-Type1: RDATA
+ ...
+ domain-name2:
+ ...
+
+
+Example
+-------
+
+* Example :ref:`mod-geoip_config-file` for subnets
+
+::
+
+ foo.example.com:
+ - net: 10.0.0.0/24
+ A: [ 192.168.1.1, 192.168.1.2 ]
+ AAAA: [ 2001:DB8::1, 2001:DB8::2 ]
+ TXT: "subnet\ 10.0.0.0/24"
+ ...
+ bar.example.com:
+ - net: 2001:DB8::/32
+ A: 192.168.1.3
+ AAAA: 2001:DB8::3
+ TXT: "subnet\ 2001:DB8::/32"
+ ...
+
+.. NOTE::
+ If a space or a quotation mark is a part of record data, such a character
+ must be prefixed with a backslash. The following notations are equivalent::
+
+ Multi-word\ string
+ "Multi-word\ string"
+ "\"Multi-word string\""
+
+* Example :ref:`mod-geoip_config-file` for geographic locations
+
+::
+
+ foo.example.com:
+ - geo: "CZ;Prague"
+ CNAME: cz.foo.example.com
+ - geo: "US;Las Vegas"
+ CNAME: vegas.foo.example.net
+ - geo: "US;*"
+ CNAME: us.foo.example.net
+ ...
+
+
+Module reference
+----------------
+
+::
+
+ mod-geoip:
+ - id: STR
+ config-file: STR
+ ttl: TIME
+ mode: geodb | subnet
+ geodb-file: STR
+ geodb-key: STR ...
+
+.. _mod-geoip_id:
+
+id
+..
+
+A module identifier.
+
+.. _mod-geoip_config-file:
+
+config-file
+...........
+
+Full path to the response configuration file as described above.
+
+*Required*
+
+.. _mod-geoip_ttl:
+
+ttl
+...
+
+The time to live of Resource Records returned by the module.
+
+*Default:* 60
+
+.. _mod-geoip_mode:
+
+mode
+....
+
+The mode of operation of the module.
+
+Possible values:
+
+- ``subnet`` – Responses are tailored according to subnets.
+- ``geodb`` – Responses are tailored according to geographic data retrieved
+ from the configured database.
+
+*Default:* subnet
+
+.. _mod-geoip_geodb-file:
+
+geodb-file
+..........
+
+Full path to a .mmdb file containing the GeoIP database.
+
+*Reqired if* :ref:`mod-geoip_mode` *is set to* **geodb**
+
+.. _mod-geoip_geodb-key:
+
+geodb-key
+.........
+
+Multi-valued item, can be specified up to **8** times. Each **geodb-key** specifies
+a path to a key in a node in the supplied GeoIP database. The module currently supports
+two types of values: **string** or **32-bit unsigned int**. In the latter
+case, the key has to be prefixed with **(id)**. Common choices of keys include:
+
+* **continent/code**
+
+* **country/iso_code**
+
+* **(id)country/geoname_id**
+
+* **city/names/en**
+
+* **(id)city/geoname_id**
+
+* **isp**
+
+* ...
+
+In the zone's config file for the module the values of the keys are entered in the same order
+as the keys in the module's configuration, separated by a semicolon. Enter the value **"*"**
+if the key is allowed to have any value.
diff --git a/src/knot/modules/noudp/Makefile.inc b/src/knot/modules/noudp/Makefile.inc
new file mode 100644
index 0000000..cf26a35
--- /dev/null
+++ b/src/knot/modules/noudp/Makefile.inc
@@ -0,0 +1,12 @@
+knot_modules_noudp_la_SOURCES = knot/modules/noudp/noudp.c
+EXTRA_DIST += knot/modules/noudp/noudp.rst
+
+if STATIC_MODULE_noudp
+libknotd_la_SOURCES += $(knot_modules_noudp_la_SOURCES)
+endif
+
+if SHARED_MODULE_noudp
+knot_modules_noudp_la_LDFLAGS = $(KNOTD_MOD_LDFLAGS)
+knot_modules_noudp_la_CPPFLAGS = $(KNOTD_MOD_CPPFLAGS)
+pkglib_LTLIBRARIES += knot/modules/noudp.la
+endif
diff --git a/src/knot/modules/noudp/noudp.c b/src/knot/modules/noudp/noudp.c
new file mode 100644
index 0000000..c2f064a
--- /dev/null
+++ b/src/knot/modules/noudp/noudp.c
@@ -0,0 +1,43 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "knot/include/module.h"
+
+static bool is_udp(knotd_qdata_t *qdata)
+{
+ return qdata->params->flags & KNOTD_QUERY_FLAG_LIMIT_SIZE;
+}
+
+static knotd_state_t noudp_begin(knotd_state_t state, knot_pkt_t *pkt,
+ knotd_qdata_t *qdata, knotd_mod_t *mod)
+{
+ if (is_udp(qdata)) {
+ knot_wire_set_tc(pkt->wire);
+ return KNOTD_STATE_DONE;
+ }
+
+ return state;
+}
+
+int noudp_load(knotd_mod_t *mod)
+{
+ knotd_mod_hook(mod, KNOTD_STAGE_BEGIN, noudp_begin);
+
+ return KNOT_EOK;
+}
+
+KNOTD_MOD_API(noudp, KNOTD_MOD_FLAG_SCOPE_ANY | KNOTD_MOD_FLAG_OPT_CONF,
+ noudp_load, NULL, NULL, NULL);
diff --git a/src/knot/modules/noudp/noudp.rst b/src/knot/modules/noudp/noudp.rst
new file mode 100644
index 0000000..03f790d
--- /dev/null
+++ b/src/knot/modules/noudp/noudp.rst
@@ -0,0 +1,20 @@
+.. _mod-noudp:
+
+``noudp`` — No UDP response
+===========================
+
+The module sends empty truncated response to any UDP query. TCP queries are
+not affected.
+
+Example
+-------
+
+To enable this module globally, you need to add something like the following
+to the configuration file::
+
+ template:
+ - id: default
+ global-module: mod-noudp
+
+.. NOTE::
+ This module is not configurable.
diff --git a/src/knot/modules/onlinesign/Makefile.inc b/src/knot/modules/onlinesign/Makefile.inc
new file mode 100644
index 0000000..bfccf3e
--- /dev/null
+++ b/src/knot/modules/onlinesign/Makefile.inc
@@ -0,0 +1,15 @@
+knot_modules_onlinesign_la_SOURCES = knot/modules/onlinesign/onlinesign.c \
+ knot/modules/onlinesign/nsec_next.c \
+ knot/modules/onlinesign/nsec_next.h
+EXTRA_DIST += knot/modules/onlinesign/onlinesign.rst
+
+if STATIC_MODULE_onlinesign
+libknotd_la_SOURCES += $(knot_modules_onlinesign_la_SOURCES)
+endif
+
+if SHARED_MODULE_onlinesign
+knot_modules_onlinesign_la_LDFLAGS = $(KNOTD_MOD_LDFLAGS)
+knot_modules_onlinesign_la_CPPFLAGS = $(KNOTD_MOD_CPPFLAGS)
+knot_modules_onlinesign_la_LIBADD = libcontrib.la
+pkglib_LTLIBRARIES += knot/modules/onlinesign.la
+endif
diff --git a/src/knot/modules/onlinesign/nsec_next.c b/src/knot/modules/onlinesign/nsec_next.c
new file mode 100644
index 0000000..1314154
--- /dev/null
+++ b/src/knot/modules/onlinesign/nsec_next.c
@@ -0,0 +1,113 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include "knot/modules/onlinesign/nsec_next.h"
+#include "libknot/libknot.h"
+
+static bool inc_label(const uint8_t *buffer, uint8_t **label_ptr)
+{
+ assert(buffer);
+ assert(label_ptr && *label_ptr);
+ assert(buffer <= *label_ptr && *label_ptr < buffer + KNOT_DNAME_MAXLEN);
+
+ const uint8_t *label = *label_ptr;
+ const uint8_t len = *label;
+ const uint8_t *first = *label_ptr + 1;
+ const uint8_t *last = *label_ptr + len;
+
+ assert(len <= KNOT_DNAME_MAXLABELLEN);
+
+ // jump over trailing 0xff chars
+ uint8_t *scan = (uint8_t *)last;
+ while (scan >= first && *scan == 0xff) {
+ scan -= 1;
+ }
+
+ // increase in place
+ if (scan >= first) {
+ if (*scan == 'A' - 1) {
+ *scan = 'Z' + 1;
+ } else {
+ *scan += 1;
+ }
+ memset(scan + 1, 0x00, last - scan);
+ return true;
+ }
+
+ // check name and label boundaries
+ if (scan - 1 < buffer || len == KNOT_DNAME_MAXLABELLEN) {
+ return false;
+ }
+
+ // append a zero byte at the end of the label
+ scan -= 1;
+ scan[0] = len + 1;
+ memmove(scan + 1, first, len);
+ scan[len + 1] = 0x00;
+
+ *label_ptr = scan;
+
+ return true;
+}
+
+static void strip_label(uint8_t **name_ptr)
+{
+ assert(name_ptr && *name_ptr);
+
+ uint8_t len = **name_ptr;
+ *name_ptr += 1 + len;
+}
+
+knot_dname_t *online_nsec_next(const knot_dname_t *dname, const knot_dname_t *apex)
+{
+ assert(dname);
+ assert(apex);
+
+ // right aligned copy of the domain name
+ uint8_t copy[KNOT_DNAME_MAXLEN] = { 0 };
+ size_t dname_len = knot_dname_size(dname);
+ size_t empty_len = sizeof(copy) - dname_len;
+ uint8_t *pos = copy + empty_len;
+ memmove(pos, dname, dname_len);
+
+ // add new zero-byte label
+ if (empty_len >= 2) {
+ pos -= 2;
+ pos[0] = 0x01;
+ pos[1] = 0x00;
+ return knot_dname_copy(pos, NULL);
+ }
+
+ // find apex position in the buffer
+ size_t apex_len = knot_dname_size(apex);
+ const uint8_t *apex_pos = copy + sizeof(copy) - apex_len;
+ assert(knot_dname_is_equal(apex, apex_pos));
+
+ // find first label which can be incremented
+ while (pos != apex_pos) {
+ if (inc_label(copy, &pos)) {
+ return knot_dname_copy(pos, NULL);
+ }
+ strip_label(&pos);
+ }
+
+ // apex completes the chain
+ return knot_dname_copy(pos, NULL);
+}
diff --git a/src/knot/modules/onlinesign/nsec_next.h b/src/knot/modules/onlinesign/nsec_next.h
new file mode 100644
index 0000000..4d9a6c4
--- /dev/null
+++ b/src/knot/modules/onlinesign/nsec_next.h
@@ -0,0 +1,29 @@
+/* Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include "libknot/dname.h"
+
+/*!
+ * \brief Get the very next possible name in NSEC chain.
+ *
+ * \param dname Current dname in the NSEC chain.
+ * \param apex Zone apex name, used when we reach the end of the chain.
+ *
+ * \return Successor of dname in the NSEC chain.
+ */
+knot_dname_t *online_nsec_next(const knot_dname_t *dname, const knot_dname_t *apex);
diff --git a/src/knot/modules/onlinesign/onlinesign.c b/src/knot/modules/onlinesign/onlinesign.c
new file mode 100644
index 0000000..8dc9d50
--- /dev/null
+++ b/src/knot/modules/onlinesign/onlinesign.c
@@ -0,0 +1,776 @@
+/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "contrib/string.h"
+#include "libdnssec/error.h"
+#include "knot/include/module.h"
+#include "knot/modules/onlinesign/nsec_next.h"
+// Next dependencies force static module!
+#include "knot/dnssec/ds_query.h"
+#include "knot/dnssec/key-events.h"
+#include "knot/dnssec/policy.h"
+#include "knot/dnssec/rrset-sign.h"
+#include "knot/dnssec/zone-events.h"
+#include "knot/nameserver/query_module.h"
+#include "knot/nameserver/process_query.h"
+
+#define MOD_POLICY "\x06""policy"
+#define MOD_NSEC_BITMAP "\x0B""nsec-bitmap"
+
+int policy_check(knotd_conf_check_args_t *args)
+{
+ int ret = knotd_conf_check_ref(args);
+ if (ret != KNOT_EOK && strcmp((const char *)args->data, "default") == 0) {
+ return KNOT_EOK;
+ }
+
+ return ret;
+}
+
+int bitmap_check(knotd_conf_check_args_t *args)
+{
+ uint16_t num;
+ int ret = knot_rrtype_from_string((const char *)args->data, &num);
+ if (ret != 0) {
+ args->err_str = "invalid RR type";
+ return KNOT_EINVAL;
+ }
+
+ return KNOT_EOK;
+}
+
+const yp_item_t online_sign_conf[] = {
+ { MOD_POLICY, YP_TREF, YP_VREF = { C_POLICY }, YP_FNONE, { policy_check } },
+ { MOD_NSEC_BITMAP, YP_TSTR, YP_VNONE, YP_FMULTI, { bitmap_check } },
+ { NULL }
+};
+
+/*!
+ * We cannot determine the true NSEC bitmap because of dynamic modules which
+ * can synthesize some types on-the-fly. The base NSEC map will be determined
+ * from zone content and this list of types.
+ *
+ * The types in the NSEC bitmap really don't have to exist. Only the QTYPE
+ * must not be present. This will make the validation work with resolvers
+ * performing negative caching.
+ */
+
+static const uint16_t NSEC_FORCE_TYPES[] = {
+ KNOT_RRTYPE_A,
+ KNOT_RRTYPE_AAAA,
+ 0
+};
+
+typedef struct {
+ knot_time_t event_rollover;
+ knot_time_t event_parent_ds_q;
+ pthread_mutex_t event_mutex;
+ pthread_rwlock_t signing_mutex;
+
+ uint16_t *nsec_force_types;
+
+ bool zone_doomed;
+} online_sign_ctx_t;
+
+static bool want_dnssec(knotd_qdata_t *qdata)
+{
+ return knot_pkt_has_dnssec(qdata->query);
+}
+
+static uint32_t dnskey_ttl(knotd_qdata_t *qdata)
+{
+ knot_rrset_t soa = knotd_qdata_zone_apex_rrset(qdata, KNOT_RRTYPE_SOA);
+ return soa.ttl;
+}
+
+static uint32_t nsec_ttl(knotd_qdata_t *qdata)
+{
+ knot_rrset_t soa = knotd_qdata_zone_apex_rrset(qdata, KNOT_RRTYPE_SOA);
+ return knot_soa_minimum(soa.rrs.rdata);
+}
+
+/*!
+ * \brief Add bitmap records synthesized by online-signing.
+ */
+static void bitmap_add_synth(dnssec_nsec_bitmap_t *map, bool is_apex)
+{
+ dnssec_nsec_bitmap_add(map, KNOT_RRTYPE_NSEC);
+ dnssec_nsec_bitmap_add(map, KNOT_RRTYPE_RRSIG);
+ if (is_apex) {
+ dnssec_nsec_bitmap_add(map, KNOT_RRTYPE_DNSKEY);
+ //dnssec_nsec_bitmap_add(map, KNOT_RRTYPE_CDS);
+ }
+}
+
+/*!
+ * \brief Add bitmap records present in the zone.
+ */
+static void bitmap_add_zone(dnssec_nsec_bitmap_t *map, const zone_node_t *node)
+{
+ if (!node) {
+ return;
+ }
+
+ for (int i = 0; i < node->rrset_count; i++) {
+ dnssec_nsec_bitmap_add(map, node->rrs[i].type);
+ }
+}
+
+/*!
+ * \brief Add bitmap records which can be synthesized by other modules.
+ *
+ * \param qtype Current QTYPE, will never be added into the map.
+ */
+static void bitmap_add_forced(dnssec_nsec_bitmap_t *map, uint16_t qtype,
+ const uint16_t *force_types)
+{
+ for (int i = 0; force_types[i] > 0; i++) {
+ if (force_types[i] != qtype) {
+ dnssec_nsec_bitmap_add(map, force_types[i]);
+ }
+ }
+}
+
+/*!
+ * \brief Add bitmap records from the actual response.
+ */
+static void bitmap_add_section(dnssec_nsec_bitmap_t *map, const knot_pktsection_t *answer)
+{
+ for (int i = 0; i < answer->count; i++) {
+ const knot_rrset_t *rr = knot_pkt_rr(answer, i);
+ dnssec_nsec_bitmap_add(map, rr->type);
+ }
+}
+
+/*!
+ * \brief Synthesize NSEC type bitmap.
+ *
+ * - The bitmap will contain types synthesized by this module.
+ * - For ANY query, the bitmap will contain types from the actual response.
+ * - For non-ANY query, the bitmap will contain types from zone and forced
+ * types which can be potentionally synthesized by other query modules.
+ */
+static dnssec_nsec_bitmap_t *synth_bitmap(knot_pkt_t *pkt, const knotd_qdata_t *qdata,
+ const uint16_t *force_types)
+{
+ dnssec_nsec_bitmap_t *map = dnssec_nsec_bitmap_new();
+ if (!map) {
+ return NULL;
+ }
+
+ uint16_t qtype = knot_pkt_qtype(qdata->query);
+ bool is_apex = qdata->extra->zone
+ && qdata->extra->zone->contents
+ && qdata->extra->node == qdata->extra->zone->contents->apex;
+
+ bitmap_add_synth(map, is_apex);
+
+ if (qtype == KNOT_RRTYPE_ANY) {
+ const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER);
+ bitmap_add_section(map, answer);
+ } else {
+ bitmap_add_zone(map, qdata->extra->node);
+ if (force_types != NULL && !node_rrtype_exists(qdata->extra->node, KNOT_RRTYPE_CNAME)) {
+ bitmap_add_forced(map, qtype, force_types);
+ }
+ }
+
+ return map;
+}
+
+static bool is_deleg(const knot_pkt_t *pkt)
+{
+ return !knot_wire_get_aa(pkt->wire);
+}
+
+static knot_rrset_t *synth_nsec(knot_pkt_t *pkt, knotd_qdata_t *qdata, knotd_mod_t *mod,
+ knot_mm_t *mm)
+{
+ const knot_dname_t *nsec_owner = is_deleg(pkt) ? qdata->extra->encloser->owner : qdata->name;
+ knot_rrset_t *nsec = knot_rrset_new(nsec_owner, KNOT_RRTYPE_NSEC,
+ KNOT_CLASS_IN, nsec_ttl(qdata), mm);
+ if (!nsec) {
+ return NULL;
+ }
+
+ knot_dname_t *next = online_nsec_next(nsec_owner, knotd_qdata_zone_name(qdata));
+ if (!next) {
+ knot_rrset_free(nsec, mm);
+ return NULL;
+ }
+
+ // If necessary, prepare types to force into NSEC bitmap.
+ uint16_t *force_types = NULL;
+ if (!is_deleg(pkt)) {
+ online_sign_ctx_t *ctx = knotd_mod_ctx(mod);
+ force_types = ctx->nsec_force_types;
+ }
+
+ dnssec_nsec_bitmap_t *bitmap = synth_bitmap(pkt, qdata, force_types);
+ if (!bitmap) {
+ free(next);
+ knot_rrset_free(nsec, mm);
+ return NULL;
+ }
+
+ size_t size = knot_dname_size(next) + dnssec_nsec_bitmap_size(bitmap);
+ uint8_t rdata[size];
+
+ int written = knot_dname_to_wire(rdata, next, size);
+ dnssec_nsec_bitmap_write(bitmap, rdata + written);
+
+ knot_dname_free(next, NULL);
+ dnssec_nsec_bitmap_free(bitmap);
+
+ if (knot_rrset_add_rdata(nsec, rdata, size, mm) != KNOT_EOK) {
+ knot_rrset_free(nsec, mm);
+ return NULL;
+ }
+
+ return nsec;
+}
+
+static knot_rrset_t *sign_rrset(const knot_dname_t *owner,
+ const knot_rrset_t *cover,
+ knotd_mod_t *mod,
+ zone_sign_ctx_t *sign_ctx,
+ knot_mm_t *mm)
+{
+ // copy of RR set with replaced owner name
+
+ knot_rrset_t *copy = knot_rrset_new(owner, cover->type, cover->rclass,
+ cover->ttl, NULL);
+ if (!copy) {
+ return NULL;
+ }
+
+ if (knot_rdataset_copy(&copy->rrs, &cover->rrs, NULL) != KNOT_EOK) {
+ knot_rrset_free(copy, NULL);
+ return NULL;
+ }
+
+ // resulting RRSIG
+
+ knot_rrset_t *rrsig = knot_rrset_new(owner, KNOT_RRTYPE_RRSIG, copy->rclass,
+ copy->ttl, mm);
+ if (!rrsig) {
+ knot_rrset_free(copy, NULL);
+ return NULL;
+ }
+
+ online_sign_ctx_t *ctx = knotd_mod_ctx(mod);
+ pthread_rwlock_rdlock(&ctx->signing_mutex);
+ int ret = knot_sign_rrset2(rrsig, copy, sign_ctx, mm);
+ pthread_rwlock_unlock(&ctx->signing_mutex);
+ if (ret != KNOT_EOK) {
+ knot_rrset_free(copy, NULL);
+ knot_rrset_free(rrsig, mm);
+ return NULL;
+ }
+
+ knot_rrset_free(copy, NULL);
+
+ return rrsig;
+}
+
+static glue_t *find_glue_for(const knot_rrset_t *rr, const knot_pkt_t *pkt)
+{
+ for (int i = KNOT_ANSWER; i <= KNOT_AUTHORITY; i++) {
+ const knot_pktsection_t *section = knot_pkt_section(pkt, i);
+ for (int j = 0; j < section->count; j++) {
+ const knot_rrset_t *attempt = knot_pkt_rr(section, j);
+ const additional_t *a = attempt->additional;
+ for (int k = 0; a != NULL && k < a->count; k++) {
+ // no need for knot_dname_cmp because the pointers are assigned
+ if (a->glues[k].node->owner == rr->owner) {
+ return &a->glues[k];
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+static bool shall_sign_rr(const knot_rrset_t *rr, const knot_pkt_t *pkt)
+{
+ if (pkt->current == KNOT_ADDITIONAL) {
+ glue_t *g = find_glue_for(rr, pkt);
+ assert(g); // finds actually the node which is rr in
+ return !(g->node->flags & NODE_FLAGS_NONAUTH);
+ } else {
+ return !is_deleg(pkt) || rr->type == KNOT_RRTYPE_NSEC;
+ }
+}
+
+static knotd_in_state_t sign_section(knotd_in_state_t state, knot_pkt_t *pkt,
+ knotd_qdata_t *qdata, knotd_mod_t *mod)
+{
+ if (!want_dnssec(qdata)) {
+ return state;
+ }
+
+ const knot_pktsection_t *section = knot_pkt_section(pkt, pkt->current);
+ assert(section);
+
+ zone_sign_ctx_t *sign_ctx = zone_sign_ctx(mod->keyset, mod->dnssec);
+ if (sign_ctx == NULL) {
+ return KNOTD_IN_STATE_ERROR;
+ }
+
+ uint16_t count_unsigned = section->count;
+ for (int i = 0; i < count_unsigned; i++) {
+ const knot_rrset_t *rr = knot_pkt_rr(section, i);
+ if (!shall_sign_rr(rr, pkt)) {
+ continue;
+ }
+
+ uint16_t rr_pos = knot_pkt_rr_offset(section, i);
+
+ uint8_t owner[KNOT_DNAME_MAXLEN] = { 0 };
+ knot_dname_unpack(owner, pkt->wire + rr_pos, sizeof(owner), pkt->wire);
+ knot_dname_to_lower(owner);
+
+ knot_rrset_t *rrsig = sign_rrset(owner, rr, mod, sign_ctx, &pkt->mm);
+ if (!rrsig) {
+ state = KNOTD_IN_STATE_ERROR;
+ break;
+ }
+
+ int r = knot_pkt_put(pkt, KNOT_COMPR_HINT_NONE, rrsig, KNOT_PF_FREE);
+ if (r != KNOT_EOK) {
+ knot_rrset_free(rrsig, &pkt->mm);
+ state = KNOTD_IN_STATE_ERROR;
+ break;
+ }
+ }
+
+ zone_sign_ctx_free(sign_ctx);
+
+ return state;
+}
+
+static knotd_in_state_t synth_authority(knotd_in_state_t state, knot_pkt_t *pkt,
+ knotd_qdata_t *qdata, knotd_mod_t *mod)
+{
+ if (state == KNOTD_IN_STATE_HIT) {
+ return state;
+ }
+
+ // synthesise NSEC
+
+ if (want_dnssec(qdata)) {
+ knot_rrset_t *nsec = synth_nsec(pkt, qdata, mod, &pkt->mm);
+ int r = knot_pkt_put(pkt, KNOT_COMPR_HINT_NONE, nsec, KNOT_PF_FREE);
+ if (r != DNSSEC_EOK) {
+ knot_rrset_free(nsec, &pkt->mm);
+ return KNOTD_IN_STATE_ERROR;
+ }
+ }
+
+ // promote NXDOMAIN to NODATA
+
+ if (state == KNOTD_IN_STATE_MISS) {
+ //! \todo Override RCODE set in solver_authority. Review.
+ qdata->rcode = KNOT_RCODE_NOERROR;
+ return KNOTD_IN_STATE_NODATA;
+ }
+
+ return state;
+}
+
+static knot_rrset_t *synth_dnskey(knotd_qdata_t *qdata, knotd_mod_t *mod,
+ knot_mm_t *mm)
+{
+ knot_rrset_t *dnskey = knot_rrset_new(knotd_qdata_zone_name(qdata),
+ KNOT_RRTYPE_DNSKEY, KNOT_CLASS_IN,
+ dnskey_ttl(qdata), mm);
+ if (!dnskey) {
+ return 0;
+ }
+
+ dnssec_binary_t rdata = { 0 };
+ online_sign_ctx_t *ctx = knotd_mod_ctx(mod);
+ pthread_rwlock_rdlock(&ctx->signing_mutex);
+ for (size_t i = 0; i < mod->keyset->count; i++) {
+ if (!mod->keyset->keys[i].is_public) {
+ continue;
+ }
+
+ dnssec_key_get_rdata(mod->keyset->keys[i].key, &rdata);
+ assert(rdata.size > 0 && rdata.data);
+
+ int r = knot_rrset_add_rdata(dnskey, rdata.data, rdata.size, mm);
+ if (r != KNOT_EOK) {
+ knot_rrset_free(dnskey, mm);
+ pthread_rwlock_unlock(&ctx->signing_mutex);
+ return NULL;
+ }
+ }
+
+ pthread_rwlock_unlock(&ctx->signing_mutex);
+ return dnskey;
+}
+
+/* copied from the middle of zone-sign.c */
+static zone_key_t *ksk_for_cds(knotd_mod_t *mod)
+{
+ zone_key_t *res = NULL;
+ unsigned crp = mod->dnssec->policy->child_records_publish;
+ int kfc_prio = (crp == CHILD_RECORDS_ALWAYS ?
+ 0 : (crp == CHILD_RECORDS_ROLLOVER ? 1 : 2));
+ for (int i = 0; i < mod->keyset->count; i++) {
+ zone_key_t *key = &mod->keyset->keys[i];
+ if (key->is_ksk && key->cds_priority > kfc_prio) {
+ res = key;
+ kfc_prio = key->cds_priority;
+ }
+ }
+ return res;
+}
+
+static knot_rrset_t *synth_cdnskey(knotd_qdata_t *qdata, knotd_mod_t *mod,
+ knot_mm_t *mm)
+{
+ knot_rrset_t *dnskey = knot_rrset_new(knotd_qdata_zone_name(qdata),
+ KNOT_RRTYPE_CDNSKEY, KNOT_CLASS_IN,
+ 0, mm);
+ if (dnskey == NULL) {
+ return 0;
+ }
+
+ dnssec_binary_t rdata = { 0 };
+ online_sign_ctx_t *ctx = knotd_mod_ctx(mod);
+ pthread_rwlock_rdlock(&ctx->signing_mutex);
+ zone_key_t *key = ksk_for_cds(mod);
+ if (key == NULL) {
+ pthread_rwlock_unlock(&ctx->signing_mutex);
+ knot_rrset_free(dnskey, mm);
+ return NULL;
+ }
+ dnssec_key_get_rdata(key->key, &rdata);
+ assert(rdata.size > 0 && rdata.data);
+
+ int ret = knot_rrset_add_rdata(dnskey, rdata.data, rdata.size, mm);
+ pthread_rwlock_unlock(&ctx->signing_mutex);
+ if (ret != KNOT_EOK) {
+ knot_rrset_free(dnskey, mm);
+ return NULL;
+ }
+
+ return dnskey;
+}
+
+static knot_rrset_t *synth_cds(knotd_qdata_t *qdata, knotd_mod_t *mod,
+ knot_mm_t *mm)
+{
+ knot_rrset_t *ds = knot_rrset_new(knotd_qdata_zone_name(qdata),
+ KNOT_RRTYPE_CDS, KNOT_CLASS_IN,
+ 0, mm);
+ if (ds == NULL) {
+ return 0;
+ }
+
+ dnssec_binary_t rdata = { 0 };
+ online_sign_ctx_t *ctx = knotd_mod_ctx(mod);
+ pthread_rwlock_rdlock(&ctx->signing_mutex);
+ zone_key_t *key = ksk_for_cds(mod);
+ if (key == NULL) {
+ pthread_rwlock_unlock(&ctx->signing_mutex);
+ knot_rrset_free(ds, mm);
+ return NULL;
+ }
+ zone_key_calculate_ds(key, &rdata);
+ assert(rdata.size > 0 && rdata.data);
+
+ int ret = knot_rrset_add_rdata(ds, rdata.data, rdata.size, mm);
+ pthread_rwlock_unlock(&ctx->signing_mutex);
+ if (ret != KNOT_EOK) {
+ knot_rrset_free(ds, mm);
+ return NULL;
+ }
+
+ return ds;
+}
+
+static bool qtype_match(knotd_qdata_t *qdata, uint16_t type)
+{
+ uint16_t qtype = knot_pkt_qtype(qdata->query);
+ return (qtype == KNOT_RRTYPE_ANY || qtype == type);
+}
+
+static bool is_apex_query(knotd_qdata_t *qdata)
+{
+ return knot_dname_is_equal(qdata->name, knotd_qdata_zone_name(qdata));
+}
+
+static knotd_in_state_t pre_routine(knotd_in_state_t state, knot_pkt_t *pkt,
+ knotd_qdata_t *qdata, knotd_mod_t *mod)
+{
+ online_sign_ctx_t *ctx = knotd_mod_ctx(mod);
+ zone_sign_reschedule_t resch = { .allow_rollover = true };
+
+ (void)pkt, (void)qdata;
+
+ pthread_mutex_lock(&ctx->event_mutex);
+ if (ctx->zone_doomed) {
+ pthread_mutex_unlock(&ctx->event_mutex);
+ return KNOTD_IN_STATE_ERROR;
+ }
+ mod->dnssec->now = time(NULL);
+ int ret = KNOT_ESEMCHECK;
+ if (knot_time_cmp(ctx->event_parent_ds_q, mod->dnssec->now) <= 0) {
+ pthread_rwlock_rdlock(&ctx->signing_mutex);
+ ret = knot_parent_ds_query(mod->dnssec, mod->keyset, 1000);
+ pthread_rwlock_unlock(&ctx->signing_mutex);
+ if (ret != KNOT_EOK && mod->dnssec->policy->ksk_sbm_check_interval > 0) {
+ ctx->event_parent_ds_q = mod->dnssec->now + mod->dnssec->policy->ksk_sbm_check_interval;
+ } else {
+ ctx->event_parent_ds_q = 0;
+ }
+ }
+ if (ret == KNOT_EOK || knot_time_cmp(ctx->event_rollover, mod->dnssec->now) <= 0) {
+ update_policy_from_zone(mod->dnssec->policy, qdata->extra->zone->contents);
+ ret = knot_dnssec_key_rollover(mod->dnssec, &resch);
+ }
+ if (ret == KNOT_EOK) {
+ if (resch.plan_ds_query && mod->dnssec->policy->ksk_sbm_check_interval > 0) {
+ ctx->event_parent_ds_q = mod->dnssec->now + mod->dnssec->policy->ksk_sbm_check_interval;
+ } else {
+ ctx->event_parent_ds_q = 0;
+ }
+
+ ctx->event_rollover = resch.next_rollover;
+
+ pthread_rwlock_wrlock(&ctx->signing_mutex);
+ knotd_mod_dnssec_unload_keyset(mod);
+ ret = knotd_mod_dnssec_load_keyset(mod, true);
+ if (ret != KNOT_EOK) {
+ ctx->zone_doomed = true;
+ state = KNOTD_IN_STATE_ERROR;
+ } else {
+ ctx->event_rollover = knot_time_min(ctx->event_rollover, knot_get_next_zone_key_event(mod->keyset));
+ }
+ pthread_rwlock_unlock(&ctx->signing_mutex);
+ }
+ pthread_mutex_unlock(&ctx->event_mutex);
+
+ return state;
+}
+
+static knotd_in_state_t synth_answer(knotd_in_state_t state, knot_pkt_t *pkt,
+ knotd_qdata_t *qdata, knotd_mod_t *mod)
+{
+ // disallowed queries
+
+ if (knot_pkt_qtype(pkt) == KNOT_RRTYPE_RRSIG) {
+ qdata->rcode = KNOT_RCODE_REFUSED;
+ return KNOTD_IN_STATE_ERROR;
+ }
+
+ // synthesized DNSSEC answers
+
+ if (qtype_match(qdata, KNOT_RRTYPE_DNSKEY) && is_apex_query(qdata)) {
+ knot_rrset_t *dnskey = synth_dnskey(qdata, mod, &pkt->mm);
+ if (!dnskey) {
+ return KNOTD_IN_STATE_ERROR;
+ }
+
+ int r = knot_pkt_put(pkt, KNOT_COMPR_HINT_QNAME, dnskey, KNOT_PF_FREE);
+ if (r != DNSSEC_EOK) {
+ knot_rrset_free(dnskey, &pkt->mm);
+ return KNOTD_IN_STATE_ERROR;
+ }
+ state = KNOTD_IN_STATE_HIT;
+ }
+
+ if (qtype_match(qdata, KNOT_RRTYPE_CDNSKEY) && is_apex_query(qdata)) {
+ knot_rrset_t *dnskey = synth_cdnskey(qdata, mod, &pkt->mm);
+ if (!dnskey) {
+ return KNOTD_IN_STATE_ERROR;
+ }
+
+ int r = knot_pkt_put(pkt, KNOT_COMPR_HINT_QNAME, dnskey, KNOT_PF_FREE);
+ if (r != DNSSEC_EOK) {
+ knot_rrset_free(dnskey, &pkt->mm);
+ return KNOTD_IN_STATE_ERROR;
+ }
+ state = KNOTD_IN_STATE_HIT;
+ }
+
+ if (qtype_match(qdata, KNOT_RRTYPE_CDS) && is_apex_query(qdata)) {
+ knot_rrset_t *ds = synth_cds(qdata, mod, &pkt->mm);
+ if (!ds) {
+ return KNOTD_IN_STATE_ERROR;
+ }
+
+ int r = knot_pkt_put(pkt, KNOT_COMPR_HINT_QNAME, ds, KNOT_PF_FREE);
+ if (r != DNSSEC_EOK) {
+ knot_rrset_free(ds, &pkt->mm);
+ return KNOTD_IN_STATE_ERROR;
+ }
+ state = KNOTD_IN_STATE_HIT;
+ }
+
+ if (qtype_match(qdata, KNOT_RRTYPE_NSEC)) {
+ knot_rrset_t *nsec = synth_nsec(pkt, qdata, mod, &pkt->mm);
+ if (!nsec) {
+ return KNOTD_IN_STATE_ERROR;
+ }
+
+ int r = knot_pkt_put(pkt, KNOT_COMPR_HINT_QNAME, nsec, KNOT_PF_FREE);
+ if (r != DNSSEC_EOK) {
+ knot_rrset_free(nsec, &pkt->mm);
+ return KNOTD_IN_STATE_ERROR;
+ }
+
+ state = KNOTD_IN_STATE_HIT;
+ }
+
+ return state;
+}
+
+static void online_sign_ctx_free(online_sign_ctx_t *ctx)
+{
+ pthread_mutex_destroy(&ctx->event_mutex);
+ pthread_rwlock_destroy(&ctx->signing_mutex);
+
+ free(ctx->nsec_force_types);
+ free(ctx);
+}
+
+static int online_sign_ctx_new(online_sign_ctx_t **ctx_ptr, knotd_mod_t *mod)
+{
+ online_sign_ctx_t *ctx = calloc(1, sizeof(*ctx));
+ if (!ctx) {
+ return KNOT_ENOMEM;
+ }
+
+ int ret = knotd_mod_dnssec_init(mod);
+ if (ret != KNOT_EOK) {
+ free(ctx);
+ return ret;
+ }
+
+ // Force Singe-Type signing scheme. This is only important for compatibility with older versions.
+ mod->dnssec->policy->singe_type_signing = true;
+
+ zone_sign_reschedule_t resch = {
+ .allow_rollover = true
+ };
+ ret = knot_dnssec_key_rollover(mod->dnssec, &resch);
+ if (ret != KNOT_EOK) {
+ free(ctx);
+ return ret;
+ }
+
+ if (resch.plan_ds_query) {
+ ctx->event_parent_ds_q = time(NULL);
+ }
+ ctx->event_rollover = resch.next_rollover;
+
+ ret = knotd_mod_dnssec_load_keyset(mod, true);
+ if (ret != KNOT_EOK) {
+ free(ctx);
+ return ret;
+ }
+
+ ctx->event_rollover = knot_time_min(ctx->event_rollover, knot_get_next_zone_key_event(mod->keyset));
+
+ pthread_mutex_init(&ctx->event_mutex, NULL);
+ pthread_rwlock_init(&ctx->signing_mutex, NULL);
+
+ *ctx_ptr = ctx;
+
+ return KNOT_EOK;
+}
+
+int load_nsec_bitmap(online_sign_ctx_t *ctx, knotd_conf_t *conf)
+{
+ int count = (conf->count > 0) ? conf->count : sizeof(NSEC_FORCE_TYPES) / sizeof(uint16_t);
+ ctx->nsec_force_types = calloc(count + 1, sizeof(uint16_t));
+ if (ctx->nsec_force_types == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ if (conf->count == 0) {
+ // Use the default list.
+ for (int i = 0; NSEC_FORCE_TYPES[i] > 0; i++) {
+ ctx->nsec_force_types[i] = NSEC_FORCE_TYPES[i];
+ }
+ } else {
+ for (int i = 0; i < conf->count; i++) {
+ int ret = knot_rrtype_from_string(conf->multi[i].string,
+ &ctx->nsec_force_types[i]);
+ if (ret != 0) {
+ return KNOT_EINVAL;
+ }
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+int online_sign_load(knotd_mod_t *mod)
+{
+ knotd_conf_t conf = knotd_conf_zone(mod, C_DNSSEC_SIGNING,
+ knotd_mod_zone(mod));
+ if (conf.single.boolean) {
+ knotd_mod_log(mod, LOG_ERR, "incompatible with automatic signing");
+ return KNOT_ENOTSUP;
+ }
+
+ online_sign_ctx_t *ctx = NULL;
+ int ret = online_sign_ctx_new(&ctx, mod);
+ if (ret != KNOT_EOK) {
+ knotd_mod_log(mod, LOG_ERR, "failed to initialize signing key (%s)",
+ knot_strerror(ret));
+ return KNOT_ERROR;
+ }
+
+ conf = knotd_conf_mod(mod, MOD_NSEC_BITMAP);
+ ret = load_nsec_bitmap(ctx, &conf);
+ knotd_conf_free(&conf);
+ if (ret != KNOT_EOK) {
+ online_sign_ctx_free(ctx);
+ return ret;
+ }
+
+ knotd_mod_ctx_set(mod, ctx);
+
+ knotd_mod_in_hook(mod, KNOTD_STAGE_ANSWER, pre_routine);
+
+ knotd_mod_in_hook(mod, KNOTD_STAGE_ANSWER, synth_answer);
+ knotd_mod_in_hook(mod, KNOTD_STAGE_ANSWER, sign_section);
+
+ knotd_mod_in_hook(mod, KNOTD_STAGE_AUTHORITY, synth_authority);
+ knotd_mod_in_hook(mod, KNOTD_STAGE_AUTHORITY, sign_section);
+
+ knotd_mod_in_hook(mod, KNOTD_STAGE_ADDITIONAL, sign_section);
+
+ return KNOT_EOK;
+}
+
+void online_sign_unload(knotd_mod_t *mod)
+{
+ online_sign_ctx_free(knotd_mod_ctx(mod));
+}
+
+KNOTD_MOD_API(onlinesign, KNOTD_MOD_FLAG_SCOPE_ZONE | KNOTD_MOD_FLAG_OPT_CONF,
+ online_sign_load, online_sign_unload, online_sign_conf, NULL);
diff --git a/src/knot/modules/onlinesign/onlinesign.rst b/src/knot/modules/onlinesign/onlinesign.rst
new file mode 100644
index 0000000..5b34186
--- /dev/null
+++ b/src/knot/modules/onlinesign/onlinesign.rst
@@ -0,0 +1,152 @@
+.. _mod-onlinesign:
+
+``onlinesign`` — Online DNSSEC signing
+======================================
+
+The module provides online DNSSEC signing. Instead of pre-computing the zone
+signatures when the zone is loaded into the server or instead of loading an
+externally signed zone, the signatures are computed on-the-fly during
+answering.
+
+The main purpose of the module is to enable authenticated responses with
+zones which use other dynamic module (e.g., automatic reverse record
+synthesis) because these zones cannot be pre-signed. However, it can be also
+used as a simple signing solution for zones with low traffic and also as
+a protection against zone content enumeration (zone walking).
+
+In order to minimize the number of computed signatures per query, the module
+produces a bit different responses from the responses that would be sent if
+the zone was pre-signed. Still, the responses should be perfectly valid for
+a DNSSEC validating resolver.
+
+.. rubric:: Differences from statically signed zones:
+
+* The NSEC records are constructed as Minimally Covering NSEC Records
+ (:rfc:`7129#appendix-A`). Therefore the generated domain names cover
+ the complete domain name space in the zone's authority.
+
+* NXDOMAIN responses are promoted to NODATA responses. The module proves
+ that the query type does not exist rather than that the domain name does not
+ exist.
+
+* Domain names matching a wildcard are expanded. The module pretends and proves
+ that the domain name exists rather than proving a presence of the wildcard.
+
+.. rubric:: Records synthesized by the module:
+
+* DNSKEY record is synthesized in the zone apex and includes public key
+ material for the active signing key.
+
+* NSEC records are synthesized as needed.
+
+* RRSIG records are synthesized for authoritative content of the zone.
+
+* CDNSKEY and CDS records are generated as usual to publish valid Secure Entry Point.
+
+.. rubric:: Known issues:
+
+* The `knotc zone-ksk-submitted` command does not work well and is discouraged.
+ The module must be reloaded afterwards.
+
+.. rubric:: Limitations:
+
+* Online-sign module always enforces Single-Type Signing scheme.
+
+* After any change to KASP DB, the module must be reloaded to apply the changed keys.
+
+* The NSEC records may differ for one domain name if queried for different
+ types. This is an implementation shortcoming as the dynamic modules
+ cooperate loosely. Possible synthesis of a type by other module cannot
+ be predicted. This dissimilarity should not affect response validation,
+ even with validators performing `aggressive negative caching
+ <https://datatracker.ietf.org/doc/draft-fujiwara-dnsop-nsec-aggressiveuse/>`_.
+
+.. rubric:: Recommendations:
+
+* Configure the module with an explicit signing policy which has the
+ :ref:`policy_rrsig-lifetime` value in the order of hours.
+
+Example
+-------
+
+* Enable the module in the zone configuration with the default signing policy::
+
+ zone:
+ - domain: example.com
+ module: mod-onlinesign
+
+ Or with an explicit signing policy::
+
+ policy:
+ - id: rsa
+ algorithm: RSASHA256
+ zsk-size: 2048
+ rrsig-lifetime: 25h
+
+ mod-onlinesign:
+ - id: explicit
+ policy: rsa
+
+ zone:
+ - domain: example.com
+ module: mod-onlinesign/explicit
+
+ Or use manual policy in an analogous manner, see
+ :ref:`Manual key management<dnssec-manual-key-management>`.
+
+* Make sure the zone is not signed and also that the automatic signing is
+ disabled. All is set, you are good to go. Reload (or start) the server:
+
+ .. code-block:: console
+
+ $ knotc reload
+
+The following example stacks the online signing with reverse record synthesis
+module::
+
+ mod-synthrecord:
+ - id: lan-forward
+ type: forward
+ prefix: ip-
+ ttl: 1200
+ network: 192.168.100.0/24
+
+ zone:
+ - domain: corp.example.net
+ module: [mod-synthrecord/lan-forward, mod-onlinesign]
+
+Module reference
+----------------
+
+::
+
+ mod-onlinesign:
+ - id: STR
+ policy: STR
+ nsec-bitmap: STR ...
+
+.. _mod-onlinesign_id:
+
+id
+..
+
+A module identifier.
+
+.. _mod-onlinesign_policy:
+
+policy
+......
+
+A :ref:`reference<policy_id>` to DNSSEC signing policy. A special *default*
+value can be used for the default policy setting.
+
+.. _mod-onlinesign_nsec-bitmap:
+
+nsec-bitmap
+...........
+
+A list of Resource Record types included in an NSEC bitmap generated by the module.
+This option should reflect zone contents or synthesized responses by modules,
+such as :ref:`synthrecord<mod-synthrecord>` and :ref:`GeoIP<mod-geoip>`.
+
+*Default:* [A, AAAA]
diff --git a/src/knot/modules/queryacl/Makefile.inc b/src/knot/modules/queryacl/Makefile.inc
new file mode 100644
index 0000000..25dcc38
--- /dev/null
+++ b/src/knot/modules/queryacl/Makefile.inc
@@ -0,0 +1,12 @@
+knot_modules_queryacl_la_SOURCES = knot/modules/queryacl/queryacl.c
+EXTRA_DIST += knot/modules/queryacl/queryacl.rst
+
+if STATIC_MODULE_queryacl
+libknotd_la_SOURCES += $(knot_modules_queryacl_la_SOURCES)
+endif
+
+if SHARED_MODULE_queryacl
+knot_modules_queryacl_la_LDFLAGS = $(KNOTD_MOD_LDFLAGS)
+knot_modules_queryacl_la_CPPFLAGS = $(KNOTD_MOD_CPPFLAGS)
+pkglib_LTLIBRARIES += knot/modules/queryacl.la
+endif
diff --git a/src/knot/modules/queryacl/queryacl.c b/src/knot/modules/queryacl/queryacl.c
new file mode 100644
index 0000000..38a4f3c
--- /dev/null
+++ b/src/knot/modules/queryacl/queryacl.c
@@ -0,0 +1,98 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "knot/include/module.h"
+#include "contrib/sockaddr.h"
+
+#define MOD_ADDRESS "\x07""address"
+#define MOD_INTERFACE "\x09""interface"
+
+const yp_item_t queryacl_conf[] = {
+ { MOD_ADDRESS, YP_TNET, YP_VNONE, YP_FMULTI },
+ { MOD_INTERFACE, YP_TNET, YP_VNONE, YP_FMULTI },
+ { NULL }
+};
+
+typedef struct {
+ knotd_conf_t allow_addr;
+ knotd_conf_t allow_iface;
+} queryacl_ctx_t;
+
+static knotd_state_t queryacl_process(knotd_state_t state, knot_pkt_t *pkt,
+ knotd_qdata_t *qdata, knotd_mod_t *mod)
+{
+ assert(pkt && qdata && mod);
+
+ queryacl_ctx_t *ctx = knotd_mod_ctx(mod);
+
+ // Continue only for regular queries.
+ if (qdata->type != KNOTD_QUERY_TYPE_NORMAL) {
+ return state;
+ }
+
+ // Get interface address.
+ struct sockaddr_storage iface;
+ socklen_t iface_len = sizeof(iface);
+ if (getsockname(qdata->params->socket, (struct sockaddr *)&iface, &iface_len) != 0) {
+ knotd_mod_log(mod, LOG_ERR, "failed to get interface address");
+ return KNOTD_STATE_FAIL;
+ }
+
+ if (ctx->allow_addr.count > 0) {
+ if (!knotd_conf_addr_range_match(&ctx->allow_addr, qdata->params->remote)) {
+ qdata->rcode = KNOT_RCODE_NOTAUTH;
+ return KNOTD_STATE_FAIL;
+ }
+ }
+
+ if (ctx->allow_iface.count > 0) {
+ if (!knotd_conf_addr_range_match(&ctx->allow_iface, &iface)) {
+ qdata->rcode = KNOT_RCODE_NOTAUTH;
+ return KNOTD_STATE_FAIL;
+ }
+ }
+
+ return state;
+}
+
+int queryacl_load(knotd_mod_t *mod)
+{
+ // Create module context.
+ queryacl_ctx_t *ctx = calloc(1, sizeof(queryacl_ctx_t));
+ if (ctx == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ ctx->allow_addr = knotd_conf_mod(mod, MOD_ADDRESS);
+ ctx->allow_iface = knotd_conf_mod(mod, MOD_INTERFACE);
+
+ knotd_mod_ctx_set(mod, ctx);
+
+ return knotd_mod_hook(mod, KNOTD_STAGE_BEGIN, queryacl_process);
+}
+
+void queryacl_unload(knotd_mod_t *mod)
+{
+ queryacl_ctx_t *ctx = knotd_mod_ctx(mod);
+ if (ctx != NULL) {
+ knotd_conf_free(&ctx->allow_addr);
+ knotd_conf_free(&ctx->allow_iface);
+ }
+ free(ctx);
+}
+
+KNOTD_MOD_API(queryacl, KNOTD_MOD_FLAG_SCOPE_ANY,
+ queryacl_load, queryacl_unload, queryacl_conf, NULL);
diff --git a/src/knot/modules/queryacl/queryacl.rst b/src/knot/modules/queryacl/queryacl.rst
new file mode 100644
index 0000000..14a5dfb
--- /dev/null
+++ b/src/knot/modules/queryacl/queryacl.rst
@@ -0,0 +1,60 @@
+.. _mod-queryacl:
+
+``queryacl`` — Limit queries by remote address or target interface
+==================================================================
+
+This module provides a simple way to whitelist incoming queries
+according to the query's source address or target interface.
+It can be used e.g. to create a restricted-access subzone with delegations from the corresponding public zone.
+The module may be enabled both globally and per-zone.
+
+.. NOTE::
+ The module limits only regular queries. Notify, transfer and update are handled by :ref:`ACL<ACL>`.
+
+Example
+-------
+
+::
+
+ mod-queryacl:
+ - id: default
+ address: [192.0.2.73-192.0.2.90, 203.0.113.0/24]
+ interface: 198.51.100
+
+ zone:
+ - domain: example.com
+ module: mod-queryacl/default
+
+Module reference
+----------------
+
+::
+
+ mod-queryacl:
+ - id: STR
+ address: ADDR[/INT] | ADDR-ADDR ...
+ interface: ADDR[/INT] | ADDR-ADDR ...
+
+.. _mod-queryacl_id:
+
+id
+..
+
+A module identifier.
+
+.. _mod-queryacl_address:
+
+address
+.......
+
+A list of allowed ranges and/or subnets for query's source address. If the query's address does not fall into any
+of the configured ranges, NOTAUTH rcode is returned.
+
+.. _mod-queryacl_interface:
+
+interface
+.........
+
+A list of allowed ranges and/or subnets for query's target interface. If the interface does not fall into any
+of the configured ranges, NOTAUTH rcode is returned. Note that every interface used has to be configured in :ref:`listen<server_listen>`.
+
diff --git a/src/knot/modules/rrl/Makefile.inc b/src/knot/modules/rrl/Makefile.inc
new file mode 100644
index 0000000..f7c7131
--- /dev/null
+++ b/src/knot/modules/rrl/Makefile.inc
@@ -0,0 +1,15 @@
+knot_modules_rrl_la_SOURCES = knot/modules/rrl/rrl.c \
+ knot/modules/rrl/functions.c \
+ knot/modules/rrl/functions.h
+EXTRA_DIST += knot/modules/rrl/rrl.rst
+
+if STATIC_MODULE_rrl
+libknotd_la_SOURCES += $(knot_modules_rrl_la_SOURCES)
+endif
+
+if SHARED_MODULE_rrl
+knot_modules_rrl_la_LDFLAGS = $(KNOTD_MOD_LDFLAGS)
+knot_modules_rrl_la_CPPFLAGS = $(KNOTD_MOD_CPPFLAGS)
+knot_modules_rrl_la_LIBADD = libcontrib.la
+pkglib_LTLIBRARIES += knot/modules/rrl.la
+endif
diff --git a/src/knot/modules/rrl/functions.c b/src/knot/modules/rrl/functions.c
new file mode 100644
index 0000000..0b2bc26
--- /dev/null
+++ b/src/knot/modules/rrl/functions.c
@@ -0,0 +1,525 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <time.h>
+
+#include "knot/modules/rrl/functions.h"
+#include "contrib/sockaddr.h"
+#include "contrib/time.h"
+#include "libdnssec/error.h"
+#include "libdnssec/random.h"
+
+/* Hopscotch defines. */
+#define HOP_LEN (sizeof(unsigned)*8)
+/* Limits */
+#define RRL_CLSBLK_MAXLEN (4 + 8 + 1 + 256)
+/* CIDR block prefix lengths for v4/v6 */
+#define RRL_V4_PREFIX ((uint32_t)0x00ffffff) /* /24 */
+#define RRL_V6_PREFIX ((uint64_t)0x00ffffffffffffff) /* /56 */
+/* Defaults */
+#define RRL_SSTART 2 /* 1/Nth of the rate for slow start */
+#define RRL_PSIZE_LARGE 1024
+#define RRL_CAPACITY 4 /* Window size in seconds */
+#define RRL_LOCK_GRANULARITY 32 /* Last digit granularity */
+
+/* Classification */
+enum {
+ CLS_NULL = 0 << 0, /* Empty bucket. */
+ CLS_NORMAL = 1 << 0, /* Normal response. */
+ CLS_ERROR = 1 << 1, /* Error response. */
+ CLS_NXDOMAIN = 1 << 2, /* NXDOMAIN (special case of error). */
+ CLS_EMPTY = 1 << 3, /* Empty response. */
+ CLS_LARGE = 1 << 4, /* Response size over threshold (1024k). */
+ CLS_WILDCARD = 1 << 5, /* Wildcard query. */
+ CLS_ANY = 1 << 6, /* ANY query (spec. class). */
+ CLS_DNSSEC = 1 << 7 /* DNSSEC related RR query (spec. class) */
+};
+
+/* Classification string. */
+struct cls_name {
+ int code;
+ const char *name;
+};
+
+static const struct cls_name rrl_cls_names[] = {
+ { CLS_NORMAL, "POSITIVE" },
+ { CLS_ERROR, "ERROR" },
+ { CLS_NXDOMAIN, "NXDOMAIN"},
+ { CLS_EMPTY, "EMPTY"},
+ { CLS_LARGE, "LARGE"},
+ { CLS_WILDCARD, "WILDCARD"},
+ { CLS_ANY, "ANY"},
+ { CLS_DNSSEC, "DNSSEC"},
+ { CLS_NULL, "NULL"},
+ { CLS_NULL, NULL}
+};
+
+static inline const char *rrl_clsstr(int code)
+{
+ for (const struct cls_name *c = rrl_cls_names; c->name; c++) {
+ if (c->code == code) {
+ return c->name;
+ }
+ }
+
+ return "unknown class";
+}
+
+/* Bucket flags. */
+enum {
+ RRL_BF_NULL = 0 << 0, /* No flags. */
+ RRL_BF_SSTART = 1 << 0, /* Bucket in slow-start after collision. */
+ RRL_BF_ELIMIT = 1 << 1 /* Bucket is rate-limited. */
+};
+
+static uint8_t rrl_clsid(rrl_req_t *p)
+{
+ /* Check error code */
+ int ret = CLS_NULL;
+ switch (knot_wire_get_rcode(p->w)) {
+ case KNOT_RCODE_NOERROR: ret = CLS_NORMAL; break;
+ case KNOT_RCODE_NXDOMAIN: return CLS_NXDOMAIN; break;
+ default: return CLS_ERROR; break;
+ }
+
+ /* Check if answered from a qname */
+ if (ret == CLS_NORMAL && p->flags & RRL_REQ_WILDCARD) {
+ return CLS_WILDCARD;
+ }
+
+ /* Check query type for spec. classes. */
+ if (p->query) {
+ switch(knot_pkt_qtype(p->query)) {
+ case KNOT_RRTYPE_ANY: /* ANY spec. class */
+ return CLS_ANY;
+ break;
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_RRSIG:
+ case KNOT_RRTYPE_DS: /* DNSSEC-related RR class. */
+ return CLS_DNSSEC;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* Check packet size for threshold. */
+ if (p->len >= RRL_PSIZE_LARGE) {
+ return CLS_LARGE;
+ }
+
+ /* Check ancount */
+ if (knot_wire_get_ancount(p->w) == 0) {
+ return CLS_EMPTY;
+ }
+
+ return ret;
+}
+
+static int rrl_clsname(uint8_t *dst, size_t maxlen, uint8_t cls, rrl_req_t *req,
+ const knot_dname_t *name)
+{
+ if (name == NULL) {
+ /* Fallback for errors etc. */
+ name = (const knot_dname_t *)"\x00";
+ }
+
+ switch (cls) {
+ case CLS_ERROR: /* Could be a non-existent zone or garbage. */
+ case CLS_NXDOMAIN: /* Queries to non-existent names in zone. */
+ case CLS_WILDCARD: /* Queries to names covered by a wildcard. */
+ break;
+ default:
+ /* Use QNAME */
+ if (req->query) {
+ name = knot_pkt_qname(req->query);
+ }
+ break;
+ }
+
+ /* Write to wire */
+ return knot_dname_to_wire(dst, name, maxlen);
+}
+
+static int rrl_classify(uint8_t *dst, size_t maxlen, const struct sockaddr_storage *a,
+ rrl_req_t *req, const knot_dname_t *name)
+{
+ /* Class */
+ uint8_t cls = rrl_clsid(req);
+ *dst = cls;
+ int blklen = sizeof(cls);
+
+ /* Address (in network byteorder, adjust masks). */
+ uint64_t nb = 0;
+ if (a->ss_family == AF_INET6) {
+ struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)a;
+ nb = *((uint64_t *)(&ipv6->sin6_addr)) & RRL_V6_PREFIX;
+ } else {
+ struct sockaddr_in *ipv4 = (struct sockaddr_in *)a;
+ nb = ((uint32_t)ipv4->sin_addr.s_addr) & RRL_V4_PREFIX;
+ }
+ if (blklen + sizeof(nb) > maxlen) {
+ return KNOT_ESPACE;
+ }
+ memcpy(dst + blklen, (void *)&nb, sizeof(nb));
+ blklen += sizeof(nb);
+
+ /* Name */
+ uint16_t *len_pos = (uint16_t *)(dst + blklen);
+ blklen += sizeof(uint16_t);
+ int ret = rrl_clsname(dst + blklen, maxlen - blklen, cls, req, name);
+ if (ret < 0) {
+ return ret;
+ }
+ uint16_t len = ret;
+ memcpy(len_pos, &len, sizeof(len));
+ blklen += len;
+
+ return blklen;
+}
+
+static int bucket_free(rrl_item_t *b, uint32_t now)
+{
+ return b->cls == CLS_NULL || (b->time + 1 < now);
+}
+
+static int bucket_match(rrl_item_t *b, rrl_item_t *m)
+{
+ return b->cls == m->cls &&
+ b->netblk == m->netblk &&
+ b->qname == m->qname;
+}
+
+static int find_free(rrl_table_t *t, unsigned i, uint32_t now)
+{
+ rrl_item_t *np = t->arr + t->size;
+ rrl_item_t *b = NULL;
+ for (b = t->arr + i; b != np; ++b) {
+ if (bucket_free(b, now)) {
+ return b - (t->arr + i);
+ }
+ }
+ np = t->arr + i;
+ for (b = t->arr; b != np; ++b) {
+ if (bucket_free(b, now)) {
+ return (b - t->arr) + (t->size - i);
+ }
+ }
+
+ /* this happens if table is full... force vacate current elm */
+ return i;
+}
+
+static inline unsigned find_match(rrl_table_t *t, uint32_t id, rrl_item_t *m)
+{
+ unsigned f = 0;
+ unsigned d = 0;
+ unsigned match = t->arr[id].hop;
+ while (match != 0) {
+ d = __builtin_ctz(match);
+ f = (id + d) % t->size;
+ if (bucket_match(t->arr + f, m)) {
+ return d;
+ } else {
+ match &= ~(1<<d); /* clear potential match */
+ }
+ }
+
+ return HOP_LEN + 1;
+}
+
+static inline unsigned reduce_dist(rrl_table_t *t, unsigned id, unsigned d, unsigned *f)
+{
+ unsigned rd = HOP_LEN - 1;
+ while (rd > 0) {
+ unsigned s = (t->size + *f - rd) % t->size; /* bucket to be vacated */
+ if (t->arr[s].hop != 0) {
+ unsigned o = __builtin_ctz(t->arr[s].hop); /* offset of first valid bucket */
+ if (o < rd) { /* only offsets in <s, f> are interesting */
+ unsigned e = (s + o) % t->size; /* this item will be displaced to [f] */
+ unsigned keep_hop = t->arr[*f].hop; /* unpredictable padding */
+ memcpy(t->arr + *f, t->arr + e, sizeof(rrl_item_t));
+ t->arr[*f].hop = keep_hop;
+ t->arr[e].cls = CLS_NULL;
+ t->arr[s].hop &= ~(1<<o);
+ t->arr[s].hop |= 1<<rd;
+ *f = e;
+ return d - (rd - o);
+ }
+ }
+ --rd;
+ }
+
+ assert(rd == 0); /* this happens with p=1/fact(HOP_LEN) */
+ *f = id;
+ d = 0; /* force vacate initial element */
+ return d;
+}
+
+static void rrl_log_state(knotd_mod_t *mod, const struct sockaddr_storage *ss,
+ uint16_t flags, uint8_t cls)
+{
+ if (mod == NULL) {
+ return;
+ }
+
+ char addr_str[SOCKADDR_STRLEN] = {0};
+ sockaddr_tostr(addr_str, sizeof(addr_str), (struct sockaddr *)ss);
+
+ const char *what = "leaves";
+ if (flags & RRL_BF_ELIMIT) {
+ what = "enters";
+ }
+
+ knotd_mod_log(mod, LOG_NOTICE, "address %s, class %s, %s limiting",
+ addr_str, rrl_clsstr(cls), what);
+}
+
+static void rrl_lock(rrl_table_t *t, int lk_id)
+{
+ assert(lk_id > -1);
+ pthread_mutex_lock(t->lk + lk_id);
+}
+
+static void rrl_unlock(rrl_table_t *t, int lk_id)
+{
+ assert(lk_id > -1);
+ pthread_mutex_unlock(t->lk + lk_id);
+}
+
+static int rrl_setlocks(rrl_table_t *rrl, uint32_t granularity)
+{
+ assert(!rrl->lk); /* Cannot change while locks are used. */
+ assert(granularity <= rrl->size / 10); /* Due to int. division err. */
+
+ if (pthread_mutex_init(&rrl->ll, NULL) < 0) {
+ return KNOT_ENOMEM;
+ }
+
+ /* Alloc new locks. */
+ rrl->lk = malloc(granularity * sizeof(pthread_mutex_t));
+ if (!rrl->lk) {
+ return KNOT_ENOMEM;
+ }
+ memset(rrl->lk, 0, granularity * sizeof(pthread_mutex_t));
+
+ /* Initialize. */
+ for (size_t i = 0; i < granularity; ++i) {
+ if (pthread_mutex_init(rrl->lk + i, NULL) < 0) {
+ break;
+ }
+ ++rrl->lk_count;
+ }
+
+ /* Incomplete initialization */
+ if (rrl->lk_count != granularity) {
+ for (size_t i = 0; i < rrl->lk_count; ++i) {
+ pthread_mutex_destroy(rrl->lk + i);
+ }
+ free(rrl->lk);
+ rrl->lk_count = 0;
+ return KNOT_ERROR;
+ }
+
+ return KNOT_EOK;
+}
+
+rrl_table_t *rrl_create(size_t size, uint32_t rate)
+{
+ if (size == 0) {
+ return NULL;
+ }
+
+ const size_t tbl_len = sizeof(rrl_table_t) + size * sizeof(rrl_item_t);
+ rrl_table_t *t = calloc(1, tbl_len);
+ if (!t) {
+ return NULL;
+ }
+ t->size = size;
+ t->rate = rate;
+
+ if (dnssec_random_buffer((uint8_t *)&t->key, sizeof(t->key)) != DNSSEC_EOK) {
+ free(t);
+ return NULL;
+ }
+
+ if (rrl_setlocks(t, RRL_LOCK_GRANULARITY) != KNOT_EOK) {
+ free(t);
+ return NULL;
+ }
+
+ return t;
+}
+
+/*! \brief Get bucket for current combination of parameters. */
+static rrl_item_t *rrl_hash(rrl_table_t *t, const struct sockaddr_storage *a,
+ rrl_req_t *req, const knot_dname_t *zone, uint32_t stamp,
+ int *lock)
+{
+ uint8_t buf[RRL_CLSBLK_MAXLEN];
+ int len = rrl_classify(buf, sizeof(buf), a, req, zone);
+ if (len < 0) {
+ return NULL;
+ }
+
+ uint32_t id = SipHash24(&t->key, buf, len) % t->size;
+
+ /* Lock for lookup. */
+ pthread_mutex_lock(&t->ll);
+
+ /* Find an exact match in <id, id + HOP_LEN). */
+ uint8_t *qname = buf + sizeof(uint8_t) + sizeof(uint64_t);
+ uint64_t netblk;
+ memcpy(&netblk, buf + sizeof(uint8_t), sizeof(netblk));
+ rrl_item_t match = {
+ .hop = 0,
+ .netblk = netblk,
+ .ntok = t->rate * RRL_CAPACITY,
+ .cls = buf[0],
+ .flags = RRL_BF_NULL,
+ .qname = SipHash24(&t->key, qname + 1, qname[0]),
+ .time = stamp
+ };
+
+ unsigned d = find_match(t, id, &match);
+ if (d > HOP_LEN) { /* not an exact match, find free element [f] */
+ d = find_free(t, id, stamp);
+ }
+
+ /* Reduce distance to fit <id, id + HOP_LEN) */
+ unsigned f = (id + d) % t->size;
+ while (d >= HOP_LEN) {
+ d = reduce_dist(t, id, d, &f);
+ }
+
+ /* Assign granular lock and unlock lookup. */
+ *lock = f % t->lk_count;
+ rrl_lock(t, *lock);
+ pthread_mutex_unlock(&t->ll);
+
+ /* found free elm 'k' which is in <id, id + HOP_LEN) */
+ t->arr[id].hop |= (1 << d);
+ rrl_item_t *b = t->arr + f;
+ assert(f == (id+d) % t->size);
+
+ /* Inspect bucket state. */
+ unsigned hop = b->hop;
+ if (b->cls == CLS_NULL) {
+ memcpy(b, &match, sizeof(rrl_item_t));
+ b->hop = hop;
+ }
+ /* Check for collisions. */
+ if (!bucket_match(b, &match)) {
+ if (!(b->flags & RRL_BF_SSTART)) {
+ memcpy(b, &match, sizeof(rrl_item_t));
+ b->hop = hop;
+ b->ntok = t->rate + t->rate / RRL_SSTART;
+ b->flags |= RRL_BF_SSTART;
+ }
+ }
+
+ return b;
+}
+
+int rrl_query(rrl_table_t *rrl, const struct sockaddr_storage *a, rrl_req_t *req,
+ const knot_dname_t *zone, knotd_mod_t *mod)
+{
+ if (!rrl || !req || !a) {
+ return KNOT_EINVAL;
+ }
+
+ /* Calculate hash and fetch */
+ int ret = KNOT_EOK;
+ int lock = -1;
+ uint32_t now = time_now().tv_sec;
+ rrl_item_t *b = rrl_hash(rrl, a, req, zone, now, &lock);
+ if (!b) {
+ if (lock > -1) {
+ rrl_unlock(rrl, lock);
+ }
+ return KNOT_ERROR;
+ }
+
+ /* Calculate rate for dT */
+ uint32_t dt = now - b->time;
+ if (dt > RRL_CAPACITY) {
+ dt = RRL_CAPACITY;
+ }
+ /* Visit bucket. */
+ b->time = now;
+ if (dt > 0) { /* Window moved. */
+
+ /* Check state change. */
+ if ((b->ntok > 0 || dt > 1) && (b->flags & RRL_BF_ELIMIT)) {
+ b->flags &= ~RRL_BF_ELIMIT;
+ rrl_log_state(mod, a, b->flags, b->cls);
+ }
+
+ /* Add new tokens. */
+ uint32_t dn = rrl->rate * dt;
+ if (b->flags & RRL_BF_SSTART) { /* Bucket in slow-start. */
+ b->flags &= ~RRL_BF_SSTART;
+ }
+ b->ntok += dn;
+ if (b->ntok > RRL_CAPACITY * rrl->rate) {
+ b->ntok = RRL_CAPACITY * rrl->rate;
+ }
+ }
+
+ /* Last item taken. */
+ if (b->ntok == 1 && !(b->flags & RRL_BF_ELIMIT)) {
+ b->flags |= RRL_BF_ELIMIT;
+ rrl_log_state(mod, a, b->flags, b->cls);
+ }
+
+ /* Decay current bucket. */
+ if (b->ntok > 0) {
+ --b->ntok;
+ } else if (b->ntok == 0) {
+ ret = KNOT_ELIMIT;
+ }
+
+ if (lock > -1) {
+ rrl_unlock(rrl, lock);
+ }
+ return ret;
+}
+
+bool rrl_slip_roll(int n_slip)
+{
+ /* Now n_slip means every Nth answer slips.
+ * That represents a chance of 1/N that answer slips.
+ * Therefore, on average, from 100 answers 100/N will slip. */
+ int threshold = RRL_SLIP_MAX / n_slip;
+ int roll = dnssec_random_uint16_t() % RRL_SLIP_MAX;
+ return (roll < threshold);
+}
+
+void rrl_destroy(rrl_table_t *rrl)
+{
+ if (rrl) {
+ if (rrl->lk_count > 0) {
+ pthread_mutex_destroy(&rrl->ll);
+ }
+ for (size_t i = 0; i < rrl->lk_count; ++i) {
+ pthread_mutex_destroy(rrl->lk + i);
+ }
+ free(rrl->lk);
+ }
+
+ free(rrl);
+}
diff --git a/src/knot/modules/rrl/functions.h b/src/knot/modules/rrl/functions.h
new file mode 100644
index 0000000..21c88a7
--- /dev/null
+++ b/src/knot/modules/rrl/functions.h
@@ -0,0 +1,114 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <pthread.h>
+#include <sys/socket.h>
+
+#include "libknot/libknot.h"
+#include "knot/include/module.h"
+#include "contrib/openbsd/siphash.h"
+
+/* Defaults */
+#define RRL_SLIP_MAX 100
+
+/*!
+ * \brief RRL hash bucket.
+ */
+typedef struct {
+ unsigned hop; /* Hop bitmap. */
+ uint64_t netblk; /* Prefix associated. */
+ uint16_t ntok; /* Tokens available. */
+ uint8_t cls; /* Bucket class. */
+ uint8_t flags; /* Flags. */
+ uint32_t qname; /* imputed(QNAME) hash. */
+ uint32_t time; /* Timestamp. */
+} rrl_item_t;
+
+/*!
+ * \brief RRL hash bucket table.
+ *
+ * Table is fixed size, so collisions may occur and are dealt with
+ * in a way, that hashbucket rate is reset and enters slow-start for 1 dt.
+ * When a bucket is in a slow-start mode, it cannot reset again for the time
+ * period.
+ *
+ * To avoid lock contention, N locks are created and distributed amongst buckets.
+ * As of now lock K for bucket N is calculated as K = N % (num_buckets).
+ */
+
+typedef struct {
+ SIPHASH_KEY key; /* Siphash key. */
+ uint32_t rate; /* Configured RRL limit. */
+ pthread_mutex_t ll;
+ pthread_mutex_t *lk; /* Table locks. */
+ unsigned lk_count; /* Table lock count (granularity). */
+ size_t size; /* Number of buckets. */
+ rrl_item_t arr[]; /* Buckets. */
+} rrl_table_t;
+
+/*! \brief RRL request flags. */
+typedef enum {
+ RRL_REQ_NOFLAG = 0 << 0, /*!< No flags. */
+ RRL_REQ_WILDCARD = 1 << 1 /*!< Query to wildcard name. */
+} rrl_req_flag_t;
+
+/*!
+ * \brief RRL request descriptor.
+ */
+typedef struct {
+ const uint8_t *w;
+ uint16_t len;
+ rrl_req_flag_t flags;
+ knot_pkt_t *query;
+} rrl_req_t;
+
+/*!
+ * \brief Create a RRL table.
+ * \param size Fixed hashtable size (reasonable large prime is recommended).
+ * \param rate Rate (in pkts/sec).
+ * \return created table or NULL.
+ */
+rrl_table_t *rrl_create(size_t size, uint32_t rate);
+
+/*!
+ * \brief Query the RRL table for accept or deny, when the rate limit is reached.
+ *
+ * \param rrl RRL table.
+ * \param a Source address.
+ * \param req RRL request (containing resp., flags and question).
+ * \param zone Zone name related to the response (or NULL).
+ * \param mod Query module (needed for logging).
+ * \retval KNOT_EOK if passed.
+ * \retval KNOT_ELIMIT when the limit is reached.
+ */
+int rrl_query(rrl_table_t *rrl, const struct sockaddr_storage *a, rrl_req_t *req,
+ const knot_dname_t *zone, knotd_mod_t *mod);
+
+/*!
+ * \brief Roll a dice whether answer slips or not.
+ * \param n_slip Number represents every Nth answer that is slipped.
+ * \return true or false
+ */
+bool rrl_slip_roll(int n_slip);
+
+/*!
+ * \brief Destroy RRL table.
+ * \param rrl RRL table.
+ */
+void rrl_destroy(rrl_table_t *rrl);
diff --git a/src/knot/modules/rrl/rrl.c b/src/knot/modules/rrl/rrl.c
new file mode 100644
index 0000000..e3cea0d
--- /dev/null
+++ b/src/knot/modules/rrl/rrl.c
@@ -0,0 +1,209 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "knot/include/module.h"
+#include "knot/nameserver/process_query.h" // Dependency on qdata->extra!
+#include "knot/modules/rrl/functions.h"
+
+#define MOD_RATE_LIMIT "\x0A""rate-limit"
+#define MOD_SLIP "\x04""slip"
+#define MOD_TBL_SIZE "\x0A""table-size"
+#define MOD_WHITELIST "\x09""whitelist"
+
+const yp_item_t rrl_conf[] = {
+ { MOD_RATE_LIMIT, YP_TINT, YP_VINT = { 1, INT32_MAX } },
+ { MOD_SLIP, YP_TINT, YP_VINT = { 0, RRL_SLIP_MAX, 1 } },
+ { MOD_TBL_SIZE, YP_TINT, YP_VINT = { 1, INT32_MAX, 393241 } },
+ { MOD_WHITELIST, YP_TNET, YP_VNONE, YP_FMULTI },
+ { NULL }
+};
+
+int rrl_conf_check(knotd_conf_check_args_t *args)
+{
+ knotd_conf_t limit = knotd_conf_check_item(args, MOD_RATE_LIMIT);
+ if (limit.count == 0) {
+ args->err_str = "no rate limit specified";
+ return KNOT_EINVAL;
+ }
+
+ return KNOT_EOK;
+}
+
+typedef struct {
+ rrl_table_t *rrl;
+ int slip;
+ knotd_conf_t whitelist;
+} rrl_ctx_t;
+
+static const knot_dname_t *name_from_rrsig(const knot_rrset_t *rr)
+{
+ if (rr == NULL) {
+ return NULL;
+ }
+ if (rr->type != KNOT_RRTYPE_RRSIG) {
+ return NULL;
+ }
+
+ // This is a signature.
+ return knot_rrsig_signer_name(rr->rrs.rdata);
+}
+
+static const knot_dname_t *name_from_authrr(const knot_rrset_t *rr)
+{
+ if (rr == NULL) {
+ return NULL;
+ }
+ if (rr->type != KNOT_RRTYPE_NS && rr->type != KNOT_RRTYPE_SOA) {
+ return NULL;
+ }
+
+ // This is a valid authority RR.
+ return rr->owner;
+}
+
+static knotd_state_t ratelimit_apply(knotd_state_t state, knot_pkt_t *pkt,
+ knotd_qdata_t *qdata, knotd_mod_t *mod)
+{
+ assert(pkt && qdata && mod);
+
+ rrl_ctx_t *ctx = knotd_mod_ctx(mod);
+
+ // Rate limit is not applied to TCP connections.
+ if (!(qdata->params->flags & KNOTD_QUERY_FLAG_LIMIT_SIZE)) {
+ return state;
+ }
+
+ // Rate limit is not applied to responses with a valid cookie.
+ if (qdata->params->flags & KNOTD_QUERY_FLAG_COOKIE) {
+ return state;
+ }
+
+ // Exempt clients.
+ if (knotd_conf_addr_range_match(&ctx->whitelist, qdata->params->remote)) {
+ return state;
+ }
+
+ rrl_req_t req = {
+ .w = pkt->wire,
+ .query = qdata->query
+ };
+
+ if (!EMPTY_LIST(qdata->extra->wildcards)) {
+ req.flags = RRL_REQ_WILDCARD;
+ }
+
+ // Take the zone name if known.
+ const knot_dname_t *zone_name = knotd_qdata_zone_name(qdata);
+
+ // Take the signer name as zone name if there is an RRSIG.
+ if (zone_name == NULL) {
+ const knot_pktsection_t *ans = knot_pkt_section(pkt, KNOT_ANSWER);
+ for (int i = 0; i < ans->count; i++) {
+ zone_name = name_from_rrsig(knot_pkt_rr(ans, i));
+ if (zone_name != NULL) {
+ break;
+ }
+ }
+ }
+
+ // Take the NS or SOA owner name if there is no RRSIG.
+ if (zone_name == NULL) {
+ const knot_pktsection_t *auth = knot_pkt_section(pkt, KNOT_AUTHORITY);
+ for (int i = 0; i < auth->count; i++) {
+ zone_name = name_from_authrr(knot_pkt_rr(auth, i));
+ if (zone_name != NULL) {
+ break;
+ }
+ }
+ }
+
+ if (rrl_query(ctx->rrl, qdata->params->remote, &req, zone_name, mod) == KNOT_EOK) {
+ // Rate limiting not applied.
+ return state;
+ }
+
+ if (ctx->slip > 0 && rrl_slip_roll(ctx->slip)) {
+ // Slip the answer.
+ knotd_mod_stats_incr(mod, 0, 0, 1);
+ qdata->err_truncated = true;
+ return KNOTD_STATE_FAIL;
+ } else {
+ // Drop the answer.
+ knotd_mod_stats_incr(mod, 1, 0, 1);
+ return KNOTD_STATE_NOOP;
+ }
+}
+
+static void ctx_free(rrl_ctx_t *ctx)
+{
+ assert(ctx);
+
+ rrl_destroy(ctx->rrl);
+ free(ctx);
+}
+
+int rrl_load(knotd_mod_t *mod)
+{
+ // Create RRL context.
+ rrl_ctx_t *ctx = calloc(1, sizeof(rrl_ctx_t));
+ if (ctx == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ // Create table.
+ knotd_conf_t rate = knotd_conf_mod(mod, MOD_RATE_LIMIT);
+ knotd_conf_t size = knotd_conf_mod(mod, MOD_TBL_SIZE);
+ ctx->rrl = rrl_create(size.single.integer, rate.single.integer);
+ if (ctx->rrl == NULL) {
+ ctx_free(ctx);
+ return KNOT_ENOMEM;
+ }
+
+ // Get slip.
+ knotd_conf_t conf = knotd_conf_mod(mod, MOD_SLIP);
+ ctx->slip = conf.single.integer;
+
+ // Get whitelist.
+ ctx->whitelist = knotd_conf_mod(mod, MOD_WHITELIST);
+
+ // Set up statistics counters.
+ int ret = knotd_mod_stats_add(mod, "slipped", 1, NULL);
+ if (ret != KNOT_EOK) {
+ ctx_free(ctx);
+ return ret;
+ }
+
+ ret = knotd_mod_stats_add(mod, "dropped", 1, NULL);
+ if (ret != KNOT_EOK) {
+ ctx_free(ctx);
+ return ret;
+ }
+
+ knotd_mod_ctx_set(mod, ctx);
+
+ return knotd_mod_hook(mod, KNOTD_STAGE_END, ratelimit_apply);
+}
+
+void rrl_unload(knotd_mod_t *mod)
+{
+ rrl_ctx_t *ctx = knotd_mod_ctx(mod);
+
+ knotd_conf_free(&ctx->whitelist);
+ ctx_free(ctx);
+}
+
+KNOTD_MOD_API(rrl, KNOTD_MOD_FLAG_SCOPE_ANY,
+ rrl_load, rrl_unload, rrl_conf, rrl_conf_check);
diff --git a/src/knot/modules/rrl/rrl.rst b/src/knot/modules/rrl/rrl.rst
new file mode 100644
index 0000000..7eac173
--- /dev/null
+++ b/src/knot/modules/rrl/rrl.rst
@@ -0,0 +1,133 @@
+.. _mod-rrl:
+
+``rrl`` — Response rate limiting
+================================
+
+Response rate limiting (RRL) is a method to combat DNS reflection amplification
+attacks. These attacks rely on the fact that source address of a UDP query
+can be forged, and without a worldwide deployment of `BCP38
+<https://tools.ietf.org/html/bcp38>`_, such a forgery cannot be prevented.
+An attacker can use a DNS server (or multiple servers) as an amplification
+source and can flood a victim with a large number of unsolicited DNS responses.
+The RRL lowers the amplification factor of these attacks by sending some of
+the responses as truncated or by dropping them altogether.
+
+.. NOTE::
+ The module introduces two statistics counters. The number of slipped and
+ dropped responses.
+
+.. NOTE::
+ If the :ref:`Cookies<mod-cookies>` module is active, RRL is not applied
+ for responses with a valid DNS cookie.
+
+Example
+-------
+
+You can enable RRL by setting the module globally or per zone.
+
+::
+
+ mod-rrl:
+ - id: default
+ rate-limit: 200 # Allow 200 resp/s for each flow
+ slip: 2 # Every other response slips
+
+ template:
+ - id: default
+ global-module: mod-rrl/default # Enable RRL globally
+
+Module reference
+----------------
+
+::
+
+ mod-rrl:
+ - id: STR
+ rate-limit: INT
+ slip: INT
+ table-size: INT
+ whitelist: ADDR[/INT] | ADDR-ADDR ...
+
+.. _mod-rrl_id:
+
+id
+..
+
+A module identifier.
+
+.. _mod-rrl_rate-limit:
+
+rate-limit
+..........
+
+Rate limiting is based on the token bucket scheme. A rate basically
+represents a number of tokens available each second. Each response is
+processed and classified (based on several discriminators, e.g.
+source netblock, query type, zone name, rcode, etc.). Classified responses are
+then hashed and assigned to a bucket containing number of available
+tokens, timestamp and metadata. When available tokens are exhausted,
+response is dropped or sent as truncated (see :ref:`mod-rrl_slip`).
+Number of available tokens is recalculated each second.
+
+*Required*
+
+.. _mod-rrl_table-size:
+
+table-size
+..........
+
+Size of the hash table in a number of buckets. The larger the hash table, the lesser
+the probability of a hash collision, but at the expense of additional memory costs.
+Each bucket is estimated roughly to 32 bytes. The size should be selected as
+a reasonably large prime due to better hash function distribution properties.
+Hash table is internally chained and works well up to a fill rate of 90 %, general
+rule of thumb is to select a prime near 1.2 * maximum_qps.
+
+*Default:* 393241
+
+.. _mod-rrl_slip:
+
+slip
+....
+
+As attacks using DNS/UDP are usually based on a forged source address,
+an attacker could deny services to the victim's netblock if all
+responses would be completely blocked. The idea behind SLIP mechanism
+is to send each N\ :sup:`th` response as truncated, thus allowing client to
+reconnect via TCP for at least some degree of service. It is worth
+noting, that some responses can't be truncated (e.g. SERVFAIL).
+
+- Setting the value to **0** will cause that all rate-limited responses will
+ be dropped. The outbound bandwidth and packet rate will be strictly capped
+ by the :ref:`mod-rrl_rate-limit` option. All legitimate requestors affected
+ by the limit will face denial of service and will observe excessive timeouts.
+ Therefore this setting is not recommended.
+
+- Setting the value to **1** will cause that all rate-limited responses will
+ be sent as truncated. The amplification factor of the attack will be reduced,
+ but the outbound data bandwidth won't be lower than the incoming bandwidth.
+ Also the outbound packet rate will be the same as without RRL.
+
+- Setting the value to **2** will cause that half of the rate-limited responses
+ will be dropped, the other half will be sent as truncated. With this
+ configuration, both outbound bandwidth and packet rate will be lower than the
+ inbound. On the other hand, the dropped responses enlarge the time window
+ for possible cache poisoning attack on the resolver.
+
+- Setting the value to anything **larger than 2** will keep on decreasing
+ the outgoing rate-limited bandwidth, packet rate, and chances to notify
+ legitimate requestors to reconnect using TCP. These attributes are inversely
+ proportional to the configured value. Setting the value high is not advisable.
+
+*Default:* 1
+
+.. _mod-rrl_whitelist:
+
+whitelist
+.........
+
+A list of IP addresses, network subnets, or network ranges to exempt from
+rate limiting. Empty list means that no incoming connection will be
+white-listed.
+
+*Default:* not set
diff --git a/src/knot/modules/static_modules.h.in b/src/knot/modules/static_modules.h.in
new file mode 100644
index 0000000..ef40dac
--- /dev/null
+++ b/src/knot/modules/static_modules.h.in
@@ -0,0 +1,25 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "knot/include/module.h"
+
+// Forward declarations of static modules (generated by configure).
+@STATIC_MODULES_DECLARS@
+
+// STATIC_MODULES initializator (generated by configure).
+#define STATIC_MODULES_INIT @STATIC_MODULES_INIT@
diff --git a/src/knot/modules/stats/Makefile.inc b/src/knot/modules/stats/Makefile.inc
new file mode 100644
index 0000000..09fe6d8
--- /dev/null
+++ b/src/knot/modules/stats/Makefile.inc
@@ -0,0 +1,12 @@
+knot_modules_stats_la_SOURCES = knot/modules/stats/stats.c
+EXTRA_DIST += knot/modules/stats/stats.rst
+
+if STATIC_MODULE_stats
+libknotd_la_SOURCES += $(knot_modules_stats_la_SOURCES)
+endif
+
+if SHARED_MODULE_stats
+knot_modules_stats_la_LDFLAGS = $(KNOTD_MOD_LDFLAGS)
+knot_modules_stats_la_CPPFLAGS = $(KNOTD_MOD_CPPFLAGS)
+pkglib_LTLIBRARIES += knot/modules/stats.la
+endif
diff --git a/src/knot/modules/stats/stats.c b/src/knot/modules/stats/stats.c
new file mode 100644
index 0000000..9f055a8
--- /dev/null
+++ b/src/knot/modules/stats/stats.c
@@ -0,0 +1,622 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "contrib/macros.h"
+#include "contrib/wire_ctx.h"
+#include "knot/include/module.h"
+#include "knot/nameserver/xfr.h" // Dependency on qdata->extra!
+
+#define MOD_PROTOCOL "\x10""request-protocol"
+#define MOD_OPERATION "\x10""server-operation"
+#define MOD_REQ_BYTES "\x0D""request-bytes"
+#define MOD_RESP_BYTES "\x0E""response-bytes"
+#define MOD_EDNS "\x0D""edns-presence"
+#define MOD_FLAG "\x0D""flag-presence"
+#define MOD_RCODE "\x0D""response-code"
+#define MOD_REQ_EOPT "\x13""request-edns-option"
+#define MOD_RESP_EOPT "\x14""response-edns-option"
+#define MOD_NODATA "\x0C""reply-nodata"
+#define MOD_QTYPE "\x0A""query-type"
+#define MOD_QSIZE "\x0A""query-size"
+#define MOD_RSIZE "\x0A""reply-size"
+
+#define OTHER "other"
+
+const yp_item_t stats_conf[] = {
+ { MOD_PROTOCOL, YP_TBOOL, YP_VBOOL = { true } },
+ { MOD_OPERATION, YP_TBOOL, YP_VBOOL = { true } },
+ { MOD_REQ_BYTES, YP_TBOOL, YP_VBOOL = { true } },
+ { MOD_RESP_BYTES, YP_TBOOL, YP_VBOOL = { true } },
+ { MOD_EDNS, YP_TBOOL, YP_VNONE },
+ { MOD_FLAG, YP_TBOOL, YP_VNONE },
+ { MOD_RCODE, YP_TBOOL, YP_VBOOL = { true } },
+ { MOD_REQ_EOPT, YP_TBOOL, YP_VNONE },
+ { MOD_RESP_EOPT, YP_TBOOL, YP_VNONE },
+ { MOD_NODATA, YP_TBOOL, YP_VNONE },
+ { MOD_QTYPE, YP_TBOOL, YP_VNONE },
+ { MOD_QSIZE, YP_TBOOL, YP_VNONE },
+ { MOD_RSIZE, YP_TBOOL, YP_VNONE },
+ { NULL }
+};
+
+enum {
+ CTR_PROTOCOL,
+ CTR_OPERATION,
+ CTR_REQ_BYTES,
+ CTR_RESP_BYTES,
+ CTR_EDNS,
+ CTR_FLAG,
+ CTR_RCODE,
+ CTR_REQ_EOPT,
+ CTR_RESP_EOPT,
+ CTR_NODATA,
+ CTR_QTYPE,
+ CTR_QSIZE,
+ CTR_RSIZE,
+};
+
+typedef struct {
+ bool protocol;
+ bool operation;
+ bool req_bytes;
+ bool resp_bytes;
+ bool edns;
+ bool flag;
+ bool rcode;
+ bool req_eopt;
+ bool resp_eopt;
+ bool nodata;
+ bool qtype;
+ bool qsize;
+ bool rsize;
+} stats_t;
+
+typedef struct {
+ yp_name_t *conf_name;
+ size_t conf_offset;
+ uint32_t count;
+ knotd_mod_idx_to_str_f fcn;
+} ctr_desc_t;
+
+enum {
+ OPERATION_QUERY = 0,
+ OPERATION_UPDATE,
+ OPERATION_NOTIFY,
+ OPERATION_AXFR,
+ OPERATION_IXFR,
+ OPERATION_INVALID,
+ OPERATION__COUNT
+};
+
+static char *operation_to_str(uint32_t idx, uint32_t count)
+{
+ switch (idx) {
+ case OPERATION_QUERY: return strdup("query");
+ case OPERATION_UPDATE: return strdup("update");
+ case OPERATION_NOTIFY: return strdup("notify");
+ case OPERATION_AXFR: return strdup("axfr");
+ case OPERATION_IXFR: return strdup("ixfr");
+ case OPERATION_INVALID: return strdup("invalid");
+ default: assert(0); return NULL;
+ }
+}
+
+enum {
+ PROTOCOL_UDP4 = 0,
+ PROTOCOL_TCP4,
+ PROTOCOL_UDP6,
+ PROTOCOL_TCP6,
+ PROTOCOL__COUNT
+};
+
+static char *protocol_to_str(uint32_t idx, uint32_t count)
+{
+ switch (idx) {
+ case PROTOCOL_UDP4: return strdup("udp4");
+ case PROTOCOL_TCP4: return strdup("tcp4");
+ case PROTOCOL_UDP6: return strdup("udp6");
+ case PROTOCOL_TCP6: return strdup("tcp6");
+ default: assert(0); return NULL;
+ }
+}
+
+enum {
+ REQ_BYTES_QUERY = 0,
+ REQ_BYTES_UPDATE,
+ REQ_BYTES_OTHER,
+ REQ_BYTES__COUNT
+};
+
+static char *req_bytes_to_str(uint32_t idx, uint32_t count)
+{
+ switch (idx) {
+ case REQ_BYTES_QUERY: return strdup("query");
+ case REQ_BYTES_UPDATE: return strdup("update");
+ case REQ_BYTES_OTHER: return strdup(OTHER);
+ default: assert(0); return NULL;
+ }
+}
+
+enum {
+ RESP_BYTES_REPLY = 0,
+ RESP_BYTES_TRANSFER,
+ RESP_BYTES_OTHER,
+ RESP_BYTES__COUNT
+};
+
+static char *resp_bytes_to_str(uint32_t idx, uint32_t count)
+{
+ switch (idx) {
+ case RESP_BYTES_REPLY: return strdup("reply");
+ case RESP_BYTES_TRANSFER: return strdup("transfer");
+ case RESP_BYTES_OTHER: return strdup(OTHER);
+ default: assert(0); return NULL;
+ }
+}
+
+enum {
+ EDNS_REQ = 0,
+ EDNS_RESP,
+ EDNS__COUNT
+};
+
+static char *edns_to_str(uint32_t idx, uint32_t count)
+{
+ switch (idx) {
+ case EDNS_REQ: return strdup("request");
+ case EDNS_RESP: return strdup("response");
+ default: assert(0); return NULL;
+ }
+}
+
+enum {
+ FLAG_DO = 0,
+ FLAG_TC,
+ FLAG__COUNT
+};
+
+static char *flag_to_str(uint32_t idx, uint32_t count)
+{
+ switch (idx) {
+ case FLAG_TC: return strdup("TC");
+ case FLAG_DO: return strdup("DO");
+ default: assert(0); return NULL;
+ }
+}
+
+enum {
+ NODATA_A = 0,
+ NODATA_AAAA,
+ NODATA_OTHER,
+ NODATA__COUNT
+};
+
+static char *nodata_to_str(uint32_t idx, uint32_t count)
+{
+ switch (idx) {
+ case NODATA_A: return strdup("A");
+ case NODATA_AAAA: return strdup("AAAA");
+ case NODATA_OTHER: return strdup(OTHER);
+ default: assert(0); return NULL;
+ }
+}
+
+#define RCODE_BADSIG 15 // Unassigned code internally used for BADSIG.
+#define RCODE_OTHER (KNOT_RCODE_BADCOOKIE + 1) // Other RCODES.
+
+static char *rcode_to_str(uint32_t idx, uint32_t count)
+{
+ const knot_lookup_t *rcode = NULL;
+
+ switch (idx) {
+ case RCODE_BADSIG:
+ rcode = knot_lookup_by_id(knot_tsig_rcode_names, KNOT_RCODE_BADSIG);
+ break;
+ case RCODE_OTHER:
+ return strdup(OTHER);
+ default:
+ rcode = knot_lookup_by_id(knot_rcode_names, idx);
+ break;
+ }
+
+ if (rcode != NULL) {
+ return strdup(rcode->name);
+ } else {
+ return NULL;
+ }
+}
+
+#define EOPT_OTHER (KNOT_EDNS_MAX_OPTION_CODE + 1)
+#define req_eopt_to_str eopt_to_str
+#define resp_eopt_to_str eopt_to_str
+
+static char *eopt_to_str(uint32_t idx, uint32_t count)
+{
+ if (idx >= EOPT_OTHER) {
+ return strdup(OTHER);
+ }
+
+ char str[32];
+ if (knot_opt_code_to_string(idx, str, sizeof(str)) < 0) {
+ return NULL;
+ } else {
+ return strdup(str);
+ }
+}
+
+enum {
+ QTYPE_OTHER = 0,
+ QTYPE_MIN1 = 1,
+ QTYPE_MAX1 = 65,
+ QTYPE_MIN2 = 99,
+ QTYPE_MAX2 = 110,
+ QTYPE_MIN3 = 255,
+ QTYPE_MAX3 = 260,
+ QTYPE_SHIFT2 = QTYPE_MIN2 - QTYPE_MAX1 - 1,
+ QTYPE_SHIFT3 = QTYPE_SHIFT2 + QTYPE_MIN3 - QTYPE_MAX2 - 1,
+ QTYPE__COUNT = QTYPE_MAX3 - QTYPE_SHIFT3 + 1
+};
+
+static char *qtype_to_str(uint32_t idx, uint32_t count)
+{
+ if (idx == QTYPE_OTHER) {
+ return strdup(OTHER);
+ }
+
+ uint16_t qtype;
+
+ if (idx <= QTYPE_MAX1) {
+ qtype = idx;
+ assert(qtype >= QTYPE_MIN1 && qtype <= QTYPE_MAX1);
+ } else if (idx <= QTYPE_MAX2 - QTYPE_SHIFT2) {
+ qtype = idx + QTYPE_SHIFT2;
+ assert(qtype >= QTYPE_MIN2 && qtype <= QTYPE_MAX2);
+ } else {
+ qtype = idx + QTYPE_SHIFT3;
+ assert(qtype >= QTYPE_MIN3 && qtype <= QTYPE_MAX3);
+ }
+
+ char str[32];
+ if (knot_rrtype_to_string(qtype, str, sizeof(str)) < 0) {
+ return NULL;
+ } else {
+ return strdup(str);
+ }
+}
+
+#define BUCKET_SIZE 16
+#define QSIZE_MAX_IDX (288 / BUCKET_SIZE)
+#define RSIZE_MAX_IDX (4096 / BUCKET_SIZE)
+
+static char *size_to_str(uint32_t idx, uint32_t count)
+{
+ char str[16];
+
+ int ret;
+ if (idx < count - 1) {
+ ret = snprintf(str, sizeof(str), "%u-%u", idx * BUCKET_SIZE,
+ (idx + 1) * BUCKET_SIZE - 1);
+ } else {
+ ret = snprintf(str, sizeof(str), "%u-65535", idx * BUCKET_SIZE);
+ }
+
+ if (ret <= 0 || (size_t)ret >= sizeof(str)) {
+ return NULL;
+ } else {
+ return strdup(str);
+ }
+}
+
+static char *qsize_to_str(uint32_t idx, uint32_t count)
+{
+ return size_to_str(idx, count);
+}
+
+static char *rsize_to_str(uint32_t idx, uint32_t count)
+{
+ return size_to_str(idx, count);
+}
+
+static const ctr_desc_t ctr_descs[] = {
+ #define item(macro, name, count) \
+ [CTR_##macro] = { MOD_##macro, offsetof(stats_t, name), (count), name##_to_str }
+ item(PROTOCOL, protocol, PROTOCOL__COUNT),
+ item(OPERATION, operation, OPERATION__COUNT),
+ item(REQ_BYTES, req_bytes, REQ_BYTES__COUNT),
+ item(RESP_BYTES, resp_bytes, RESP_BYTES__COUNT),
+ item(EDNS, edns, EDNS__COUNT),
+ item(FLAG, flag, FLAG__COUNT),
+ item(RCODE, rcode, RCODE_OTHER + 1),
+ item(REQ_EOPT, req_eopt, EOPT_OTHER + 1),
+ item(RESP_EOPT, resp_eopt, EOPT_OTHER + 1),
+ item(NODATA, nodata, NODATA__COUNT),
+ item(QTYPE, qtype, QTYPE__COUNT),
+ item(QSIZE, qsize, QSIZE_MAX_IDX + 1),
+ item(RSIZE, rsize, RSIZE_MAX_IDX + 1),
+ { NULL }
+};
+
+static void incr_edns_option(knotd_mod_t *mod, const knot_pkt_t *pkt, unsigned ctr_name)
+{
+ if (!knot_pkt_has_edns(pkt)) {
+ return;
+ }
+
+ knot_rdata_t *rdata = pkt->opt_rr->rrs.rdata;
+ if (rdata == NULL || rdata->len == 0) {
+ return;
+ }
+
+ wire_ctx_t wire = wire_ctx_init_const(rdata->data, rdata->len);
+ while (wire_ctx_available(&wire) > 0) {
+ uint16_t opt_code = wire_ctx_read_u16(&wire);
+ uint16_t opt_len = wire_ctx_read_u16(&wire);
+ wire_ctx_skip(&wire, opt_len);
+ if (wire.error != KNOT_EOK) {
+ break;
+ }
+ knotd_mod_stats_incr(mod, ctr_name, MIN(opt_code, EOPT_OTHER), 1);
+ }
+}
+
+static knotd_state_t update_counters(knotd_state_t state, knot_pkt_t *pkt,
+ knotd_qdata_t *qdata, knotd_mod_t *mod)
+{
+ assert(pkt && qdata);
+
+ stats_t *stats = knotd_mod_ctx(mod);
+
+ uint16_t operation;
+ unsigned xfr_packets = 0;
+
+ // Get the server operation.
+ switch (qdata->type) {
+ case KNOTD_QUERY_TYPE_NORMAL:
+ operation = OPERATION_QUERY;
+ break;
+ case KNOTD_QUERY_TYPE_UPDATE:
+ operation = OPERATION_UPDATE;
+ break;
+ case KNOTD_QUERY_TYPE_NOTIFY:
+ operation = OPERATION_NOTIFY;
+ break;
+ case KNOTD_QUERY_TYPE_AXFR:
+ operation = OPERATION_AXFR;
+ if (qdata->extra->ext != NULL) {
+ xfr_packets = ((struct xfr_proc *)qdata->extra->ext)->stats.messages;
+ }
+ break;
+ case KNOTD_QUERY_TYPE_IXFR:
+ operation = OPERATION_IXFR;
+ if (qdata->extra->ext != NULL) {
+ xfr_packets = ((struct xfr_proc *)qdata->extra->ext)->stats.messages;
+ }
+ break;
+ default:
+ operation = OPERATION_INVALID;
+ break;
+ }
+
+ // Count request bytes.
+ if (stats->req_bytes) {
+ switch (operation) {
+ case OPERATION_QUERY:
+ knotd_mod_stats_incr(mod, CTR_REQ_BYTES, REQ_BYTES_QUERY,
+ knot_pkt_size(qdata->query));
+ break;
+ case OPERATION_UPDATE:
+ knotd_mod_stats_incr(mod, CTR_REQ_BYTES, REQ_BYTES_UPDATE,
+ knot_pkt_size(qdata->query));
+ break;
+ default:
+ if (xfr_packets <= 1) {
+ knotd_mod_stats_incr(mod, CTR_REQ_BYTES, REQ_BYTES_OTHER,
+ knot_pkt_size(qdata->query));
+ }
+ break;
+ }
+ }
+
+ // Count response bytes.
+ if (stats->resp_bytes && state != KNOTD_STATE_NOOP) {
+ switch (operation) {
+ case OPERATION_QUERY:
+ knotd_mod_stats_incr(mod, CTR_RESP_BYTES, RESP_BYTES_REPLY,
+ knot_pkt_size(pkt));
+ break;
+ case OPERATION_AXFR:
+ case OPERATION_IXFR:
+ knotd_mod_stats_incr(mod, CTR_RESP_BYTES, RESP_BYTES_TRANSFER,
+ knot_pkt_size(pkt));
+ break;
+ default:
+ knotd_mod_stats_incr(mod, CTR_RESP_BYTES, RESP_BYTES_OTHER,
+ knot_pkt_size(pkt));
+ break;
+ }
+ }
+
+ // Get the extended response code.
+ uint16_t rcode = qdata->rcode;
+ if (qdata->rcode_tsig != KNOT_RCODE_NOERROR) {
+ rcode = qdata->rcode_tsig;
+ }
+
+ // Count the response code.
+ if (stats->rcode && state != KNOTD_STATE_NOOP) {
+ if (xfr_packets <= 1 || rcode != KNOT_RCODE_NOERROR) {
+ if (xfr_packets > 1) {
+ assert(rcode != KNOT_RCODE_NOERROR);
+ // Ignore the leading XFR message NOERROR.
+ knotd_mod_stats_decr(mod, CTR_RCODE,
+ KNOT_RCODE_NOERROR, 1);
+ }
+
+ if (qdata->rcode_tsig == KNOT_RCODE_BADSIG) {
+ knotd_mod_stats_incr(mod, CTR_RCODE, RCODE_BADSIG, 1);
+ } else {
+ knotd_mod_stats_incr(mod, CTR_RCODE,
+ MIN(rcode, RCODE_OTHER), 1);
+ }
+ }
+ }
+
+ // Return if non-first transfer message.
+ if (xfr_packets > 1) {
+ return state;
+ }
+
+ // Count the server opearation.
+ if (stats->operation) {
+ knotd_mod_stats_incr(mod, CTR_OPERATION, operation, 1);
+ }
+
+ // Count the request protocol.
+ if (stats->protocol) {
+ if (qdata->params->remote->ss_family == AF_INET) {
+ if (qdata->params->flags & KNOTD_QUERY_FLAG_LIMIT_SIZE) {
+ knotd_mod_stats_incr(mod, CTR_PROTOCOL,
+ PROTOCOL_UDP4, 1);
+ } else {
+ knotd_mod_stats_incr(mod, CTR_PROTOCOL,
+ PROTOCOL_TCP4, 1);
+ }
+ } else {
+ if (qdata->params->flags & KNOTD_QUERY_FLAG_LIMIT_SIZE) {
+ knotd_mod_stats_incr(mod, CTR_PROTOCOL,
+ PROTOCOL_UDP6, 1);
+ } else {
+ knotd_mod_stats_incr(mod, CTR_PROTOCOL,
+ PROTOCOL_TCP6, 1);
+ }
+ }
+ }
+
+ // Count EDNS occurrences.
+ if (stats->edns) {
+ if (knot_pkt_has_edns(qdata->query)) {
+ knotd_mod_stats_incr(mod, CTR_EDNS, EDNS_REQ, 1);
+ }
+ if (knot_pkt_has_edns(pkt) && state != KNOTD_STATE_NOOP) {
+ knotd_mod_stats_incr(mod, CTR_EDNS, EDNS_RESP, 1);
+ }
+ }
+
+ // Count interesting message header flags.
+ if (stats->flag) {
+ if (state != KNOTD_STATE_NOOP && knot_wire_get_tc(pkt->wire)) {
+ knotd_mod_stats_incr(mod, CTR_FLAG, FLAG_TC, 1);
+ }
+ if (knot_pkt_has_dnssec(pkt)) {
+ knotd_mod_stats_incr(mod, CTR_FLAG, FLAG_DO, 1);
+ }
+ }
+
+ // Count EDNS options.
+ if (stats->req_eopt) {
+ incr_edns_option(mod, qdata->query, CTR_REQ_EOPT);
+ }
+ if (stats->resp_eopt) {
+ incr_edns_option(mod, pkt, CTR_RESP_EOPT);
+ }
+
+ // Return if not query operation.
+ if (operation != OPERATION_QUERY) {
+ return state;
+ }
+
+ // Count NODATA reply (RFC 2308, Section 2.2).
+ if (stats->nodata && rcode == KNOT_RCODE_NOERROR && state != KNOTD_STATE_NOOP &&
+ knot_wire_get_ancount(pkt->wire) == 0 && !knot_wire_get_tc(pkt->wire) &&
+ (knot_wire_get_nscount(pkt->wire) == 0 ||
+ knot_pkt_rr(knot_pkt_section(pkt, KNOT_AUTHORITY), 0)->type == KNOT_RRTYPE_SOA)) {
+ switch (knot_pkt_qtype(qdata->query)) {
+ case KNOT_RRTYPE_A:
+ knotd_mod_stats_incr(mod, CTR_NODATA, NODATA_A, 1);
+ break;
+ case KNOT_RRTYPE_AAAA:
+ knotd_mod_stats_incr(mod, CTR_NODATA, NODATA_AAAA, 1);
+ break;
+ default:
+ knotd_mod_stats_incr(mod, CTR_NODATA, NODATA_OTHER, 1);
+ break;
+ }
+ }
+
+ // Count the query type.
+ if (stats->qtype) {
+ uint16_t qtype = knot_pkt_qtype(qdata->query);
+
+ uint16_t idx;
+ switch (qtype) {
+ case QTYPE_MIN1 ... QTYPE_MAX1: idx = qtype; break;
+ case QTYPE_MIN2 ... QTYPE_MAX2: idx = qtype - QTYPE_SHIFT2; break;
+ case QTYPE_MIN3 ... QTYPE_MAX3: idx = qtype - QTYPE_SHIFT3; break;
+ default: idx = QTYPE_OTHER; break;
+ }
+
+ knotd_mod_stats_incr(mod, CTR_QTYPE, idx, 1);
+ }
+
+ // Count the query size.
+ if (stats->qsize) {
+ uint64_t idx = knot_pkt_size(qdata->query) / BUCKET_SIZE;
+ knotd_mod_stats_incr(mod, CTR_QSIZE, MIN(idx, QSIZE_MAX_IDX), 1);
+ }
+
+ // Count the reply size.
+ if (stats->rsize && state != KNOTD_STATE_NOOP) {
+ uint64_t idx = knot_pkt_size(pkt) / BUCKET_SIZE;
+ knotd_mod_stats_incr(mod, CTR_RSIZE, MIN(idx, RSIZE_MAX_IDX), 1);
+ }
+
+ return state;
+}
+
+int stats_load(knotd_mod_t *mod)
+{
+ stats_t *stats = calloc(1, sizeof(*stats));
+ if (stats == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ for (const ctr_desc_t *desc = ctr_descs; desc->conf_name != NULL; desc++) {
+ knotd_conf_t conf = knotd_conf_mod(mod, desc->conf_name);
+ bool enabled = conf.single.boolean;
+
+ // Initialize corresponding configuration item.
+ *(bool *)((uint8_t *)stats + desc->conf_offset) = enabled;
+
+ int ret = knotd_mod_stats_add(mod, enabled ? desc->conf_name + 1 : NULL,
+ enabled ? desc->count : 1, desc->fcn);
+ if (ret != KNOT_EOK) {
+ free(stats);
+ return ret;
+ }
+ }
+
+ knotd_mod_ctx_set(mod, stats);
+
+ return knotd_mod_hook(mod, KNOTD_STAGE_END, update_counters);
+}
+
+void stats_unload(knotd_mod_t *mod)
+{
+ free(knotd_mod_ctx(mod));
+}
+
+KNOTD_MOD_API(stats, KNOTD_MOD_FLAG_SCOPE_ANY | KNOTD_MOD_FLAG_OPT_CONF,
+ stats_load, stats_unload, stats_conf, NULL);
diff --git a/src/knot/modules/stats/stats.rst b/src/knot/modules/stats/stats.rst
new file mode 100644
index 0000000..45dbc86
--- /dev/null
+++ b/src/knot/modules/stats/stats.rst
@@ -0,0 +1,266 @@
+.. _mod-stats:
+
+``stats`` — Query statistics
+============================
+
+The module extends server statistics with incoming DNS request and corresponding
+response counters, such as used network protocol, total number of responded bytes,
+etc (see module reference for full list of supported counters).
+This module should be configured as the last module.
+
+.. NOTE::
+ Server initiated communication (outgoing NOTIFY, incoming \*XFR,...) is not
+ counted by this module.
+
+.. NOTE::
+ Leading 16-bit message size over TCP is not considered.
+
+Example
+-------
+
+Common statistics with default module configuration::
+
+ template:
+ - id: default
+ global-module: mod-stats
+
+Per zone statistics with explicit module configuration::
+
+ mod-stats:
+ - id: custom
+ edns-presence: on
+ query-type: on
+
+ template:
+ - id: default
+ module: mod-stats/custom
+
+Module reference
+----------------
+
+::
+
+ mod-stats:
+ - id: STR
+ request-protocol: BOOL
+ server-operation: BOOL
+ request-bytes: BOOL
+ response-bytes: BOOL
+ edns-presence: BOOL
+ flag-presence: BOOL
+ response-code: BOOL
+ request-edns-option: BOOL
+ response-edns-option: BOOL
+ reply-nodata: BOOL
+ query-type: BOOL
+ query-size: BOOL
+ reply-size: BOOL
+
+.. _mod-stats_id:
+
+id
+..
+
+A module identifier.
+
+.. _mod-stats_request-protocol:
+
+request-protocol
+................
+
+If enabled, all incoming requests are counted by the network protocol:
+
+* udp4 - UDP over IPv4
+* tcp4 - TCP over IPv4
+* udp6 - UDP over IPv6
+* tcp6 - TCP over IPv6
+
+*Default:* on
+
+.. _mod-stats_server-operation:
+
+server-operation
+................
+
+If enabled, all incoming requests are counted by the server operation. The
+server operation is based on message header OpCode and message query (meta) type:
+
+* query - Normal query operation
+* update - Dynamic update operation
+* notify - NOTIFY request operation
+* axfr - Full zone transfer operation
+* ixfr - Incremental zone transfer operation
+* invalid - Invalid server operation
+
+*Default:* on
+
+.. _mod-stats_request-bytes:
+
+request-bytes
+.............
+
+If enabled, all incoming request bytes are counted by the server operation:
+
+* query - Normal query bytes
+* update - Dynamic update bytes
+* other - Other request bytes
+
+*Default:* on
+
+.. _mod-stats_response-bytes:
+
+response-bytes
+..............
+
+If enabled, outgoing response bytes are counted by the server operation:
+
+* reply - Normal response bytes
+* transfer - Zone transfer bytes
+* other - Other response bytes
+
+.. WARNING::
+ Dynamic update response bytes are not counted by this module.
+
+*Default:* on
+
+.. _mod-stats_edns-presence:
+
+edns-presence
+.............
+
+If enabled, EDNS pseudo section presence is counted by the message direction:
+
+* request - EDNS present in request
+* response - EDNS present in response
+
+*Default:* off
+
+.. _mod-stats_flag-presence:
+
+flag-presence
+.............
+
+If enabled, some message header flags are counted:
+
+* TC - Truncated Answer in response
+* DO - DNSSEC OK in request
+
+*Default:* off
+
+.. _mod-stats_response-code:
+
+response-code
+.............
+
+If enabled, outgoing response code is counted:
+
+* NOERROR
+* ...
+* NOTZONE
+* BADVERS
+* ...
+* BADCOOKIE
+* other - All other codes
+
+.. NOTE::
+ In the case of multi-message zone transfer response, just one counter is
+ incremented.
+
+.. WARNING::
+ Dynamic update response code is not counted by this module.
+
+*Default:* on
+
+.. _mod-stats_request-edns-option:
+
+request-edns-option
+...................
+
+If enabled, EDNS options in requests are counted by their code:
+
+* CODE0
+* ...
+* EDNS-KEY-TAG (CODE14)
+* other - All other codes
+
+*Default:* off
+
+.. _mod-stats_response-edns-option:
+
+response-edns-option
+....................
+
+If enabled, EDNS options in responses are counted by their code. See
+:ref:`mod-stats_request-edns-option`.
+
+*Default:* off
+
+.. _mod-stats_reply-nodata:
+
+reply-nodata
+............
+
+If enabled, NODATA pseudo RCODE (:rfc:`2308#section-2.2`) is counted by the
+query type:
+
+* A
+* AAAA
+* other - All other types
+
+*Default:* off
+
+.. _mod-stats_query-type:
+
+query-type
+..........
+
+If enabled, normal query type is counted:
+
+* A (TYPE1)
+* ...
+* TYPE65
+* SPF (TYPE99)
+* ...
+* TYPE110
+* ANY (TYPE255)
+* ...
+* TYPE260
+* other - All other types
+
+.. NOTE::
+ Not all assigned meta types (IXFR, AXFR,...) have their own counters,
+ because such types are not processed as normal query.
+
+*Default:* off
+
+.. _mod-stats_query-size:
+
+query-size
+..........
+
+If enabled, normal query message size distribution is counted by the size range
+in bytes:
+
+* 0-15
+* 16-31
+* ...
+* 272-287
+* 288-65535
+
+*Default:* off
+
+.. _mod-stats_reply-size:
+
+reply-size
+..........
+
+If enabled, normal reply message size distribution is counted by the size range
+in bytes:
+
+* 0-15
+* 16-31
+* ...
+* 4080-4095
+* 4096-65535
+
+*Default:* off
diff --git a/src/knot/modules/synthrecord/Makefile.inc b/src/knot/modules/synthrecord/Makefile.inc
new file mode 100644
index 0000000..d7aca3b
--- /dev/null
+++ b/src/knot/modules/synthrecord/Makefile.inc
@@ -0,0 +1,13 @@
+knot_modules_synthrecord_la_SOURCES = knot/modules/synthrecord/synthrecord.c
+EXTRA_DIST += knot/modules/synthrecord/synthrecord.rst
+
+if STATIC_MODULE_synthrecord
+libknotd_la_SOURCES += $(knot_modules_synthrecord_la_SOURCES)
+endif
+
+if SHARED_MODULE_synthrecord
+knot_modules_synthrecord_la_LDFLAGS = $(KNOTD_MOD_LDFLAGS)
+knot_modules_synthrecord_la_CPPFLAGS = $(KNOTD_MOD_CPPFLAGS)
+knot_modules_synthrecord_la_LIBADD = libcontrib.la
+pkglib_LTLIBRARIES += knot/modules/synthrecord.la
+endif
diff --git a/src/knot/modules/synthrecord/synthrecord.c b/src/knot/modules/synthrecord/synthrecord.c
new file mode 100644
index 0000000..b54e783
--- /dev/null
+++ b/src/knot/modules/synthrecord/synthrecord.c
@@ -0,0 +1,498 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "contrib/ctype.h"
+#include "contrib/net.h"
+#include "contrib/sockaddr.h"
+#include "contrib/wire_ctx.h"
+#include "knot/include/module.h"
+
+#define MOD_NET "\x07""network"
+#define MOD_ORIGIN "\x06""origin"
+#define MOD_PREFIX "\x06""prefix"
+#define MOD_TTL "\x03""ttl"
+#define MOD_TYPE "\x04""type"
+
+/*! \brief Supported answer synthesis template types. */
+enum synth_template_type {
+ SYNTH_NULL = 0,
+ SYNTH_FORWARD = 1,
+ SYNTH_REVERSE = 2
+};
+
+static const knot_lookup_t synthetic_types[] = {
+ { SYNTH_FORWARD, "forward" },
+ { SYNTH_REVERSE, "reverse" },
+ { 0, NULL }
+};
+
+int check_prefix(knotd_conf_check_args_t *args)
+{
+ if (strchr((const char *)args->data, '.') != NULL) {
+ args->err_str = "dot '.' is not allowed";
+ return KNOT_EINVAL;
+ }
+
+ return KNOT_EOK;
+}
+
+const yp_item_t synth_record_conf[] = {
+ { MOD_TYPE, YP_TOPT, YP_VOPT = { synthetic_types, SYNTH_NULL } },
+ { MOD_PREFIX, YP_TSTR, YP_VSTR = { "" }, YP_FNONE, { check_prefix } },
+ { MOD_ORIGIN, YP_TDNAME, YP_VNONE },
+ { MOD_TTL, YP_TINT, YP_VINT = { 0, UINT32_MAX, 3600, YP_STIME } },
+ { MOD_NET, YP_TNET, YP_VNONE, YP_FMULTI },
+ { NULL }
+};
+
+int synth_record_conf_check(knotd_conf_check_args_t *args)
+{
+ // Check type.
+ knotd_conf_t type = knotd_conf_check_item(args, MOD_TYPE);
+ if (type.count == 0) {
+ args->err_str = "no synthesis type specified";
+ return KNOT_EINVAL;
+ }
+
+ // Check origin.
+ knotd_conf_t origin = knotd_conf_check_item(args, MOD_ORIGIN);
+ if (origin.count == 0 && type.single.option == SYNTH_REVERSE) {
+ args->err_str = "no origin specified";
+ return KNOT_EINVAL;
+ }
+ if (origin.count != 0 && type.single.option == SYNTH_FORWARD) {
+ args->err_str = "origin not allowed with forward type";
+ return KNOT_EINVAL;
+ }
+
+ // Check network subnet.
+ knotd_conf_t net = knotd_conf_check_item(args, MOD_NET);
+ if (net.count == 0) {
+ args->err_str = "no network subnet specified";
+ return KNOT_EINVAL;
+ }
+ knotd_conf_free(&net);
+
+ return KNOT_EOK;
+}
+
+#define ARPA_ZONE_LABELS 2
+#define IPV4_ADDR_LABELS 4
+#define IPV6_ADDR_LABELS 32
+#define IPV4_ARPA_DNAME (uint8_t *)"\x07""in-addr""\x04""arpa"
+#define IPV6_ARPA_DNAME (uint8_t *)"\x03""ip6""\x04""arpa"
+
+/*!
+ * \brief Synthetic response template.
+ */
+typedef struct {
+ struct sockaddr_storage addr;
+ struct sockaddr_storage addr_max;
+ int addr_mask;
+} synth_templ_addr_t;
+
+typedef struct {
+ enum synth_template_type type;
+ char *prefix;
+ size_t prefix_len;
+ char *zone;
+ size_t zone_len;
+ uint32_t ttl;
+ size_t addr_count;
+ synth_templ_addr_t *addr;
+} synth_template_t;
+
+/*! \brief Substitute all occurrences of given character. */
+static void str_subst(char *str, size_t len, char from, char to)
+{
+ for (int i = 0; i < len; ++i) {
+ if (str[i] == from) {
+ str[i] = to;
+ }
+ }
+}
+
+/*! \brief Separator character for address family. */
+static char str_separator(int addr_family)
+{
+ if (addr_family == AF_INET6) {
+ return ':';
+ }
+ return '.';
+}
+
+/*! \brief Return true if query type is satisfied with provided address family. */
+static bool query_satisfied_by_family(uint16_t qtype, int family)
+{
+ switch (qtype) {
+ case KNOT_RRTYPE_A: return family == AF_INET;
+ case KNOT_RRTYPE_AAAA: return family == AF_INET6;
+ case KNOT_RRTYPE_ANY: return true;
+ default: return false;
+ }
+}
+
+/*! \brief Parse address from reverse query QNAME and return address family. */
+static int reverse_addr_parse(knotd_qdata_t *qdata, char *addr_str, int *addr_family)
+{
+ /* QNAME required format is [address].[subnet/zone]
+ * f.e. [1.0...0].[h.g.f.e.0.0.0.0.d.c.b.a.ip6.arpa] represents
+ * [abcd:0:efgh::1] */
+ const knot_dname_t *label = qdata->name;
+ const uint8_t *wire = qdata->query->wire;
+
+ switch (knot_dname_labels(label, wire)) {
+ case IPV4_ADDR_LABELS + ARPA_ZONE_LABELS:
+ *addr_family = AF_INET;
+
+ const knot_dname_t *label1 = label;
+ const knot_dname_t *label2 = knot_wire_next_label(label1, wire);
+ const knot_dname_t *label3 = knot_wire_next_label(label2, wire);
+ const knot_dname_t *label4 = knot_wire_next_label(label3, wire);
+ assert(label1 && label2 && label3 && label4);
+
+ label = knot_wire_next_label(label4, wire);
+ if (!knot_dname_is_equal(label, IPV4_ARPA_DNAME)) {
+ return KNOT_EINVAL;
+ }
+
+ // 255.255.255.255
+ wire_ctx_t ctx = wire_ctx_init((uint8_t *)addr_str,
+ IPV4_ADDR_LABELS * 3 + 3 + 1);
+ wire_ctx_write(&ctx, label4 + 1, label4[0]);
+ wire_ctx_write_u8(&ctx, '.');
+ wire_ctx_write(&ctx, label3 + 1, label3[0]);
+ wire_ctx_write_u8(&ctx, '.');
+ wire_ctx_write(&ctx, label2 + 1, label2[0]);
+ wire_ctx_write_u8(&ctx, '.');
+ wire_ctx_write(&ctx, label1 + 1, label1[0]);
+ wire_ctx_write_u8(&ctx, '\0');
+ if (ctx.error != KNOT_EOK) {
+ return ctx.error;
+ }
+
+ return KNOT_EOK;
+ case IPV6_ADDR_LABELS + ARPA_ZONE_LABELS:
+ *addr_family = AF_INET6;
+
+ // 1-char labels + separators.
+ const int addr_len = IPV6_ADDR_LABELS + 7;
+ for (int i = 1; i <= addr_len; i++) {
+ if (i % 5 == 0) {
+ addr_str[addr_len - i] = ':';
+ } else if (label[0] == 1) {
+ addr_str[addr_len - i] = label[1];
+ label = knot_wire_next_label(label, wire);
+ assert(label);
+ } else {
+ return KNOT_EINVAL;
+ }
+ }
+ addr_str[addr_len] = '\0';
+
+ if (!knot_dname_is_equal(label, IPV6_ARPA_DNAME)) {
+ return KNOT_EINVAL;
+ }
+
+ return KNOT_EOK;
+ default:
+ return KNOT_EINVAL;
+ }
+}
+
+static int forward_addr_parse(knotd_qdata_t *qdata, const synth_template_t *tpl,
+ char *addr_str, int *addr_family)
+{
+ const knot_dname_t *label = qdata->name;
+
+ // Check for prefix mismatch.
+ if (label[0] <= tpl->prefix_len ||
+ memcmp(label + 1, tpl->prefix, tpl->prefix_len) != 0) {
+ return KNOT_EINVAL;
+ }
+
+ // Copy address part.
+ int addr_len = label[0] - tpl->prefix_len;
+ memcpy(addr_str, label + 1 + tpl->prefix_len, addr_len);
+ addr_str[addr_len] = '\0';
+
+ // Determine query family: v6 if *-ABCD.zone.
+ const char *last_octet = addr_str + addr_len;
+ while (last_octet > addr_str && is_xdigit(*--last_octet));
+ *addr_family = (last_octet + 5 == addr_str + addr_len ? AF_INET6 : AF_INET);
+
+ // Restore correct address format.
+ const char sep = str_separator(*addr_family);
+ str_subst(addr_str, addr_len, '-', sep);
+
+ return KNOT_EOK;
+}
+
+static int addr_parse(knotd_qdata_t *qdata, const synth_template_t *tpl, char *addr_str,
+ int *addr_family)
+{
+ switch (tpl->type) {
+ case SYNTH_REVERSE: return reverse_addr_parse(qdata, addr_str, addr_family);
+ case SYNTH_FORWARD: return forward_addr_parse(qdata, tpl, addr_str, addr_family);
+ default: return KNOT_EINVAL;
+ }
+}
+
+static knot_dname_t *synth_ptrname(uint8_t *out, const char *addr_str,
+ const synth_template_t *tpl, int addr_family)
+{
+ char ptrname[KNOT_DNAME_TXT_MAXLEN];
+ int addr_len = strlen(addr_str);
+ const char sep = str_separator(addr_family);
+
+ // PTR right-hand value is [prefix][address][zone]
+ wire_ctx_t ctx = wire_ctx_init((uint8_t *)ptrname, sizeof(ptrname));
+ wire_ctx_write(&ctx, tpl->prefix, tpl->prefix_len);
+ wire_ctx_write(&ctx, addr_str, addr_len);
+ wire_ctx_write_u8(&ctx, '.');
+ wire_ctx_write(&ctx, tpl->zone, tpl->zone_len);
+ wire_ctx_write_u8(&ctx, '\0');
+ if (ctx.error != KNOT_EOK) {
+ return NULL;
+ }
+
+ // Substitute address separator by '-'.
+ str_subst(ptrname + tpl->prefix_len, addr_len, sep, '-');
+
+ // Convert to domain name.
+ return knot_dname_from_str(out, ptrname, KNOT_DNAME_MAXLEN);
+}
+
+static int reverse_rr(char *addr_str, const synth_template_t *tpl, knot_pkt_t *pkt,
+ knot_rrset_t *rr, int addr_family)
+{
+ // Synthetize PTR record data.
+ uint8_t ptrname[KNOT_DNAME_MAXLEN];
+ if (synth_ptrname(ptrname, addr_str, tpl, addr_family) == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ rr->type = KNOT_RRTYPE_PTR;
+ knot_rrset_add_rdata(rr, ptrname, knot_dname_size(ptrname), &pkt->mm);
+
+ return KNOT_EOK;
+}
+
+static int forward_rr(char *addr_str, const synth_template_t *tpl, knot_pkt_t *pkt,
+ knot_rrset_t *rr, int addr_family)
+{
+ struct sockaddr_storage query_addr;
+ sockaddr_set(&query_addr, addr_family, addr_str, 0);
+
+ // Specify address type and data.
+ if (addr_family == AF_INET6) {
+ rr->type = KNOT_RRTYPE_AAAA;
+ const struct sockaddr_in6* ip = (const struct sockaddr_in6*)&query_addr;
+ knot_rrset_add_rdata(rr, (const uint8_t *)&ip->sin6_addr,
+ sizeof(struct in6_addr), &pkt->mm);
+ } else if (addr_family == AF_INET) {
+ rr->type = KNOT_RRTYPE_A;
+ const struct sockaddr_in* ip = (const struct sockaddr_in*)&query_addr;
+ knot_rrset_add_rdata(rr, (const uint8_t *)&ip->sin_addr,
+ sizeof(struct in_addr), &pkt->mm);
+ } else {
+ return KNOT_EINVAL;
+ }
+
+ return KNOT_EOK;
+}
+
+static knot_rrset_t *synth_rr(char *addr_str, const synth_template_t *tpl, knot_pkt_t *pkt,
+ knotd_qdata_t *qdata, int addr_family)
+{
+ knot_rrset_t *rr = knot_rrset_new(qdata->name, 0, KNOT_CLASS_IN, tpl->ttl,
+ &pkt->mm);
+ if (rr == NULL) {
+ return NULL;
+ }
+
+ // Fill in the specific data.
+ int ret = KNOT_ERROR;
+ switch (tpl->type) {
+ case SYNTH_REVERSE: ret = reverse_rr(addr_str, tpl, pkt, rr, addr_family); break;
+ case SYNTH_FORWARD: ret = forward_rr(addr_str, tpl, pkt, rr, addr_family); break;
+ default: break;
+ }
+
+ if (ret != KNOT_EOK) {
+ knot_rrset_free(rr, &pkt->mm);
+ return NULL;
+ }
+
+ return rr;
+}
+
+/*! \brief Check if query fits the template requirements. */
+static knotd_in_state_t template_match(knotd_in_state_t state, const synth_template_t *tpl,
+ knot_pkt_t *pkt, knotd_qdata_t *qdata)
+{
+ int provided_af = AF_UNSPEC;
+ struct sockaddr_storage query_addr;
+ char addr_str[SOCKADDR_STRLEN];
+ assert(SOCKADDR_STRLEN > KNOT_DNAME_MAXLABELLEN);
+
+ // Parse address from query name.
+ if (addr_parse(qdata, tpl, addr_str, &provided_af) != KNOT_EOK ||
+ sockaddr_set(&query_addr, provided_af, addr_str, 0) != KNOT_EOK) {
+ return state;
+ }
+
+ // Try all available addresses.
+ int i;
+ for (i = 0; i < tpl->addr_count; i++) {
+ if (tpl->addr[i].addr_max.ss_family == AF_UNSPEC) {
+ if (sockaddr_net_match((struct sockaddr *)&query_addr,
+ (struct sockaddr *)&tpl->addr[i].addr,
+ tpl->addr[i].addr_mask)) {
+ break;
+ }
+ } else {
+ if (sockaddr_range_match((struct sockaddr *)&query_addr,
+ (struct sockaddr *)&tpl->addr[i].addr,
+ (struct sockaddr *)&tpl->addr[i].addr_max)) {
+ break;
+ }
+ }
+ }
+ if (i >= tpl->addr_count) {
+ return state;
+ }
+
+ // Check if the request is for an available query type.
+ uint16_t qtype = knot_pkt_qtype(qdata->query);
+ switch (tpl->type) {
+ case SYNTH_FORWARD:
+ if (!query_satisfied_by_family(qtype, provided_af)) {
+ qdata->rcode = KNOT_RCODE_NOERROR;
+ return KNOTD_IN_STATE_NODATA;
+ }
+ break;
+ case SYNTH_REVERSE:
+ if (qtype != KNOT_RRTYPE_PTR && qtype != KNOT_RRTYPE_ANY) {
+ qdata->rcode = KNOT_RCODE_NOERROR;
+ return KNOTD_IN_STATE_NODATA;
+ }
+ break;
+ default:
+ return state;
+ }
+
+ // Synthetise record from template.
+ knot_rrset_t *rr = synth_rr(addr_str, tpl, pkt, qdata, provided_af);
+ if (rr == NULL) {
+ qdata->rcode = KNOT_RCODE_SERVFAIL;
+ return KNOTD_IN_STATE_ERROR;
+ }
+
+ // Insert synthetic response into packet.
+ if (knot_pkt_put(pkt, 0, rr, KNOT_PF_FREE) != KNOT_EOK) {
+ return KNOTD_IN_STATE_ERROR;
+ }
+
+ // Authoritative response.
+ knot_wire_set_aa(pkt->wire);
+
+ return KNOTD_IN_STATE_HIT;
+}
+
+static knotd_in_state_t solve_synth_record(knotd_in_state_t state, knot_pkt_t *pkt,
+ knotd_qdata_t *qdata, knotd_mod_t *mod)
+{
+ assert(pkt && qdata && mod);
+
+ // Applicable when search in zone fails.
+ if (state != KNOTD_IN_STATE_MISS) {
+ return state;
+ }
+
+ // Check if template fits.
+ return template_match(state, knotd_mod_ctx(mod), pkt, qdata);
+}
+
+int synth_record_load(knotd_mod_t *mod)
+{
+ // Create synthesis template.
+ synth_template_t *tpl = calloc(1, sizeof(*tpl));
+ if (tpl == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ // Set type.
+ knotd_conf_t conf = knotd_conf_mod(mod, MOD_TYPE);
+ tpl->type = conf.single.option;
+
+ /* Set prefix. */
+ conf = knotd_conf_mod(mod, MOD_PREFIX);
+ tpl->prefix = strdup(conf.single.string);
+ tpl->prefix_len = strlen(tpl->prefix);
+
+ // Set origin if generating reverse record.
+ if (tpl->type == SYNTH_REVERSE) {
+ conf = knotd_conf_mod(mod, MOD_ORIGIN);
+ tpl->zone = knot_dname_to_str_alloc(conf.single.dname);
+ if (tpl->zone == NULL) {
+ free(tpl->prefix);
+ free(tpl);
+ return KNOT_ENOMEM;
+ }
+ tpl->zone_len = strlen(tpl->zone);
+ }
+
+ // Set ttl.
+ conf = knotd_conf_mod(mod, MOD_TTL);
+ tpl->ttl = conf.single.integer;
+
+ // Set address.
+ conf = knotd_conf_mod(mod, MOD_NET);
+ tpl->addr_count = conf.count;
+ tpl->addr = calloc(conf.count, sizeof(*tpl->addr));
+ if (tpl->addr == NULL) {
+ knotd_conf_free(&conf);
+ free(tpl->zone);
+ free(tpl->prefix);
+ free(tpl);
+ return KNOT_ENOMEM;
+ }
+ for (size_t i = 0; i < conf.count; i++) {
+ tpl->addr[i].addr = conf.multi[i].addr;
+ tpl->addr[i].addr_max = conf.multi[i].addr_max;
+ tpl->addr[i].addr_mask = conf.multi[i].addr_mask;
+ }
+ knotd_conf_free(&conf);
+
+ knotd_mod_ctx_set(mod, tpl);
+
+ return knotd_mod_in_hook(mod, KNOTD_STAGE_ANSWER, solve_synth_record);
+}
+
+void synth_record_unload(knotd_mod_t *mod)
+{
+ synth_template_t *tpl = knotd_mod_ctx(mod);
+
+ free(tpl->addr);
+ free(tpl->zone);
+ free(tpl->prefix);
+ free(tpl);
+}
+
+KNOTD_MOD_API(synthrecord, KNOTD_MOD_FLAG_SCOPE_ZONE,
+ synth_record_load, synth_record_unload, synth_record_conf,
+ synth_record_conf_check);
diff --git a/src/knot/modules/synthrecord/synthrecord.rst b/src/knot/modules/synthrecord/synthrecord.rst
new file mode 100644
index 0000000..eddac2f
--- /dev/null
+++ b/src/knot/modules/synthrecord/synthrecord.rst
@@ -0,0 +1,161 @@
+.. _mod-synthrecord:
+
+``synthrecord`` – Automatic forward/reverse records
+===================================================
+
+This module is able to synthesize either forward or reverse records for
+a given prefix and subnet.
+
+Records are synthesized only if the query can't be satisfied from the zone.
+Both IPv4 and IPv6 are supported.
+
+Example
+-------
+
+Automatic forward records
+.........................
+
+::
+
+ mod-synthrecord:
+ - id: test1
+ type: forward
+ prefix: dynamic-
+ ttl: 400
+ network: 2620:0:b61::/52
+
+ zone:
+ - domain: test.
+ file: test.zone # Must exist
+ module: mod-synthrecord/test1
+
+Result:
+
+.. code-block:: console
+
+ $ kdig AAAA dynamic-2620-0000-0b61-0100-0000-0000-0000-0001.test.
+ ...
+ ;; QUESTION SECTION:
+ ;; dynamic-2620-0000-0b61-0100-0000-0000-0000-0001.test. IN AAAA
+
+ ;; ANSWER SECTION:
+ dynamic-2620-0000-0b61-0100-0000-0000-0000-0001.test. 400 IN AAAA 2620:0:b61:100::1
+
+You can also have CNAME aliases to the dynamic records, which are going to be
+further resolved:
+
+.. code-block:: console
+
+ $ kdig AAAA alias.test.
+ ...
+ ;; QUESTION SECTION:
+ ;; alias.test. IN AAAA
+
+ ;; ANSWER SECTION:
+ alias.test. 3600 IN CNAME dynamic-2620-0000-0b61-0100-0000-0000-0000-0002.test.
+ dynamic-2620-0000-0b61-0100-0000-0000-0000-0002.test. 400 IN AAAA 2620:0:b61:100::2
+
+Automatic reverse records
+.........................
+
+::
+
+ mod-synthrecord:
+ - id: test2
+ type: reverse
+ prefix: dynamic-
+ origin: test
+ ttl: 400
+ network: 2620:0:b61::/52
+
+ zone:
+ - domain: 1.6.b.0.0.0.0.0.0.2.6.2.ip6.arpa.
+ file: 1.6.b.0.0.0.0.0.0.2.6.2.ip6.arpa.zone # Must exist
+ module: mod-synthrecord/test2
+
+Result:
+
+.. code-block:: console
+
+ $ kdig -x 2620:0:b61::1
+ ...
+ ;; QUESTION SECTION:
+ ;; 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.6.b.0.0.0.0.0.0.2.6.2.ip6.arpa. IN PTR
+
+ ;; ANSWER SECTION:
+ 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.6.b.0.0.0.0.0.0.2.6.2.ip6.arpa. 400 IN PTR
+ dynamic-2620-0000-0b61-0000-0000-0000-0000-0001.test.
+
+Module reference
+----------------
+
+::
+
+ mod-synthrecord:
+ - id: STR
+ type: forward | reverse
+ prefix: STR
+ origin: DNAME
+ ttl: INT
+ network: ADDR[/INT] | ADDR-ADDR ...
+
+.. _mod-synthrecord_id:
+
+id
+..
+
+A module identifier.
+
+.. _mod-synthrecord_type:
+
+type
+....
+
+The type of generated records.
+
+Possible values:
+
+- ``forward`` – Forward records
+- ``reverse`` – Reverse records
+
+*Required*
+
+.. _mod-synthrecord_prefix:
+
+prefix
+......
+
+A record owner prefix.
+
+.. NOTE::
+ The value doesn’t allow dots, address parts in the synthetic names are
+ separated with a dash.
+
+*Default:* empty
+
+.. _mod-synthrecord_origin:
+
+origin
+......
+
+A zone origin (only valid for the :ref:`reverse type<mod-synthrecord_type>`).
+
+*Required*
+
+.. _mod-synthrecord_ttl:
+
+ttl
+...
+
+Time to live of the generated records.
+
+*Default:* 3600
+
+.. _mod-synthrecord_network:
+
+network
+.......
+
+An IP address, a network subnet, or a network range the query must match.
+
+*Required*
diff --git a/src/knot/modules/whoami/Makefile.inc b/src/knot/modules/whoami/Makefile.inc
new file mode 100644
index 0000000..4d20fcb
--- /dev/null
+++ b/src/knot/modules/whoami/Makefile.inc
@@ -0,0 +1,12 @@
+knot_modules_whoami_la_SOURCES = knot/modules/whoami/whoami.c
+EXTRA_DIST += knot/modules/whoami/whoami.rst
+
+if STATIC_MODULE_whoami
+libknotd_la_SOURCES += $(knot_modules_whoami_la_SOURCES)
+endif
+
+if SHARED_MODULE_whoami
+knot_modules_whoami_la_LDFLAGS = $(KNOTD_MOD_LDFLAGS)
+knot_modules_whoami_la_CPPFLAGS = $(KNOTD_MOD_CPPFLAGS)
+pkglib_LTLIBRARIES += knot/modules/whoami.la
+endif
diff --git a/src/knot/modules/whoami/whoami.c b/src/knot/modules/whoami/whoami.c
new file mode 100644
index 0000000..ea80fc9
--- /dev/null
+++ b/src/knot/modules/whoami/whoami.c
@@ -0,0 +1,114 @@
+/* Copyright (C) 2017 Fastly, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <netinet/in.h>
+
+#include "knot/include/module.h"
+
+static knotd_in_state_t whoami_query(knotd_in_state_t state, knot_pkt_t *pkt,
+ knotd_qdata_t *qdata, knotd_mod_t *mod)
+{
+ assert(pkt && qdata);
+
+ const knot_dname_t *zone_name = knotd_qdata_zone_name(qdata);
+ if (zone_name == NULL) {
+ return KNOTD_IN_STATE_ERROR;
+ }
+
+ /* Retrieve the query tuple. */
+ const knot_dname_t *qname = knot_pkt_qname(qdata->query);
+ const uint16_t qtype = knot_pkt_qtype(qdata->query);
+ const uint16_t qclass = knot_pkt_qclass(qdata->query);
+
+ /* We only generate A and AAAA records, which are Internet class. */
+ if (qclass != KNOT_CLASS_IN) {
+ return state;
+ }
+
+ /* Only handle queries with qname set to the zone name. */
+ if (!knot_dname_is_equal(qname, zone_name)) {
+ return state;
+ }
+
+ /* Only handle A and AAAA queries. */
+ if (qtype != KNOT_RRTYPE_A && qtype != KNOT_RRTYPE_AAAA) {
+ return state;
+ }
+
+ /* Retrieve the IP address that sent the query. */
+ const struct sockaddr_storage *query_source = qdata->params->remote;
+ if (query_source == NULL) {
+ return KNOTD_IN_STATE_ERROR;
+ }
+
+ /* If the socket address family corresponds to the query type (i.e.,
+ * AF_INET <-> A and AF_INET6 <-> AAAA), put the socket address and
+ * length into 'rdata' and 'len_rdata'.
+ */
+ const void *rdata = NULL;
+ uint16_t len_rdata = 0;
+ if (query_source->ss_family == AF_INET && qtype == KNOT_RRTYPE_A) {
+ const struct sockaddr_in *sai = (struct sockaddr_in *)query_source;
+ rdata = &sai->sin_addr.s_addr;
+ len_rdata = sizeof(sai->sin_addr.s_addr);
+ } else if (query_source->ss_family == AF_INET6 && qtype == KNOT_RRTYPE_AAAA) {
+ const struct sockaddr_in6 *sai6 = (struct sockaddr_in6 *)query_source;
+ rdata = &sai6->sin6_addr;
+ len_rdata = sizeof(sai6->sin6_addr);
+ } else {
+ /* Query type didn't match address family. */
+ return state;
+ }
+
+ /* Synthesize the response RRset. */
+
+ /* TTL is taken from the TTL of the SOA record. */
+ knot_rrset_t soa = knotd_qdata_zone_apex_rrset(qdata, KNOT_RRTYPE_SOA);
+
+ /* Owner name, type, and class are taken from the question. */
+ knot_rrset_t *rrset = knot_rrset_new(qname, qtype, qclass, soa.ttl, &pkt->mm);
+ if (rrset == NULL) {
+ return KNOTD_IN_STATE_ERROR;
+ }
+
+ /* Record data is the query source address. */
+ int ret = knot_rrset_add_rdata(rrset, rdata, len_rdata, &pkt->mm);
+ if (ret != KNOT_EOK) {
+ knot_rrset_free(rrset, &pkt->mm);
+ return KNOTD_IN_STATE_ERROR;
+ }
+
+ /* Add the new RRset to the response packet. */
+ ret = knot_pkt_put(pkt, KNOT_COMPR_HINT_QNAME, rrset, KNOT_PF_FREE);
+ if (ret != KNOT_EOK) {
+ knot_rrset_free(rrset, &pkt->mm);
+ return KNOTD_IN_STATE_ERROR;
+ }
+
+ /* Success. */
+ return KNOTD_IN_STATE_HIT;
+}
+
+int whoami_load(knotd_mod_t *mod)
+{
+ /* Hook to the query plan. */
+ knotd_mod_in_hook(mod, KNOTD_STAGE_ANSWER, whoami_query);
+
+ return KNOT_EOK;
+}
+
+KNOTD_MOD_API(whoami, KNOTD_MOD_FLAG_SCOPE_ZONE | KNOTD_MOD_FLAG_OPT_CONF,
+ whoami_load, NULL, NULL, NULL);
diff --git a/src/knot/modules/whoami/whoami.rst b/src/knot/modules/whoami/whoami.rst
new file mode 100644
index 0000000..25d0174
--- /dev/null
+++ b/src/knot/modules/whoami/whoami.rst
@@ -0,0 +1,97 @@
+.. _mod-whoami:
+
+``whoami`` — Whoami response
+============================
+
+The module synthesizes an A or AAAA record containing the query source IP address,
+at the apex of the zone being served. It makes sure to allow Knot DNS to generate
+cacheable negative responses, and to allow fallback to extra records defined in the
+underlying zone file. The TTL of the synthesized record is copied from
+the TTL of the SOA record in the zone file.
+
+Because a DNS query for type A or AAAA has nothing to do with whether
+the query occurs over IPv4 or IPv6, this module requires a special
+zone configuration to support both address families. For A queries, the
+underlying zone must have a set of nameservers that only have IPv4
+addresses, and for AAAA queries, the underlying zone must have a set of
+nameservers that only have IPv6 addresses.
+
+Example
+-------
+
+To enable this module, you need to add something like the following to
+the Knot DNS configuration file::
+
+ zone:
+ - domain: whoami.domain.example
+ file: "/path/to/whoami.domain.example"
+ module: mod-whoami
+
+ zone:
+ - domain: whoami6.domain.example
+ file: "/path/to/whoami6.domain.example"
+ module: mod-whoami
+
+The whoami.domain.example zone file example:
+
+ .. code-block:: none
+
+ $TTL 1
+
+ @ SOA (
+ whoami.domain.example. ; MNAME
+ hostmaster.domain.example. ; RNAME
+ 2016051300 ; SERIAL
+ 86400 ; REFRESH
+ 86400 ; RETRY
+ 86400 ; EXPIRE
+ 1 ; MINIMUM
+ )
+
+ $TTL 86400
+
+ @ NS ns1.whoami.domain.example.
+ @ NS ns2.whoami.domain.example.
+ @ NS ns3.whoami.domain.example.
+ @ NS ns4.whoami.domain.example.
+
+ ns1 A 198.51.100.53
+ ns2 A 192.0.2.53
+ ns3 A 203.0.113.53
+ ns4 A 198.19.123.53
+
+The whoami6.domain.example zone file example:
+
+ .. code-block:: none
+
+ $TTL 1
+
+ @ SOA (
+ whoami6.domain.example. ; MNAME
+ hostmaster.domain.example. ; RNAME
+ 2016051300 ; SERIAL
+ 86400 ; REFRESH
+ 86400 ; RETRY
+ 86400 ; EXPIRE
+ 1 ; MINIMUM
+ )
+
+ $TTL 86400
+
+ @ NS ns1.whoami6.domain.example.
+ @ NS ns2.whoami6.domain.example.
+ @ NS ns3.whoami6.domain.example.
+ @ NS ns4.whoami6.domain.example.
+
+ ns1 AAAA 2001:db8:100::53
+ ns2 AAAA 2001:db8:200::53
+ ns3 AAAA 2001:db8:300::53
+ ns4 AAAA 2001:db8:400::53
+
+The parent domain would then delegate whoami.domain.example to
+ns[1-4].whoami.domain.example and whoami6.domain.example to
+ns[1-4].whoami6.domain.example, and include the corresponding A-only or
+AAAA-only glue records.
+
+.. NOTE::
+ This module is not configurable.
diff --git a/src/knot/nameserver/axfr.c b/src/knot/nameserver/axfr.c
new file mode 100644
index 0000000..6a60b19
--- /dev/null
+++ b/src/knot/nameserver/axfr.c
@@ -0,0 +1,214 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <urcu.h>
+
+#include "contrib/mempattern.h"
+#include "contrib/sockaddr.h"
+#include "knot/nameserver/axfr.h"
+#include "knot/nameserver/internet.h"
+#include "knot/nameserver/log.h"
+#include "knot/nameserver/xfr.h"
+#include "libknot/libknot.h"
+
+#define ZONE_NAME(qdata) knot_pkt_qname((qdata)->query)
+#define REMOTE(qdata) (struct sockaddr *)(qdata)->params->remote
+
+#define AXFROUT_LOG(priority, qdata, fmt...) \
+ ns_log(priority, ZONE_NAME(qdata), LOG_OPERATION_AXFR, \
+ LOG_DIRECTION_OUT, REMOTE(qdata), fmt)
+
+/* AXFR context. @note aliasing the generic xfr_proc */
+struct axfr_proc {
+ struct xfr_proc proc;
+ trie_it_t *i;
+ unsigned cur_rrset;
+};
+
+static int axfr_put_rrsets(knot_pkt_t *pkt, zone_node_t *node,
+ struct axfr_proc *state)
+{
+ assert(node != NULL);
+
+ /* Append all RRs. */
+ for (unsigned i = state->cur_rrset; i < node->rrset_count; ++i) {
+ knot_rrset_t rrset = node_rrset_at(node, i);
+ if (rrset.type == KNOT_RRTYPE_SOA) {
+ continue;
+ }
+
+ int ret = knot_pkt_put(pkt, 0, &rrset, KNOT_PF_NOTRUNC | KNOT_PF_ORIGTTL);
+ if (ret != KNOT_EOK) {
+ /* If something failed, remember the current RR for later. */
+ state->cur_rrset = i;
+ return ret;
+ }
+ }
+
+ state->cur_rrset = 0;
+
+ return KNOT_EOK;
+}
+
+static int axfr_process_node_tree(knot_pkt_t *pkt, const void *item,
+ struct xfr_proc *state)
+{
+ assert(item != NULL);
+
+ struct axfr_proc *axfr = (struct axfr_proc*)state;
+
+ if (axfr->i == NULL) {
+ axfr->i = trie_it_begin((trie_t *)item);
+ }
+
+ /* Put responses. */
+ int ret = KNOT_EOK;
+ while (!trie_it_finished(axfr->i)) {
+ zone_node_t *node = (zone_node_t *)*trie_it_val(axfr->i);
+ ret = axfr_put_rrsets(pkt, node, axfr);
+ if (ret != KNOT_EOK) {
+ break;
+ }
+ trie_it_next(axfr->i);
+ }
+
+ /* Finished all nodes. */
+ if (ret == KNOT_EOK) {
+ trie_it_free(axfr->i);
+ axfr->i = NULL;
+ }
+ return ret;
+}
+
+static void axfr_query_cleanup(knotd_qdata_t *qdata)
+{
+ struct axfr_proc *axfr = (struct axfr_proc *)qdata->extra->ext;
+
+ trie_it_free(axfr->i);
+ ptrlist_free(&axfr->proc.nodes, qdata->mm);
+ mm_free(qdata->mm, axfr);
+
+ /* Allow zone changes (finished). */
+ rcu_read_unlock();
+}
+
+static int axfr_query_check(knotd_qdata_t *qdata)
+{
+ NS_NEED_ZONE(qdata, KNOT_RCODE_NOTAUTH);
+ NS_NEED_AUTH(qdata, qdata->extra->zone->name, ACL_ACTION_TRANSFER);
+ NS_NEED_ZONE_CONTENTS(qdata, KNOT_RCODE_SERVFAIL);
+
+ return KNOT_STATE_DONE;
+}
+
+static int axfr_query_init(knotd_qdata_t *qdata)
+{
+ assert(qdata);
+
+ /* Check AXFR query validity. */
+ if (axfr_query_check(qdata) == KNOT_STATE_FAIL) {
+ if (qdata->rcode == KNOT_RCODE_FORMERR) {
+ return KNOT_EMALF;
+ } else {
+ return KNOT_EDENIED;
+ }
+ }
+
+ /* Create transfer processing context. */
+ knot_mm_t *mm = qdata->mm;
+ struct axfr_proc *axfr = mm_alloc(mm, sizeof(struct axfr_proc));
+ if (axfr == NULL) {
+ return KNOT_ENOMEM;
+ }
+ memset(axfr, 0, sizeof(struct axfr_proc));
+ init_list(&axfr->proc.nodes);
+
+ /* Put data to process. */
+ xfr_stats_begin(&axfr->proc.stats);
+ zone_contents_t *contents = qdata->extra->zone->contents;
+ /* Must be non-NULL for the first message. */
+ assert(contents);
+ ptrlist_add(&axfr->proc.nodes, contents->nodes, mm);
+ /* Put NSEC3 data if exists. */
+ if (!zone_tree_is_empty(contents->nsec3_nodes)) {
+ ptrlist_add(&axfr->proc.nodes, contents->nsec3_nodes, mm);
+ }
+
+ /* Set up cleanup callback. */
+ qdata->extra->ext = axfr;
+ qdata->extra->ext_cleanup = &axfr_query_cleanup;
+
+ /* No zone changes during multipacket answer (unlocked in axfr_answer_cleanup) */
+ rcu_read_lock();
+
+ return KNOT_EOK;
+}
+
+int axfr_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata)
+{
+ if (pkt == NULL || qdata == NULL) {
+ return KNOT_STATE_FAIL;
+ }
+
+ /* If AXFR is disabled, respond with NOTIMPL. */
+ if (qdata->params->flags & KNOTD_QUERY_FLAG_NO_AXFR) {
+ qdata->rcode = KNOT_RCODE_NOTIMPL;
+ return KNOT_STATE_FAIL;
+ }
+
+ /* Initialize on first call. */
+ struct axfr_proc *axfr = qdata->extra->ext;
+ if (axfr == NULL) {
+ int ret = axfr_query_init(qdata);
+ axfr = qdata->extra->ext;
+ switch (ret) {
+ case KNOT_EOK: /* OK */
+ AXFROUT_LOG(LOG_INFO, qdata, "started, serial %u",
+ zone_contents_serial(qdata->extra->zone->contents));
+ break;
+ case KNOT_EDENIED: /* Not authorized, already logged. */
+ return KNOT_STATE_FAIL;
+ case KNOT_EMALF: /* Malformed query. */
+ AXFROUT_LOG(LOG_DEBUG, qdata, "malformed query");
+ return KNOT_STATE_FAIL;
+ default:
+ AXFROUT_LOG(LOG_ERR, qdata, "failed to start (%s)",
+ knot_strerror(ret));
+ return KNOT_STATE_FAIL;
+ }
+ }
+
+ /* Reserve space for TSIG. */
+ int ret = knot_pkt_reserve(pkt, knot_tsig_wire_size(&qdata->sign.tsig_key));
+ if (ret != KNOT_EOK) {
+ return KNOT_STATE_FAIL;
+ }
+
+ /* Answer current packet (or continue). */
+ ret = xfr_process_list(pkt, &axfr_process_node_tree, qdata);
+ switch (ret) {
+ case KNOT_ESPACE: /* Couldn't write more, send packet and continue. */
+ return KNOT_STATE_PRODUCE; /* Check for more. */
+ case KNOT_EOK: /* Last response. */
+ xfr_stats_end(&axfr->proc.stats);
+ xfr_log_finished(ZONE_NAME(qdata), LOG_OPERATION_AXFR, LOG_DIRECTION_OUT,
+ REMOTE(qdata), &axfr->proc.stats);
+ return KNOT_STATE_DONE;
+ default: /* Generic error. */
+ AXFROUT_LOG(LOG_ERR, qdata, "failed (%s)", knot_strerror(ret));
+ return KNOT_STATE_FAIL;
+ }
+}
diff --git a/src/knot/nameserver/axfr.h b/src/knot/nameserver/axfr.h
new file mode 100644
index 0000000..1d1e4ea
--- /dev/null
+++ b/src/knot/nameserver/axfr.h
@@ -0,0 +1,27 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "knot/nameserver/process_query.h"
+#include "libknot/packet/pkt.h"
+
+/*!
+ * \brief Process an AXFR query message.
+ *
+ * \return KNOT_STATE_* processing states
+ */
+int axfr_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata);
diff --git a/src/knot/nameserver/chaos.c b/src/knot/nameserver/chaos.c
new file mode 100644
index 0000000..04b646a
--- /dev/null
+++ b/src/knot/nameserver/chaos.c
@@ -0,0 +1,145 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <strings.h>
+#include <stdlib.h>
+
+#include "knot/nameserver/chaos.h"
+#include "knot/conf/conf.h"
+#include "libknot/libknot.h"
+
+#define WISH "Knot DNS developers wish you "
+#define HOPE "Knot DNS developers hope you "
+
+static const char *wishes[] = {
+ HOPE "have all your important life questions aswered without SERVFAIL.",
+ WISH "many wonderful people in your domain.",
+ WISH "non-empty lymph nodes.",
+ HOPE "resolve the . of your problems.",
+ WISH "long enough TTL.",
+ HOPE "become authoritative master in your domain.",
+ HOPE "always find useful PTR in CHAOS.",
+ "Canonical name is known to both DNS experts and Ubuntu users.",
+ HOPE "never forget both your name and address.",
+ "Don't fix broken CNAME chains with glue!",
+ WISH "no Additional section in your TODO list.",
+ HOPE "won't find surprising news in today's journal.",
+ HOPE "perform rollover often just when playing roulette.",
+ HOPE "get notified before your domain registration expires.",
+};
+
+#undef WISH
+#undef HOPE
+
+static const char *get_txt_response_string(knot_pkt_t *response)
+{
+ char qname[32];
+ if (knot_dname_to_str(qname, knot_pkt_qname(response), sizeof(qname)) == NULL) {
+ return NULL;
+ }
+
+ const char *response_str = NULL;
+
+ /* Allow hostname.bind. for compatibility. */
+ if (strcasecmp("id.server.", qname) == 0 ||
+ strcasecmp("hostname.bind.", qname) == 0) {
+ conf_val_t val = conf_get(conf(), C_SRV, C_IDENT);
+ if (val.code == KNOT_EOK) {
+ response_str = conf_str(&val); // Can be NULL!
+ } else {
+ response_str = conf()->hostname;
+ }
+ /* Allow version.bind. for compatibility. */
+ } else if (strcasecmp("version.server.", qname) == 0 ||
+ strcasecmp("version.bind.", qname) == 0) {
+ conf_val_t val = conf_get(conf(), C_SRV, C_VERSION);
+ if (val.code == KNOT_EOK) {
+ response_str = conf_str(&val); // Can be NULL!
+ } else {
+ response_str = "Knot DNS " PACKAGE_VERSION;
+ }
+ } else if (strcasecmp("fortune.", qname) == 0) {
+ conf_val_t val = conf_get(conf(), C_SRV, C_VERSION);
+ if (val.code != KNOT_EOK) {
+ uint16_t wishno = knot_wire_get_id(response->wire) %
+ (sizeof(wishes) / sizeof(wishes[0]));
+ response_str = wishes[wishno];
+ }
+ }
+
+ return response_str;
+}
+
+static int create_txt_rrset(knot_rrset_t *rrset, const knot_dname_t *owner,
+ const char *response_str, knot_mm_t *mm)
+{
+ /* Truncate response to one TXT label. */
+ size_t response_len = strlen(response_str);
+ if (response_len > UINT8_MAX) {
+ response_len = UINT8_MAX;
+ }
+
+ knot_dname_t *rowner = knot_dname_copy(owner, mm);
+ if (rowner == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ knot_rrset_init(rrset, rowner, KNOT_RRTYPE_TXT, KNOT_CLASS_CH, 0);
+ uint8_t rdata[response_len + 1];
+
+ rdata[0] = response_len;
+ memcpy(&rdata[1], response_str, response_len);
+
+ int ret = knot_rrset_add_rdata(rrset, rdata, response_len + 1, mm);
+ if (ret != KNOT_EOK) {
+ knot_dname_free(rrset->owner, mm);
+ return ret;
+ }
+
+ return KNOT_EOK;
+}
+
+static int answer_txt(knot_pkt_t *response)
+{
+ const char *response_str = get_txt_response_string(response);
+ if (response_str == NULL || response_str[0] == '\0') {
+ return KNOT_RCODE_REFUSED;
+ }
+
+ knot_rrset_t rrset;
+ int ret = create_txt_rrset(&rrset, knot_pkt_qname(response),
+ response_str, &response->mm);
+ if (ret != KNOT_EOK) {
+ return KNOT_RCODE_SERVFAIL;
+ }
+
+ int result = knot_pkt_put(response, 0, &rrset, KNOT_PF_FREE);
+ if (result != KNOT_EOK) {
+ knot_rrset_clear(&rrset, &response->mm);
+ return KNOT_RCODE_SERVFAIL;
+ }
+
+ return KNOT_RCODE_NOERROR;
+}
+
+int knot_chaos_answer(knot_pkt_t *pkt)
+{
+ if (knot_pkt_qtype(pkt) != KNOT_RRTYPE_TXT) {
+ return KNOT_RCODE_REFUSED;
+ }
+
+ return answer_txt(pkt);
+}
diff --git a/src/knot/nameserver/chaos.h b/src/knot/nameserver/chaos.h
new file mode 100644
index 0000000..14923d1
--- /dev/null
+++ b/src/knot/nameserver/chaos.h
@@ -0,0 +1,34 @@
+/* Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief Chaos class processing.
+ *
+ * \addtogroup query_processing
+ * @{
+ */
+
+#pragma once
+
+#include "libknot/packet/pkt.h"
+
+/*!
+ * \brief Create a response for a given query in the CHAOS class.
+ */
+int knot_chaos_answer(knot_pkt_t *pkt);
+
+/*! @} */
diff --git a/src/knot/nameserver/internet.c b/src/knot/nameserver/internet.c
new file mode 100644
index 0000000..62830e7
--- /dev/null
+++ b/src/knot/nameserver/internet.c
@@ -0,0 +1,664 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "libknot/libknot.h"
+#include "knot/nameserver/internet.h"
+#include "knot/nameserver/nsec_proofs.h"
+#include "knot/nameserver/query_module.h"
+#include "knot/zone/serial.h"
+#include "contrib/mempattern.h"
+
+/*! \brief Check if given node was already visited. */
+static int wildcard_has_visited(knotd_qdata_t *qdata, const zone_node_t *node)
+{
+ struct wildcard_hit *item = NULL;
+ WALK_LIST(item, qdata->extra->wildcards) {
+ if (item->node == node) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/*! \brief Mark given node as visited. */
+static int wildcard_visit(knotd_qdata_t *qdata, const zone_node_t *node,
+ const zone_node_t *prev, const knot_dname_t *sname)
+{
+ assert(qdata);
+ assert(node);
+
+ /* Already in the list. */
+ if (wildcard_has_visited(qdata, node)) {
+ return KNOT_EOK;
+ }
+
+ knot_mm_t *mm = qdata->mm;
+ struct wildcard_hit *item = mm_alloc(mm, sizeof(struct wildcard_hit));
+ item->node = node;
+ item->prev = prev;
+ item->sname = sname;
+ add_tail(&qdata->extra->wildcards, (node_t *)item);
+ return KNOT_EOK;
+}
+
+/*! \brief Synthetizes a CNAME RR from a DNAME. */
+static int dname_cname_synth(const knot_rrset_t *dname_rr,
+ const knot_dname_t *qname,
+ knot_rrset_t *cname_rrset,
+ knot_mm_t *mm)
+{
+ if (cname_rrset == NULL) {
+ return KNOT_EINVAL;
+ }
+ knot_dname_t *owner_copy = knot_dname_copy(qname, mm);
+ if (owner_copy == NULL) {
+ return KNOT_ENOMEM;
+ }
+ knot_rrset_init(cname_rrset, owner_copy, KNOT_RRTYPE_CNAME, dname_rr->rclass,
+ dname_rr->ttl);
+
+ /* Replace last labels of qname with DNAME. */
+ const knot_dname_t *dname_wire = dname_rr->owner;
+ const knot_dname_t *dname_tgt = knot_dname_target(dname_rr->rrs.rdata);
+ size_t labels = knot_dname_labels(dname_wire, NULL);
+ knot_dname_t *cname = knot_dname_replace_suffix(qname, labels, dname_tgt, mm);
+ if (cname == NULL) {
+ knot_dname_free(owner_copy, mm);
+ return KNOT_ENOMEM;
+ }
+
+ /* Store DNAME into RDATA. */
+ size_t cname_size = knot_dname_size(cname);
+ uint8_t cname_rdata[cname_size];
+ memcpy(cname_rdata, cname, cname_size);
+ knot_dname_free(cname, mm);
+
+ int ret = knot_rrset_add_rdata(cname_rrset, cname_rdata, cname_size, mm);
+ if (ret != KNOT_EOK) {
+ knot_dname_free(owner_copy, mm);
+ return ret;
+ }
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Checks if the name created by replacing the owner of \a dname_rrset
+ * in the \a qname by the DNAME's target would be longer than allowed.
+ */
+static bool dname_cname_cannot_synth(const knot_rrset_t *rrset, const knot_dname_t *qname)
+{
+ if (knot_dname_labels(qname, NULL) - knot_dname_labels(rrset->owner, NULL) +
+ knot_dname_labels(knot_dname_target(rrset->rrs.rdata), NULL) > KNOT_DNAME_MAXLABELS) {
+ return true;
+ } else if (knot_dname_size(qname) - knot_dname_size(rrset->owner) +
+ knot_dname_size(knot_dname_target(rrset->rrs.rdata)) > KNOT_DNAME_MAXLEN) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/*! \brief DNSSEC both requested & available. */
+static bool have_dnssec(knotd_qdata_t *qdata)
+{
+ return knot_pkt_has_dnssec(qdata->query) &&
+ qdata->extra->zone->contents->dnssec;
+}
+
+/*! \brief This is a wildcard-covered or any other terminal node for QNAME.
+ * e.g. positive answer.
+ */
+static int put_answer(knot_pkt_t *pkt, uint16_t type, knotd_qdata_t *qdata)
+{
+ knot_rrset_t rrset;
+ knot_rrset_init_empty(&rrset);
+
+ /* Wildcard expansion or exact match, either way RRSet owner is
+ * is QNAME. We can fake name synthesis by setting compression hint to
+ * QNAME position. Just need to check if we're answering QNAME and not
+ * a CNAME target.
+ */
+ uint16_t compr_hint = KNOT_COMPR_HINT_NONE;
+ if (pkt->rrset_count == 0) { /* Guaranteed first answer. */
+ compr_hint = KNOT_COMPR_HINT_QNAME;
+ }
+
+ unsigned put_rr_flags = (qdata->params->flags & KNOTD_QUERY_FLAG_LIMIT_SIZE) ?
+ KNOT_PF_NULL : KNOT_PF_NOTRUNC;
+ put_rr_flags |= KNOT_PF_ORIGTTL;
+
+ int ret = KNOT_EOK;
+ switch (type) {
+ case KNOT_RRTYPE_ANY: /* Append all RRSets. */ {
+ conf_val_t val = conf_zone_get(conf(), C_DISABLE_ANY,
+ qdata->extra->zone->name);
+ /* If ANY not allowed, set TC bit. */
+ if ((qdata->params->flags & KNOTD_QUERY_FLAG_LIMIT_ANY) &&
+ conf_bool(&val)) {
+ knot_wire_set_tc(pkt->wire);
+ return KNOT_ESPACE;
+ }
+ for (unsigned i = 0; i < qdata->extra->node->rrset_count; ++i) {
+ rrset = node_rrset_at(qdata->extra->node, i);
+ ret = process_query_put_rr(pkt, qdata, &rrset, NULL,
+ compr_hint, put_rr_flags);
+ if (ret != KNOT_EOK) {
+ break;
+ }
+ }
+ break;
+ }
+ default: /* Single RRSet of given type. */
+ rrset = node_rrset(qdata->extra->node, type);
+ if (!knot_rrset_empty(&rrset)) {
+ knot_rrset_t rrsigs = node_rrset(qdata->extra->node, KNOT_RRTYPE_RRSIG);
+ ret = process_query_put_rr(pkt, qdata, &rrset, &rrsigs,
+ compr_hint, put_rr_flags);
+ }
+ break;
+ }
+
+ return ret;
+}
+
+/*! \brief Puts optional SOA RRSet to the Authority section of the response. */
+static int put_authority_soa(knot_pkt_t *pkt, knotd_qdata_t *qdata,
+ const zone_contents_t *zone)
+{
+ knot_rrset_t soa = node_rrset(zone->apex, KNOT_RRTYPE_SOA);
+ knot_rrset_t rrsigs = node_rrset(zone->apex, KNOT_RRTYPE_RRSIG);
+ return process_query_put_rr(pkt, qdata, &soa, &rrsigs,
+ KNOT_COMPR_HINT_NONE, KNOT_PF_NOTRUNC);
+}
+
+/*! \brief Put the delegation NS RRSet to the Authority section. */
+static int put_delegation(knot_pkt_t *pkt, knotd_qdata_t *qdata)
+{
+ /* Find closest delegation point. */
+ while (!(qdata->extra->node->flags & NODE_FLAGS_DELEG)) {
+ qdata->extra->node = qdata->extra->node->parent;
+ }
+
+ /* Insert NS record. */
+ knot_rrset_t rrset = node_rrset(qdata->extra->node, KNOT_RRTYPE_NS);
+ knot_rrset_t rrsigs = node_rrset(qdata->extra->node, KNOT_RRTYPE_RRSIG);
+ return process_query_put_rr(pkt, qdata, &rrset, &rrsigs,
+ KNOT_COMPR_HINT_NONE, 0);
+}
+
+/*! \brief Put additional records for given RR. */
+static int put_additional(knot_pkt_t *pkt, const knot_rrset_t *rr,
+ knotd_qdata_t *qdata, knot_rrinfo_t *info, int state)
+{
+ if (rr->additional == NULL) {
+ return KNOT_EOK;
+ }
+
+ /* Valid types for ADDITIONALS insertion. */
+ /* \note Not resolving CNAMEs as MX/NS name must not be an alias. (RFC2181/10.3) */
+ static const uint16_t ar_type_list[] = { KNOT_RRTYPE_A, KNOT_RRTYPE_AAAA };
+ static const int ar_type_count = 2;
+
+ int ret = KNOT_EOK;
+
+ additional_t *additional = (additional_t *)rr->additional;
+
+ /* Iterate over the additionals. */
+ for (uint16_t i = 0; i < additional->count; i++) {
+ glue_t *glue = &additional->glues[i];
+ uint32_t flags = KNOT_PF_NULL;
+
+ /* Optional glue doesn't cause truncation. (RFC 1034/4.3.2 step 3b). */
+ if (state != KNOTD_IN_STATE_DELEG || glue->optional) {
+ flags |= KNOT_PF_NOTRUNC;
+ }
+
+ uint16_t hint = knot_compr_hint(info, KNOT_COMPR_HINT_RDATA +
+ glue->ns_pos);
+ knot_rrset_t rrsigs = node_rrset(glue->node, KNOT_RRTYPE_RRSIG);
+ for (int k = 0; k < ar_type_count; ++k) {
+ knot_rrset_t rrset = node_rrset(glue->node, ar_type_list[k]);
+ if (knot_rrset_empty(&rrset)) {
+ continue;
+ }
+ ret = process_query_put_rr(pkt, qdata, &rrset, &rrsigs,
+ hint, flags);
+ if (ret != KNOT_EOK) {
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int follow_cname(knot_pkt_t *pkt, uint16_t rrtype, knotd_qdata_t *qdata)
+{
+ const zone_node_t *cname_node = qdata->extra->node;
+ knot_rrset_t cname_rr = node_rrset(qdata->extra->node, rrtype);
+ knot_rrset_t rrsigs = node_rrset(qdata->extra->node, KNOT_RRTYPE_RRSIG);
+
+ assert(!knot_rrset_empty(&cname_rr));
+
+ /* Check whether RR is already in the packet. */
+ uint16_t flags = KNOT_PF_CHECKDUP;
+
+ /* Now, try to put CNAME to answer. */
+ uint16_t rr_count_before = pkt->rrset_count;
+ int ret = process_query_put_rr(pkt, qdata, &cname_rr, &rrsigs, 0, flags);
+ switch (ret) {
+ case KNOT_EOK: break;
+ case KNOT_ESPACE: return KNOTD_IN_STATE_TRUNC;
+ default: return KNOTD_IN_STATE_ERROR;
+ }
+
+ /* Check if RR count increased. */
+ if (pkt->rrset_count <= rr_count_before) {
+ qdata->extra->node = NULL; /* Act is if the name leads to nowhere. */
+ return KNOTD_IN_STATE_HIT;
+ }
+
+ /* Synthesize CNAME if followed DNAME. */
+ if (rrtype == KNOT_RRTYPE_DNAME) {
+ if (dname_cname_cannot_synth(&cname_rr, qdata->name)) {
+ qdata->rcode = KNOT_RCODE_YXDOMAIN;
+ } else {
+ knot_rrset_t dname_rr = cname_rr;
+ int ret = dname_cname_synth(&dname_rr, qdata->name,
+ &cname_rr, &pkt->mm);
+ if (ret != KNOT_EOK) {
+ qdata->rcode = KNOT_RCODE_SERVFAIL;
+ return KNOTD_IN_STATE_ERROR;
+ }
+ ret = process_query_put_rr(pkt, qdata, &cname_rr, NULL, 0, KNOT_PF_FREE);
+ switch (ret) {
+ case KNOT_EOK: break;
+ case KNOT_ESPACE: return KNOTD_IN_STATE_TRUNC;
+ default: return KNOTD_IN_STATE_ERROR;
+ }
+ }
+ }
+
+ /* If node is a wildcard, follow only if we didn't visit the same node
+ * earlier, as that would mean a CNAME loop. */
+ if (knot_dname_is_wildcard(cname_node->owner)) {
+
+ /* Check if is not in wildcard nodes (loop). */
+ if (wildcard_has_visited(qdata, cname_node)) {
+ qdata->extra->node = NULL; /* Act is if the name leads to nowhere. */
+ return KNOTD_IN_STATE_HIT;
+ }
+
+ /* Put to wildcard node list. */
+ if (wildcard_visit(qdata, cname_node, qdata->extra->previous, qdata->name) != KNOT_EOK) {
+ return KNOTD_IN_STATE_ERROR;
+ }
+ }
+
+ /* Now follow the next CNAME TARGET. */
+ qdata->name = knot_cname_name(cname_rr.rrs.rdata);
+
+ return KNOTD_IN_STATE_FOLLOW;
+}
+
+static int name_found(knot_pkt_t *pkt, knotd_qdata_t *qdata)
+{
+ uint16_t qtype = knot_pkt_qtype(pkt);
+
+ if (node_rrtype_exists(qdata->extra->node, KNOT_RRTYPE_CNAME)
+ && qtype != KNOT_RRTYPE_CNAME
+ && qtype != KNOT_RRTYPE_RRSIG
+ && qtype != KNOT_RRTYPE_NSEC
+ && qtype != KNOT_RRTYPE_ANY) {
+ return follow_cname(pkt, KNOT_RRTYPE_CNAME, qdata);
+ }
+
+ /* DS query at DP is answered normally, but everything else at/below DP
+ * triggers referral response. */
+ if (((qdata->extra->node->flags & NODE_FLAGS_DELEG) && qtype != KNOT_RRTYPE_DS) ||
+ (qdata->extra->node->flags & NODE_FLAGS_NONAUTH)) {
+ return KNOTD_IN_STATE_DELEG;
+ }
+
+ uint16_t old_rrcount = pkt->rrset_count;
+ int ret = put_answer(pkt, qtype, qdata);
+ if (ret != KNOT_EOK) {
+ if (ret == KNOT_ESPACE && (qdata->params->flags & KNOTD_QUERY_FLAG_LIMIT_SIZE)) {
+ return KNOTD_IN_STATE_TRUNC;
+ } else {
+ return KNOTD_IN_STATE_ERROR;
+ }
+ }
+
+ /* Check for NODATA (=0 RRs added). */
+ if (old_rrcount == pkt->rrset_count) {
+ return KNOTD_IN_STATE_NODATA;
+ } else {
+ return KNOTD_IN_STATE_HIT;
+ }
+}
+
+static int name_not_found(knot_pkt_t *pkt, knotd_qdata_t *qdata)
+{
+ /* Name is covered by wildcard. */
+ if (qdata->extra->encloser->flags & NODE_FLAGS_WILDCARD_CHILD) {
+ /* Find wildcard child in the zone. */
+ const zone_node_t *wildcard_node =
+ zone_contents_find_wildcard_child(
+ qdata->extra->zone->contents, qdata->extra->encloser);
+
+ qdata->extra->node = wildcard_node;
+ assert(qdata->extra->node != NULL);
+
+ /* Follow expanded wildcard. */
+ int next_state = name_found(pkt, qdata);
+
+ /* Put to wildcard node list. */
+ if (wildcard_visit(qdata, wildcard_node, qdata->extra->previous, qdata->name) != KNOT_EOK) {
+ next_state = KNOTD_IN_STATE_ERROR;
+ }
+
+ return next_state;
+ }
+
+ /* Name is under DNAME, use it for substitution. */
+ knot_rrset_t dname_rrset = node_rrset(qdata->extra->encloser, KNOT_RRTYPE_DNAME);
+ if (!knot_rrset_empty(&dname_rrset)) {
+ qdata->extra->node = qdata->extra->encloser; /* Follow encloser as new node. */
+ return follow_cname(pkt, KNOT_RRTYPE_DNAME, qdata);
+ }
+
+ /* Look up an authoritative encloser or its parent. */
+ const zone_node_t *node = qdata->extra->encloser;
+ while (node->rrset_count == 0 || node->flags & NODE_FLAGS_NONAUTH) {
+ node = node->parent;
+ assert(node);
+ }
+
+ /* Name is below delegation. */
+ if ((node->flags & NODE_FLAGS_DELEG)) {
+ qdata->extra->node = node;
+ return KNOTD_IN_STATE_DELEG;
+ }
+
+ return KNOTD_IN_STATE_MISS;
+}
+
+static int solve_name(int state, knot_pkt_t *pkt, knotd_qdata_t *qdata)
+{
+ int ret = zone_contents_find_dname(qdata->extra->zone->contents, qdata->name,
+ &qdata->extra->node, &qdata->extra->encloser,
+ &qdata->extra->previous);
+
+ switch (ret) {
+ case ZONE_NAME_FOUND:
+ return name_found(pkt, qdata);
+ case ZONE_NAME_NOT_FOUND:
+ return name_not_found(pkt, qdata);
+ case KNOT_EOUTOFZONE:
+ assert(state == KNOTD_IN_STATE_FOLLOW); /* CNAME/DNAME chain only. */
+ return KNOTD_IN_STATE_HIT;
+ default:
+ return KNOTD_IN_STATE_ERROR;
+ }
+}
+
+static int solve_answer(int state, knot_pkt_t *pkt, knotd_qdata_t *qdata, void *ctx)
+{
+ /* Do not solve if already solved, e.g. in a module. */
+ if (state == KNOTD_IN_STATE_HIT) {
+ return state;
+ }
+
+ /* Get answer to QNAME. */
+ state = solve_name(state, pkt, qdata);
+
+ /* Is authoritative answer unless referral.
+ * Must check before we chase the CNAME chain. */
+ if (state != KNOTD_IN_STATE_DELEG) {
+ knot_wire_set_aa(pkt->wire);
+ }
+
+ /* Additional resolving for CNAME/DNAME chain. */
+ while (state == KNOTD_IN_STATE_FOLLOW) {
+ state = solve_name(state, pkt, qdata);
+ }
+
+ return state;
+}
+
+static int solve_answer_dnssec(int state, knot_pkt_t *pkt, knotd_qdata_t *qdata, void *ctx)
+{
+ /* RFC4035, section 3.1 RRSIGs for RRs in ANSWER are mandatory. */
+ int ret = nsec_append_rrsigs(pkt, qdata, false);
+ switch (ret) {
+ case KNOT_ESPACE: return KNOTD_IN_STATE_TRUNC;
+ case KNOT_EOK: return state;
+ default: return KNOTD_IN_STATE_ERROR;
+ }
+}
+
+static int solve_authority(int state, knot_pkt_t *pkt, knotd_qdata_t *qdata, void *ctx)
+{
+ int ret = KNOT_ERROR;
+ const zone_contents_t *zone_contents = qdata->extra->zone->contents;
+
+ switch (state) {
+ case KNOTD_IN_STATE_HIT: /* Positive response. */
+ ret = KNOT_EOK;
+ break;
+ case KNOTD_IN_STATE_MISS: /* MISS, set NXDOMAIN RCODE. */
+ qdata->rcode = KNOT_RCODE_NXDOMAIN;
+ ret = put_authority_soa(pkt, qdata, zone_contents);
+ break;
+ case KNOTD_IN_STATE_NODATA: /* NODATA append AUTHORITY SOA. */
+ ret = put_authority_soa(pkt, qdata, zone_contents);
+ break;
+ case KNOTD_IN_STATE_DELEG: /* Referral response. */
+ ret = put_delegation(pkt, qdata);
+ break;
+ case KNOTD_IN_STATE_TRUNC: /* Truncated ANSWER. */
+ ret = KNOT_ESPACE;
+ break;
+ case KNOTD_IN_STATE_ERROR: /* Error resolving ANSWER. */
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ /* Evaluate final state. */
+ switch (ret) {
+ case KNOT_EOK: return state; /* Keep current state. */
+ case KNOT_ESPACE: return KNOTD_IN_STATE_TRUNC; /* Truncated. */
+ default: return KNOTD_IN_STATE_ERROR; /* Error. */
+ }
+}
+
+static int solve_authority_dnssec(int state, knot_pkt_t *pkt, knotd_qdata_t *qdata, void *ctx)
+{
+ int ret = KNOT_ERROR;
+
+ /* Authenticated denial of existence. */
+ switch (state) {
+ case KNOTD_IN_STATE_HIT: ret = KNOT_EOK; break;
+ case KNOTD_IN_STATE_MISS: ret = nsec_prove_nxdomain(pkt, qdata); break;
+ case KNOTD_IN_STATE_NODATA: ret = nsec_prove_nodata(pkt, qdata); break;
+ case KNOTD_IN_STATE_DELEG: ret = nsec_prove_dp_security(pkt, qdata); break;
+ case KNOTD_IN_STATE_TRUNC: ret = KNOT_ESPACE; break;
+ case KNOTD_IN_STATE_ERROR: ret = KNOT_ERROR; break;
+ default:
+ assert(0);
+ break;
+ }
+
+ /* RFC4035 3.1.3 Prove visited wildcards.
+ * Wildcard expansion applies for Name Error, Wildcard Answer and
+ * No Data proofs if at one point the search expanded a wildcard node.
+ * \note Do not attempt to prove non-authoritative data. */
+ if (ret == KNOT_EOK && state != KNOTD_IN_STATE_DELEG) {
+ ret = nsec_prove_wildcards(pkt, qdata);
+ }
+
+ /* RFC4035, section 3.1 RRSIGs for RRs in AUTHORITY are mandatory. */
+ if (ret == KNOT_EOK) {
+ ret = nsec_append_rrsigs(pkt, qdata, false);
+ }
+
+ /* Evaluate final state. */
+ switch (ret) {
+ case KNOT_EOK: return state; /* Keep current state. */
+ case KNOT_ESPACE: return KNOTD_IN_STATE_TRUNC; /* Truncated. */
+ default: return KNOTD_IN_STATE_ERROR; /* Error. */
+ }
+}
+
+static int solve_additional(int state, knot_pkt_t *pkt, knotd_qdata_t *qdata,
+ void *ctx)
+{
+ int ret = KNOT_EOK;
+
+ /* Scan all RRs in ANSWER/AUTHORITY. */
+ for (uint16_t i = 0; i < pkt->rrset_count; ++i) {
+ knot_rrset_t *rr = &pkt->rr[i];
+ knot_rrinfo_t *info = &pkt->rr_info[i];
+
+ /* Skip types for which it doesn't apply. */
+ if (!knot_rrtype_additional_needed(rr->type)) {
+ continue;
+ }
+
+ /* Put additional records for given type. */
+ ret = put_additional(pkt, rr, qdata, info, state);
+ if (ret != KNOT_EOK) {
+ break;
+ }
+ }
+
+ /* Evaluate final state. */
+ switch (ret) {
+ case KNOT_EOK: return state; /* Keep current state. */
+ case KNOT_ESPACE: return KNOTD_IN_STATE_TRUNC; /* Truncated. */
+ default: return KNOTD_IN_STATE_ERROR; /* Error. */
+ }
+}
+
+static int solve_additional_dnssec(int state, knot_pkt_t *pkt, knotd_qdata_t *qdata, void *ctx)
+{
+ /* RFC4035, section 3.1 RRSIGs for RRs in ADDITIONAL are optional. */
+ int ret = nsec_append_rrsigs(pkt, qdata, true);
+ switch (ret) {
+ case KNOT_ESPACE: return KNOTD_IN_STATE_TRUNC;
+ case KNOT_EOK: return state;
+ default: return KNOTD_IN_STATE_ERROR;
+ }
+}
+
+/*! \brief Helper for internet_query repetitive code. */
+#define SOLVE_STEP(solver, state, context) \
+ state = (solver)(state, pkt, qdata, context); \
+ if (state == KNOTD_IN_STATE_TRUNC) { \
+ return KNOT_STATE_DONE; \
+ } else if (state == KNOTD_IN_STATE_ERROR) { \
+ return KNOT_STATE_FAIL; \
+ }
+
+static int answer_query(knot_pkt_t *pkt, knotd_qdata_t *qdata)
+{
+ int state = KNOTD_IN_STATE_BEGIN;
+ struct query_plan *plan = qdata->extra->zone->query_plan;
+ struct query_step *step = NULL;
+
+ bool with_dnssec = have_dnssec(qdata);
+
+ /* Resolve PREANSWER. */
+ if (plan != NULL) {
+ WALK_LIST(step, plan->stage[KNOTD_STAGE_PREANSWER]) {
+ SOLVE_STEP(step->process, state, step->ctx);
+ }
+ }
+
+ /* Resolve ANSWER. */
+ knot_pkt_begin(pkt, KNOT_ANSWER);
+ SOLVE_STEP(solve_answer, state, NULL);
+ if (with_dnssec) {
+ SOLVE_STEP(solve_answer_dnssec, state, NULL);
+ }
+ if (plan != NULL) {
+ WALK_LIST(step, plan->stage[KNOTD_STAGE_ANSWER]) {
+ SOLVE_STEP(step->process, state, step->ctx);
+ }
+ }
+
+ /* Resolve AUTHORITY. */
+ knot_pkt_begin(pkt, KNOT_AUTHORITY);
+ SOLVE_STEP(solve_authority, state, NULL);
+ if (with_dnssec) {
+ SOLVE_STEP(solve_authority_dnssec, state, NULL);
+ }
+ if (plan != NULL) {
+ WALK_LIST(step, plan->stage[KNOTD_STAGE_AUTHORITY]) {
+ SOLVE_STEP(step->process, state, step->ctx);
+ }
+ }
+
+ /* Resolve ADDITIONAL. */
+ knot_pkt_begin(pkt, KNOT_ADDITIONAL);
+ SOLVE_STEP(solve_additional, state, NULL);
+ if (with_dnssec) {
+ SOLVE_STEP(solve_additional_dnssec, state, NULL);
+ }
+ if (plan != NULL) {
+ WALK_LIST(step, plan->stage[KNOTD_STAGE_ADDITIONAL]) {
+ SOLVE_STEP(step->process, state, step->ctx);
+ }
+ }
+
+ /* Write resulting RCODE. */
+ knot_wire_set_rcode(pkt->wire, qdata->rcode);
+
+ return KNOT_STATE_DONE;
+}
+
+int internet_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata)
+{
+ if (pkt == NULL || qdata == NULL) {
+ return KNOT_STATE_FAIL;
+ }
+
+ /* Check valid zone, transaction security (optional) and contents. */
+ NS_NEED_ZONE(qdata, KNOT_RCODE_REFUSED);
+
+ /* No applicable ACL, refuse transaction security. */
+ if (knot_pkt_has_tsig(qdata->query)) {
+ /* We have been challenged... */
+ NS_NEED_AUTH(qdata, qdata->extra->zone->name, ACL_ACTION_NONE);
+
+ /* Reserve space for TSIG. */
+ int ret = knot_pkt_reserve(pkt, knot_tsig_wire_size(&qdata->sign.tsig_key));
+ if (ret != KNOT_EOK) {
+ return KNOT_STATE_FAIL;
+ }
+ }
+
+ NS_NEED_ZONE_CONTENTS(qdata, KNOT_RCODE_SERVFAIL); /* Expired */
+
+ /* Get answer to QNAME. */
+ qdata->name = knot_pkt_qname(qdata->query);
+
+ return answer_query(pkt, qdata);
+}
diff --git a/src/knot/nameserver/internet.h b/src/knot/nameserver/internet.h
new file mode 100644
index 0000000..d70ca0e
--- /dev/null
+++ b/src/knot/nameserver/internet.h
@@ -0,0 +1,76 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "libknot/packet/pkt.h"
+#include "knot/include/module.h"
+
+/*!
+ * \brief Answer query from an IN class zone.
+ *
+ * \retval KNOT_STATE_FAIL if it encountered an error.
+ * \retval KNOT_STATE_DONE if finished.
+ */
+int internet_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata);
+
+/*! \brief Require given QUERY TYPE or return error code. */
+#define NS_NEED_QTYPE(qdata, qtype_want, error_rcode) \
+ if (knot_pkt_qtype((qdata)->query) != (qtype_want)) { \
+ qdata->rcode = (error_rcode); \
+ return KNOT_STATE_FAIL; \
+ }
+
+/*! \brief Require given QUERY NAME or return error code. */
+#define NS_NEED_QNAME(qdata, qname_want, error_rcode) \
+ if (!knot_dname_is_equal(knot_pkt_qname((qdata)->query), (qname_want))) { \
+ qdata->rcode = (error_rcode); \
+ return KNOT_STATE_FAIL; \
+ }
+
+/*! \brief Require existing zone or return failure. */
+#define NS_NEED_ZONE(qdata, error_rcode) \
+ if ((qdata)->extra->zone == NULL) { \
+ qdata->rcode = (error_rcode); \
+ return KNOT_STATE_FAIL; \
+ }
+
+/*! \brief Require existing zone contents or return failure. */
+#define NS_NEED_ZONE_CONTENTS(qdata, error_rcode) \
+ if ((qdata)->extra->zone->contents == NULL) { \
+ qdata->rcode = (error_rcode); \
+ return KNOT_STATE_FAIL; \
+ }
+
+/*! \brief Require authentication. */
+#define NS_NEED_AUTH(qdata, zone_name, action) \
+ if (!process_query_acl_check(conf(), (zone_name), (action), (qdata)) || \
+ process_query_verify(qdata) != KNOT_EOK) { \
+ return KNOT_STATE_FAIL; \
+ }
+
+/*! \brief Require maximum number of unsigned messages. */
+#define NS_NEED_TSIG_SIGNED(tsig_ctx, max_unsigned) \
+ if (tsig_unsigned_count(tsig_ctx) > max_unsigned) { \
+ return KNOT_STATE_FAIL; \
+ }
+
+/*! \brief Require the zone not to be frozen. */
+#define NS_NEED_NOT_FROZEN(qdata, error_rcode) \
+ if ((qdata)->extra->zone->events.ufrozen) { \
+ (qdata)->rcode = (error_rcode); \
+ return KNOT_STATE_FAIL; \
+ }
diff --git a/src/knot/nameserver/ixfr.c b/src/knot/nameserver/ixfr.c
new file mode 100644
index 0000000..fa1447e
--- /dev/null
+++ b/src/knot/nameserver/ixfr.c
@@ -0,0 +1,298 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <urcu.h>
+
+#include "contrib/mempattern.h"
+#include "contrib/sockaddr.h"
+#include "knot/journal/chgset_ctx.h"
+#include "knot/nameserver/axfr.h"
+#include "knot/nameserver/internet.h"
+#include "knot/nameserver/ixfr.h"
+#include "knot/nameserver/log.h"
+#include "knot/nameserver/xfr.h"
+#include "knot/zone/serial.h"
+#include "libknot/libknot.h"
+
+#define ZONE_NAME(qdata) knot_pkt_qname((qdata)->query)
+#define REMOTE(qdata) (struct sockaddr *)(qdata)->params->remote
+
+#define IXFROUT_LOG(priority, qdata, fmt...) \
+ ns_log(priority, ZONE_NAME(qdata), LOG_OPERATION_IXFR, \
+ LOG_DIRECTION_OUT, REMOTE(qdata), fmt)
+
+/*! \brief Helper macro for putting RRs into packet. */
+#define IXFR_SAFE_PUT(pkt, rr) \
+ int ret = knot_pkt_put((pkt), 0, (rr), KNOT_PF_NOTRUNC | KNOT_PF_ORIGTTL); \
+ if (ret != KNOT_EOK) { \
+ return ret; \
+ }
+
+/*! \brief Puts current RR into packet, stores state for retries. */
+static int ixfr_put_chg_part(knot_pkt_t *pkt, struct ixfr_proc *ixfr,
+ chgset_ctx_t *itt)
+{
+ assert(pkt);
+ assert(ixfr);
+ assert(itt);
+
+ if (!knot_rrset_empty(&ixfr->cur_rr)) {
+ IXFR_SAFE_PUT(pkt, &ixfr->cur_rr);
+ knot_rrset_clear(&ixfr->cur_rr, NULL);
+ }
+
+ while (itt->phase != CHGSET_CTX_DONE) {
+ int r = chgset_ctx_next(itt, &ixfr->cur_rr);
+ if (r != KNOT_EOK) {
+ knot_rrset_clear(&ixfr->cur_rr, NULL);
+ return r;
+ }
+ IXFR_SAFE_PUT(pkt, &ixfr->cur_rr);
+ knot_rrset_clear(&ixfr->cur_rr, NULL);
+ }
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Process single changeset.
+ * \note Keep in mind that this function must be able to resume processing,
+ * for example if it fills a packet and returns ESPACE, it is called again
+ * with next empty answer and it must resume the processing exactly where
+ * it's left off.
+ */
+static int ixfr_process_changeset(knot_pkt_t *pkt, const void *item,
+ struct xfr_proc *xfer)
+{
+ int ret = KNOT_EOK;
+ struct ixfr_proc *ixfr = (struct ixfr_proc *)xfer;
+ chgset_ctx_t *chgset = (chgset_ctx_t *)item;
+
+ ret = ixfr_put_chg_part(pkt, ixfr, chgset);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ /* Finished change set. */
+ IXFROUT_LOG(LOG_DEBUG, ixfr->qdata, "serial %u -> %u", chgset->serial_from, chgset->serial_to);
+
+ return ret;
+}
+
+#undef IXFR_SAFE_PUT
+
+static int ixfr_load_chsets(chgset_ctx_list_t *chgsets, zone_t *zone,
+ const knot_rrset_t *their_soa)
+{
+ assert(chgsets);
+ assert(zone);
+
+ /* Compare serials. */
+ uint32_t serial_to = zone_contents_serial(zone->contents);
+ uint32_t serial_from = knot_soa_serial(their_soa->rrs.rdata);
+ if (serial_compare(serial_to, serial_from) & SERIAL_MASK_LEQ) { /* We have older/same age zone. */
+ return KNOT_EUPTODATE;
+ }
+
+ return zone_chgset_ctx_load(conf(), zone, chgsets, serial_from);
+}
+
+static int ixfr_query_check(knotd_qdata_t *qdata)
+{
+ NS_NEED_ZONE(qdata, KNOT_RCODE_NOTAUTH);
+ NS_NEED_AUTH(qdata, qdata->extra->zone->name, ACL_ACTION_TRANSFER);
+ NS_NEED_ZONE_CONTENTS(qdata, KNOT_RCODE_SERVFAIL);
+
+ /* Need SOA authority record. */
+ const knot_pktsection_t *authority = knot_pkt_section(qdata->query, KNOT_AUTHORITY);
+ const knot_rrset_t *their_soa = knot_pkt_rr(authority, 0);
+ if (authority->count < 1 || their_soa->type != KNOT_RRTYPE_SOA) {
+ qdata->rcode = KNOT_RCODE_FORMERR;
+ return KNOT_STATE_FAIL;
+ }
+ /* SOA needs to match QNAME. */
+ NS_NEED_QNAME(qdata, their_soa->owner, KNOT_RCODE_FORMERR);
+
+ return KNOT_STATE_DONE;
+}
+
+static void ixfr_answer_cleanup(knotd_qdata_t *qdata)
+{
+ struct ixfr_proc *ixfr = (struct ixfr_proc *)qdata->extra->ext;
+ knot_mm_t *mm = qdata->mm;
+
+ ptrlist_free(&ixfr->proc.nodes, mm);
+ chgset_ctx_list_close(&ixfr->changesets);
+ mm_free(mm, qdata->extra->ext);
+
+ /* Allow zone changes (finished). */
+ rcu_read_unlock();
+}
+
+static int ixfr_answer_init(knotd_qdata_t *qdata)
+{
+ assert(qdata);
+
+ /* Check IXFR query validity. */
+ if (ixfr_query_check(qdata) == KNOT_STATE_FAIL) {
+ if (qdata->rcode == KNOT_RCODE_FORMERR) {
+ return KNOT_EMALF;
+ } else {
+ return KNOT_EDENIED;
+ }
+ }
+
+ /* Compare serials. */
+ const knot_pktsection_t *authority = knot_pkt_section(qdata->query, KNOT_AUTHORITY);
+ const knot_rrset_t *their_soa = knot_pkt_rr(authority, 0);
+
+ /* Initialize transfer processing. */
+ knot_mm_t *mm = qdata->mm;
+ struct ixfr_proc *xfer = mm_alloc(mm, sizeof(struct ixfr_proc));
+ if (xfer == NULL) {
+ return KNOT_ENOMEM;
+ }
+ memset(xfer, 0, sizeof(struct ixfr_proc));
+
+ int ret = ixfr_load_chsets(&xfer->changesets, (zone_t *)qdata->extra->zone, their_soa);
+ if (ret != KNOT_EOK) {
+ mm_free(mm, xfer);
+ return ret;
+ }
+
+ xfr_stats_begin(&xfer->proc.stats);
+ xfer->state = IXFR_SOA_DEL;
+ init_list(&xfer->proc.nodes);
+ knot_rrset_init_empty(&xfer->cur_rr);
+ xfer->qdata = qdata;
+
+ /* Put all changesets to processing queue. */
+ chgset_ctx_t *chs = NULL;
+ WALK_LIST(chs, xfer->changesets.l) {
+ ptrlist_add(&xfer->proc.nodes, chs, mm);
+ chgset_ctx_iterate(chs); // init already, so we don't have to decide later, no harm
+ }
+
+ /* Keep first and last serial. */
+ chs = HEAD(xfer->changesets.l);
+ xfer->soa_from = chs->serial_from;
+ chs = TAIL(xfer->changesets.l);
+ xfer->soa_to = chs->serial_to;
+
+ /* Set up cleanup callback. */
+ qdata->extra->ext = xfer;
+ qdata->extra->ext_cleanup = &ixfr_answer_cleanup;
+
+ /* No zone changes during multipacket answer (unlocked in ixfr_answer_cleanup) */
+ rcu_read_lock();
+
+ return KNOT_EOK;
+}
+
+static int ixfr_answer_soa(knot_pkt_t *pkt, knotd_qdata_t *qdata)
+{
+ assert(pkt);
+ assert(qdata);
+
+ /* Check query. */
+ int state = ixfr_query_check(qdata);
+ if (state == KNOT_STATE_FAIL) {
+ return state; /* Malformed query. */
+ }
+
+ /* Reserve space for TSIG. */
+ int ret = knot_pkt_reserve(pkt, knot_tsig_wire_size(&qdata->sign.tsig_key));
+ if (ret != KNOT_EOK) {
+ return KNOT_STATE_FAIL;
+ }
+
+ /* Guaranteed to have zone contents. */
+ const zone_node_t *apex = qdata->extra->zone->contents->apex;
+ knot_rrset_t soa_rr = node_rrset(apex, KNOT_RRTYPE_SOA);
+ if (knot_rrset_empty(&soa_rr)) {
+ return KNOT_STATE_FAIL;
+ }
+ ret = knot_pkt_put(pkt, 0, &soa_rr, 0);
+ if (ret != KNOT_EOK) {
+ qdata->rcode = KNOT_RCODE_SERVFAIL;
+ return KNOT_STATE_FAIL;
+ }
+
+ return KNOT_STATE_DONE;
+}
+
+int ixfr_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata)
+{
+ if (pkt == NULL || qdata == NULL) {
+ return KNOT_STATE_FAIL;
+ }
+
+ /* If IXFR is disabled, respond with SOA. */
+ if (qdata->params->flags & KNOTD_QUERY_FLAG_NO_IXFR) {
+ return ixfr_answer_soa(pkt, qdata);
+ }
+
+ /* Initialize on first call. */
+ struct ixfr_proc *ixfr = qdata->extra->ext;
+ if (ixfr == NULL) {
+ int ret = ixfr_answer_init(qdata);
+ ixfr = qdata->extra->ext;
+ switch (ret) {
+ case KNOT_EOK: /* OK */
+ IXFROUT_LOG(LOG_INFO, qdata, "started, serial %u -> %u",
+ ixfr->soa_from, ixfr->soa_to);
+ break;
+ case KNOT_EUPTODATE: /* Our zone is same age/older, send SOA. */
+ IXFROUT_LOG(LOG_INFO, qdata, "zone is up-to-date");
+ return ixfr_answer_soa(pkt, qdata);
+ case KNOT_ERANGE: /* No history -> AXFR. */
+ case KNOT_ENOENT:
+ IXFROUT_LOG(LOG_INFO, qdata, "incomplete history, fallback to AXFR");
+ qdata->type = KNOTD_QUERY_TYPE_AXFR; /* Solve as AXFR. */
+ return axfr_process_query(pkt, qdata);
+ case KNOT_EDENIED: /* Not authorized, already logged. */
+ return KNOT_STATE_FAIL;
+ case KNOT_EMALF: /* Malformed query. */
+ IXFROUT_LOG(LOG_DEBUG, qdata, "malformed query");
+ return KNOT_STATE_FAIL;
+ default: /* Server errors. */
+ IXFROUT_LOG(LOG_ERR, qdata, "failed to start (%s)",
+ knot_strerror(ret));
+ return KNOT_STATE_FAIL;
+ }
+ }
+
+ /* Reserve space for TSIG. */
+ int ret = knot_pkt_reserve(pkt, knot_tsig_wire_size(&qdata->sign.tsig_key));
+ if (ret != KNOT_EOK) {
+ return KNOT_STATE_FAIL;
+ }
+
+ /* Answer current packet (or continue). */
+ ret = xfr_process_list(pkt, &ixfr_process_changeset, qdata);
+ switch (ret) {
+ case KNOT_ESPACE: /* Couldn't write more, send packet and continue. */
+ return KNOT_STATE_PRODUCE; /* Check for more. */
+ case KNOT_EOK: /* Last response. */
+ xfr_stats_end(&ixfr->proc.stats);
+ xfr_log_finished(ZONE_NAME(qdata), LOG_OPERATION_IXFR, LOG_DIRECTION_OUT,
+ REMOTE(qdata), &ixfr->proc.stats);
+ return KNOT_STATE_DONE;
+ default: /* Generic error. */
+ IXFROUT_LOG(LOG_ERR, qdata, "failed (%s)", knot_strerror(ret));
+ return KNOT_STATE_FAIL;
+ }
+}
diff --git a/src/knot/nameserver/ixfr.h b/src/knot/nameserver/ixfr.h
new file mode 100644
index 0000000..6c8ba2e
--- /dev/null
+++ b/src/knot/nameserver/ixfr.h
@@ -0,0 +1,60 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "knot/nameserver/process_query.h"
+#include "knot/nameserver/xfr.h"
+#include "libknot/packet/pkt.h"
+
+/*! \brief IXFR-in processing states. */
+enum ixfr_state {
+ IXFR_INVALID = 0,
+ IXFR_START, /* IXFR-in starting, expecting final SOA. */
+ IXFR_SOA_DEL, /* Expecting starting SOA. */
+ IXFR_SOA_ADD, /* Expecting ending SOA. */
+ IXFR_DEL, /* Expecting RR to delete. */
+ IXFR_ADD, /* Expecting RR to add. */
+ IXFR_DONE /* Processing done, IXFR-in complete. */
+};
+
+/*! \brief Extended structure for IXFR-in/IXFR-out processing. */
+struct ixfr_proc {
+ /* Processing state. */
+ struct xfr_proc proc;
+ enum ixfr_state state;
+
+ /* Changes to be sent. */
+ chgset_ctx_list_t changesets;
+
+ /* Currenty processed changeset. */
+ knot_rrset_t cur_rr;
+ uint32_t soa_from;
+ uint32_t soa_to;
+
+ /* Processing context. */
+ knotd_qdata_t *qdata;
+ knot_mm_t *mm;
+};
+
+/*!
+ * \brief IXFR query processing module.
+ *
+ * \retval PRODUCE if it has an answer, but not yet finished.
+ * \retval FAIL if it encountered an error.
+ * \retval DONE if finished.
+ */
+int ixfr_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata);
diff --git a/src/knot/nameserver/log.h b/src/knot/nameserver/log.h
new file mode 100644
index 0000000..c46a908
--- /dev/null
+++ b/src/knot/nameserver/log.h
@@ -0,0 +1,90 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "contrib/sockaddr.h"
+#include "knot/common/log.h"
+#include "libknot/dname.h"
+
+enum log_operation {
+ LOG_OPERATION_AXFR,
+ LOG_OPERATION_IXFR,
+ LOG_OPERATION_NOTIFY,
+ LOG_OPERATION_REFRESH,
+ LOG_OPERATION_UPDATE,
+ LOG_OPERATION_PARENT,
+};
+
+enum log_direction {
+ LOG_DIRECTION_IN,
+ LOG_DIRECTION_OUT,
+};
+
+static inline const char *log_operation_name(enum log_operation operation)
+{
+ switch (operation) {
+ case LOG_OPERATION_AXFR:
+ return "AXFR";
+ case LOG_OPERATION_IXFR:
+ return "IXFR";
+ case LOG_OPERATION_NOTIFY:
+ return "notify";
+ case LOG_OPERATION_REFRESH:
+ return "refresh";
+ case LOG_OPERATION_UPDATE:
+ return "DDNS";
+ case LOG_OPERATION_PARENT:
+ return "parent DS check";
+ default:
+ return "?";
+ }
+}
+
+static inline const char *log_direction_name(enum log_direction direction)
+{
+ switch (direction) {
+ case LOG_DIRECTION_IN:
+ return "incoming";
+ case LOG_DIRECTION_OUT:
+ return "outgoing";
+ default:
+ return "?";
+ }
+}
+
+/*!
+ * \brief Generate log message for server communication.
+ *
+ * If this macro was a function:
+ *
+ * void ns_log(int priority, const knot_dname_t *zone, enum log_operation op,
+ * enum log_direction dir, const struct sockaddr *remote,
+ * const char *fmt, ...);
+ *
+ * Example output:
+ *
+ * [example.com] NOTIFY, outgoing, 2001:db8::1@53: serial 123
+ *
+ */
+#define ns_log(priority, zone, op, dir, remote, fmt, ...) \
+ do { \
+ char address[SOCKADDR_STRLEN] = ""; \
+ sockaddr_tostr(address, sizeof(address), remote); \
+ log_fmt_zone(priority, LOG_SOURCE_ZONE, zone, NULL, "%s, %s, %s: " fmt, \
+ log_operation_name(op), log_direction_name(dir), address, \
+ ## __VA_ARGS__); \
+ } while (0)
diff --git a/src/knot/nameserver/notify.c b/src/knot/nameserver/notify.c
new file mode 100644
index 0000000..fe9273b
--- /dev/null
+++ b/src/knot/nameserver/notify.c
@@ -0,0 +1,93 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "knot/common/log.h"
+#include "knot/nameserver/notify.h"
+#include "knot/nameserver/internet.h"
+#include "knot/nameserver/log.h"
+#include "knot/nameserver/tsig_ctx.h"
+#include "knot/zone/serial.h"
+#include "libdnssec/random.h"
+#include "libknot/libknot.h"
+
+#define NOTIFY_LOG(priority, qdata, fmt...) \
+ ns_log(priority, knot_pkt_qname(qdata->query), LOG_OPERATION_NOTIFY, \
+ LOG_DIRECTION_IN, (struct sockaddr *)qdata->params->remote, fmt)
+
+static int notify_check_query(knotd_qdata_t *qdata)
+{
+ NS_NEED_ZONE(qdata, KNOT_RCODE_NOTAUTH);
+ NS_NEED_AUTH(qdata, qdata->extra->zone->name, ACL_ACTION_NOTIFY);
+ /* RFC1996 requires SOA question. */
+ NS_NEED_QTYPE(qdata, KNOT_RRTYPE_SOA, KNOT_RCODE_FORMERR);
+
+ return KNOT_STATE_DONE;
+}
+
+int notify_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata)
+{
+ if (pkt == NULL || qdata == NULL) {
+ return KNOT_STATE_FAIL;
+ }
+
+ /* Validate notification query. */
+ int state = notify_check_query(qdata);
+ if (state == KNOT_STATE_FAIL) {
+ switch (qdata->rcode) {
+ case KNOT_RCODE_NOTAUTH: /* Not authorized, already logged. */
+ break;
+ default: /* Other errors. */
+ NOTIFY_LOG(LOG_DEBUG, qdata, "invalid query");
+ break;
+ }
+ return state;
+ }
+
+ /* Reserve space for TSIG. */
+ int ret = knot_pkt_reserve(pkt, knot_tsig_wire_size(&qdata->sign.tsig_key));
+ if (ret != KNOT_EOK) {
+ return KNOT_STATE_FAIL;
+ }
+
+ /* SOA RR in answer may be included, recover serial. */
+ zone_t *zone = (zone_t *)qdata->extra->zone;
+ const knot_pktsection_t *answer = knot_pkt_section(qdata->query, KNOT_ANSWER);
+ if (answer->count > 0) {
+ const knot_rrset_t *soa = knot_pkt_rr(answer, 0);
+ if (soa->type == KNOT_RRTYPE_SOA) {
+ uint32_t serial = knot_soa_serial(soa->rrs.rdata);
+ uint32_t zone_serial = zone_contents_serial(zone->contents);
+ (void)zone_get_master_serial(zone, &zone_serial);
+ NOTIFY_LOG(LOG_INFO, qdata, "received, serial %u", serial);
+ if (serial_equal(serial, zone_serial)) {
+ // NOTIFY serial == zone serial => ignore, keep timers
+ return KNOT_STATE_DONE;
+ }
+ } else { /* Complain, but accept N/A record. */
+ NOTIFY_LOG(LOG_NOTICE, qdata, "received, bad record in answer section");
+ }
+ } else {
+ NOTIFY_LOG(LOG_INFO, qdata, "received, serial none");
+ }
+
+ /* Incoming NOTIFY expires REFRESH timer and renews EXPIRE timer. */
+ zone_set_preferred_master(zone, qdata->params->remote);
+ zone_events_schedule_now(zone, ZONE_EVENT_REFRESH);
+
+ return KNOT_STATE_DONE;
+}
diff --git a/src/knot/nameserver/notify.h b/src/knot/nameserver/notify.h
new file mode 100644
index 0000000..4f282da
--- /dev/null
+++ b/src/knot/nameserver/notify.h
@@ -0,0 +1,30 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "libknot/packet/pkt.h"
+#include "knot/nameserver/process_query.h"
+
+#define NOTIFY_TIMEOUT 3 /*!< Interval between NOTIFY retries. */
+
+/*!
+ * \brief Answer IN class zone NOTIFY message (RFC1996).
+ *
+ * \retval FAIL if it encountered an error.
+ * \retval DONE if finished.
+ */
+int notify_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata);
diff --git a/src/knot/nameserver/nsec_proofs.c b/src/knot/nameserver/nsec_proofs.c
new file mode 100644
index 0000000..cbbdf2d
--- /dev/null
+++ b/src/knot/nameserver/nsec_proofs.c
@@ -0,0 +1,677 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "libknot/libknot.h"
+#include "knot/nameserver/nsec_proofs.h"
+#include "knot/nameserver/internet.h"
+#include "knot/dnssec/zone-nsec.h"
+
+/*!
+ * \brief Check if node is empty non-terminal.
+ */
+static bool empty_nonterminal(const zone_node_t *node)
+{
+ return node && node->rrset_count == 0;
+}
+
+/*!
+ * \brief Check if wildcard expansion happened for given node and QNAME.
+ */
+static bool wildcard_expanded(const zone_node_t *node, const knot_dname_t *qname)
+{
+ return !knot_dname_is_wildcard(qname) && knot_dname_is_wildcard(node->owner);
+}
+
+/*!
+ * \brief Check if opt-out can take an effect.
+ */
+static bool ds_optout(const zone_node_t *node)
+{
+ return node->nsec3_node == NULL && node->flags & NODE_FLAGS_DELEG;
+}
+
+/*!
+ * \brief Check if node is part of the NSEC chain.
+ *
+ * NSEC is created for each node with authoritative data or delegation.
+ *
+ * \see https://tools.ietf.org/html/rfc4035#section-2.3
+ */
+static bool node_in_nsec(const zone_node_t *node)
+{
+ return (node->flags & NODE_FLAGS_NONAUTH) == 0 && !empty_nonterminal(node);
+}
+
+/*!
+ * \brief Check if node is part of the NSEC3 chain.
+ *
+ * NSEC3 is created for each node with authoritative data, empty-non terminal,
+ * and delegation (unless opt-out is in effect).
+ *
+ * \see https://tools.ietf.org/html/rfc5155#section-7.1
+ */
+static bool node_in_nsec3(const zone_node_t *node)
+{
+ return (node->flags & NODE_FLAGS_NONAUTH) == 0 && !ds_optout(node);
+}
+
+/*!
+ * \brief Walk previous names until we reach a node in NSEC chain.
+ *
+ */
+static const zone_node_t *nsec_previous(const zone_node_t *previous)
+{
+ assert(previous);
+
+ while (!node_in_nsec(previous)) {
+ previous = previous->prev;
+ assert(previous);
+ }
+
+ return previous;
+}
+
+/*!
+ * \brief Get closest provable encloser from closest matching parent node.
+ */
+static const zone_node_t *nsec3_encloser(const zone_node_t *closest)
+{
+ assert(closest);
+
+ while (!node_in_nsec3(closest)) {
+ closest = closest->parent;
+ assert(closest);
+ }
+
+ return closest;
+}
+
+/*!
+ * \brief Create a 'next closer name' to the given domain name.
+ *
+ * Next closer is the name one label longer than the closest provable encloser
+ * of a name.
+ *
+ * \see https://tools.ietf.org/html/rfc5155#section-1.3
+ *
+ * \param closest_encloser Closest provable encloser of \a name.
+ * \param name Domain name to create the 'next closer' name to.
+ *
+ * \return Next closer name, NULL on error.
+ */
+static const knot_dname_t *get_next_closer(const knot_dname_t *closest_encloser,
+ const knot_dname_t *name)
+{
+ // make name only one label longer than closest_encloser
+ size_t ce_labels = knot_dname_labels(closest_encloser, NULL);
+ size_t qname_labels = knot_dname_labels(name, NULL);
+ for (int i = 0; i < (qname_labels - ce_labels - 1); ++i) {
+ name = knot_wire_next_label(name, NULL);
+ }
+
+ // the common labels should match
+ assert(knot_dname_is_equal(knot_wire_next_label(name, NULL), closest_encloser));
+
+ return name;
+}
+
+/*!
+ * \brief Put NSEC/NSEC3 record with corresponding RRSIG into the response.
+ */
+static int put_nxt_from_node(const zone_node_t *node,
+ uint16_t type,
+ knotd_qdata_t *qdata,
+ knot_pkt_t *resp)
+{
+ assert(type == KNOT_RRTYPE_NSEC || type == KNOT_RRTYPE_NSEC3);
+
+ knot_rrset_t rrset = node_rrset(node, type);
+ if (knot_rrset_empty(&rrset)) {
+ return KNOT_EOK;
+ }
+
+ knot_rrset_t rrsigs = node_rrset(node, KNOT_RRTYPE_RRSIG);
+
+ return process_query_put_rr(resp, qdata, &rrset, &rrsigs,
+ KNOT_COMPR_HINT_NONE, KNOT_PF_CHECKDUP);
+}
+
+/*!
+ * \brief Put NSEC record with corresponding RRSIG into the response.
+ */
+static int put_nsec_from_node(const zone_node_t *node,
+ knotd_qdata_t *qdata,
+ knot_pkt_t *resp)
+{
+ return put_nxt_from_node(node, KNOT_RRTYPE_NSEC, qdata, resp);
+}
+
+/*!
+ * \brief Put NSEC3 record with corresponding RRSIG into the response.
+ */
+static int put_nsec3_from_node(const zone_node_t *node,
+ knotd_qdata_t *qdata,
+ knot_pkt_t *resp)
+{
+ return put_nxt_from_node(node, KNOT_RRTYPE_NSEC3, qdata, resp);
+}
+
+/*!
+ * \brief Find NSEC for given name and put it into the response.
+ *
+ * Note this function allows the name to match the QNAME. The NODATA proof
+ * for empty non-terminal is equivalent to NXDOMAIN proof, except that the
+ * names may exist. This is why.
+ */
+static int put_covering_nsec(const zone_contents_t *zone,
+ const knot_dname_t *name,
+ knotd_qdata_t *qdata,
+ knot_pkt_t *resp)
+{
+ const zone_node_t *match = NULL;
+ const zone_node_t *closest = NULL;
+ const zone_node_t *prev = NULL;
+
+ const zone_node_t *proof = NULL;
+
+ int ret = zone_contents_find_dname(zone, name, &match, &closest, &prev);
+ if (ret == ZONE_NAME_FOUND) {
+ proof = match;
+ } else if (ret == ZONE_NAME_NOT_FOUND) {
+ proof = nsec_previous(prev);
+ } else {
+ assert(ret < 0);
+ return ret;
+ }
+
+ return put_nsec_from_node(proof, qdata, resp);
+}
+
+/*!
+ * \brief Find NSEC3 covering the given name and put it into the response.
+ */
+static int put_covering_nsec3(const zone_contents_t *zone,
+ const knot_dname_t *name,
+ knotd_qdata_t *qdata,
+ knot_pkt_t *resp)
+{
+ const zone_node_t *prev = NULL;
+ const zone_node_t *node = NULL;
+
+ int match = zone_contents_find_nsec3_for_name(zone, name, &node, &prev);
+ if (match < 0) {
+ // ignore if missing
+ return KNOT_EOK;
+ }
+
+ if (match == ZONE_NAME_FOUND || prev == NULL){
+ return KNOT_ERROR;
+ }
+
+ return put_nsec3_from_node(prev, qdata, resp);
+}
+
+/*!
+ * \brief Add NSEC3 covering the next closer name to closest encloser.
+ *
+ * \param cpe Closest provable encloser of \a qname.
+ * \param qname Source QNAME.
+ * \param zone Source zone.
+ * \param qdata Query processing data.
+ * \param resp Response packet.
+ *
+ * \return KNOT_E*
+ */
+static int put_nsec3_next_closer(const zone_node_t *cpe,
+ const knot_dname_t *qname,
+ const zone_contents_t *zone,
+ knotd_qdata_t *qdata,
+ knot_pkt_t *resp)
+{
+ const knot_dname_t *next_closer = get_next_closer(cpe->owner, qname);
+
+ return put_covering_nsec3(zone, next_closer, qdata, resp);
+}
+
+/*!
+ * \brief Add NSEC3s for closest encloser proof.
+ *
+ * Adds up to two NSEC3 records. The first one proves that closest encloser
+ * of the queried name exists, the second one proves that the name bellow the
+ * encloser doesn't.
+ *
+ * \see https://tools.ietf.org/html/rfc5155#section-7.2.1
+ *
+ * \param qname Source QNAME.
+ * \param zone Source zone.
+ * \param cpe Closest provable encloser of \a qname.
+ * \param qdata Query processing data.
+ * \param resp Response packet.
+ *
+ * \return KNOT_E*
+ */
+static int put_closest_encloser_proof(const knot_dname_t *qname,
+ const zone_contents_t *zone,
+ const zone_node_t *cpe,
+ knotd_qdata_t *qdata,
+ knot_pkt_t *resp)
+{
+ // An NSEC3 RR that matches the closest (provable) encloser.
+
+ int ret = put_nsec3_from_node(cpe->nsec3_node, qdata, resp);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // An NSEC3 RR that covers the "next closer" name to the closest encloser.
+
+ return put_nsec3_next_closer(cpe, qname, zone, qdata, resp);
+}
+
+/*!
+ * \brief Put NSEC for wildcard answer into the response.
+ *
+ * Add NSEC record proving that no better match on QNAME exists.
+ *
+ * \see https://tools.ietf.org/html/rfc4035#section-3.1.3.3
+ *
+ * \param previous Previous name for QNAME.
+ * \param qdata Query processing data.
+ * \param resp Response packet.
+ *
+ * \return KNOT_E*
+ */
+static int put_nsec_wildcard(const zone_node_t *previous,
+ knotd_qdata_t *qdata,
+ knot_pkt_t *resp)
+{
+ return put_nsec_from_node(previous, qdata, resp);
+}
+
+/*!
+ * \brief Put NSEC3s for wildcard answer into the response.
+ *
+ * Add NSEC3 record proving that no better match on QNAME exists.
+ *
+ * \see https://tools.ietf.org/html/rfc5155#section-7.2.6
+ *
+ * \param wildcard Wildcard node that was used for expansion.
+ * \param qname Source QNAME.
+ * \param zone Source zone.
+ * \param qdata Query processing data.
+ * \param resp Response packet.
+ */
+static int put_nsec3_wildcard(const zone_node_t *wildcard,
+ const knot_dname_t *qname,
+ const zone_contents_t *zone,
+ knotd_qdata_t *qdata,
+ knot_pkt_t *resp)
+{
+ const zone_node_t *cpe = nsec3_encloser(wildcard->parent);
+
+ return put_nsec3_next_closer(cpe, qname, zone, qdata, resp);
+}
+
+/*!
+ * \brief Put NSECs or NSEC3s for wildcard expansion in the response.
+ *
+ * \return KNOT_E*
+ */
+static int put_wildcard_answer(const zone_node_t *wildcard,
+ const zone_node_t *previous,
+ const zone_contents_t *zone,
+ const knot_dname_t *qname,
+ knotd_qdata_t *qdata,
+ knot_pkt_t *resp)
+{
+ if (!wildcard_expanded(wildcard, qname)) {
+ return KNOT_EOK;
+ }
+
+ int ret = 0;
+
+ if (knot_is_nsec3_enabled(zone)) {
+ ret = put_nsec3_wildcard(wildcard, qname, zone, qdata, resp);
+ } else {
+ previous = nsec_previous(previous);
+ ret = put_nsec_wildcard(previous, qdata, resp);
+ }
+
+ return ret;
+}
+
+/*!
+ * \brief Put NSECs for NXDOMAIN error into the response.
+ *
+ * Adds up to two NSEC records. We have to prove that the queried name doesn't
+ * exist and that no wildcard expansion is possible for that name.
+ *
+ * \see https://tools.ietf.org/html/rfc4035#section-3.1.3.2
+ *
+ * \param zone Source zone.
+ * \param previous Previous node to QNAME.
+ * \param closest Closest matching parent of QNAME.
+ * \param qdata Query data.
+ * \param resp Response packet.
+ *
+ * \return KNOT_E*
+ */
+static int put_nsec_nxdomain(const zone_contents_t *zone,
+ const zone_node_t *previous,
+ const zone_node_t *closest,
+ knotd_qdata_t *qdata,
+ knot_pkt_t *resp)
+{
+ assert(previous);
+ assert(closest);
+
+ // An NSEC RR proving that there is no exact match for <SNAME, SCLASS>.
+
+ previous = nsec_previous(previous);
+ int ret = put_nsec_from_node(previous, qdata, resp);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // An NSEC RR proving that the zone contains no RRsets that would match
+ // <SNAME, SCLASS> via wildcard name expansion.
+
+ // NOTE: closest may be empty non-terminal and thus not authoritative.
+
+ size_t size = knot_dname_size(closest->owner);
+ if (size > KNOT_DNAME_MAXLEN - 2) {
+ return KNOT_EINVAL;
+ }
+ assert(size > 0);
+ uint8_t wildcard[2 + size];
+ memcpy(wildcard, "\x01""*", 2);
+ memcpy(wildcard + 2, closest->owner, size);
+
+ return put_covering_nsec(zone, wildcard, qdata, resp);
+}
+
+/*!
+ * \brief Put NSEC3s for NXDOMAIN error into the response.
+ *
+ * Adds up to three NSEC3 records. We have to prove that some parent name
+ * exists (closest encloser proof) and that no wildcard expansion is possible
+ * bellow that closest encloser.
+ *
+ * \see https://tools.ietf.org/html/rfc5155#section-7.2.2
+ *
+ * \param qname Source QNAME.
+ * \param zone Source zone.
+ * \param closest Closest matching parent of \a qname.
+ * \param qdata Query processing data.
+ * \param resp Response packet.
+ *
+ * \retval KNOT_E*
+ */
+static int put_nsec3_nxdomain(const knot_dname_t *qname,
+ const zone_contents_t *zone,
+ const zone_node_t *closest,
+ knotd_qdata_t *qdata,
+ knot_pkt_t *resp)
+{
+ const zone_node_t *cpe = nsec3_encloser(closest);
+
+ // Closest encloser proof.
+
+ int ret = put_closest_encloser_proof(qname, zone, cpe, qdata, resp);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // NSEC3 covering the (nonexistent) wildcard at the closest encloser.
+
+ if (cpe->nsec3_wildcard_prev == NULL) {
+ return KNOT_ERROR;
+ }
+
+ return put_nsec3_from_node(cpe->nsec3_wildcard_prev, qdata, resp);
+}
+
+/*!
+ * \brief Put NSECs or NSEC3s for the NXDOMAIN error into the response.
+ *
+ * \param zone Zone used for answering.
+ * \param previous Previous node to \a qname.
+ * \param closest Closest matching parent name for \a qname.
+ * \param qname Source QNAME.
+ * \param qdata Query processing data.
+ * \param resp Response packet.
+ *
+ * \return KNOT_E*
+ */
+static int put_nxdomain(const zone_contents_t *zone,
+ const zone_node_t *previous,
+ const zone_node_t *closest,
+ const knot_dname_t *qname,
+ knotd_qdata_t *qdata,
+ knot_pkt_t *resp)
+{
+ if (knot_is_nsec3_enabled(zone)) {
+ return put_nsec3_nxdomain(qname, zone, closest, qdata, resp);
+ } else {
+ return put_nsec_nxdomain(zone, previous, closest, qdata, resp);
+ }
+}
+
+/*!
+ * \brief Put NSEC for NODATA error into the response.
+ *
+ * Then NSEC matching the QNAME must be added into the response and the bitmap
+ * will indicate that the QTYPE doesn't exist. As NSECs for empty non-terminals
+ * don't exist, the proof for NODATA match on non-terminal is proved as for
+ * NXDOMAIN.
+ *
+ * \see https://tools.ietf.org/html/rfc4035#section-3.1.3.1
+ * \see https://tools.ietf.org/html/rfc4035#section-3.1.3.2 (empty non-terminal)
+ *
+ * \param zone Source zone.
+ * \param match Node matching QNAME.
+ * \param previous Previous node to QNAME in the zone.
+ * \param qdata Query procssing data.
+ * \param resp Response packet.
+ *
+ * \return KNOT_E*
+ */
+static int put_nsec_nodata(const zone_contents_t *zone,
+ const zone_node_t *match,
+ const zone_node_t *closest,
+ const zone_node_t *previous,
+ knotd_qdata_t *qdata,
+ knot_pkt_t *resp)
+{
+ if (empty_nonterminal(match)) {
+ return put_nsec_nxdomain(zone, previous, closest, qdata, resp);
+ } else {
+ return put_nsec_from_node(match, qdata, resp);
+ }
+}
+
+/*!
+ * \brief Put NSEC3 for NODATA error into the response.
+ *
+ * The NSEC3 matching the QNAME is added into the response and the bitmap
+ * will indicate that the QTYPE doesn't exist. For QTYPE==DS, the server
+ * may alternatively serve a closest encloser proof with opt-out. For wildcard
+ * expansion, the closest encloser proof must included as well.
+ *
+ * \see https://tools.ietf.org/html/rfc5155#section-7.2.3
+ * \see https://tools.ietf.org/html/rfc5155#section-7.2.4
+ * \see https://tools.ietf.org/html/rfc5155#section-7.2.5
+ */
+static int put_nsec3_nodata(const knot_dname_t *qname,
+ const zone_contents_t *zone,
+ const zone_node_t *match,
+ const zone_node_t *closest,
+ knotd_qdata_t *qdata,
+ knot_pkt_t *resp)
+{
+ int ret = KNOT_EOK;
+
+ // NSEC3 matching QNAME is always included.
+
+ if (match->nsec3_node) {
+ ret = put_nsec3_from_node(match->nsec3_node, qdata, resp);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ // Closest encloser proof for wildcard effect or NSEC3 opt-out.
+
+ if (wildcard_expanded(match, qname) || ds_optout(match)) {
+ const zone_node_t *cpe = nsec3_encloser(closest);
+ ret = put_closest_encloser_proof(qname, zone, cpe, qdata, resp);
+ }
+
+ return ret;
+}
+
+/*!
+ * \brief Put NSECs or NSEC3s for the NODATA error into the response.
+ *
+ * \param node Source node.
+ * \param qdata Query processing data.
+ * \param resp Response packet.
+ */
+static int put_nodata(const zone_node_t *node,
+ const zone_node_t *closest,
+ const zone_node_t *previous,
+ const zone_contents_t *zone,
+ const knot_dname_t *qname,
+ knotd_qdata_t *qdata,
+ knot_pkt_t *resp)
+{
+ if (knot_is_nsec3_enabled(zone)) {
+ return put_nsec3_nodata(qname, zone, node, closest, qdata, resp);
+ } else {
+ return put_nsec_nodata(zone, node, closest, previous, qdata, resp);
+ }
+}
+
+int nsec_prove_wildcards(knot_pkt_t *pkt, knotd_qdata_t *qdata)
+{
+ if (qdata->extra->zone->contents == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = KNOT_EOK;
+ struct wildcard_hit *item = NULL;
+
+ WALK_LIST(item, qdata->extra->wildcards) {
+ if (item->node == NULL) {
+ return KNOT_EINVAL;
+ }
+ ret = put_wildcard_answer(item->node, item->prev,
+ qdata->extra->zone->contents,
+ item->sname, qdata, pkt);
+ if (ret != KNOT_EOK) {
+ break;
+ }
+ }
+
+ return ret;
+}
+
+int nsec_prove_nodata(knot_pkt_t *pkt, knotd_qdata_t *qdata)
+{
+ if (qdata->extra->zone->contents == NULL || qdata->extra->node == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ return put_nodata(qdata->extra->node, qdata->extra->encloser, qdata->extra->previous,
+ qdata->extra->zone->contents, qdata->name, qdata, pkt);
+}
+
+int nsec_prove_nxdomain(knot_pkt_t *pkt, knotd_qdata_t *qdata)
+{
+ if (qdata->extra->zone->contents == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ return put_nxdomain(qdata->extra->zone->contents,
+ qdata->extra->previous, qdata->extra->encloser,
+ qdata->name, qdata, pkt);
+}
+
+int nsec_prove_dp_security(knot_pkt_t *pkt, knotd_qdata_t *qdata)
+{
+ if (qdata->extra->node == NULL || qdata->extra->encloser == NULL ||
+ qdata->extra->zone->contents == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ // Add DS into the response.
+
+ knot_rrset_t rrset = node_rrset(qdata->extra->node, KNOT_RRTYPE_DS);
+ if (!knot_rrset_empty(&rrset)) {
+ knot_rrset_t rrsigs = node_rrset(qdata->extra->node, KNOT_RRTYPE_RRSIG);
+ return process_query_put_rr(pkt, qdata, &rrset, &rrsigs,
+ KNOT_COMPR_HINT_NONE, 0);
+ }
+
+ // Alternatively prove that DS doesn't exist.
+
+ return put_nodata(qdata->extra->node, qdata->extra->encloser, qdata->extra->previous,
+ qdata->extra->zone->contents, qdata->name, qdata, pkt);
+}
+
+int nsec_append_rrsigs(knot_pkt_t *pkt, knotd_qdata_t *qdata, bool optional)
+{
+ int ret = KNOT_EOK;
+ uint32_t flags = optional ? KNOT_PF_NOTRUNC : KNOT_PF_NULL;
+ flags |= KNOT_PF_FREE; // Free all RRSIGs, they are synthesized
+ flags |= KNOT_PF_ORIGTTL;
+
+ /* Append RRSIGs for section. */
+ struct rrsig_info *info = NULL;
+ WALK_LIST(info, qdata->extra->rrsigs) {
+ knot_rrset_t *rrsig = &info->synth_rrsig;
+ uint16_t compr_hint = info->rrinfo->compress_ptr[KNOT_COMPR_HINT_OWNER];
+ ret = knot_pkt_put(pkt, compr_hint, rrsig, flags);
+ if (ret != KNOT_EOK) {
+ break;
+ }
+ /* RRSIG is owned by packet now. */
+ knot_rdataset_init(&info->synth_rrsig.rrs);
+ };
+
+ /* Clear the list. */
+ nsec_clear_rrsigs(qdata);
+
+ return ret;
+}
+
+void nsec_clear_rrsigs(knotd_qdata_t *qdata)
+{
+ if (qdata == NULL) {
+ return;
+ }
+
+ struct rrsig_info *info = NULL;
+ WALK_LIST(info, qdata->extra->rrsigs) {
+ knot_rrset_t *rrsig = &info->synth_rrsig;
+ knot_rrset_clear(rrsig, qdata->mm);
+ };
+
+ ptrlist_free(&qdata->extra->rrsigs, qdata->mm);
+ init_list(&qdata->extra->rrsigs);
+}
diff --git a/src/knot/nameserver/nsec_proofs.h b/src/knot/nameserver/nsec_proofs.h
new file mode 100644
index 0000000..1a5528f
--- /dev/null
+++ b/src/knot/nameserver/nsec_proofs.h
@@ -0,0 +1,38 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "libknot/packet/pkt.h"
+#include "knot/nameserver/process_query.h"
+
+/*! \brief Prove wildcards visited during answer resolution. */
+int nsec_prove_wildcards(knot_pkt_t *pkt, knotd_qdata_t *qdata);
+
+/*! \brief Prove answer leading to non-existent name. */
+int nsec_prove_nxdomain(knot_pkt_t *pkt, knotd_qdata_t *qdata);
+
+/*! \brief Prove empty answer. */
+int nsec_prove_nodata(knot_pkt_t *pkt, knotd_qdata_t *qdata);
+
+/*! \brief Prove delegation point security. */
+int nsec_prove_dp_security(knot_pkt_t *pkt, knotd_qdata_t *qdata);
+
+/*! \brief Append missing RRSIGs for current processing section. */
+int nsec_append_rrsigs(knot_pkt_t *pkt, knotd_qdata_t *qdata, bool optional);
+
+/*! \brief Clear RRSIG list. */
+void nsec_clear_rrsigs(knotd_qdata_t *qdata);
diff --git a/src/knot/nameserver/process_query.c b/src/knot/nameserver/process_query.c
new file mode 100644
index 0000000..39a905d
--- /dev/null
+++ b/src/knot/nameserver/process_query.c
@@ -0,0 +1,891 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <urcu.h>
+
+#include "libdnssec/tsig.h"
+#include "knot/common/log.h"
+#include "knot/dnssec/rrset-sign.h"
+#include "knot/nameserver/process_query.h"
+#include "knot/nameserver/query_module.h"
+#include "knot/nameserver/chaos.h"
+#include "knot/nameserver/internet.h"
+#include "knot/nameserver/axfr.h"
+#include "knot/nameserver/ixfr.h"
+#include "knot/nameserver/update.h"
+#include "knot/nameserver/nsec_proofs.h"
+#include "knot/nameserver/notify.h"
+#include "knot/server/server.h"
+#include "libknot/libknot.h"
+#include "contrib/macros.h"
+#include "contrib/mempattern.h"
+
+/*! \brief Accessor to query-specific data. */
+#define QUERY_DATA(ctx) ((knotd_qdata_t *)(ctx)->data)
+
+static knotd_query_type_t query_type(const knot_pkt_t *pkt)
+{
+ switch (knot_wire_get_opcode(pkt->wire)) {
+ case KNOT_OPCODE_QUERY:
+ switch (knot_pkt_qtype(pkt)) {
+ case 0 /* RESERVED */: return KNOTD_QUERY_TYPE_INVALID;
+ case KNOT_RRTYPE_AXFR: return KNOTD_QUERY_TYPE_AXFR;
+ case KNOT_RRTYPE_IXFR: return KNOTD_QUERY_TYPE_IXFR;
+ default: return KNOTD_QUERY_TYPE_NORMAL;
+ }
+ case KNOT_OPCODE_NOTIFY: return KNOTD_QUERY_TYPE_NOTIFY;
+ case KNOT_OPCODE_UPDATE: return KNOTD_QUERY_TYPE_UPDATE;
+ default: return KNOTD_QUERY_TYPE_INVALID;
+ }
+}
+
+/*! \brief Reinitialize query data structure. */
+static void query_data_init(knot_layer_t *ctx, knotd_qdata_params_t *params,
+ knotd_qdata_extra_t *extra)
+{
+ /* Initialize persistent data. */
+ knotd_qdata_t *data = QUERY_DATA(ctx);
+ memset(data, 0, sizeof(*data));
+ data->mm = ctx->mm;
+ data->params = params;
+ data->extra = extra;
+
+ /* Initialize lists. */
+ memset(extra, 0, sizeof(*extra));
+ init_list(&extra->wildcards);
+ init_list(&extra->rrsigs);
+}
+
+static int process_query_begin(knot_layer_t *ctx, void *params)
+{
+ /* Initialize context. */
+ assert(ctx);
+ ctx->data = mm_alloc(ctx->mm, sizeof(knotd_qdata_t));
+ knotd_qdata_extra_t *extra = mm_alloc(ctx->mm, sizeof(*extra));
+
+ /* Initialize persistent data. */
+ query_data_init(ctx, params, extra);
+
+ /* Await packet. */
+ return KNOT_STATE_CONSUME;
+}
+
+static int process_query_reset(knot_layer_t *ctx)
+{
+ assert(ctx);
+ knotd_qdata_t *qdata = QUERY_DATA(ctx);
+
+ /* Remember persistent parameters. */
+ knotd_qdata_params_t *params = qdata->params;
+ knotd_qdata_extra_t *extra = qdata->extra;
+
+ /* Free allocated data. */
+ knot_rrset_clear(&qdata->opt_rr, qdata->mm);
+ ptrlist_free(&extra->wildcards, qdata->mm);
+ nsec_clear_rrsigs(qdata);
+ if (extra->ext_cleanup != NULL) {
+ extra->ext_cleanup(qdata);
+ }
+
+ /* Initialize persistent data. */
+ query_data_init(ctx, params, extra);
+
+ /* Await packet. */
+ return KNOT_STATE_CONSUME;
+}
+
+static int process_query_finish(knot_layer_t *ctx)
+{
+ process_query_reset(ctx);
+ mm_free(ctx->mm, ctx->data);
+ ctx->data = NULL;
+
+ return KNOT_STATE_NOOP;
+}
+
+static int process_query_in(knot_layer_t *ctx, knot_pkt_t *pkt)
+{
+ assert(pkt && ctx);
+ knotd_qdata_t *qdata = QUERY_DATA(ctx);
+
+ /* Check if at least header is parsed. */
+ if (pkt->parsed < KNOT_WIRE_HEADER_SIZE) {
+ return KNOT_STATE_NOOP; /* Ignore. */
+ }
+
+ /* Accept only queries. */
+ if (knot_wire_get_qr(pkt->wire)) {
+ return KNOT_STATE_NOOP; /* Ignore. */
+ }
+
+ /* Store for processing. */
+ qdata->query = pkt;
+ qdata->type = query_type(pkt);
+
+ /* Declare having response. */
+ return KNOT_STATE_PRODUCE;
+}
+
+/*!
+ * \brief Create a response for a given query in the INTERNET class.
+ */
+static int query_internet(knot_pkt_t *pkt, knot_layer_t *ctx)
+{
+ knotd_qdata_t *data = QUERY_DATA(ctx);
+
+ switch (data->type) {
+ case KNOTD_QUERY_TYPE_NORMAL: return internet_process_query(pkt, data);
+ case KNOTD_QUERY_TYPE_NOTIFY: return notify_process_query(pkt, data);
+ case KNOTD_QUERY_TYPE_AXFR: return axfr_process_query(pkt, data);
+ case KNOTD_QUERY_TYPE_IXFR: return ixfr_process_query(pkt, data);
+ case KNOTD_QUERY_TYPE_UPDATE: return update_process_query(pkt, data);
+ default:
+ /* Nothing else is supported. */
+ data->rcode = KNOT_RCODE_NOTIMPL;
+ return KNOT_STATE_FAIL;
+ }
+}
+
+/*!
+ * \brief Create a response for a given query in the CHAOS class.
+ */
+static int query_chaos(knot_pkt_t *pkt, knot_layer_t *ctx)
+{
+ knotd_qdata_t *data = QUERY_DATA(ctx);
+
+ /* Nothing except normal queries is supported. */
+ if (data->type != KNOTD_QUERY_TYPE_NORMAL) {
+ data->rcode = KNOT_RCODE_NOTIMPL;
+ return KNOT_STATE_FAIL;
+ }
+
+ data->rcode = knot_chaos_answer(pkt);
+ if (data->rcode != KNOT_RCODE_NOERROR) {
+ return KNOT_STATE_FAIL;
+ }
+
+ return KNOT_STATE_DONE;
+}
+
+/*! \brief Find zone for given question. */
+static const zone_t *answer_zone_find(const knot_pkt_t *query, knot_zonedb_t *zonedb)
+{
+ uint16_t qtype = knot_pkt_qtype(query);
+ uint16_t qclass = knot_pkt_qclass(query);
+ const knot_dname_t *qname = knot_pkt_qname(query);
+ const zone_t *zone = NULL;
+
+ // search for zone only for IN and ANY classes
+ if (qclass != KNOT_CLASS_IN && qclass != KNOT_CLASS_ANY) {
+ return NULL;
+ }
+
+ /* In case of DS query, we strip the leftmost label when searching for
+ * the zone (but use whole qname in search for the record), as the DS
+ * records are only present in a parent zone.
+ */
+ if (qtype == KNOT_RRTYPE_DS) {
+ const knot_dname_t *parent = knot_wire_next_label(qname, NULL);
+ zone = knot_zonedb_find_suffix(zonedb, parent);
+ /* If zone does not exist, search for its parent zone,
+ this will later result to NODATA answer. */
+ /*! \note This is not 100% right, it may lead to DS name for example
+ * when following a CNAME chain, that should also be answered
+ * from the parent zone (if it exists).
+ */
+ }
+
+ if (zone == NULL) {
+ if (query_type(query) == KNOTD_QUERY_TYPE_NORMAL) {
+ zone = knot_zonedb_find_suffix(zonedb, qname);
+ } else {
+ // Direct match required.
+ zone = knot_zonedb_find(zonedb, qname);
+ }
+ }
+
+ return zone;
+}
+
+static int answer_edns_reserve(knot_pkt_t *resp, knotd_qdata_t *qdata)
+{
+ if (knot_rrset_empty(&qdata->opt_rr)) {
+ return KNOT_EOK;
+ }
+
+ /* Reserve size in the response. */
+ return knot_pkt_reserve(resp, knot_edns_wire_size(&qdata->opt_rr));
+}
+
+static int answer_edns_init(const knot_pkt_t *query, knot_pkt_t *resp,
+ knotd_qdata_t *qdata)
+{
+ if (!knot_pkt_has_edns(query)) {
+ return KNOT_EOK;
+ }
+
+ /* Initialize OPT record. */
+ int16_t max_payload;
+ switch (qdata->params->remote->ss_family) {
+ case AF_INET:
+ max_payload = conf()->cache.srv_max_ipv4_udp_payload;
+ break;
+ case AF_INET6:
+ max_payload = conf()->cache.srv_max_ipv6_udp_payload;
+ break;
+ default:
+ return KNOT_ERROR;
+ }
+ int ret = knot_edns_init(&qdata->opt_rr, max_payload, 0,
+ KNOT_EDNS_VERSION, qdata->mm);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ /* Check supported version. */
+ if (knot_edns_get_version(query->opt_rr) != KNOT_EDNS_VERSION) {
+ qdata->rcode = KNOT_RCODE_BADVERS;
+ }
+
+ /* Set DO bit if set (DNSSEC requested). */
+ if (knot_pkt_has_dnssec(query)) {
+ knot_edns_set_do(&qdata->opt_rr);
+ }
+
+ /* Append NSID if requested and available. */
+ if (knot_pkt_edns_option(query, KNOT_EDNS_OPTION_NSID) != NULL) {
+ conf_val_t *nsid = &conf()->cache.srv_nsid;
+ size_t nsid_len;
+ const uint8_t *nsid_data = conf_bin(nsid, &nsid_len);
+
+ if (nsid->code != KNOT_EOK) {
+ ret = knot_edns_add_option(&qdata->opt_rr,
+ KNOT_EDNS_OPTION_NSID,
+ strlen(conf()->hostname),
+ (uint8_t *)conf()->hostname,
+ qdata->mm);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ } else if (nsid_len > 0) {
+ ret = knot_edns_add_option(&qdata->opt_rr,
+ KNOT_EDNS_OPTION_NSID,
+ nsid_len, nsid_data,
+ qdata->mm);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+ }
+
+ /* Initialize EDNS Client Subnet if configured and present in query. */
+ if (conf()->cache.use_ecs) {
+ uint8_t *ecs_opt = knot_pkt_edns_option(query, KNOT_EDNS_OPTION_CLIENT_SUBNET);
+ if (ecs_opt != NULL) {
+ qdata->ecs = mm_alloc(qdata->mm, sizeof(knot_edns_client_subnet_t));
+ if (qdata->ecs == NULL) {
+ return KNOT_ENOMEM;
+ }
+ const uint8_t *ecs_data = knot_edns_opt_get_data(ecs_opt);
+ uint16_t ecs_len = knot_edns_opt_get_length(ecs_opt);
+ ret = knot_edns_client_subnet_parse(qdata->ecs, ecs_data, ecs_len);
+ if (ret != KNOT_EOK) {
+ qdata->rcode = KNOT_RCODE_FORMERR;
+ return ret;
+ }
+ qdata->ecs->scope_len = 0;
+
+ /* Reserve space for the option in the answer. */
+ ret = knot_edns_reserve_option(&qdata->opt_rr, KNOT_EDNS_OPTION_CLIENT_SUBNET,
+ ecs_len, NULL, qdata->mm);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+ } else {
+ qdata->ecs = NULL;
+ }
+
+ return answer_edns_reserve(resp, qdata);
+}
+
+static int answer_edns_put(knot_pkt_t *resp, knotd_qdata_t *qdata)
+{
+ if (knot_rrset_empty(&qdata->opt_rr)) {
+ return KNOT_EOK;
+ }
+
+ /* Add ECS if present. */
+ int ret = KNOT_EOK;
+ if (qdata->ecs != NULL) {
+ uint8_t *ecs_opt = knot_edns_get_option(&qdata->opt_rr, KNOT_EDNS_OPTION_CLIENT_SUBNET);
+ if (ecs_opt != NULL) {
+ uint8_t *ecs_data = knot_edns_opt_get_data(ecs_opt);
+ uint16_t ecs_len = knot_edns_opt_get_length(ecs_opt);
+ ret = knot_edns_client_subnet_write(ecs_data, ecs_len, qdata->ecs);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+ }
+
+ /* Reclaim reserved size. */
+ ret = knot_pkt_reclaim(resp, knot_edns_wire_size(&qdata->opt_rr));
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ uint8_t *wire_end = resp->wire + resp->size;
+
+ /* Write to packet. */
+ assert(resp->current == KNOT_ADDITIONAL);
+ ret = knot_pkt_put(resp, KNOT_COMPR_HINT_NONE, &qdata->opt_rr, 0);
+ if (ret == KNOT_EOK) {
+ /* Save position of the OPT RR. */
+ qdata->extra->opt_rr_pos = wire_end;
+ }
+
+ return ret;
+}
+
+/*! \brief Initialize response, sizes and find zone from which we're going to answer. */
+static int prepare_answer(knot_pkt_t *query, knot_pkt_t *resp, knot_layer_t *ctx)
+{
+ knotd_qdata_t *qdata = QUERY_DATA(ctx);
+ server_t *server = qdata->params->server;
+
+ /* Initialize response. */
+ int ret = knot_pkt_init_response(resp, query);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ knot_wire_clear_cd(resp->wire);
+
+ /* Setup EDNS. */
+ ret = answer_edns_init(query, resp, qdata);
+ if (ret != KNOT_EOK || qdata->rcode != 0) {
+ return KNOT_ERROR;
+ }
+
+ /* Update maximal answer size. */
+ bool has_limit = qdata->params->flags & KNOTD_QUERY_FLAG_LIMIT_SIZE;
+ if (has_limit) {
+ resp->max_size = KNOT_WIRE_MIN_PKTSIZE;
+ if (knot_pkt_has_edns(query)) {
+ uint16_t server;
+ switch (qdata->params->remote->ss_family) {
+ case AF_INET:
+ server = conf()->cache.srv_max_ipv4_udp_payload;
+ break;
+ case AF_INET6:
+ server = conf()->cache.srv_max_ipv6_udp_payload;
+ break;
+ default:
+ return KNOT_ERROR;
+ }
+ uint16_t client = knot_edns_get_payload(query->opt_rr);
+ uint16_t transfer = MIN(client, server);
+ resp->max_size = MAX(resp->max_size, transfer);
+ }
+ } else {
+ resp->max_size = KNOT_WIRE_MAX_PKTSIZE;
+ }
+
+ /* Query MUST carry a question. */
+ const knot_dname_t *qname = knot_pkt_qname(query);
+ if (qname == NULL) {
+ qdata->rcode = KNOT_RCODE_FORMERR;
+ return KNOT_EMALF;
+ }
+
+ /* Convert query QNAME to lowercase, but keep original QNAME case.
+ * Already checked for absence of compression and length.
+ */
+ memcpy(qdata->extra->orig_qname, qname, query->qname_size);
+ process_query_qname_case_lower(query);
+
+ /* Find zone for QNAME. */
+ qdata->extra->zone = answer_zone_find(query, server->zone_db);
+
+ return KNOT_EOK;
+}
+
+static void set_rcode_to_packet(knot_pkt_t *pkt, knotd_qdata_t *qdata)
+{
+ uint8_t ext_rcode = KNOT_EDNS_RCODE_HI(qdata->rcode);
+
+ if (ext_rcode != 0) {
+ /* No OPT RR and Ext RCODE results in SERVFAIL. */
+ if (qdata->extra->opt_rr_pos == NULL) {
+ knot_wire_set_rcode(pkt->wire, KNOT_RCODE_SERVFAIL);
+ return;
+ }
+
+ knot_edns_set_ext_rcode_wire(qdata->extra->opt_rr_pos, ext_rcode);
+ }
+
+ knot_wire_set_rcode(pkt->wire, KNOT_EDNS_RCODE_LO(qdata->rcode));
+}
+
+static int process_query_err(knot_layer_t *ctx, knot_pkt_t *pkt)
+{
+ assert(ctx && pkt);
+
+ knotd_qdata_t *qdata = QUERY_DATA(ctx);
+
+ /* Initialize response from query packet. */
+ knot_pkt_t *query = qdata->query;
+ (void)knot_pkt_init_response(pkt, query);
+ knot_wire_clear_cd(pkt->wire);
+
+ /* Set TC bit if required. */
+ if (qdata->err_truncated) {
+ knot_wire_set_tc(pkt->wire);
+ }
+
+ /* Restore original QNAME. */
+ process_query_qname_case_restore(pkt, qdata);
+
+ /* Move to Additionals to add OPT and TSIG. */
+ if (pkt->current != KNOT_ADDITIONAL) {
+ (void)knot_pkt_begin(pkt, KNOT_ADDITIONAL);
+ }
+
+ /* Put OPT RR to the additional section. */
+ if (answer_edns_reserve(pkt, qdata) != KNOT_EOK ||
+ answer_edns_put(pkt, qdata) != KNOT_EOK) {
+ qdata->rcode = KNOT_RCODE_FORMERR;
+ }
+
+ /* Set final RCODE to packet. */
+ if (qdata->rcode == KNOT_RCODE_NOERROR) {
+ /* Default RCODE is SERVFAIL if not otherwise specified. */
+ qdata->rcode = KNOT_RCODE_SERVFAIL;
+ }
+ set_rcode_to_packet(pkt, qdata);
+
+ /* Transaction security (if applicable). */
+ if (process_query_sign_response(pkt, qdata) != KNOT_EOK) {
+ set_rcode_to_packet(pkt, qdata);
+ }
+
+ return KNOT_STATE_DONE;
+}
+
+#define PROCESS_BEGIN(plan, step, next_state, qdata) \
+ if (plan != NULL) { \
+ WALK_LIST(step, plan->stage[KNOTD_STAGE_BEGIN]) { \
+ next_state = step->process(next_state, pkt, qdata, step->ctx); \
+ if (next_state == KNOT_STATE_FAIL) { \
+ goto finish; \
+ } \
+ } \
+ }
+
+#define PROCESS_END(plan, step, next_state, qdata) \
+ if (plan != NULL) { \
+ WALK_LIST(step, plan->stage[KNOTD_STAGE_END]) { \
+ next_state = step->process(next_state, pkt, qdata, step->ctx); \
+ if (next_state == KNOT_STATE_FAIL) { \
+ next_state = process_query_err(ctx, pkt); \
+ } \
+ } \
+ }
+
+static int process_query_out(knot_layer_t *ctx, knot_pkt_t *pkt)
+{
+ assert(pkt && ctx);
+
+ rcu_read_lock();
+
+ knotd_qdata_t *qdata = QUERY_DATA(ctx);
+ struct query_plan *plan = conf()->query_plan;
+ struct query_plan *zone_plan = NULL;
+ struct query_step *step = NULL;
+
+ int next_state = KNOT_STATE_PRODUCE;
+
+ /* Check parse state. */
+ knot_pkt_t *query = qdata->query;
+ if (query->parsed < query->size) {
+ qdata->rcode = KNOT_RCODE_FORMERR;
+ next_state = KNOT_STATE_FAIL;
+ goto finish;
+ }
+
+ /* Preprocessing. */
+ if (prepare_answer(query, pkt, ctx) != KNOT_EOK) {
+ next_state = KNOT_STATE_FAIL;
+ goto finish;
+ }
+
+ if (qdata->extra->zone != NULL && qdata->extra->zone->query_plan != NULL) {
+ zone_plan = qdata->extra->zone->query_plan;
+ }
+
+ /* Before query processing code. */
+ PROCESS_BEGIN(plan, step, next_state, qdata);
+ PROCESS_BEGIN(zone_plan, step, next_state, qdata);
+
+ /* Answer based on qclass. */
+ if (next_state == KNOT_STATE_PRODUCE) {
+ switch (knot_pkt_qclass(pkt)) {
+ case KNOT_CLASS_CH:
+ next_state = query_chaos(pkt, ctx);
+ break;
+ case KNOT_CLASS_ANY:
+ case KNOT_CLASS_IN:
+ next_state = query_internet(pkt, ctx);
+ break;
+ default:
+ qdata->rcode = KNOT_RCODE_REFUSED;
+ next_state = KNOT_STATE_FAIL;
+ break;
+ }
+ }
+
+ /* Postprocessing. */
+ if (next_state == KNOT_STATE_DONE || next_state == KNOT_STATE_PRODUCE) {
+ /* Restore original QNAME. */
+ process_query_qname_case_restore(pkt, qdata);
+
+ /* Move to Additionals to add OPT and TSIG. */
+ if (pkt->current != KNOT_ADDITIONAL) {
+ (void)knot_pkt_begin(pkt, KNOT_ADDITIONAL);
+ }
+
+ /* Put OPT RR to the additional section. */
+ if (answer_edns_put(pkt, qdata) != KNOT_EOK) {
+ qdata->rcode = KNOT_RCODE_FORMERR;
+ next_state = KNOT_STATE_FAIL;
+ goto finish;
+ }
+
+ /* Transaction security (if applicable). */
+ if (process_query_sign_response(pkt, qdata) != KNOT_EOK) {
+ next_state = KNOT_STATE_FAIL;
+ goto finish;
+ }
+ }
+
+finish:
+ switch (next_state) {
+ case KNOT_STATE_NOOP:
+ break;
+ case KNOT_STATE_FAIL:
+ /* Error processing. */
+ next_state = process_query_err(ctx, pkt);
+ break;
+ case KNOT_STATE_FINAL:
+ /* Just skipped postprocessing. */
+ next_state = KNOT_STATE_DONE;
+ break;
+ default:
+ set_rcode_to_packet(pkt, qdata);
+ }
+
+ /* After query processing code. */
+ PROCESS_END(plan, step, next_state, qdata);
+ PROCESS_END(zone_plan, step, next_state, qdata);
+
+ rcu_read_unlock();
+
+ return next_state;
+}
+
+bool process_query_acl_check(conf_t *conf, const knot_dname_t *zone_name,
+ acl_action_t action, knotd_qdata_t *qdata)
+{
+ knot_pkt_t *query = qdata->query;
+ const struct sockaddr_storage *query_source = qdata->params->remote;
+ knot_tsig_key_t tsig = { 0 };
+
+ /* Skip if already checked and valid. */
+ if (qdata->sign.tsig_key.name != NULL) {
+ return true;
+ }
+
+ /* Authenticate with NOKEY if the packet isn't signed. */
+ if (query->tsig_rr) {
+ tsig.name = query->tsig_rr->owner;
+ tsig.algorithm = knot_tsig_rdata_alg(query->tsig_rr);
+ }
+
+ /* Check if authenticated. */
+ conf_val_t acl = conf_zone_get(conf, C_ACL, zone_name);
+ if (!acl_allowed(conf, &acl, action, query_source, &tsig)) {
+ char addr_str[SOCKADDR_STRLEN] = { 0 };
+ sockaddr_tostr(addr_str, sizeof(addr_str), (struct sockaddr *)query_source);
+ const knot_lookup_t *act = knot_lookup_by_id((knot_lookup_t *)acl_actions,
+ action);
+ char *key_name = knot_dname_to_str_alloc(tsig.name);
+
+ log_zone_debug(zone_name,
+ "ACL, denied, action %s, remote %s, key %s%s%s",
+ (act != NULL) ? act->name : "query",
+ addr_str,
+ (key_name != NULL) ? "'" : "",
+ (key_name != NULL) ? key_name : "none",
+ (key_name != NULL) ? "'" : "");
+ free(key_name);
+
+ qdata->rcode = KNOT_RCODE_NOTAUTH;
+ qdata->rcode_tsig = KNOT_RCODE_BADKEY;
+ return false;
+ }
+
+ /* Remember used TSIG key. */
+ qdata->sign.tsig_key = tsig;
+
+ return true;
+}
+
+int process_query_verify(knotd_qdata_t *qdata)
+{
+ knot_pkt_t *query = qdata->query;
+ knot_sign_context_t *ctx = &qdata->sign;
+
+ /* NOKEY => no verification. */
+ if (query->tsig_rr == NULL) {
+ return KNOT_EOK;
+ }
+
+ /* Keep digest for signing response. */
+ /*! \note This memory will be rewritten for multi-pkt answers. */
+ ctx->tsig_digest = (uint8_t *)knot_tsig_rdata_mac(query->tsig_rr);
+ ctx->tsig_digestlen = knot_tsig_rdata_mac_length(query->tsig_rr);
+
+ /* Checking query. */
+ process_query_qname_case_restore(query, qdata);
+ int ret = knot_tsig_server_check(query->tsig_rr, query->wire,
+ query->size, &ctx->tsig_key);
+ process_query_qname_case_lower(query);
+
+ /* Evaluate TSIG check results. */
+ switch(ret) {
+ case KNOT_EOK:
+ qdata->rcode = KNOT_RCODE_NOERROR;
+ break;
+ case KNOT_TSIG_EBADKEY:
+ qdata->rcode = KNOT_RCODE_NOTAUTH;
+ qdata->rcode_tsig = KNOT_RCODE_BADKEY;
+ break;
+ case KNOT_TSIG_EBADSIG:
+ qdata->rcode = KNOT_RCODE_NOTAUTH;
+ qdata->rcode_tsig = KNOT_RCODE_BADSIG;
+ break;
+ case KNOT_TSIG_EBADTIME:
+ qdata->rcode = KNOT_RCODE_NOTAUTH;
+ qdata->rcode_tsig = KNOT_RCODE_BADTIME;
+ ctx->tsig_time_signed = knot_tsig_rdata_time_signed(query->tsig_rr);
+ break;
+ case KNOT_EMALF:
+ qdata->rcode = KNOT_RCODE_FORMERR;
+ break;
+ default:
+ qdata->rcode = KNOT_RCODE_SERVFAIL;
+ break;
+ }
+
+ /* Log possible error. */
+ if (qdata->rcode == KNOT_RCODE_SERVFAIL) {
+ log_zone_error(qdata->extra->zone->name,
+ "TSIG, verification failed (%s)", knot_strerror(ret));
+ } else if (qdata->rcode != KNOT_RCODE_NOERROR) {
+ const knot_lookup_t *item = NULL;
+ if (qdata->rcode_tsig != KNOT_RCODE_NOERROR) {
+ item = knot_lookup_by_id(knot_tsig_rcode_names, qdata->rcode_tsig);
+ if (item == NULL) {
+ item = knot_lookup_by_id(knot_rcode_names, qdata->rcode_tsig);
+ }
+ } else {
+ item = knot_lookup_by_id(knot_rcode_names, qdata->rcode);
+ }
+
+ char *key_name = knot_dname_to_str_alloc(ctx->tsig_key.name);
+ log_zone_debug(qdata->extra->zone->name,
+ "TSIG, key '%s', verification failed '%s'",
+ (key_name != NULL) ? key_name : "",
+ (item != NULL) ? item->name : "");
+ free(key_name);
+ }
+
+ return ret;
+}
+
+int process_query_sign_response(knot_pkt_t *pkt, knotd_qdata_t *qdata)
+{
+ if (pkt->size == 0) {
+ // Nothing to sign.
+ return KNOT_EOK;
+ }
+
+ int ret = KNOT_EOK;
+ knot_pkt_t *query = qdata->query;
+ knot_sign_context_t *ctx = &qdata->sign;
+
+ /* KEY provided and verified TSIG or BADTIME allows signing. */
+ if (ctx->tsig_key.name != NULL && knot_tsig_can_sign(qdata->rcode_tsig)) {
+ /* Sign query response. */
+ size_t new_digest_len = dnssec_tsig_algorithm_size(ctx->tsig_key.algorithm);
+ if (ctx->pkt_count == 0) {
+ ret = knot_tsig_sign(pkt->wire, &pkt->size, pkt->max_size,
+ ctx->tsig_digest, ctx->tsig_digestlen,
+ ctx->tsig_digest, &new_digest_len,
+ &ctx->tsig_key, qdata->rcode_tsig,
+ ctx->tsig_time_signed);
+ } else {
+ ret = knot_tsig_sign_next(pkt->wire, &pkt->size, pkt->max_size,
+ ctx->tsig_digest, ctx->tsig_digestlen,
+ ctx->tsig_digest, &new_digest_len,
+ &ctx->tsig_key,
+ pkt->wire, pkt->size);
+ }
+ if (ret != KNOT_EOK) {
+ goto fail; /* Failed to sign. */
+ } else {
+ ++ctx->pkt_count;
+ }
+ } else {
+ /* Copy TSIG from query and set RCODE. */
+ if (query->tsig_rr && qdata->rcode_tsig != KNOT_RCODE_NOERROR) {
+ ret = knot_tsig_add(pkt->wire, &pkt->size, pkt->max_size,
+ qdata->rcode_tsig, query->tsig_rr);
+ if (ret != KNOT_EOK) {
+ goto fail; /* Whatever it is, it's server fail. */
+ }
+ }
+ }
+
+ return KNOT_EOK;
+
+ /* Server failure in signing. */
+fail:
+ qdata->rcode = KNOT_RCODE_SERVFAIL;
+ qdata->rcode_tsig = KNOT_RCODE_NOERROR; /* Don't sign again. */
+ return ret;
+}
+
+/*! \brief Synthesize RRSIG for given parameters, store in 'qdata' for later use */
+static int put_rrsig(const knot_dname_t *sig_owner, uint16_t type,
+ const knot_rrset_t *rrsigs, knot_rrinfo_t *rrinfo,
+ knotd_qdata_t *qdata)
+{
+ knot_rdataset_t synth_rrs;
+ knot_rdataset_init(&synth_rrs);
+ int ret = knot_synth_rrsig(type, &rrsigs->rrs, &synth_rrs, qdata->mm);
+ if (ret == KNOT_ENOENT) {
+ // No signature
+ return KNOT_EOK;
+ }
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ /* Create rrsig info structure. */
+ struct rrsig_info *info = mm_alloc(qdata->mm, sizeof(struct rrsig_info));
+ if (info == NULL) {
+ knot_rdataset_clear(&synth_rrs, qdata->mm);
+ return KNOT_ENOMEM;
+ }
+
+ /* Store RRSIG into info structure. */
+ knot_dname_t *owner_copy = knot_dname_copy(sig_owner, qdata->mm);
+ if (owner_copy == NULL) {
+ mm_free(qdata->mm, info);
+ knot_rdataset_clear(&synth_rrs, qdata->mm);
+ return KNOT_ENOMEM;
+ }
+ knot_rrset_init(&info->synth_rrsig, owner_copy, rrsigs->type,
+ rrsigs->rclass, rrsigs->ttl);
+ /* Store filtered signature. */
+ info->synth_rrsig.rrs = synth_rrs;
+
+ info->rrinfo = rrinfo;
+ add_tail(&qdata->extra->rrsigs, &info->n);
+
+ return KNOT_EOK;
+}
+
+int process_query_put_rr(knot_pkt_t *pkt, knotd_qdata_t *qdata,
+ const knot_rrset_t *rr, const knot_rrset_t *rrsigs,
+ uint16_t compr_hint, uint32_t flags)
+{
+ if (rr->rrs.count < 1) {
+ return KNOT_EMALF;
+ }
+
+ /* Wildcard expansion applies only for answers. */
+ bool expand = false;
+ if (pkt->current == KNOT_ANSWER) {
+ /* Expand if RR is wildcard & we didn't query for wildcard. */
+ expand = (knot_dname_is_wildcard(rr->owner) && !knot_dname_is_wildcard(qdata->name));
+ }
+
+ int ret = KNOT_EOK;
+
+ /* If we already have compressed name on the wire and compression hint,
+ * we can just insert RRSet and fake synthesis by using compression
+ * hint. */
+ knot_rrset_t to_add;
+ if (compr_hint == KNOT_COMPR_HINT_NONE && expand) {
+ knot_dname_t *qname_cpy = knot_dname_copy(qdata->name, &pkt->mm);
+ if (qname_cpy == NULL) {
+ return KNOT_ENOMEM;
+ }
+ knot_rrset_init(&to_add, qname_cpy, rr->type, rr->rclass, rr->ttl);
+ ret = knot_rdataset_copy(&to_add.rrs, &rr->rrs, &pkt->mm);
+ if (ret != KNOT_EOK) {
+ knot_dname_free(qname_cpy, &pkt->mm);
+ return ret;
+ }
+ to_add.additional = rr->additional;
+ flags |= KNOT_PF_FREE;
+ } else {
+ to_add = *rr;
+ }
+
+ uint16_t rotate = conf()->cache.srv_ans_rotate ? knot_wire_get_id(qdata->query->wire) : 0;
+ uint16_t prev_count = pkt->rrset_count;
+ ret = knot_pkt_put_rotate(pkt, compr_hint, &to_add, rotate, flags);
+ if (ret != KNOT_EOK && (flags & KNOT_PF_FREE)) {
+ knot_rrset_clear(&to_add, &pkt->mm);
+ return ret;
+ }
+
+ const bool inserted = (prev_count != pkt->rrset_count);
+ if (inserted &&
+ !knot_rrset_empty(rrsigs) && rr->type != KNOT_RRTYPE_RRSIG) {
+ // Get rrinfo of just inserted RR.
+ knot_rrinfo_t *rrinfo = &pkt->rr_info[pkt->rrset_count - 1];
+ ret = put_rrsig(rr->owner, rr->type, rrsigs, rrinfo, qdata);
+ }
+
+ return ret;
+}
+
+/*! \brief Module implementation. */
+const knot_layer_api_t *process_query_layer(void)
+{
+ static const knot_layer_api_t api = {
+ .begin = &process_query_begin,
+ .reset = &process_query_reset,
+ .finish = &process_query_finish,
+ .consume = &process_query_in,
+ .produce = &process_query_out,
+ };
+ return &api;
+}
diff --git a/src/knot/nameserver/process_query.h b/src/knot/nameserver/process_query.h
new file mode 100644
index 0000000..c91a7be
--- /dev/null
+++ b/src/knot/nameserver/process_query.h
@@ -0,0 +1,133 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "knot/include/module.h"
+#include "knot/query/layer.h"
+#include "knot/updates/acl.h"
+#include "knot/zone/zone.h"
+
+/* Query processing module implementation. */
+const knot_layer_api_t *process_query_layer(void);
+
+/*! \brief Query processing intermediate data. */
+typedef struct knotd_qdata_extra {
+ const zone_t *zone; /*!< Zone from which is answered. */
+ list_t wildcards; /*!< Visited wildcards. */
+ list_t rrsigs; /*!< Section RRSIGs. */
+ uint8_t *opt_rr_pos; /*!< Place of the OPT RR in wire. */
+
+ /* Currently processed nodes. */
+ const zone_node_t *node, *encloser, *previous;
+
+ /* Original QNAME case. */
+ uint8_t orig_qname[KNOT_DNAME_MAXLEN];
+
+ /* Extensions. */
+ void *ext;
+ void (*ext_cleanup)(knotd_qdata_t *); /*!< Extensions cleanup callback. */
+} knotd_qdata_extra_t;
+
+/*! \brief Visited wildcard node list. */
+struct wildcard_hit {
+ node_t n;
+ const zone_node_t *node; /* Visited node. */
+ const zone_node_t *prev; /* Previous node from the SNAME. */
+ const knot_dname_t *sname; /* Name leading to this node. */
+};
+
+/*! \brief RRSIG info node list. */
+struct rrsig_info {
+ node_t n;
+ knot_rrset_t synth_rrsig; /* Synthesized RRSIG. */
+ knot_rrinfo_t *rrinfo; /* RR info. */
+};
+
+/*!
+ * \brief Check current query against ACL.
+ *
+ * \param conf Configuration.
+ * \param zone_name Current zone name.
+ * \param action ACL action.
+ * \param qdata Query data.
+ * \return true if accepted, false if denied.
+ */
+bool process_query_acl_check(conf_t *conf, const knot_dname_t *zone_name,
+ acl_action_t action, knotd_qdata_t *qdata);
+
+/*!
+ * \brief Verify current query transaction security and update query data.
+ *
+ * \param qdata
+ * \retval KNOT_EOK
+ * \retval KNOT_TSIG_EBADKEY
+ * \retval KNOT_TSIG_EBADSIG
+ * \retval KNOT_TSIG_EBADTIME
+ * \retval (other generic errors)
+ */
+int process_query_verify(knotd_qdata_t *qdata);
+
+/*!
+ * \brief Sign current query using configured TSIG keys.
+ *
+ * \param pkt Outgoing message.
+ * \param qdata Query data.
+ *
+ * \retval KNOT_E*
+ */
+int process_query_sign_response(knot_pkt_t *pkt, knotd_qdata_t *qdata);
+
+/*!
+ * \brief Restore QNAME letter case.
+ *
+ * \param pkt Incoming message.
+ * \param qdata Query data.
+ */
+static inline void process_query_qname_case_restore(knot_pkt_t *pkt, knotd_qdata_t *qdata)
+{
+ // If original QNAME is empty, query is either unparsed or for root domain.
+ if (qdata->extra->orig_qname[0] != '\0') {
+ memcpy(pkt->wire + KNOT_WIRE_HEADER_SIZE,
+ qdata->extra->orig_qname, qdata->query->qname_size);
+ }
+}
+
+/*!
+ * \brief Convert QNAME to lowercase format for processing.
+ *
+ * \param pkt Incoming message.
+ */
+static inline void process_query_qname_case_lower(knot_pkt_t *pkt)
+{
+ knot_dname_to_lower(knot_pkt_qname(pkt));
+}
+
+/*!
+ * \brief Puts RRSet to packet, will store its RRSIG for later use.
+ *
+ * \param pkt Packet to store RRSet into.
+ * \param qdata Query data structure.
+ * \param rr RRSet to be stored.
+ * \param rrsigs RRSIGs to be stored.
+ * \param compr_hint Compression hint.
+ * \param flags Flags.
+ *
+ * \return KNOT_E*
+ */
+int process_query_put_rr(knot_pkt_t *pkt, knotd_qdata_t *qdata,
+ const knot_rrset_t *rr, const knot_rrset_t *rrsigs,
+ uint16_t compr_hint, uint32_t flags);
diff --git a/src/knot/nameserver/query_module.c b/src/knot/nameserver/query_module.c
new file mode 100644
index 0000000..de85bbc
--- /dev/null
+++ b/src/knot/nameserver/query_module.c
@@ -0,0 +1,641 @@
+/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "contrib/sockaddr.h"
+#include "libknot/attribute.h"
+#include "knot/common/log.h"
+#include "knot/conf/module.h"
+#include "knot/conf/tools.h"
+#include "knot/dnssec/rrset-sign.h"
+#include "knot/dnssec/zone-sign.h"
+#include "knot/nameserver/query_module.h"
+#include "knot/nameserver/process_query.h"
+
+#ifdef HAVE_ATOMIC
+ #define ATOMIC_ADD(dst, val) __atomic_add_fetch(&(dst), (val), __ATOMIC_RELAXED)
+ #define ATOMIC_SUB(dst, val) __atomic_sub_fetch(&(dst), (val), __ATOMIC_RELAXED)
+ #define ATOMIC_SET(dst, val) __atomic_store_n(&(dst), (val), __ATOMIC_RELAXED)
+#else
+ #warning "Statistics data can be inaccurate if configured with multiple udp/tcp workers"
+ #define ATOMIC_ADD(dst, val) ((dst) += (val))
+ #define ATOMIC_SUB(dst, val) ((dst) -= (val))
+ #define ATOMIC_SET(dst, val) ((dst) = (val))
+#endif
+
+_public_
+int knotd_conf_check_ref(knotd_conf_check_args_t *args)
+{
+ return check_ref(args);
+}
+
+struct query_plan *query_plan_create(void)
+{
+ struct query_plan *plan = malloc(sizeof(struct query_plan));
+ if (plan == NULL) {
+ return NULL;
+ }
+
+ for (unsigned i = 0; i < KNOTD_STAGES; ++i) {
+ init_list(&plan->stage[i]);
+ }
+
+ return plan;
+}
+
+void query_plan_free(struct query_plan *plan)
+{
+ if (plan == NULL) {
+ return;
+ }
+
+ for (unsigned i = 0; i < KNOTD_STAGES; ++i) {
+ struct query_step *step = NULL, *next = NULL;
+ WALK_LIST_DELSAFE(step, next, plan->stage[i]) {
+ free(step);
+ }
+ }
+
+ free(plan);
+}
+
+static struct query_step *make_step(query_step_process_f process, void *ctx)
+{
+ struct query_step *step = calloc(1, sizeof(struct query_step));
+ if (step == NULL) {
+ return NULL;
+ }
+
+ step->process = process;
+ step->ctx = ctx;
+
+ return step;
+}
+
+int query_plan_step(struct query_plan *plan, knotd_stage_t stage,
+ query_step_process_f process, void *ctx)
+{
+ struct query_step *step = make_step(process, ctx);
+ if (step == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ add_tail(&plan->stage[stage], &step->node);
+
+ return KNOT_EOK;
+}
+
+_public_
+int knotd_mod_hook(knotd_mod_t *mod, knotd_stage_t stage, knotd_mod_hook_f hook)
+{
+ if (stage != KNOTD_STAGE_BEGIN && stage != KNOTD_STAGE_END) {
+ return KNOT_EINVAL;
+ }
+
+ return query_plan_step(mod->plan, stage, hook, mod);
+}
+
+_public_
+int knotd_mod_in_hook(knotd_mod_t *mod, knotd_stage_t stage, knotd_mod_in_hook_f hook)
+{
+ if (stage == KNOTD_STAGE_BEGIN || stage == KNOTD_STAGE_END) {
+ return KNOT_EINVAL;
+ }
+
+ return query_plan_step(mod->plan, stage, hook, mod);
+}
+
+knotd_mod_t *query_module_open(conf_t *conf, conf_mod_id_t *mod_id,
+ struct query_plan *plan, const knot_dname_t *zone)
+{
+ if (conf == NULL || mod_id == NULL || plan == NULL) {
+ return NULL;
+ }
+
+ /* Locate the module. */
+ const module_t *mod = conf_mod_find(conf, mod_id->name + 1,
+ mod_id->name[0], false);
+ if (mod == NULL) {
+ return NULL;
+ }
+
+ /* Create query module. */
+ knotd_mod_t *module = calloc(1, sizeof(knotd_mod_t));
+ if (module == NULL) {
+ return NULL;
+ }
+
+ module->plan = plan;
+ module->config = conf;
+ module->zone = zone;
+ module->id = mod_id;
+ module->api = mod->api;
+
+ return module;
+}
+
+void query_module_close(knotd_mod_t *module)
+{
+ if (module == NULL) {
+ return;
+ }
+
+ knotd_mod_stats_free(module);
+ conf_free_mod_id(module->id);
+
+ zone_sign_ctx_free(module->sign_ctx);
+ free_zone_keys(module->keyset);
+ free(module->keyset);
+ kdnssec_ctx_deinit(module->dnssec);
+ free(module->dnssec);
+
+ free(module);
+}
+
+_public_
+void *knotd_mod_ctx(knotd_mod_t *mod)
+{
+ return (mod != NULL) ? mod->ctx : NULL;
+}
+
+_public_
+void knotd_mod_ctx_set(knotd_mod_t *mod, void *ctx)
+{
+ if (mod != NULL) mod->ctx = ctx;
+}
+
+_public_
+const knot_dname_t *knotd_mod_zone(knotd_mod_t *mod)
+{
+ return (mod != NULL) ? mod->zone : NULL;
+}
+
+_public_
+void knotd_mod_log(knotd_mod_t *mod, int priority, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ knotd_mod_vlog(mod, priority, fmt, args);
+ va_end(args);
+}
+
+_public_
+void knotd_mod_vlog(knotd_mod_t *mod, int priority, const char *fmt, va_list args)
+{
+ if (mod == NULL || fmt == NULL) {
+ return;
+ }
+
+ char msg[512];
+
+ if (vsnprintf(msg, sizeof(msg), fmt, args) < 0) {
+ msg[0] = '\0';
+ }
+
+ #define LOG_ARGS(mod_id, msg) "module '%s%s%.*s', %s", \
+ mod_id->name + 1, (mod_id->len > 0) ? "/" : "", (int)mod_id->len, \
+ mod_id->data, msg
+
+ if (mod->zone == NULL) {
+ log_fmt(priority, LOG_SOURCE_SERVER, LOG_ARGS(mod->id, msg));
+ } else {
+ log_fmt_zone(priority, LOG_SOURCE_ZONE, mod->zone, NULL,
+ LOG_ARGS(mod->id, msg));
+ }
+
+ #undef LOG_ARGS
+}
+
+_public_
+int knotd_mod_stats_add(knotd_mod_t *mod, const char *ctr_name, uint32_t idx_count,
+ knotd_mod_idx_to_str_f idx_to_str)
+{
+ if (mod == NULL || idx_count == 0) {
+ return KNOT_EINVAL;
+ }
+
+ mod_ctr_t *stats = NULL;
+ if (mod->stats == NULL) {
+ assert(mod->stats_count == 0);
+ stats = malloc(sizeof(*stats));
+ if (stats == NULL) {
+ return KNOT_ENOMEM;
+ }
+ mod->stats = stats;
+ } else {
+ assert(mod->stats_count > 0);
+ size_t old_size = mod->stats_count * sizeof(*stats);
+ size_t new_size = old_size + sizeof(*stats);
+ stats = realloc(mod->stats, new_size);
+ if (stats == NULL) {
+ knotd_mod_stats_free(mod);
+ return KNOT_ENOMEM;
+ }
+ mod->stats = stats;
+ stats += mod->stats_count;
+ }
+
+ mod->stats_count++;
+
+ if (idx_count == 1) {
+ stats->counter = 0;
+ } else {
+ size_t size = idx_count * sizeof(((mod_ctr_t *)0)->counter);
+ stats->counters = calloc(1, size);
+ if (stats->counters == NULL) {
+ knotd_mod_stats_free(mod);
+ return KNOT_ENOMEM;
+ }
+ stats->idx_to_str = idx_to_str;
+ }
+ stats->name = ctr_name;
+ stats->count = idx_count;
+
+ return KNOT_EOK;
+}
+
+_public_
+void knotd_mod_stats_free(knotd_mod_t *mod)
+{
+ if (mod == NULL || mod->stats == NULL) {
+ return;
+ }
+
+ for (int i = 0; i < mod->stats_count; i++) {
+ if (mod->stats[i].count > 1) {
+ free(mod->stats[i].counters);
+ }
+ }
+
+ free(mod->stats);
+}
+
+#define STATS_BODY(OPERATION) { \
+ if (mod == NULL) return; \
+ \
+ mod_ctr_t *ctr = mod->stats + ctr_id; \
+ if (ctr->count == 1) { \
+ assert(idx == 0); \
+ OPERATION(ctr->counter, val); \
+ } else { \
+ assert(idx < ctr->count); \
+ OPERATION(ctr->counters[idx], val); \
+ } \
+}
+
+_public_
+void knotd_mod_stats_incr(knotd_mod_t *mod, uint32_t ctr_id, uint32_t idx, uint64_t val)
+{
+ STATS_BODY(ATOMIC_ADD)
+}
+
+_public_
+void knotd_mod_stats_decr(knotd_mod_t *mod, uint32_t ctr_id, uint32_t idx, uint64_t val)
+{
+ STATS_BODY(ATOMIC_SUB)
+}
+
+_public_
+void knotd_mod_stats_store(knotd_mod_t *mod, uint32_t ctr_id, uint32_t idx, uint64_t val)
+{
+ STATS_BODY(ATOMIC_SET)
+}
+
+_public_
+knotd_conf_t knotd_conf_env(knotd_mod_t *mod, knotd_conf_env_t env)
+{
+ static const char *version = "Knot DNS " PACKAGE_VERSION;
+
+ knotd_conf_t out = { { 0 } };
+
+ if (mod == NULL) {
+ return out;
+ }
+
+ conf_t *config = (mod->config != NULL) ? mod->config : conf();
+
+ switch (env) {
+ case KNOTD_CONF_ENV_VERSION:
+ out.single.string = version;
+ break;
+ case KNOTD_CONF_ENV_HOSTNAME:
+ out.single.string = config->hostname;
+ break;
+ case KNOTD_CONF_ENV_WORKERS_UDP:
+ out.single.integer = conf_udp_threads(config);
+ break;
+ case KNOTD_CONF_ENV_WORKERS_TCP:
+ out.single.integer = conf_tcp_threads(config);
+ break;
+ default:
+ return out;
+ }
+
+ out.count = 1;
+
+ return out;
+}
+
+static void set_val(yp_type_t type, knotd_conf_val_t *item, conf_val_t *val)
+{
+ switch (type) {
+ case YP_TINT:
+ item->integer = conf_int(val);
+ break;
+ case YP_TBOOL:
+ item->boolean = conf_bool(val);
+ break;
+ case YP_TOPT:
+ item->option = conf_opt(val);
+ break;
+ case YP_TSTR:
+ item->string = conf_str(val);
+ break;
+ case YP_TDNAME:
+ item->dname = conf_dname(val);
+ break;
+ case YP_TADDR:
+ item->addr = conf_addr(val, NULL);
+ break;
+ case YP_TNET:
+ item->addr = conf_addr_range(val, &item->addr_max,
+ &item->addr_mask);
+ break;
+ case YP_TREF:
+ if (val->code == KNOT_EOK) {
+ conf_val(val);
+ item->data_len = val->len;
+ item->data = val->data;
+ }
+ break;
+ case YP_THEX:
+ case YP_TB64:
+ item->data = conf_bin(val, &item->data_len);
+ break;
+ case YP_TDATA:
+ item->data = conf_data(val, &item->data_len);
+ break;
+ default:
+ return;
+ }
+}
+
+static void set_conf_out(knotd_conf_t *out, conf_val_t *val)
+{
+ if (!(val->item->flags & YP_FMULTI)) {
+ out->count = (val->code == KNOT_EOK) ? 1 : 0;
+ set_val(val->item->type, &out->single, val);
+ } else {
+ size_t count = conf_val_count(val);
+ if (count == 0) {
+ return;
+ }
+
+ out->multi = malloc(count * sizeof(*out->multi));
+ if (out->multi == NULL) {
+ return;
+ }
+ memset(out->multi, 0, count * sizeof(*out->multi));
+
+ for (size_t i = 0; i < count; i++) {
+ set_val(val->item->type, &out->multi[i], val);
+ conf_val_next(val);
+ }
+ out->count = count;
+ }
+}
+
+_public_
+knotd_conf_t knotd_conf(knotd_mod_t *mod, const yp_name_t *section_name,
+ const yp_name_t *item_name, const knotd_conf_t *id)
+{
+ knotd_conf_t out = { { 0 } };
+
+ if (mod == NULL || section_name == NULL || item_name == NULL) {
+ return out;
+ }
+
+ conf_t *config = (mod->config != NULL) ? mod->config : conf();
+
+ const uint8_t *raw_id = (id != NULL) ? id->single.data : NULL;
+ size_t raw_id_len = (id != NULL) ? id->single.data_len : 0;
+ conf_val_t val = conf_rawid_get(config, section_name, item_name,
+ raw_id, raw_id_len);
+
+ set_conf_out(&out, &val);
+
+ return out;
+}
+
+_public_
+knotd_conf_t knotd_conf_mod(knotd_mod_t *mod, const yp_name_t *item_name)
+{
+ knotd_conf_t out = { { 0 } };
+
+ if (mod == NULL || item_name == NULL) {
+ return out;
+ }
+
+ conf_t *config = (mod->config != NULL) ? mod->config : conf();
+
+ conf_val_t val = conf_mod_get(config, item_name, mod->id);
+ if (val.item == NULL) {
+ return out;
+ }
+
+ set_conf_out(&out, &val);
+
+ return out;
+}
+
+_public_
+knotd_conf_t knotd_conf_zone(knotd_mod_t *mod, const yp_name_t *item_name,
+ const knot_dname_t *zone)
+{
+ knotd_conf_t out = { { 0 } };
+
+ if (mod == NULL || item_name == NULL || zone == NULL) {
+ return out;
+ }
+
+ conf_t *config = (mod->config != NULL) ? mod->config : conf();
+
+ conf_val_t val = conf_zone_get(config, item_name, zone);
+
+ set_conf_out(&out, &val);
+
+ return out;
+}
+
+_public_
+knotd_conf_t knotd_conf_check_item(knotd_conf_check_args_t *args,
+ const yp_name_t *item_name)
+{
+ knotd_conf_t out = { { 0 } };
+
+ conf_val_t val = conf_rawid_get_txn(args->extra->conf, args->extra->txn,
+ args->item->name, item_name,
+ args->id, args->id_len);
+
+ set_conf_out(&out, &val);
+
+ return out;
+}
+
+_public_
+bool knotd_conf_addr_range_match(const knotd_conf_t *range,
+ const struct sockaddr_storage *addr)
+{
+ if (range == NULL || addr == NULL) {
+ return false;
+ }
+
+ for (size_t i = 0; i < range->count; i++) {
+ knotd_conf_val_t *val = &range->multi[i];
+ if (val->addr_max.ss_family == AF_UNSPEC) {
+ if (sockaddr_net_match((struct sockaddr *)addr,
+ (struct sockaddr *)&val->addr,
+ val->addr_mask)) {
+ return true;
+ }
+ } else {
+ if (sockaddr_range_match((struct sockaddr *)addr,
+ (struct sockaddr *)&val->addr,
+ (struct sockaddr *)&val->addr_max)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+_public_
+void knotd_conf_free(knotd_conf_t *conf)
+{
+ if (conf == NULL) {
+ return;
+ }
+
+ if (conf->count > 0 && conf->multi != NULL) {
+ memset(conf->multi, 0, conf->count * sizeof(*conf->multi));
+ free(conf->multi);
+ }
+ memset(conf, 0, sizeof(*conf));
+}
+
+_public_
+const knot_dname_t *knotd_qdata_zone_name(knotd_qdata_t *qdata)
+{
+ if (qdata == NULL || qdata->extra->zone == NULL) {
+ return NULL;
+ }
+
+ return qdata->extra->zone->name;
+}
+
+_public_
+knot_rrset_t knotd_qdata_zone_apex_rrset(knotd_qdata_t *qdata, uint16_t type)
+{
+ if (qdata == NULL || qdata->extra->zone == NULL ||
+ qdata->extra->zone->contents == NULL) {
+ return node_rrset(NULL, type);
+ }
+
+ return node_rrset(qdata->extra->zone->contents->apex, type);
+}
+
+_public_
+int knotd_mod_dnssec_init(knotd_mod_t *mod)
+{
+ if (mod == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ mod->dnssec = calloc(1, sizeof(*(mod->dnssec)));
+ if (mod->dnssec == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ conf_val_t conf = conf_zone_get(mod->config, C_DNSSEC_SIGNING, mod->zone);
+ int ret = kdnssec_ctx_init(mod->config, mod->dnssec, mod->zone,
+ conf_bool(&conf) ? NULL : mod->id);
+ if (ret != KNOT_EOK) {
+ free(mod->dnssec);
+ return ret;
+ }
+
+ return KNOT_EOK;
+}
+
+_public_
+int knotd_mod_dnssec_load_keyset(knotd_mod_t *mod, bool verbose)
+{
+ if (mod == NULL || mod->dnssec == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ mod->keyset = calloc(1, sizeof(*(mod->keyset)));
+ if (mod->keyset == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ int ret = load_zone_keys(mod->dnssec, mod->keyset, verbose);
+ if (ret != KNOT_EOK) {
+ free(mod->keyset);
+ mod->keyset = NULL;
+ return ret;
+ }
+
+ mod->sign_ctx = zone_sign_ctx(mod->keyset, mod->dnssec);
+ if (mod->sign_ctx == NULL) {
+ free_zone_keys(mod->keyset);
+ free(mod->keyset);
+ mod->keyset = NULL;
+ return KNOT_ENOMEM;
+ }
+
+ return KNOT_EOK;
+}
+
+_public_
+void knotd_mod_dnssec_unload_keyset(knotd_mod_t *mod)
+{
+ if (mod != NULL && mod->keyset != NULL) {
+ zone_sign_ctx_free(mod->sign_ctx);
+ mod->sign_ctx = NULL;
+
+ free_zone_keys(mod->keyset);
+ free(mod->keyset);
+ mod->keyset = NULL;
+ }
+}
+
+_public_
+int knotd_mod_dnssec_sign_rrset(knotd_mod_t *mod, knot_rrset_t *rrsigs,
+ const knot_rrset_t *rrset, knot_mm_t *mm)
+{
+ if (mod == NULL || rrsigs == NULL || rrset == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ return knot_sign_rrset2(rrsigs, rrset, mod->sign_ctx, mm);
+}
diff --git a/src/knot/nameserver/query_module.h b/src/knot/nameserver/query_module.h
new file mode 100644
index 0000000..3d2e867
--- /dev/null
+++ b/src/knot/nameserver/query_module.h
@@ -0,0 +1,98 @@
+/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "libknot/libknot.h"
+#include "knot/conf/conf.h"
+#include "knot/dnssec/context.h"
+#include "knot/dnssec/zone-keys.h"
+#include "knot/include/module.h"
+#include "contrib/ucw/lists.h"
+
+#ifdef HAVE_ATOMIC
+ #define ATOMIC_GET(src) __atomic_load_n(&(src), __ATOMIC_RELAXED)
+#else
+ #define ATOMIC_GET(src) (src)
+#endif
+
+#define KNOTD_STAGES (KNOTD_STAGE_END + 1)
+
+typedef unsigned (*query_step_process_f)
+ (unsigned state, knot_pkt_t *pkt, knotd_qdata_t *qdata, knotd_mod_t *mod);
+
+/*! \brief Single processing step in query processing. */
+struct query_step {
+ node_t node;
+ void *ctx;
+ query_step_process_f process;
+};
+
+/*! Query plan represents a sequence of steps needed for query processing
+ * divided into several stages, where each stage represents a current response
+ * assembly phase, for example 'before processing', 'answer section' and so on.
+ */
+struct query_plan {
+ list_t stage[KNOTD_STAGES];
+};
+
+/*! \brief Create an empty query plan. */
+struct query_plan *query_plan_create(void);
+
+/*! \brief Free query plan and all planned steps. */
+void query_plan_free(struct query_plan *plan);
+
+/*! \brief Plan another step for given stage. */
+int query_plan_step(struct query_plan *plan, knotd_stage_t stage,
+ query_step_process_f process, void *ctx);
+
+/*! \brief Open query module identified by name. */
+knotd_mod_t *query_module_open(conf_t *conf, conf_mod_id_t *mod_id,
+ struct query_plan *plan, const knot_dname_t *zone);
+
+/*! \brief Close query module. */
+void query_module_close(knotd_mod_t *module);
+
+typedef char* (*mod_idx_to_str_f)(uint32_t idx, uint32_t count);
+
+typedef struct {
+ const char *name;
+ union {
+ uint64_t counter;
+ struct {
+ uint64_t *counters;
+ mod_idx_to_str_f idx_to_str;
+ };
+ };
+ uint32_t count;
+} mod_ctr_t;
+
+struct knotd_mod {
+ node_t node;
+ conf_t *config;
+ conf_mod_id_t *id;
+ struct query_plan *plan;
+ const knot_dname_t *zone;
+ const knotd_mod_api_t *api;
+ kdnssec_ctx_t *dnssec;
+ zone_keyset_t *keyset;
+ zone_sign_ctx_t *sign_ctx;
+ mod_ctr_t *stats;
+ uint32_t stats_count;
+ void *ctx;
+};
+
+void knotd_mod_stats_free(knotd_mod_t *mod);
diff --git a/src/knot/nameserver/tsig_ctx.c b/src/knot/nameserver/tsig_ctx.c
new file mode 100644
index 0000000..8b4f9b7
--- /dev/null
+++ b/src/knot/nameserver/tsig_ctx.c
@@ -0,0 +1,188 @@
+/* Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "knot/nameserver/tsig_ctx.h"
+#include "libknot/libknot.h"
+
+/*!
+ * Maximal total size for unsigned messages.
+ */
+static const size_t TSIG_BUFFER_MAX_SIZE = (UINT16_MAX * 100);
+
+void tsig_init(tsig_ctx_t *ctx, const knot_tsig_key_t *key)
+{
+ if (!ctx) {
+ return;
+ }
+
+ memset(ctx, 0, sizeof(*ctx));
+ ctx->key = key;
+}
+
+void tsig_cleanup(tsig_ctx_t *ctx)
+{
+ if (!ctx) {
+ return;
+ }
+
+ free(ctx->buffer);
+ memset(ctx, 0, sizeof(*ctx));
+}
+
+void tsig_reset(tsig_ctx_t *ctx)
+{
+ if (!ctx) {
+ return;
+ }
+
+ const knot_tsig_key_t *backup = ctx->key;
+ tsig_cleanup(ctx);
+ tsig_init(ctx, backup);
+}
+
+int tsig_sign_packet(tsig_ctx_t *ctx, knot_pkt_t *packet)
+{
+ if (!ctx || !packet) {
+ return KNOT_EINVAL;
+ }
+
+ if (ctx->key == NULL) {
+ return KNOT_EOK;
+ }
+
+ int ret = KNOT_ERROR;
+ if (ctx->digest_size == 0) {
+ ctx->digest_size = dnssec_tsig_algorithm_size(ctx->key->algorithm);
+ ret = knot_tsig_sign(packet->wire, &packet->size, packet->max_size,
+ NULL, 0,
+ ctx->digest, &ctx->digest_size,
+ ctx->key, 0, 0);
+ } else {
+ uint8_t previous_digest[ctx->digest_size];
+ memcpy(previous_digest, ctx->digest, ctx->digest_size);
+
+ ret = knot_tsig_sign_next(packet->wire, &packet->size, packet->max_size,
+ previous_digest, ctx->digest_size,
+ ctx->digest, &ctx->digest_size,
+ ctx->key, packet->wire, packet->size);
+ }
+
+ return ret;
+}
+
+static int update_ctx_after_verify(tsig_ctx_t *ctx, knot_rrset_t *tsig_rr)
+{
+ assert(ctx);
+ assert(tsig_rr);
+
+ if (ctx->digest_size != knot_tsig_rdata_mac_length(tsig_rr)) {
+ return KNOT_EMALF;
+ }
+
+ memcpy(ctx->digest, knot_tsig_rdata_mac(tsig_rr), ctx->digest_size);
+ ctx->prev_signed_time = knot_tsig_rdata_time_signed(tsig_rr);
+ ctx->unsigned_count = 0;
+ ctx->buffer_used = 0;
+
+ return KNOT_EOK;
+}
+
+static int buffer_add_packet(tsig_ctx_t *ctx, knot_pkt_t *packet)
+{
+ size_t need = ctx->buffer_used + packet->size;
+
+ // Inflate the buffer if necessary.
+
+ if (need > TSIG_BUFFER_MAX_SIZE) {
+ return KNOT_ENOMEM;
+ }
+
+ if (need > ctx->buffer_size) {
+ uint8_t *buffer = realloc(ctx->buffer, need);
+ if (!buffer) {
+ return KNOT_ENOMEM;
+ }
+
+ ctx->buffer = buffer;
+ ctx->buffer_size = need;
+ }
+
+ // Buffer the packet.
+
+ uint8_t *write = ctx->buffer + ctx->buffer_used;
+ memcpy(write, packet->wire, packet->size);
+ ctx->buffer_used = need;
+
+ return KNOT_EOK;
+}
+
+int tsig_verify_packet(tsig_ctx_t *ctx, knot_pkt_t *packet)
+{
+ if (!ctx || !packet) {
+ return KNOT_EINVAL;
+ }
+
+ if (ctx->key == NULL) {
+ return KNOT_EOK;
+ }
+
+ int ret = buffer_add_packet(ctx, packet);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Unsigned packet.
+
+ if (packet->tsig_rr == NULL) {
+ ctx->unsigned_count += 1;
+ return KNOT_EOK;
+ }
+
+ // Signed packet.
+
+ if (ctx->prev_signed_time == 0) {
+ ret = knot_tsig_client_check(packet->tsig_rr, ctx->buffer,
+ ctx->buffer_used, ctx->digest,
+ ctx->digest_size, ctx->key, 0);
+ } else {
+ ret = knot_tsig_client_check_next(packet->tsig_rr, ctx->buffer,
+ ctx->buffer_used, ctx->digest,
+ ctx->digest_size, ctx->key,
+ ctx->prev_signed_time);
+ }
+
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = update_ctx_after_verify(ctx, packet->tsig_rr);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ return KNOT_EOK;
+}
+
+unsigned tsig_unsigned_count(tsig_ctx_t *ctx)
+{
+ if (!ctx) {
+ return -1;
+ }
+
+ return ctx->unsigned_count;
+}
diff --git a/src/knot/nameserver/tsig_ctx.h b/src/knot/nameserver/tsig_ctx.h
new file mode 100644
index 0000000..256ada3
--- /dev/null
+++ b/src/knot/nameserver/tsig_ctx.h
@@ -0,0 +1,97 @@
+/* Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#include "libknot/packet/pkt.h"
+#include "libknot/tsig.h"
+
+#define TSIG_MAX_DIGEST_SIZE 64
+
+/*!
+ \brief TSIG context.
+ */
+typedef struct tsig_ctx {
+ const knot_tsig_key_t *key;
+ uint64_t prev_signed_time;
+
+ uint8_t digest[TSIG_MAX_DIGEST_SIZE];
+ size_t digest_size;
+
+ /* Unsigned packets handling. */
+ unsigned unsigned_count;
+ uint8_t *buffer;
+ size_t buffer_used;
+ size_t buffer_size;
+} tsig_ctx_t;
+
+/*!
+ * \brief Initialize TSIG context.
+ *
+ * \param ctx TSIG context to be initialized.
+ * \param key Key to be used for signing. If NULL, all performed operations
+ * will do nothing and always successful.
+ */
+void tsig_init(tsig_ctx_t *ctx, const knot_tsig_key_t *key);
+
+/*!
+ * \brief Cleanup TSIG context.
+ *
+ * \param ctx TSIG context to be cleaned up.
+ */
+void tsig_cleanup(tsig_ctx_t *ctx);
+
+/*!
+ * \brief Reset TSIG context for new message exchange.
+ */
+void tsig_reset(tsig_ctx_t *ctx);
+
+/*!
+ * \brief Sign outgoing packet.
+ *
+ * \param ctx TSIG signing context.
+ * \param packet Packet to be signed.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int tsig_sign_packet(tsig_ctx_t *ctx, knot_pkt_t *packet);
+
+/*!
+ * \brief Verify incoming packet.
+ *
+ * If the packet is not signed, the function will succeed, but an internal
+ * counter of unsigned packets is increased. When a packet is signed, the
+ * same counter is reset to zero.
+ *
+ * \see tsig_unsigned_count
+ *
+ * \param ctx TSIG signing context.
+ * \param packet Packet to be verified.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int tsig_verify_packet(tsig_ctx_t *ctx, knot_pkt_t *packet);
+
+/*!
+ * \brief Get number of unsigned packets since the last signed one.
+ *
+ * \param ctx TSIG signing context.
+ *
+ * \return Number of unsigned packets since the last signed one.
+ */
+unsigned tsig_unsigned_count(tsig_ctx_t *ctx);
diff --git a/src/knot/nameserver/update.c b/src/knot/nameserver/update.c
new file mode 100644
index 0000000..a9d0475
--- /dev/null
+++ b/src/knot/nameserver/update.c
@@ -0,0 +1,477 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <sys/socket.h>
+
+#include "libdnssec/random.h"
+#include "knot/common/log.h"
+#include "knot/dnssec/zone-events.h"
+#include "knot/events/handlers.h"
+#include "knot/query/capture.h"
+#include "knot/query/requestor.h"
+#include "knot/nameserver/update.h"
+#include "knot/nameserver/internet.h"
+#include "knot/nameserver/process_query.h"
+#include "knot/nameserver/log.h"
+#include "knot/updates/ddns.h"
+#include "knot/updates/apply.h"
+#include "knot/events/events.h"
+#include "libknot/libknot.h"
+#include "contrib/net.h"
+#include "contrib/time.h"
+
+#define UPDATE_LOG(priority, qdata, fmt...) \
+ ns_log(priority, knot_pkt_qname(qdata->query), LOG_OPERATION_UPDATE, \
+ LOG_DIRECTION_IN, (struct sockaddr *)qdata->params->remote, fmt)
+
+static void init_qdata_from_request(knotd_qdata_t *qdata,
+ const zone_t *zone,
+ struct knot_request *req,
+ knotd_qdata_params_t *params,
+ knotd_qdata_extra_t *extra)
+{
+ memset(qdata, 0, sizeof(*qdata));
+ qdata->params = params;
+ qdata->query = req->query;
+ qdata->sign = req->sign;
+ qdata->extra = extra;
+ memset(extra, 0, sizeof(*extra));
+ qdata->extra->zone = zone;
+}
+
+static int check_prereqs(struct knot_request *request,
+ const zone_t *zone, zone_update_t *update,
+ knotd_qdata_t *qdata)
+{
+ uint16_t rcode = KNOT_RCODE_NOERROR;
+ int ret = ddns_process_prereqs(request->query, update, &rcode);
+ if (ret != KNOT_EOK) {
+ UPDATE_LOG(LOG_WARNING, qdata, "prerequisites not met (%s)",
+ knot_strerror(ret));
+ assert(rcode != KNOT_RCODE_NOERROR);
+ knot_wire_set_rcode(request->resp->wire, rcode);
+ return ret;
+ }
+
+ return KNOT_EOK;
+}
+
+static int process_single_update(struct knot_request *request,
+ const zone_t *zone, zone_update_t *update,
+ knotd_qdata_t *qdata)
+{
+ uint16_t rcode = KNOT_RCODE_NOERROR;
+ int ret = ddns_process_update(zone, request->query, update, &rcode);
+ if (ret != KNOT_EOK) {
+ UPDATE_LOG(LOG_WARNING, qdata, "failed to apply (%s)",
+ knot_strerror(ret));
+ assert(rcode != KNOT_RCODE_NOERROR);
+ knot_wire_set_rcode(request->resp->wire, rcode);
+ return ret;
+ }
+
+ return KNOT_EOK;
+}
+
+static void set_rcodes(list_t *requests, const uint16_t rcode)
+{
+ ptrnode_t *node = NULL;
+ WALK_LIST(node, *requests) {
+ struct knot_request *req = node->d;
+ if (knot_wire_get_rcode(req->resp->wire) == KNOT_RCODE_NOERROR) {
+ knot_wire_set_rcode(req->resp->wire, rcode);
+ }
+ }
+}
+
+static void store_original_qname(knotd_qdata_t *qdata, const knot_pkt_t *pkt)
+{
+ memcpy(qdata->extra->orig_qname, knot_pkt_qname(pkt), pkt->qname_size);
+}
+
+static int process_bulk(zone_t *zone, list_t *requests, zone_update_t *up)
+{
+ // Walk all the requests and process.
+ ptrnode_t *node = NULL;
+ WALK_LIST(node, *requests) {
+ struct knot_request *req = node->d;
+ // Init qdata structure for logging (unique per-request).
+ knotd_qdata_params_t params = {
+ .remote = &req->remote
+ };
+ knotd_qdata_t qdata;
+ knotd_qdata_extra_t extra;
+ init_qdata_from_request(&qdata, zone, req, &params, &extra);
+
+ store_original_qname(&qdata, req->query);
+ process_query_qname_case_lower(req->query);
+
+ int ret = check_prereqs(req, zone, up, &qdata);
+ if (ret != KNOT_EOK) {
+ // Skip updates with failed prereqs.
+ continue;
+ }
+
+ ret = process_single_update(req, zone, up, &qdata);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ process_query_qname_case_restore(req->query, &qdata);
+ }
+
+ return KNOT_EOK;
+}
+
+static int process_normal(conf_t *conf, zone_t *zone, list_t *requests)
+{
+ assert(requests);
+
+ // Init zone update structure
+ zone_update_t up;
+ int ret = zone_update_init(&up, zone, UPDATE_INCREMENTAL | UPDATE_SIGN);
+ if (ret != KNOT_EOK) {
+ set_rcodes(requests, KNOT_RCODE_SERVFAIL);
+ return ret;
+ }
+
+ // Process all updates.
+ ret = process_bulk(zone, requests, &up);
+ if (ret != KNOT_EOK) {
+ zone_update_clear(&up);
+ set_rcodes(requests, KNOT_RCODE_SERVFAIL);
+ return ret;
+ }
+
+ // Sign update.
+ conf_val_t val = conf_zone_get(conf, C_DNSSEC_SIGNING, zone->name);
+ bool dnssec_enable = (up.flags & UPDATE_SIGN) && conf_bool(&val);
+ if (dnssec_enable) {
+ zone_sign_reschedule_t resch = { 0 };
+ ret = knot_dnssec_sign_update(&up, &resch);
+ if (ret != KNOT_EOK) {
+ zone_update_clear(&up);
+ set_rcodes(requests, KNOT_RCODE_SERVFAIL);
+ return ret;
+ }
+ event_dnssec_reschedule(conf, zone, &resch, false); // false since we handle NOTIFY after processing ddns queue
+ }
+
+ // Apply changes.
+ ret = zone_update_commit(conf, &up);
+ zone_update_clear(&up);
+ if (ret != KNOT_EOK) {
+ if (ret == KNOT_EZONESIZE) {
+ set_rcodes(requests, KNOT_RCODE_REFUSED);
+ } else {
+ set_rcodes(requests, KNOT_RCODE_SERVFAIL);
+ }
+ return ret;
+ }
+
+ return KNOT_EOK;
+}
+
+static void process_requests(conf_t *conf, zone_t *zone, list_t *requests)
+{
+ assert(zone);
+ assert(requests);
+
+ /* Keep original state. */
+ struct timespec t_start = time_now();
+ const uint32_t old_serial = zone_contents_serial(zone->contents);
+
+ /* Process authenticated packet. */
+ int ret = process_normal(conf, zone, requests);
+ if (ret != KNOT_EOK) {
+ log_zone_error(zone->name, "DDNS, processing failed (%s)",
+ knot_strerror(ret));
+ return;
+ }
+
+ /* Evaluate response. */
+ const uint32_t new_serial = zone_contents_serial(zone->contents);
+ if (new_serial == old_serial) {
+ log_zone_info(zone->name, "DDNS, finished, no changes to the zone were made");
+ return;
+ }
+
+ struct timespec t_end = time_now();
+ log_zone_info(zone->name, "DDNS, update finished, serial %u -> %u, "
+ "%.02f seconds", old_serial, new_serial,
+ time_diff_ms(&t_start, &t_end) / 1000.0);
+
+ zone_events_schedule_at(zone, ZONE_EVENT_NOTIFY, time(NULL) + 1);
+}
+
+static int remote_forward(conf_t *conf, struct knot_request *request, conf_remote_t *remote)
+{
+ /* Copy request and assign new ID. */
+ knot_pkt_t *query = knot_pkt_new(NULL, request->query->max_size, NULL);
+ int ret = knot_pkt_copy(query, request->query);
+ if (ret != KNOT_EOK) {
+ knot_pkt_free(query);
+ return ret;
+ }
+ knot_wire_set_id(query->wire, dnssec_random_uint16_t());
+ knot_tsig_append(query->wire, &query->size, query->max_size, query->tsig_rr);
+
+ /* Prepare packet capture layer. */
+ const knot_layer_api_t *capture = query_capture_api();
+ struct capture_param capture_param = {
+ .sink = request->resp
+ };
+
+ /* Create requestor instance. */
+ struct knot_requestor re;
+ ret = knot_requestor_init(&re, capture, &capture_param, NULL);
+ if (ret != KNOT_EOK) {
+ knot_pkt_free(query);
+ return ret;
+ }
+
+ /* Create a request. */
+ const struct sockaddr *dst = (const struct sockaddr *)&remote->addr;
+ const struct sockaddr *src = (const struct sockaddr *)&remote->via;
+ struct knot_request *req = knot_request_make(re.mm, dst, src, query, NULL, 0);
+ if (req == NULL) {
+ knot_requestor_clear(&re);
+ knot_pkt_free(query);
+ return KNOT_ENOMEM;
+ }
+
+ /* Execute the request. */
+ int timeout = 1000 * conf->cache.srv_tcp_reply_timeout;
+ ret = knot_requestor_exec(&re, req, timeout);
+
+ knot_request_free(req, re.mm);
+ knot_requestor_clear(&re);
+
+ return ret;
+}
+
+static void forward_request(conf_t *conf, zone_t *zone, struct knot_request *request)
+{
+ /* Read the ddns master or the first master. */
+ conf_val_t remote = conf_zone_get(conf, C_DDNS_MASTER, zone->name);
+ if (remote.code != KNOT_EOK) {
+ remote = conf_zone_get(conf, C_MASTER, zone->name);
+ }
+
+ /* Get the number of remote addresses. */
+ conf_val_t addr = conf_id_get(conf, C_RMT, C_ADDR, &remote);
+ size_t addr_count = conf_val_count(&addr);
+ assert(addr_count > 0);
+
+ /* Try all remote addresses to forward the request to. */
+ int ret = KNOT_EOK;
+ for (size_t i = 0; i < addr_count; i++) {
+ conf_remote_t master = conf_remote(conf, &remote, i);
+
+ ret = remote_forward(conf, request, &master);
+ if (ret == KNOT_EOK) {
+ break;
+ }
+ }
+
+ /* Restore message ID and TSIG. */
+ knot_wire_set_id(request->resp->wire, knot_wire_get_id(request->query->wire));
+ knot_tsig_append(request->resp->wire, &request->resp->size,
+ request->resp->max_size, request->resp->tsig_rr);
+
+ /* Set RCODE if forwarding failed. */
+ if (ret != KNOT_EOK) {
+ knot_wire_set_rcode(request->resp->wire, KNOT_RCODE_SERVFAIL);
+ log_zone_error(zone->name, "DDNS, failed to forward updates to the master (%s)",
+ knot_strerror(ret));
+ } else {
+ log_zone_info(zone->name, "DDNS, updates forwarded to the master");
+ }
+}
+
+static void forward_requests(conf_t *conf, zone_t *zone, list_t *requests)
+{
+ assert(zone);
+ assert(requests);
+
+ ptrnode_t *node = NULL;
+ WALK_LIST(node, *requests) {
+ struct knot_request *req = node->d;
+ forward_request(conf, zone, req);
+ }
+}
+
+static bool update_tsig_check(conf_t *conf, knotd_qdata_t *qdata, struct knot_request *req)
+{
+ // Check that ACL is still valid.
+ if (!process_query_acl_check(conf, qdata->extra->zone->name, ACL_ACTION_UPDATE, qdata) ||
+ process_query_verify(qdata) != KNOT_EOK) {
+ knot_wire_set_rcode(req->resp->wire, qdata->rcode);
+ return false;
+ }
+
+ // Store signing context for response.
+ req->sign = qdata->sign;
+
+ return true;
+}
+
+static void send_update_response(conf_t *conf, const zone_t *zone, struct knot_request *req)
+{
+ if (req->resp) {
+ if (!zone_is_slave(conf, zone)) {
+ // Sign the response with TSIG where applicable
+ knotd_qdata_t qdata;
+ knotd_qdata_extra_t extra;
+ init_qdata_from_request(&qdata, zone, req, NULL, &extra);
+
+ (void)process_query_sign_response(req->resp, &qdata);
+ }
+
+ if (net_is_stream(req->fd)) {
+ int timeout = 1000 * conf->cache.srv_tcp_reply_timeout;
+ net_dns_tcp_send(req->fd, req->resp->wire, req->resp->size,
+ timeout);
+ } else {
+ net_dgram_send(req->fd, req->resp->wire, req->resp->size,
+ (struct sockaddr *)&req->remote);
+ }
+ }
+}
+
+static void free_request(struct knot_request *req)
+{
+ close(req->fd);
+ knot_pkt_free(req->query);
+ knot_pkt_free(req->resp);
+ free(req);
+}
+
+static void send_update_responses(conf_t *conf, const zone_t *zone, list_t *updates)
+{
+ ptrnode_t *node = NULL, *nxt = NULL;
+ WALK_LIST_DELSAFE(node, nxt, *updates) {
+ struct knot_request *req = node->d;
+ send_update_response(conf, zone, req);
+ free_request(req);
+ }
+ ptrlist_free(updates, NULL);
+}
+
+static int init_update_responses(conf_t *conf, const zone_t *zone, list_t *updates,
+ size_t *update_count)
+{
+ ptrnode_t *node = NULL, *nxt = NULL;
+ WALK_LIST_DELSAFE(node, nxt, *updates) {
+ struct knot_request *req = node->d;
+ req->resp = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, NULL);
+ if (req->resp == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ assert(req->query);
+ knot_pkt_init_response(req->resp, req->query);
+ if (zone_is_slave(conf, zone)) {
+ // Don't check TSIG for forwards.
+ continue;
+ }
+
+ knotd_qdata_params_t params = {
+ .remote = &req->remote
+ };
+ knotd_qdata_t qdata;
+ knotd_qdata_extra_t extra;
+ init_qdata_from_request(&qdata, zone, req, &params, &extra);
+
+ if (!update_tsig_check(conf, &qdata, req)) {
+ // ACL/TSIG check failed, send response.
+ send_update_response(conf, zone, req);
+ // Remove this request from processing list.
+ free_request(req);
+ ptrlist_rem(node, NULL);
+ *update_count -= 1;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+int update_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata)
+{
+ /* RFC1996 require SOA question. */
+ NS_NEED_QTYPE(qdata, KNOT_RRTYPE_SOA, KNOT_RCODE_FORMERR);
+
+ /* Check valid zone. */
+ NS_NEED_ZONE(qdata, KNOT_RCODE_NOTAUTH);
+
+ /* Need valid transaction security. */
+ zone_t *zone = (zone_t *)qdata->extra->zone;
+ NS_NEED_AUTH(qdata, zone->name, ACL_ACTION_UPDATE);
+ /* Check expiration. */
+ NS_NEED_ZONE_CONTENTS(qdata, KNOT_RCODE_SERVFAIL);
+
+ NS_NEED_NOT_FROZEN(qdata, KNOT_RCODE_REFUSED);
+
+ /* Restore original QNAME for DDNS ACL checks. */
+ process_query_qname_case_restore(qdata->query, qdata);
+ /* Store update into DDNS queue. */
+ int ret = zone_update_enqueue(zone, qdata->query, qdata->params);
+ if (ret != KNOT_EOK) {
+ return KNOT_STATE_FAIL;
+ }
+
+ /* No immediate response. */
+ return KNOT_STATE_NOOP;
+}
+
+void updates_execute(conf_t *conf, zone_t *zone)
+{
+ /* Get list of pending updates. */
+ list_t updates;
+ size_t update_count = zone_update_dequeue(zone, &updates);
+ if (update_count == 0) {
+ return;
+ }
+
+ /* Init updates respones. */
+ int ret = init_update_responses(conf, zone, &updates, &update_count);
+ if (ret != KNOT_EOK) {
+ /* Send what responses we can. */
+ set_rcodes(&updates, KNOT_RCODE_SERVFAIL);
+ send_update_responses(conf, zone, &updates);
+ return;
+ }
+
+ if (update_count == 0) {
+ /* All updates failed their ACL checks. */
+ return;
+ }
+
+ /* Process update list - forward if zone has master, or execute.
+ RCODEs are set. */
+ if (zone_is_slave(conf, zone)) {
+ log_zone_info(zone->name,
+ "DDNS, forwarding %zu updates", update_count);
+ forward_requests(conf, zone, &updates);
+ } else {
+ log_zone_info(zone->name,
+ "DDNS, processing %zu updates", update_count);
+ process_requests(conf, zone, &updates);
+ }
+
+ /* Send responses. */
+ send_update_responses(conf, zone, &updates);
+}
diff --git a/src/knot/nameserver/update.h b/src/knot/nameserver/update.h
new file mode 100644
index 0000000..8de10b6
--- /dev/null
+++ b/src/knot/nameserver/update.h
@@ -0,0 +1,34 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "libknot/packet/pkt.h"
+#include "knot/nameserver/process_query.h"
+#include "knot/zone/zone.h"
+
+/*!
+ * \brief UPDATE query processing module.
+ *
+ * \return KNOT_STATE_* processing states
+ */
+int update_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata);
+
+/*!
+ * \brief Processes serialized packet with DDNS. Function expects that the
+ * query is already authenticated and TSIG signature is verified.
+ */
+void updates_execute(conf_t *conf, zone_t *zone);
diff --git a/src/knot/nameserver/xfr.c b/src/knot/nameserver/xfr.c
new file mode 100644
index 0000000..c9b3f9e
--- /dev/null
+++ b/src/knot/nameserver/xfr.c
@@ -0,0 +1,96 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "knot/nameserver/xfr.h"
+#include "contrib/mempattern.h"
+
+int xfr_process_list(knot_pkt_t *pkt, xfr_put_cb put, knotd_qdata_t *qdata)
+{
+ if (pkt == NULL || qdata == NULL || qdata->extra->ext == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = KNOT_EOK;
+ knot_mm_t *mm = qdata->mm;
+ struct xfr_proc *xfer = qdata->extra->ext;
+
+ /* Check if the zone wasn't expired during multi-message transfer. */
+ zone_contents_t *contents = qdata->extra->zone->contents;
+ if (contents == NULL) {
+ return KNOT_ENOZONE;
+ }
+ knot_rrset_t soa_rr = node_rrset(contents->apex, KNOT_RRTYPE_SOA);
+
+ /* Prepend SOA on first packet. */
+ if (xfer->stats.messages == 0) {
+ ret = knot_pkt_put(pkt, 0, &soa_rr, KNOT_PF_NOTRUNC);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ /* Process all items in the list. */
+ while (!EMPTY_LIST(xfer->nodes)) {
+ ptrnode_t *head = HEAD(xfer->nodes);
+ ret = put(pkt, head->d, xfer);
+ if (ret == KNOT_EOK) { /* Finished. */
+ /* Complete change set. */
+ rem_node((node_t *)head);
+ mm_free(mm, head);
+ } else { /* Packet full or other error. */
+ break;
+ }
+ }
+
+ /* Append SOA on last packet. */
+ if (ret == KNOT_EOK) {
+ ret = knot_pkt_put(pkt, 0, &soa_rr, KNOT_PF_NOTRUNC);
+ }
+
+ /* Update counters. */
+ xfr_stats_add(&xfer->stats, pkt->size + knot_rrset_size(&qdata->opt_rr));
+
+ /* If a rrset is larger than the message,
+ * fail to avoid infinite loop of empty messages */
+ if (ret == KNOT_ESPACE && pkt->rrset_count < 1) {
+ return KNOT_ENOXFR;
+ }
+
+ return ret;
+}
+
+void xfr_stats_begin(struct xfr_stats *stats)
+{
+ assert(stats);
+
+ memset(stats, 0, sizeof(*stats));
+ stats->begin = time_now();
+}
+
+void xfr_stats_add(struct xfr_stats *stats, unsigned bytes)
+{
+ assert(stats);
+
+ stats->messages += 1;
+ stats->bytes += bytes;
+}
+
+void xfr_stats_end(struct xfr_stats *stats)
+{
+ assert(stats);
+
+ stats->end = time_now();
+}
diff --git a/src/knot/nameserver/xfr.h b/src/knot/nameserver/xfr.h
new file mode 100644
index 0000000..579e317
--- /dev/null
+++ b/src/knot/nameserver/xfr.h
@@ -0,0 +1,69 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "contrib/time.h"
+#include "contrib/ucw/lists.h"
+#include "knot/nameserver/log.h"
+#include "knot/nameserver/process_query.h"
+#include "knot/zone/contents.h"
+#include "libknot/packet/pkt.h"
+
+struct xfr_stats {
+ unsigned messages;
+ unsigned bytes;
+ struct timespec begin;
+ struct timespec end;
+};
+
+void xfr_stats_begin(struct xfr_stats *stats);
+void xfr_stats_add(struct xfr_stats *stats, unsigned bytes);
+void xfr_stats_end(struct xfr_stats *stats);
+
+static inline
+void xfr_log_finished(const knot_dname_t *zone, enum log_operation op,
+ enum log_direction dir, const struct sockaddr *remote,
+ const struct xfr_stats *stats)
+{
+ ns_log(LOG_INFO, zone, op, dir, remote,
+ "finished, %0.2f seconds, %u messages, %u bytes",
+ time_diff_ms(&stats->begin, &stats->end) / 1000.0,
+ stats->messages, stats->bytes);
+}
+
+/*!
+ * \brief Generic transfer processing state.
+ */
+struct xfr_proc {
+ list_t nodes; //!< Items to process (ptrnode_t).
+ zone_contents_t *contents; //!< Processed zone.
+ struct xfr_stats stats; //!< Packet transfer statistics.
+};
+
+/*!
+ * \brief Generic transfer processing.
+ *
+ * \return KNOT_EOK or an error
+ */
+typedef int (*xfr_put_cb)(knot_pkt_t *pkt, const void *item, struct xfr_proc *xfer);
+
+/*!
+ * \brief Put all items from xfr_proc.nodes to packet using a callback function.
+ *
+ * \note qdata->extra->ext points to struct xfr_proc* (this is xfer-specific context)
+ */
+int xfr_process_list(knot_pkt_t *pkt, xfr_put_cb put, knotd_qdata_t *qdata);
diff --git a/src/knot/query/capture.c b/src/knot/query/capture.c
new file mode 100644
index 0000000..983692f
--- /dev/null
+++ b/src/knot/query/capture.c
@@ -0,0 +1,72 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "knot/query/capture.h"
+
+static int reset(knot_layer_t *ctx)
+{
+ return KNOT_STATE_PRODUCE;
+}
+
+static int finish(knot_layer_t *ctx)
+{
+ return KNOT_STATE_NOOP;
+}
+
+static int begin(knot_layer_t *ctx, void *module_param)
+{
+ ctx->data = module_param; /* struct capture_param */
+ return reset(ctx);
+}
+
+static int prepare_query(knot_layer_t *ctx, knot_pkt_t *pkt)
+{
+ assert(pkt && ctx && ctx->data);
+ struct capture_param *param = ctx->data;
+
+ // Restore to original QNAME if requested.
+ if (param->orig_qname != NULL && param->orig_qname[0] != '\0') {
+ memcpy(pkt->wire + KNOT_WIRE_HEADER_SIZE,
+ param->orig_qname, pkt->qname_size);
+ }
+
+ return KNOT_STATE_CONSUME;
+}
+
+static int capture(knot_layer_t *ctx, knot_pkt_t *pkt)
+{
+ assert(pkt && ctx && ctx->data);
+ struct capture_param *param = ctx->data;
+
+ knot_pkt_copy(param->sink, pkt);
+
+ return KNOT_STATE_DONE;
+}
+
+const knot_layer_api_t *query_capture_api(void)
+{
+ static const knot_layer_api_t API = {
+ .begin = begin,
+ .reset = reset,
+ .finish = finish,
+ .consume = capture,
+ .produce = prepare_query,
+ };
+
+ return &API;
+}
diff --git a/src/knot/query/capture.h b/src/knot/query/capture.h
new file mode 100644
index 0000000..5c78479
--- /dev/null
+++ b/src/knot/query/capture.h
@@ -0,0 +1,33 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "knot/query/layer.h"
+#include "libknot/packet/pkt.h"
+
+/*!
+ * \brief Processing module for packet capture.
+ */
+const knot_layer_api_t *query_capture_api(void);
+
+/*!
+ * \brief Processing module parameters.
+ */
+struct capture_param {
+ knot_pkt_t *sink; /*!< Container for captured response. */
+ uint8_t *orig_qname; /*!< Original query name (case sensitive). */
+};
diff --git a/src/knot/query/layer.h b/src/knot/query/layer.h
new file mode 100644
index 0000000..d0fb12f
--- /dev/null
+++ b/src/knot/query/layer.h
@@ -0,0 +1,135 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "libknot/packet/pkt.h"
+#include "libknot/mm_ctx.h"
+#include "knot/nameserver/tsig_ctx.h"
+
+/*!
+ * \brief Layer processing states.
+ *
+ * Each state represents the state machine transition,
+ * and determines readiness for the next action.
+ */
+typedef enum {
+ KNOT_STATE_NOOP = 0, //!< Invalid.
+ KNOT_STATE_CONSUME, //!< Consume data.
+ KNOT_STATE_PRODUCE, //!< Produce data.
+ KNOT_STATE_RESET, //!< Restart processing.
+ KNOT_STATE_DONE, //!< Finished.
+ KNOT_STATE_FAIL, //!< Error.
+ KNOT_STATE_FINAL, //!< Finished and finalized.
+} knot_layer_state_t;
+
+typedef struct knot_layer_api knot_layer_api_t;
+
+/*! \brief Packet processing context. */
+typedef struct {
+ const knot_layer_api_t *api; //!< Layer API.
+ knot_mm_t *mm; //!< Processing memory context.
+ knot_layer_state_t state; //!< Processing state.
+ void *data; //!< Module specific.
+ tsig_ctx_t *tsig; //!< TODO: remove
+ unsigned flags; //!< Custom flags.
+} knot_layer_t;
+
+/*! \brief Packet processing module API. */
+struct knot_layer_api {
+ int (*begin)(knot_layer_t *ctx, void *params);
+ int (*reset)(knot_layer_t *ctx);
+ int (*finish)(knot_layer_t *ctx);
+ int (*consume)(knot_layer_t *ctx, knot_pkt_t *pkt);
+ int (*produce)(knot_layer_t *ctx, knot_pkt_t *pkt);
+};
+
+/*! \brief Helper for conditional layer call. */
+#define LAYER_CALL(layer, func, ...) \
+ assert(layer->api); \
+ if (layer->api->func) { \
+ layer->state = layer->api->func(layer, ##__VA_ARGS__); \
+ }
+
+/*!
+ * \brief Initialize packet processing context.
+ *
+ * \param ctx Layer context.
+ * \param mm Memory context.
+ * \param api Layer API.
+ */
+inline static void knot_layer_init(knot_layer_t *ctx, knot_mm_t *mm,
+ const knot_layer_api_t *api)
+{
+ memset(ctx, 0, sizeof(*ctx));
+
+ ctx->mm = mm;
+ ctx->api = api;
+ ctx->state = KNOT_STATE_NOOP;
+}
+
+/*!
+ * \brief Prepare packet processing.
+ *
+ * \param ctx Layer context.
+ * \param params Initialization params.
+ */
+inline static void knot_layer_begin(knot_layer_t *ctx, void *params)
+{
+ LAYER_CALL(ctx, begin, params);
+}
+
+/*!
+ * \brief Reset current packet processing context.
+ *
+ * \param ctx Layer context.
+ */
+inline static void knot_layer_reset(knot_layer_t *ctx)
+{
+ LAYER_CALL(ctx, reset);
+}
+
+/*!
+ * \brief Finish and close packet processing context.
+ *
+ * \param ctx Layer context.
+ */
+inline static void knot_layer_finish(knot_layer_t *ctx)
+{
+ LAYER_CALL(ctx, finish);
+}
+
+/*!
+ * \brief Add more data to layer processing.
+ *
+ * \param ctx Layer context.
+ * \param pkt Data packet.
+ */
+inline static void knot_layer_consume(knot_layer_t *ctx, knot_pkt_t *pkt)
+{
+ LAYER_CALL(ctx, consume, pkt);
+}
+
+/*!
+ * \brief Generate output from layer.
+ *
+ * \param ctx Layer context.
+ * \param pkt Data packet.
+ */
+inline static void knot_layer_produce(knot_layer_t *ctx, knot_pkt_t *pkt)
+{
+ LAYER_CALL(ctx, produce, pkt);
+}
diff --git a/src/knot/query/query.c b/src/knot/query/query.c
new file mode 100644
index 0000000..b995d53
--- /dev/null
+++ b/src/knot/query/query.c
@@ -0,0 +1,118 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "knot/query/query.h"
+
+#include <stdint.h>
+
+#include "contrib/wire_ctx.h"
+#include "libdnssec/random.h"
+#include "knot/conf/conf.h"
+#include "libknot/yparser/yptrafo.h"
+#include "libknot/rrset.h"
+
+int query_init_pkt(knot_pkt_t *pkt)
+{
+ if (!pkt) {
+ return KNOT_EINVAL;
+ }
+
+ knot_pkt_clear(pkt);
+ knot_wire_set_id(pkt->wire, dnssec_random_uint16_t());
+
+ return KNOT_EOK;
+}
+
+int query_edns_data_init(struct query_edns_data *edns_ptr, conf_t *conf,
+ const knot_dname_t *zone, int remote_family)
+{
+ if (!edns_ptr || !conf || !zone) {
+ return KNOT_EINVAL;
+ }
+
+ struct query_edns_data edns = { 0 };
+
+ // Determine max payload
+
+ switch (remote_family) {
+ case AF_INET:
+ edns.max_payload = conf->cache.srv_max_ipv4_udp_payload;
+ break;
+ case AF_INET6:
+ edns.max_payload = conf->cache.srv_max_ipv6_udp_payload;
+ break;
+ default:
+ return KNOT_EINVAL;
+ }
+
+ // Determine custom option
+
+ conf_val_t val = conf_zone_get(conf, C_REQUEST_EDNS_OPTION, zone);
+ size_t opt_len = 0;
+ const uint8_t *opt_data = conf_data(&val, &opt_len);
+ if (opt_data != NULL) {
+ wire_ctx_t ctx = wire_ctx_init_const(opt_data, opt_len);
+ edns.custom_code = wire_ctx_read_u64(&ctx);
+ edns.custom_len = wire_ctx_read_u16(&ctx);
+ edns.custom_data = ctx.position;
+ assert(ctx.error == KNOT_EOK);
+ assert(wire_ctx_available(&ctx) == edns.custom_len);
+ }
+
+ *edns_ptr = edns;
+ return KNOT_EOK;
+}
+
+int query_put_edns(knot_pkt_t *pkt, const struct query_edns_data *edns)
+{
+ if (!pkt || !edns) {
+ return KNOT_EINVAL;
+ }
+
+ // Construct EDNS RR
+
+ knot_rrset_t opt_rr = { 0 };
+ int ret = knot_edns_init(&opt_rr, edns->max_payload, 0, KNOT_EDNS_VERSION, &pkt->mm);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ if (edns->do_flag) {
+ knot_edns_set_do(&opt_rr);
+ }
+
+ if (edns->custom_code != 0) {
+ ret = knot_edns_add_option(&opt_rr, edns->custom_code,
+ edns->custom_len, edns->custom_data,
+ &pkt->mm);
+ if (ret != KNOT_EOK) {
+ knot_rrset_clear(&opt_rr, &pkt->mm);
+ return ret;
+ }
+ }
+
+ // Add result into the packet
+
+ knot_pkt_begin(pkt, KNOT_ADDITIONAL);
+
+ ret = knot_pkt_put(pkt, KNOT_COMPR_HINT_NOCOMP, &opt_rr, KNOT_PF_FREE);
+ if (ret != KNOT_EOK) {
+ knot_rrset_clear(&opt_rr, &pkt->mm);
+ return ret;
+ }
+
+ return KNOT_EOK;
+}
diff --git a/src/knot/query/query.h b/src/knot/query/query.h
new file mode 100644
index 0000000..57a12d2
--- /dev/null
+++ b/src/knot/query/query.h
@@ -0,0 +1,67 @@
+/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "knot/nameserver/log.h"
+#include "libknot/packet/pkt.h"
+
+/*!
+ * \brief EDNS data.
+ */
+struct query_edns_data {
+ uint16_t max_payload;
+ bool do_flag;
+
+ // Custom EDNS option:
+ uint16_t custom_code;
+ const uint8_t *custom_data;
+ uint16_t custom_len;
+};
+
+/*!
+ * \brief Initialize new packet.
+ *
+ * Clear the packet and generate random transaction ID.
+ *
+ * \param pkt Packet to initialize.
+ *
+ * \return Always KNOT_EOK if valid parameters supplied.
+ */
+int query_init_pkt(knot_pkt_t *pkt);
+
+/*!
+ * \brief Initialize EDNS parameters from server configuration.
+ *
+ * \param[out] edns EDNS parameters to initialize.
+ * \param[in] conf Server configuration.
+ * \param[in] zone Zone name.
+ * \param[in] remote_family Address family for remote host.
+ *
+ * \return KNOT_E*
+ */
+int query_edns_data_init(struct query_edns_data *edns, conf_t *conf,
+ const knot_dname_t *zone, int remote_family);
+
+/*!
+ * \brief Append EDNS into the packet.
+ *
+ * \param pkt Packet to add EDNS into.
+ * \param edns EDNS data.
+ *
+ * \return KNOT_E*
+ */
+int query_put_edns(knot_pkt_t *pkt, const struct query_edns_data *edns);
diff --git a/src/knot/query/requestor.c b/src/knot/query/requestor.c
new file mode 100644
index 0000000..d28b9c9
--- /dev/null
+++ b/src/knot/query/requestor.c
@@ -0,0 +1,328 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "libknot/attribute.h"
+#include "knot/query/requestor.h"
+#include "libknot/errcode.h"
+#include "contrib/mempattern.h"
+#include "contrib/net.h"
+#include "contrib/sockaddr.h"
+
+static bool use_tcp(struct knot_request *request)
+{
+ return (request->flags & KNOT_RQ_UDP) == 0;
+}
+
+static bool is_answer_to_query(const knot_pkt_t *query, const knot_pkt_t *answer)
+{
+ return knot_wire_get_id(query->wire) == knot_wire_get_id(answer->wire);
+}
+
+/*! \brief Ensure a socket is connected. */
+static int request_ensure_connected(struct knot_request *request)
+{
+ if (request->fd >= 0) {
+ return KNOT_EOK;
+ }
+
+ int sock_type = use_tcp(request) ? SOCK_STREAM : SOCK_DGRAM;
+ request->fd = net_connected_socket(sock_type,
+ (struct sockaddr *)&request->remote,
+ (struct sockaddr *)&request->source);
+ if (request->fd < 0) {
+ return KNOT_ECONN;
+ }
+
+ return KNOT_EOK;
+}
+
+static int request_send(struct knot_request *request, int timeout_ms)
+{
+ /* Initiate non-blocking connect if not connected. */
+ int ret = request_ensure_connected(request);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ /* Send query, construct if not exists. */
+ knot_pkt_t *query = request->query;
+ uint8_t *wire = query->wire;
+ size_t wire_len = query->size;
+
+ /* Send query. */
+ if (use_tcp(request)) {
+ ret = net_dns_tcp_send(request->fd, wire, wire_len, timeout_ms);
+ } else {
+ ret = net_dgram_send(request->fd, wire, wire_len, NULL);
+ }
+ if (ret != wire_len) {
+ return KNOT_ECONN;
+ }
+
+ return KNOT_EOK;
+}
+
+static int request_recv(struct knot_request *request, int timeout_ms)
+{
+ knot_pkt_t *resp = request->resp;
+ knot_pkt_clear(resp);
+
+ /* Wait for readability */
+ int ret = request_ensure_connected(request);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ /* Receive it */
+ if (use_tcp(request)) {
+ ret = net_dns_tcp_recv(request->fd, resp->wire, resp->max_size, timeout_ms);
+ } else {
+ ret = net_dgram_recv(request->fd, resp->wire, resp->max_size, timeout_ms);
+ }
+ if (ret <= 0) {
+ resp->size = 0;
+ if (ret == 0) {
+ return KNOT_ECONN;
+ }
+ return ret;
+ }
+
+ resp->size = ret;
+ return ret;
+}
+
+struct knot_request *knot_request_make(knot_mm_t *mm,
+ const struct sockaddr *remote,
+ const struct sockaddr *source,
+ knot_pkt_t *query,
+ const knot_tsig_key_t *tsig_key,
+ unsigned flags)
+{
+ if (remote == NULL || query == NULL) {
+ return NULL;
+ }
+
+ struct knot_request *request = mm_alloc(mm, sizeof(*request));
+ if (request == NULL) {
+ return NULL;
+ }
+ memset(request, 0, sizeof(*request));
+
+ request->resp = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, mm);
+ if (request->resp == NULL) {
+ mm_free(mm, request);
+ return NULL;
+ }
+
+ request->query = query;
+ request->fd = -1;
+ request->flags = flags;
+ memcpy(&request->remote, remote, sockaddr_len(remote));
+ if (source) {
+ memcpy(&request->source, source, sockaddr_len(source));
+ } else {
+ request->source.ss_family = AF_UNSPEC;
+ }
+
+ if (tsig_key && tsig_key->algorithm == DNSSEC_TSIG_UNKNOWN) {
+ tsig_key = NULL;
+ }
+ tsig_init(&request->tsig, tsig_key);
+
+ return request;
+}
+
+void knot_request_free(struct knot_request *request, knot_mm_t *mm)
+{
+ if (request == NULL) {
+ return;
+ }
+
+ if (request->fd >= 0) {
+ close(request->fd);
+ }
+ knot_pkt_free(request->query);
+ knot_pkt_free(request->resp);
+ tsig_cleanup(&request->tsig);
+
+ mm_free(mm, request);
+}
+
+int knot_requestor_init(struct knot_requestor *requestor,
+ const knot_layer_api_t *proc, void *proc_param,
+ knot_mm_t *mm)
+{
+ if (requestor == NULL || proc == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ memset(requestor, 0, sizeof(*requestor));
+
+ requestor->mm = mm;
+ knot_layer_init(&requestor->layer, mm, proc);
+ knot_layer_begin(&requestor->layer, proc_param);
+
+ return KNOT_EOK;
+}
+
+void knot_requestor_clear(struct knot_requestor *requestor)
+{
+ if (requestor == NULL) {
+ return;
+ }
+
+ knot_layer_finish(&requestor->layer);
+
+ memset(requestor, 0, sizeof(*requestor));
+}
+
+static int request_reset(struct knot_requestor *req,
+ struct knot_request *last)
+{
+ knot_layer_reset(&req->layer);
+ tsig_reset(&last->tsig);
+
+ if (req->layer.flags & KNOT_RQ_LAYER_CLOSE) {
+ req->layer.flags &= ~KNOT_RQ_LAYER_CLOSE;
+ if (last->fd >= 0) {
+ close(last->fd);
+ last->fd = -1;
+ }
+ }
+
+ if (req->layer.state == KNOT_STATE_RESET) {
+ return KNOT_LAYER_ERROR;
+ }
+
+ return KNOT_EOK;
+}
+
+static int request_produce(struct knot_requestor *req,
+ struct knot_request *last,
+ int timeout_ms)
+{
+ knot_layer_produce(&req->layer, last->query);
+
+ int ret = tsig_sign_packet(&last->tsig, last->query);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // TODO: verify condition
+ if (req->layer.state == KNOT_STATE_CONSUME) {
+ ret = request_send(last, timeout_ms);
+ }
+
+ return ret;
+}
+
+static int request_consume(struct knot_requestor *req,
+ struct knot_request *last,
+ int timeout_ms)
+{
+ int ret = request_recv(last, timeout_ms);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = knot_pkt_parse(last->resp, 0);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ if (!is_answer_to_query(last->query, last->resp)) {
+ return KNOT_EMALF;
+ }
+
+ ret = tsig_verify_packet(&last->tsig, last->resp);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ if (tsig_unsigned_count(&last->tsig) >= 100) {
+ return KNOT_TSIG_EBADSIG;
+ }
+
+ knot_layer_consume(&req->layer, last->resp);
+
+ return KNOT_EOK;
+}
+
+static bool layer_active(knot_layer_state_t state)
+{
+ switch (state) {
+ case KNOT_STATE_CONSUME:
+ case KNOT_STATE_PRODUCE:
+ case KNOT_STATE_RESET:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int request_io(struct knot_requestor *req, struct knot_request *last,
+ int timeout_ms)
+{
+ switch (req->layer.state) {
+ case KNOT_STATE_CONSUME:
+ return request_consume(req, last, timeout_ms);
+ case KNOT_STATE_PRODUCE:
+ return request_produce(req, last, timeout_ms);
+ case KNOT_STATE_RESET:
+ return request_reset(req, last);
+ default:
+ return KNOT_EINVAL;
+ }
+}
+
+int knot_requestor_exec(struct knot_requestor *requestor,
+ struct knot_request *request,
+ int timeout_ms)
+{
+ if (!requestor || !request) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = KNOT_EOK;
+
+ requestor->layer.tsig = &request->tsig;
+
+ /* Do I/O until the processing is satisifed or fails. */
+ while (layer_active(requestor->layer.state)) {
+ ret = request_io(requestor, request, timeout_ms);
+ if (ret != KNOT_EOK) {
+ knot_layer_finish(&requestor->layer);
+ return ret;
+ }
+ }
+
+ /* Expect complete request. */
+ if (requestor->layer.state != KNOT_STATE_DONE) {
+ ret = KNOT_LAYER_ERROR;
+ }
+
+ /* Verify last TSIG */
+ if (tsig_unsigned_count(&request->tsig) != 0) {
+ ret = KNOT_TSIG_EBADSIG;
+ }
+
+ /* Finish current query processing. */
+ knot_layer_finish(&requestor->layer);
+
+ return ret;
+}
diff --git a/src/knot/query/requestor.h b/src/knot/query/requestor.h
new file mode 100644
index 0000000..e0ee14e
--- /dev/null
+++ b/src/knot/query/requestor.h
@@ -0,0 +1,119 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include "knot/nameserver/tsig_ctx.h"
+#include "knot/query/layer.h"
+#include "libknot/mm_ctx.h"
+#include "libknot/rrtype/tsig.h"
+
+struct knot_request;
+
+/* Requestor flags. */
+enum {
+ KNOT_RQ_UDP = 1 << 0 /* Use UDP for requests. */
+};
+
+enum {
+ KNOT_RQ_LAYER_CLOSE = 1 << 0
+};
+
+/*! \brief Requestor structure.
+ *
+ * Requestor holds a FIFO of pending queries.
+ */
+struct knot_requestor {
+ knot_mm_t *mm; /*!< Memory context. */
+ knot_layer_t layer; /*!< Response processing layer. */
+};
+
+/*! \brief Request data (socket, payload, response, TSIG and endpoints). */
+struct knot_request {
+ int fd;
+ unsigned flags;
+ struct sockaddr_storage remote, source;
+ knot_pkt_t *query;
+ knot_pkt_t *resp;
+ tsig_ctx_t tsig;
+
+ knot_sign_context_t sign; /* TODO: Remove. Used in updates only, should
+ be part of the zone update context. */
+};
+
+/*!
+ * \brief Make request out of endpoints and query.
+ *
+ * \param mm Memory context.
+ * \param dst Remote endpoint address.
+ * \param src Source address (or NULL).
+ * \param query Query message.
+ * \param key TSIG key for authentication.
+ * \param flags Request flags.
+ *
+ * \return Prepared request or NULL in case of error.
+ */
+struct knot_request *knot_request_make(knot_mm_t *mm,
+ const struct sockaddr *dst,
+ const struct sockaddr *src,
+ knot_pkt_t *query,
+ const knot_tsig_key_t *key,
+ unsigned flags);
+
+/*!
+ * \brief Free request and associated data.
+ *
+ * \param request Freed request.
+ * \param mm Memory context.
+ */
+void knot_request_free(struct knot_request *request, knot_mm_t *mm);
+
+/*!
+ * \brief Initialize requestor structure.
+ *
+ * \param requestor Requestor instance.
+ * \param proc Response processing module.
+ * \param proc_param Processing module context.
+ * \param mm Memory context.
+ *
+ * \return KNOT_EOK or error
+ */
+int knot_requestor_init(struct knot_requestor *requestor,
+ const knot_layer_api_t *proc, void *proc_param,
+ knot_mm_t *mm);
+
+/*!
+ * \brief Clear the requestor structure and close pending queries.
+ *
+ * \param requestor Requestor instance.
+ */
+void knot_requestor_clear(struct knot_requestor *requestor);
+
+/*!
+ * \brief Execute a request.
+ *
+ * \param requestor Requestor instance.
+ * \param request Request instance.
+ * \param timeout_ms Timeout of each operation in miliseconds (-1 for infinity).
+ *
+ * \return KNOT_EOK or error
+ */
+int knot_requestor_exec(struct knot_requestor *requestor,
+ struct knot_request *request,
+ int timeout_ms);
diff --git a/src/knot/server/dthreads.c b/src/knot/server/dthreads.c
new file mode 100644
index 0000000..30689f5
--- /dev/null
+++ b/src/knot/server/dthreads.c
@@ -0,0 +1,766 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <urcu.h>
+
+#ifdef HAVE_PTHREAD_NP_H
+#include <pthread_np.h>
+#endif /* HAVE_PTHREAD_NP_H */
+
+#include "knot/server/dthreads.h"
+#include "libknot/libknot.h"
+
+/* BSD cpu set compatibility. */
+#if defined(HAVE_CPUSET_BSD)
+typedef cpuset_t cpu_set_t;
+#endif
+
+/*! \brief Lock thread state for R/W. */
+static inline void lock_thread_rw(dthread_t *thread)
+{
+ pthread_mutex_lock(&thread->_mx);
+}
+/*! \brief Unlock thread state for R/W. */
+static inline void unlock_thread_rw(dthread_t *thread)
+{
+ pthread_mutex_unlock(&thread->_mx);
+}
+
+/*! \brief Signalize thread state change. */
+static inline void unit_signalize_change(dt_unit_t *unit)
+{
+ pthread_mutex_lock(&unit->_report_mx);
+ pthread_cond_signal(&unit->_report);
+ pthread_mutex_unlock(&unit->_report_mx);
+}
+
+/*!
+ * \brief Update thread state with notification.
+ * \param thread Given thread.
+ * \param state New state for thread.
+ * \retval 0 on success.
+ * \retval <0 on error (EINVAL, ENOTSUP).
+ */
+static inline int dt_update_thread(dthread_t *thread, int state)
+{
+ if (thread == 0) {
+ return KNOT_EINVAL;
+ }
+
+ // Cancel with lone thread
+ dt_unit_t *unit = thread->unit;
+ if (unit == 0) {
+ return KNOT_ENOTSUP;
+ }
+
+ // Cancel current runnable if running
+ pthread_mutex_lock(&unit->_notify_mx);
+ lock_thread_rw(thread);
+ if (thread->state & (ThreadIdle | ThreadActive)) {
+
+ // Update state
+ thread->state = state;
+ unlock_thread_rw(thread);
+
+ // Notify thread
+ pthread_cond_broadcast(&unit->_notify);
+ pthread_mutex_unlock(&unit->_notify_mx);
+ } else {
+ /* Unable to update thread, it is already dead. */
+ unlock_thread_rw(thread);
+ pthread_mutex_unlock(&unit->_notify_mx);
+ return KNOT_EINVAL;
+ }
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Thread entrypoint function.
+ *
+ * When a thread is created and started, it immediately enters this function.
+ * Depending on thread state, it either enters runnable or
+ * blocks until it is awakened.
+ *
+ * This function also handles "ThreadIdle" state to quickly suspend and resume
+ * threads and mitigate thread creation costs. Also, thread runnable may
+ * be changed to alter the thread behavior on runtime
+ */
+static void *thread_ep(void *data)
+{
+ dthread_t *thread = (dthread_t *)data;
+ if (thread == 0) {
+ return 0;
+ }
+
+ // Check if is a member of unit
+ dt_unit_t *unit = thread->unit;
+ if (unit == 0) {
+ return 0;
+ }
+
+ // Unblock SIGALRM for synchronization
+ sigset_t mask;
+ (void)sigemptyset(&mask);
+ sigaddset(&mask, SIGALRM);
+ pthread_sigmask(SIG_UNBLOCK, &mask, NULL);
+
+ rcu_register_thread();
+
+ // Run loop
+ for (;;) {
+
+ // Check thread state
+ lock_thread_rw(thread);
+ if (thread->state == ThreadDead) {
+ unlock_thread_rw(thread);
+ break;
+ }
+
+ // Update data
+ thread->data = thread->_adata;
+ runnable_t _run = thread->run;
+
+ // Start runnable if thread is marked Active
+ if ((thread->state == ThreadActive) && (thread->run != 0)) {
+ unlock_thread_rw(thread);
+ _run(thread);
+ } else {
+ unlock_thread_rw(thread);
+ }
+
+ // If the runnable was cancelled, start new iteration
+ lock_thread_rw(thread);
+ if (thread->state & ThreadCancelled) {
+ thread->state &= ~ThreadCancelled;
+ unlock_thread_rw(thread);
+ continue;
+ }
+ unlock_thread_rw(thread);
+
+ // Runnable finished without interruption, mark as Idle
+ pthread_mutex_lock(&unit->_notify_mx);
+ lock_thread_rw(thread);
+ if (thread->state & ThreadActive) {
+ thread->state &= ~ThreadActive;
+ thread->state |= ThreadIdle;
+ }
+
+ // Go to sleep if idle
+ if (thread->state & ThreadIdle) {
+ unlock_thread_rw(thread);
+
+ // Signalize state change
+ unit_signalize_change(unit);
+
+ // Wait for notification from unit
+ pthread_cond_wait(&unit->_notify, &unit->_notify_mx);
+ pthread_mutex_unlock(&unit->_notify_mx);
+ } else {
+ unlock_thread_rw(thread);
+ pthread_mutex_unlock(&unit->_notify_mx);
+ }
+ }
+
+ // Thread destructor
+ if (thread->destruct) {
+ thread->destruct(thread);
+ }
+
+ // Report thread state change
+ unit_signalize_change(unit);
+ lock_thread_rw(thread);
+ thread->state |= ThreadJoinable;
+ unlock_thread_rw(thread);
+ rcu_unregister_thread();
+
+ // Return
+ return 0;
+}
+
+/*!
+ * \brief Create single thread.
+ * \retval New thread instance on success.
+ * \retval NULL on error.
+ */
+static dthread_t *dt_create_thread(dt_unit_t *unit)
+{
+ // Alloc thread
+ dthread_t *thread = malloc(sizeof(dthread_t));
+ if (thread == 0) {
+ return 0;
+ }
+
+ memset(thread, 0, sizeof(dthread_t));
+
+ // Blank thread state
+ thread->state = ThreadJoined;
+ pthread_mutex_init(&thread->_mx, 0);
+
+ // Set membership in unit
+ thread->unit = unit;
+
+ // Initialize attribute
+ pthread_attr_t *attr = &thread->_attr;
+ pthread_attr_init(attr);
+ //pthread_attr_setinheritsched(attr, PTHREAD_INHERIT_SCHED);
+ //pthread_attr_setschedpolicy(attr, SCHED_OTHER);
+ pthread_attr_setstacksize(attr, 1024*1024);
+ return thread;
+}
+
+/*! \brief Delete single thread. */
+static void dt_delete_thread(dthread_t **thread)
+{
+ if (!thread || !*thread) {
+ return;
+ }
+
+ dthread_t* thr = *thread;
+ thr->unit = 0;
+ *thread = 0;
+
+ // Delete attribute
+ pthread_attr_destroy(&(thr)->_attr);
+
+ // Delete mutex
+ pthread_mutex_destroy(&(thr)->_mx);
+
+ // Free memory
+ free(thr);
+}
+
+static dt_unit_t *dt_create_unit(int count)
+{
+ if (count <= 0) {
+ return 0;
+ }
+
+ dt_unit_t *unit = malloc(sizeof(dt_unit_t));
+ if (unit == 0) {
+ return 0;
+ }
+
+ // Initialize conditions
+ if (pthread_cond_init(&unit->_notify, 0) != 0) {
+ free(unit);
+ return 0;
+ }
+ if (pthread_cond_init(&unit->_report, 0) != 0) {
+ pthread_cond_destroy(&unit->_notify);
+ free(unit);
+ return 0;
+ }
+
+ // Initialize mutexes
+ if (pthread_mutex_init(&unit->_notify_mx, 0) != 0) {
+ pthread_cond_destroy(&unit->_notify);
+ pthread_cond_destroy(&unit->_report);
+ free(unit);
+ return 0;
+ }
+ if (pthread_mutex_init(&unit->_report_mx, 0) != 0) {
+ pthread_cond_destroy(&unit->_notify);
+ pthread_cond_destroy(&unit->_report);
+ pthread_mutex_destroy(&unit->_notify_mx);
+ free(unit);
+ return 0;
+ }
+ if (pthread_mutex_init(&unit->_mx, 0) != 0) {
+ pthread_cond_destroy(&unit->_notify);
+ pthread_cond_destroy(&unit->_report);
+ pthread_mutex_destroy(&unit->_notify_mx);
+ pthread_mutex_destroy(&unit->_report_mx);
+ free(unit);
+ return 0;
+ }
+
+ // Save unit size
+ unit->size = count;
+
+ // Alloc threads
+ unit->threads = calloc(count, sizeof(dthread_t *));
+ if (unit->threads == 0) {
+ pthread_cond_destroy(&unit->_notify);
+ pthread_cond_destroy(&unit->_report);
+ pthread_mutex_destroy(&unit->_notify_mx);
+ pthread_mutex_destroy(&unit->_report_mx);
+ pthread_mutex_destroy(&unit->_mx);
+ free(unit);
+ return 0;
+ }
+
+ // Initialize threads
+ int init_success = 1;
+ for (int i = 0; i < count; ++i) {
+ unit->threads[i] = dt_create_thread(unit);
+ if (unit->threads[i] == 0) {
+ init_success = 0;
+ break;
+ }
+ }
+
+ // Check thread initialization
+ if (!init_success) {
+
+ // Delete created threads
+ for (int i = 0; i < count; ++i) {
+ dt_delete_thread(&unit->threads[i]);
+ }
+
+ // Free rest of the unit
+ pthread_cond_destroy(&unit->_notify);
+ pthread_cond_destroy(&unit->_report);
+ pthread_mutex_destroy(&unit->_notify_mx);
+ pthread_mutex_destroy(&unit->_report_mx);
+ pthread_mutex_destroy(&unit->_mx);
+ free(unit->threads);
+ free(unit);
+ return 0;
+ }
+
+ return unit;
+}
+
+dt_unit_t *dt_create(int count, runnable_t runnable, runnable_t destructor, void *data)
+{
+ if (count <= 0) {
+ return 0;
+ }
+
+ // Create unit
+ dt_unit_t *unit = dt_create_unit(count);
+ if (unit == 0) {
+ return 0;
+ }
+
+ // Set threads common purpose
+ pthread_mutex_lock(&unit->_notify_mx);
+ dt_unit_lock(unit);
+
+ for (int i = 0; i < count; ++i) {
+ dthread_t *thread = unit->threads[i];
+ lock_thread_rw(thread);
+ thread->run = runnable;
+ thread->destruct = destructor;
+ thread->_adata = data;
+ unlock_thread_rw(thread);
+ }
+
+ dt_unit_unlock(unit);
+ pthread_mutex_unlock(&unit->_notify_mx);
+
+ return unit;
+}
+
+void dt_delete(dt_unit_t **unit)
+{
+ /*
+ * All threads must be stopped or idle at this point,
+ * or else the behavior is undefined.
+ * Sorry.
+ */
+
+ if (unit == 0) {
+ return;
+ }
+ if (*unit == 0) {
+ return;
+ }
+
+ // Compact and reclaim idle threads
+ dt_unit_t *d_unit = *unit;
+ dt_compact(d_unit);
+
+ // Delete threads
+ for (int i = 0; i < d_unit->size; ++i) {
+ dt_delete_thread(&d_unit->threads[i]);
+ }
+
+ // Deinit mutexes
+ pthread_mutex_destroy(&d_unit->_notify_mx);
+ pthread_mutex_destroy(&d_unit->_report_mx);
+ pthread_mutex_destroy(&d_unit->_mx);
+
+ // Deinit conditions
+ pthread_cond_destroy(&d_unit->_notify);
+ pthread_cond_destroy(&d_unit->_report);
+
+ // Free memory
+ free(d_unit->threads);
+ free(d_unit);
+ *unit = 0;
+}
+
+static int dt_start_id(dthread_t *thread)
+{
+ if (thread == 0) {
+ return KNOT_EINVAL;
+ }
+
+ lock_thread_rw(thread);
+
+ // Update state
+ int prev_state = thread->state;
+ thread->state |= ThreadActive;
+ thread->state &= ~ThreadIdle;
+ thread->state &= ~ThreadDead;
+ thread->state &= ~ThreadJoined;
+ thread->state &= ~ThreadJoinable;
+
+ // Do not re-create running threads
+ if (prev_state != ThreadJoined) {
+ unlock_thread_rw(thread);
+ return 0;
+ }
+
+ // Start thread
+ sigset_t mask_all, mask_old;
+ sigfillset(&mask_all);
+ sigdelset(&mask_all, SIGPROF);
+ pthread_sigmask(SIG_SETMASK, &mask_all, &mask_old);
+ int res = pthread_create(&thread->_thr, /* pthread_t */
+ &thread->_attr, /* pthread_attr_t */
+ thread_ep, /* routine: thread_ep */
+ thread); /* passed object: dthread_t */
+ pthread_sigmask(SIG_SETMASK, &mask_old, NULL);
+
+ // Unlock thread
+ unlock_thread_rw(thread);
+ return res;
+}
+
+int dt_start(dt_unit_t *unit)
+{
+ if (unit == 0) {
+ return KNOT_EINVAL;
+ }
+
+ // Lock unit
+ pthread_mutex_lock(&unit->_notify_mx);
+ dt_unit_lock(unit);
+ for (int i = 0; i < unit->size; ++i) {
+
+ dthread_t *thread = unit->threads[i];
+ int res = dt_start_id(thread);
+ if (res != 0) {
+ dt_unit_unlock(unit);
+ pthread_mutex_unlock(&unit->_notify_mx);
+ return res;
+ }
+ }
+
+ // Unlock unit
+ dt_unit_unlock(unit);
+ pthread_cond_broadcast(&unit->_notify);
+ pthread_mutex_unlock(&unit->_notify_mx);
+ return KNOT_EOK;
+}
+
+int dt_signalize(dthread_t *thread, int signum)
+{
+ if (thread == 0) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = pthread_kill(thread->_thr, signum);
+
+ /* Not thread id found or invalid signum. */
+ if (ret == EINVAL || ret == ESRCH) {
+ return KNOT_EINVAL;
+ }
+
+ /* Generic error. */
+ if (ret < 0) {
+ return KNOT_ERROR;
+ }
+
+ return KNOT_EOK;
+}
+
+int dt_join(dt_unit_t *unit)
+{
+ if (unit == 0) {
+ return KNOT_EINVAL;
+ }
+
+ for (;;) {
+
+ // Lock unit
+ pthread_mutex_lock(&unit->_report_mx);
+ dt_unit_lock(unit);
+
+ // Browse threads
+ int active_threads = 0;
+ for (int i = 0; i < unit->size; ++i) {
+
+ // Count active or cancelled but pending threads
+ dthread_t *thread = unit->threads[i];
+ lock_thread_rw(thread);
+ if (thread->state & (ThreadActive|ThreadCancelled)) {
+ ++active_threads;
+ }
+
+ // Reclaim dead threads, but only fast
+ if (thread->state & ThreadJoinable) {
+ unlock_thread_rw(thread);
+ pthread_join(thread->_thr, 0);
+ lock_thread_rw(thread);
+ thread->state = ThreadJoined;
+ unlock_thread_rw(thread);
+ } else {
+ unlock_thread_rw(thread);
+ }
+ }
+
+ // Unlock unit
+ dt_unit_unlock(unit);
+
+ // Check result
+ if (active_threads == 0) {
+ pthread_mutex_unlock(&unit->_report_mx);
+ break;
+ }
+
+ // Wait for a thread to finish
+ pthread_cond_wait(&unit->_report, &unit->_report_mx);
+ pthread_mutex_unlock(&unit->_report_mx);
+ }
+
+ return KNOT_EOK;
+}
+
+int dt_stop(dt_unit_t *unit)
+{
+ if (unit == 0) {
+ return KNOT_EINVAL;
+ }
+
+ // Lock unit
+ pthread_mutex_lock(&unit->_notify_mx);
+ dt_unit_lock(unit);
+
+ // Signalize all threads to stop
+ for (int i = 0; i < unit->size; ++i) {
+
+ // Lock thread
+ dthread_t *thread = unit->threads[i];
+ lock_thread_rw(thread);
+ if (thread->state & (ThreadIdle | ThreadActive)) {
+ thread->state = ThreadDead | ThreadCancelled;
+ dt_signalize(thread, SIGALRM);
+ }
+ unlock_thread_rw(thread);
+ }
+
+ // Unlock unit
+ dt_unit_unlock(unit);
+
+ // Broadcast notification
+ pthread_cond_broadcast(&unit->_notify);
+ pthread_mutex_unlock(&unit->_notify_mx);
+
+ return KNOT_EOK;
+}
+
+int dt_setaffinity(dthread_t *thread, unsigned* cpu_id, size_t cpu_count)
+{
+ if (thread == NULL) {
+ return KNOT_EINVAL;
+ }
+
+#ifdef HAVE_PTHREAD_SETAFFINITY_NP
+ int ret = -1;
+
+/* Linux, FreeBSD interface. */
+#if defined(HAVE_CPUSET_LINUX) || defined(HAVE_CPUSET_BSD)
+ cpu_set_t set;
+ CPU_ZERO(&set);
+ for (unsigned i = 0; i < cpu_count; ++i) {
+ CPU_SET(cpu_id[i], &set);
+ }
+ ret = pthread_setaffinity_np(thread->_thr, sizeof(cpu_set_t), &set);
+/* NetBSD interface. */
+#elif defined(HAVE_CPUSET_NETBSD)
+ cpuset_t *set = cpuset_create();
+ if (set == NULL) {
+ return KNOT_ENOMEM;
+ }
+ cpuset_zero(set);
+ for (unsigned i = 0; i < cpu_count; ++i) {
+ cpuset_set(cpu_id[i], set);
+ }
+ ret = pthread_setaffinity_np(thread->_thr, cpuset_size(set), set);
+ cpuset_destroy(set);
+#endif /* interface */
+
+ if (ret < 0) {
+ return KNOT_ERROR;
+ }
+
+#else /* HAVE_PTHREAD_SETAFFINITY_NP */
+ return KNOT_ENOTSUP;
+#endif
+
+ return KNOT_EOK;
+}
+
+int dt_activate(dthread_t *thread)
+{
+ return dt_update_thread(thread, ThreadActive);
+}
+
+int dt_cancel(dthread_t *thread)
+{
+ return dt_update_thread(thread, ThreadIdle | ThreadCancelled);
+}
+
+int dt_compact(dt_unit_t *unit)
+{
+ if (unit == 0) {
+ return KNOT_EINVAL;
+ }
+
+ // Lock unit
+ pthread_mutex_lock(&unit->_notify_mx);
+ dt_unit_lock(unit);
+
+ // Reclaim all Idle threads
+ for (int i = 0; i < unit->size; ++i) {
+
+ // Locked state update
+ dthread_t *thread = unit->threads[i];
+ lock_thread_rw(thread);
+ if (thread->state & (ThreadIdle)) {
+ thread->state = ThreadDead | ThreadCancelled;
+ dt_signalize(thread, SIGALRM);
+ }
+ unlock_thread_rw(thread);
+ }
+
+ // Notify all threads
+ pthread_cond_broadcast(&unit->_notify);
+ pthread_mutex_unlock(&unit->_notify_mx);
+
+ // Join all threads
+ for (int i = 0; i < unit->size; ++i) {
+
+ // Reclaim all dead threads
+ dthread_t *thread = unit->threads[i];
+ lock_thread_rw(thread);
+ if (thread->state & (ThreadDead)) {
+ unlock_thread_rw(thread);
+ pthread_join(thread->_thr, 0);
+ lock_thread_rw(thread);
+ thread->state = ThreadJoined;
+ unlock_thread_rw(thread);
+ } else {
+ unlock_thread_rw(thread);
+ }
+ }
+
+ // Unlock unit
+ dt_unit_unlock(unit);
+
+ return KNOT_EOK;
+}
+
+int dt_online_cpus(void)
+{
+ int ret = -1;
+/* Linux, Solaris, OS X 10.4+ */
+#ifdef _SC_NPROCESSORS_ONLN
+ ret = (int) sysconf(_SC_NPROCESSORS_ONLN);
+#else
+/* FreeBSD, NetBSD, OpenBSD, OS X < 10.4 */
+#if HAVE_SYSCTLBYNAME
+ size_t rlen = sizeof(int);
+ if (sysctlbyname("hw.ncpu", &ret, &rlen, NULL, 0) < 0) {
+ ret = -1;
+ }
+#endif
+#endif
+ return ret;
+}
+
+int dt_optimal_size(void)
+{
+ int ret = dt_online_cpus();
+ if (ret > 1) {
+ return ret;
+ }
+
+ return DEFAULT_THR_COUNT;
+}
+
+int dt_is_cancelled(dthread_t *thread)
+{
+ if (thread == 0) {
+ return 0;
+ }
+
+ return thread->state & ThreadCancelled; /* No need to be locked. */
+}
+
+unsigned dt_get_id(dthread_t *thread)
+{
+ if (thread == NULL || thread->unit == NULL) {
+ return 0;
+ }
+
+ dt_unit_t *unit = thread->unit;
+ for(int tid = 0; tid < unit->size; ++tid) {
+ if (thread == unit->threads[tid]) {
+ return tid;
+ }
+ }
+
+ return 0;
+}
+
+int dt_unit_lock(dt_unit_t *unit)
+{
+ if (unit == 0) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = pthread_mutex_lock(&unit->_mx);
+ if (ret < 0) {
+ return knot_map_errno();
+ }
+
+ return KNOT_EOK;
+}
+
+int dt_unit_unlock(dt_unit_t *unit)
+{
+ if (unit == 0) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = pthread_mutex_unlock(&unit->_mx);
+ if (ret < 0) {
+ return knot_map_errno();
+ }
+
+ return KNOT_EOK;
+}
diff --git a/src/knot/server/dthreads.h b/src/knot/server/dthreads.h
new file mode 100644
index 0000000..bb6c7b8
--- /dev/null
+++ b/src/knot/server/dthreads.h
@@ -0,0 +1,294 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \brief Threading API.
+ *
+ * Dynamic threads provide:
+ * - coherent and incoherent threading capabilities
+ * - thread repurposing
+ * - thread prioritization
+ * - on-the-fly changing of threading unit size
+ *
+ * Coherent threading unit is when all threads execute
+ * the same runnable function.
+ *
+ * Incoherent function is when at least one thread executes
+ * a different runnable than the others.
+ */
+
+#pragma once
+
+#include <pthread.h>
+
+#define DEFAULT_THR_COUNT 2 /*!< Default thread count. */
+
+/* Forward decls */
+struct dthread;
+struct dt_unit;
+
+/*!
+ * \brief Thread state enumeration.
+ */
+typedef enum {
+ ThreadJoined = 1 << 0, /*!< Thread is finished and joined. */
+ ThreadJoinable = 1 << 1, /*!< Thread is waiting to be reclaimed. */
+ ThreadCancelled = 1 << 2, /*!< Thread is cancelled, finishing task. */
+ ThreadDead = 1 << 3, /*!< Thread is finished, exiting. */
+ ThreadIdle = 1 << 4, /*!< Thread is idle, waiting for purpose. */
+ ThreadActive = 1 << 5 /*!< Thread is active, working on a task. */
+} dt_state_t;
+
+/*!
+ * \brief Thread runnable prototype.
+ *
+ * Runnable is basically a pointer to function which is called on active
+ * thread runtime.
+ *
+ * \note When implementing a runnable, keep in mind to check thread state as
+ * it may change, and implement a cooperative cancellation point.
+ *
+ * Implement this by checking dt_is_cancelled() and return
+ * as soon as possible.
+ */
+typedef int (*runnable_t)(struct dthread *);
+
+/*!
+ * \brief Single thread descriptor public API.
+ */
+typedef struct dthread {
+ volatile unsigned state; /*!< Bitfield of dt_flag flags. */
+ runnable_t run; /*!< Runnable function or 0. */
+ runnable_t destruct; /*!< Destructor function or 0. */
+ void *data; /*!< Currently active data */
+ struct dt_unit *unit; /*!< Reference to assigned unit. */
+ void *_adata; /*!< Thread-specific data. */
+ pthread_t _thr; /*!< Thread */
+ pthread_attr_t _attr; /*!< Thread attributes */
+ pthread_mutex_t _mx; /*!< Thread state change lock. */
+} dthread_t;
+
+/*!
+ * \brief Thread unit descriptor API.
+ *
+ * Thread unit consists of 1..N threads.
+ * Unit is coherent if all threads execute
+ * the same runnable.
+ */
+typedef struct dt_unit {
+ int size; /*!< Unit width (number of threads) */
+ struct dthread **threads; /*!< Array of threads */
+ pthread_cond_t _notify; /*!< Notify thread */
+ pthread_mutex_t _notify_mx; /*!< Condition mutex */
+ pthread_cond_t _report; /*!< Report thread state */
+ pthread_mutex_t _report_mx; /*!< Condition mutex */
+ pthread_mutex_t _mx; /*!< Unit lock */
+} dt_unit_t;
+
+/*!
+ * \brief Create a set of coherent threads.
+ *
+ * Coherent means, that the threads will share a common runnable and the data.
+ *
+ * \param count Requested thread count.
+ * \param runnable Runnable function for all threads.
+ * \param destructor Destructor for all threads.
+ * \param data Any data passed onto threads.
+ *
+ * \retval New instance if successful
+ * \retval NULL on error
+ */
+dt_unit_t *dt_create(int count, runnable_t runnable, runnable_t destructor, void *data);
+
+/*!
+ * \brief Free unit.
+ *
+ * \warning Behavior is undefined if threads are still active, make sure
+ * to call dt_join() first.
+ *
+ * \param unit Unit to be deleted.
+ */
+void dt_delete(dt_unit_t **unit);
+
+/*!
+ * \brief Start all threads in selected unit.
+ *
+ * \param unit Unit to be started.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_EINVAL on invalid parameters (unit is null).
+ */
+int dt_start(dt_unit_t *unit);
+
+/*!
+ * \brief Send given signal to thread.
+ *
+ * \note This is useful to interrupt some blocking I/O as well, for example
+ * with SIGALRM, which is handled by default.
+ * \note Signal handler may be overriden in runnable.
+ *
+ * \param thread Target thread instance.
+ * \param signum Signal code.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_EINVAL on invalid parameters.
+ * \retval KNOT_ERROR unspecified error.
+ */
+int dt_signalize(dthread_t *thread, int signum);
+
+/*!
+ * \brief Wait for all thread in unit to finish.
+ *
+ * \param unit Unit to be joined.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_EINVAL on invalid parameters.
+ */
+int dt_join(dt_unit_t *unit);
+
+/*!
+ * \brief Stop all threads in unit.
+ *
+ * Thread is interrupted at the nearest runnable cancellation point.
+ *
+ * \param unit Unit to be stopped.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_EINVAL on invalid parameters.
+ */
+int dt_stop(dt_unit_t *unit);
+
+/*!
+ * \brief Set thread affinity to masked CPU's.
+ *
+ * \param thread Target thread instance.
+ * \param cpu_id Array of CPU IDs to set affinity to.
+ * \param cpu_count Number of CPUs in the array, set to 0 for no CPU.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_EINVAL on invalid parameters.
+ */
+int dt_setaffinity(dthread_t *thread, unsigned* cpu_id, size_t cpu_count);
+
+/*!
+ * \brief Wake up thread from idle state.
+ *
+ * Thread is awoken from idle state and reenters runnable.
+ * This function only affects idle threads.
+ *
+ * \note Unit needs to be started with dt_start() first, as the function
+ * doesn't affect dead threads.
+ *
+ * \param thread Target thread instance.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_EINVAL on invalid parameters.
+ * \retval KNOT_ENOTSUP operation not supported.
+ */
+int dt_activate(dthread_t *thread);
+
+/*!
+ * \brief Put thread to idle state, cancells current runnable function.
+ *
+ * Thread is flagged with Cancel flag and returns from runnable at the nearest
+ * cancellation point, which requires complying runnable function.
+ *
+ * \note Thread isn't disposed, but put to idle state until it's requested
+ * again or collected by dt_compact().
+ *
+ * \param thread Target thread instance.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_EINVAL on invalid parameters.
+ */
+int dt_cancel(dthread_t *thread);
+
+/*!
+ * \brief Collect and dispose idle threads.
+ *
+ * \param unit Target unit instance.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_EINVAL on invalid parameters.
+ */
+int dt_compact(dt_unit_t *unit);
+
+/*!
+ * \brief Return number of online processors.
+ *
+ * \retval Number of online CPU's if success.
+ * \retval <0 on failure.
+ */
+int dt_online_cpus(void);
+
+/*!
+ * \brief Return optimal number of threads for instance.
+ *
+ * It is estimated as NUM_CPUs + CONSTANT.
+ * Fallback is DEFAULT_THR_COUNT (\see common.h).
+ *
+ * \return Number of threads.
+ */
+int dt_optimal_size(void);
+
+/*!
+ * \brief Return true if thread is cancelled.
+ *
+ * Synchronously check for ThreadCancelled flag.
+ *
+ * \param thread Target thread instance.
+ *
+ * \retval 1 if cancelled.
+ * \retval 0 if not cancelled.
+ */
+int dt_is_cancelled(dthread_t *thread);
+
+/*!
+ * \brief Return thread index in threading unit.
+ *
+ * \note Returns 0 when thread doesn't have a unit.
+ *
+ * \param thread Target thread instance.
+ *
+ * \return Thread index.
+ */
+unsigned dt_get_id(dthread_t *thread);
+
+/*!
+ * \brief Lock unit to prevent parallel operations which could alter unit
+ * at the same time.
+ *
+ * \param unit Target unit instance.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_EINVAL on invalid parameters.
+ * \retval KNOT_EAGAIN lack of resources to lock unit, try again.
+ * \retval KNOT_ERROR unspecified error.
+ */
+int dt_unit_lock(dt_unit_t *unit);
+
+/*!
+ * \brief Unlock unit.
+ *
+ * \see dt_unit_lock()
+ *
+ * \param unit Target unit instance.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_EINVAL on invalid parameters.
+ * \retval KNOT_EAGAIN lack of resources to unlock unit, try again.
+ * \retval KNOT_ERROR unspecified error.
+ */
+int dt_unit_unlock(dt_unit_t *unit);
diff --git a/src/knot/server/server.c b/src/knot/server/server.c
new file mode 100644
index 0000000..6d4ac44
--- /dev/null
+++ b/src/knot/server/server.c
@@ -0,0 +1,932 @@
+/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define __APPLE_USE_RFC_3542
+
+#include <stdlib.h>
+#include <assert.h>
+#include <urcu.h>
+#include <netinet/tcp.h>
+
+#include "libknot/errcode.h"
+#include "libknot/yparser/ypschema.h"
+#include "knot/common/log.h"
+#include "knot/common/stats.h"
+#include "knot/conf/confio.h"
+#include "knot/conf/migration.h"
+#include "knot/conf/module.h"
+#include "knot/dnssec/kasp/kasp_db.h"
+#include "knot/server/server.h"
+#include "knot/server/udp-handler.h"
+#include "knot/server/tcp-handler.h"
+#include "knot/zone/timers.h"
+#include "knot/zone/zonedb-load.h"
+#include "knot/worker/pool.h"
+#include "contrib/net.h"
+#include "contrib/sockaddr.h"
+#include "contrib/trim.h"
+
+/*! \brief Minimal send/receive buffer sizes. */
+enum {
+ UDP_MIN_RCVSIZE = 4096,
+ UDP_MIN_SNDSIZE = 4096,
+ TCP_MIN_RCVSIZE = 4096,
+ TCP_MIN_SNDSIZE = sizeof(uint16_t) + UINT16_MAX
+};
+
+/*! \brief Unbind interface and clear the structure. */
+static void server_deinit_iface(iface_t *iface)
+{
+ /* Free UDP handler. */
+ for (int i = 0; i < iface->fd_udp_count; i++) {
+ if (iface->fd_udp[i] > -1) {
+ close(iface->fd_udp[i]);
+ }
+ }
+ free(iface->fd_udp);
+
+ /* Free TCP handler. */
+ if (iface->fd_tcp > -1) {
+ close(iface->fd_tcp);
+ }
+
+ memset(iface, 0, sizeof(*iface));
+}
+
+/*! \brief Unbind and dispose given interface. */
+static void server_remove_iface(iface_t *iface)
+{
+ if (!iface) {
+ return;
+ }
+
+ server_deinit_iface(iface);
+ free(iface);
+}
+
+/*! \brief Set lower bound for socket option. */
+static bool setsockopt_min(int sock, int option, int min)
+{
+ int value = 0;
+ socklen_t len = sizeof(value);
+
+ if (getsockopt(sock, SOL_SOCKET, option, &value, &len) != 0) {
+ return false;
+ }
+
+ assert(len == sizeof(value));
+ if (value >= min) {
+ return true;
+ }
+
+ return setsockopt(sock, SOL_SOCKET, option, &min, sizeof(min)) == 0;
+}
+
+/*!
+ * \brief Enlarge send/receive buffers.
+ */
+static bool enlarge_net_buffers(int sock, int min_recvsize, int min_sndsize)
+{
+ return setsockopt_min(sock, SO_RCVBUF, min_recvsize) &&
+ setsockopt_min(sock, SO_SNDBUF, min_sndsize);
+}
+
+/*!
+ * \brief Enable source packet information retrieval.
+ */
+static bool enable_pktinfo(int sock, int family)
+{
+ int level = 0;
+ int option = 0;
+
+ switch (family) {
+ case AF_INET:
+ level = IPPROTO_IP;
+#if defined(IP_PKTINFO)
+ option = IP_PKTINFO; /* Linux */
+#elif defined(IP_RECVDSTADDR)
+ option = IP_RECVDSTADDR; /* BSD */
+#else
+ return false;
+#endif
+ break;
+ case AF_INET6:
+ level = IPPROTO_IPV6;
+ option = IPV6_RECVPKTINFO;
+ break;
+ default:
+ return false;
+ }
+
+ const int on = 1;
+ return setsockopt(sock, level, option, &on, sizeof(on)) == 0;
+}
+
+/**
+ * \brief Enable TCP Fast Open.
+ */
+static int enable_fastopen(int sock, int backlog)
+{
+#if defined(TCP_FASTOPEN)
+#if __APPLE__
+ if (backlog > 0) {
+ backlog = 1; // just on-off switch on macOS
+ }
+#endif
+ if (setsockopt(sock, IPPROTO_TCP, TCP_FASTOPEN, &backlog, sizeof(backlog)) != 0) {
+ return knot_map_errno();
+ }
+#endif
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Initialize new interface from config value.
+ *
+ * Both TCP and UDP sockets will be created for the interface.
+ *
+ * \param new_if Allocated memory for the interface.
+ * \param cfg_if Interface template from config.
+ *
+ * \retval 0 if successful (EOK).
+ * \retval <0 on errors (EACCES, EINVAL, ENOMEM, EADDRINUSE).
+ */
+static int server_init_iface(iface_t *new_if, struct sockaddr_storage *addr, int udp_thread_count)
+{
+ /* Initialize interface. */
+ int ret = 0;
+ memset(new_if, 0, sizeof(iface_t));
+ memcpy(&new_if->addr, addr, sizeof(struct sockaddr_storage));
+
+ /* Convert to string address format. */
+ char addr_str[SOCKADDR_STRLEN] = { 0 };
+ sockaddr_tostr(addr_str, sizeof(addr_str), (struct sockaddr *)addr);
+
+ int udp_socket_count = 1;
+ int udp_bind_flags = 0;
+
+#ifdef ENABLE_REUSEPORT
+ udp_socket_count = udp_thread_count;
+ udp_bind_flags |= NET_BIND_MULTIPLE;
+#endif
+
+ new_if->fd_udp = malloc(udp_socket_count * sizeof(int));
+ if (!new_if->fd_udp) {
+ return KNOT_ENOMEM;
+ }
+
+ /* Initialize the sockets to ensure safe early deinitialization. */
+ for (int i = 0; i < udp_socket_count; i++) {
+ new_if->fd_udp[i] = -1;
+ }
+ new_if->fd_tcp = -1;
+
+ bool warn_bind = false;
+ bool warn_bufsize = false;
+
+ /* Create bound UDP sockets. */
+ for (int i = 0; i < udp_socket_count; i++ ) {
+ int sock = net_bound_socket(SOCK_DGRAM, (struct sockaddr *)addr, udp_bind_flags);
+ if (sock == KNOT_EADDRNOTAVAIL) {
+ udp_bind_flags |= NET_BIND_NONLOCAL;
+ sock = net_bound_socket(SOCK_DGRAM, (struct sockaddr *)addr, udp_bind_flags);
+ if (sock >= 0 && !warn_bind) {
+ log_warning("address %s UDP bound, but required nonlocal bind", addr_str);
+ warn_bind = true;
+ }
+ }
+
+ if (sock < 0) {
+ log_error("cannot bind address %s (%s)", addr_str,
+ knot_strerror(sock));
+ server_deinit_iface(new_if);
+ return sock;
+ }
+
+ if (!enlarge_net_buffers(sock, UDP_MIN_RCVSIZE, UDP_MIN_SNDSIZE) &&
+ !warn_bufsize) {
+ log_warning("failed to set network buffer sizes for UDP");
+ warn_bufsize = true;
+ }
+
+ if (sockaddr_is_any((struct sockaddr *)addr) && !enable_pktinfo(sock, addr->ss_family)) {
+ log_warning("failed to enable received packet information retrieval");
+ }
+
+ new_if->fd_udp[new_if->fd_udp_count] = sock;
+ new_if->fd_udp_count += 1;
+ }
+
+ /* Create bound TCP socket. */
+ int tcp_bind_flags = 0;
+ int sock = net_bound_socket(SOCK_STREAM, (struct sockaddr *)addr, tcp_bind_flags);
+ if (sock == KNOT_EADDRNOTAVAIL) {
+ tcp_bind_flags |= NET_BIND_NONLOCAL;
+ sock = net_bound_socket(SOCK_STREAM, (struct sockaddr *)addr, tcp_bind_flags);
+ if (sock >= 0) {
+ log_warning("address %s TCP bound, but required nonlocal bind", addr_str);
+ }
+ }
+
+ if (sock < 0) {
+ log_error("cannot bind address %s (%s)", addr_str,
+ knot_strerror(sock));
+ server_deinit_iface(new_if);
+ return sock;
+ }
+
+ if (!enlarge_net_buffers(sock, TCP_MIN_RCVSIZE, TCP_MIN_SNDSIZE)) {
+ log_warning("failed to set network buffer sizes for TCP");
+ }
+
+ new_if->fd_tcp = sock;
+
+ /* Listen for incoming connections. */
+ ret = listen(sock, TCP_BACKLOG_SIZE);
+ if (ret < 0) {
+ log_error("failed to listen on TCP interface %s", addr_str);
+ server_deinit_iface(new_if);
+ return KNOT_ERROR;
+ }
+
+ /* TCP Fast Open. */
+ ret = enable_fastopen(sock, TCP_BACKLOG_SIZE);
+ if (ret < 0) {
+ log_warning("failed to enable TCP Fast Open on %s (%s)",
+ addr_str, knot_strerror(ret));
+ }
+
+ return KNOT_EOK;
+}
+
+static void remove_ifacelist(struct ref *p)
+{
+ ifacelist_t *ifaces = (ifacelist_t *)p;
+
+ /* Remove deprecated interfaces. */
+ char addr_str[SOCKADDR_STRLEN] = {0};
+ iface_t *n = NULL, *m = NULL;
+ WALK_LIST_DELSAFE(n, m, ifaces->u) {
+ sockaddr_tostr(addr_str, sizeof(addr_str), (struct sockaddr *)&n->addr);
+ log_info("removing interface %s", addr_str);
+ server_remove_iface(n);
+ }
+ WALK_LIST_DELSAFE(n, m, ifaces->l) {
+ free(n);
+ }
+
+ free(ifaces);
+}
+
+/*!
+ * \brief Update bound sockets according to configuration.
+ *
+ * \param server Server instance.
+ * \return number of added sockets.
+ */
+static int reconfigure_sockets(conf_t *conf, server_t *s)
+{
+ /* Prepare helper lists. */
+ int bound = 0;
+ ifacelist_t *oldlist = s->ifaces;
+ ifacelist_t *newlist = malloc(sizeof(ifacelist_t));
+ ref_init(&newlist->ref, &remove_ifacelist);
+ ref_retain(&newlist->ref);
+ init_list(&newlist->u);
+ init_list(&newlist->l);
+
+ /* Duplicate current list. */
+ /*! \note Pointers to addr, handlers etc. will be shared. */
+ if (s->ifaces) {
+ list_dup(&s->ifaces->u, &s->ifaces->l, sizeof(iface_t));
+ }
+
+ /* Update bound interfaces. */
+ conf_val_t listen_val = conf_get(conf, C_SRV, C_LISTEN);
+ conf_val_t rundir_val = conf_get(conf, C_SRV, C_RUNDIR);
+ char *rundir = conf_abs_path(&rundir_val, NULL);
+ while (listen_val.code == KNOT_EOK) {
+ iface_t *m = NULL;
+
+ /* Find already matching interface. */
+ int found_match = 0;
+ struct sockaddr_storage addr = conf_addr(&listen_val, rundir);
+ if (s->ifaces) {
+ WALK_LIST(m, s->ifaces->u) {
+ /* Matching port and address. */
+ if (sockaddr_cmp((struct sockaddr *)&addr,
+ (struct sockaddr *)&m->addr) == 0) {
+ found_match = 1;
+ break;
+ }
+ }
+ }
+
+ /* Found already bound interface. */
+ if (found_match) {
+ rem_node((node_t *)m);
+ } else {
+ char addr_str[SOCKADDR_STRLEN] = { 0 };
+ sockaddr_tostr(addr_str, sizeof(addr_str), (struct sockaddr *)&addr);
+ log_info("binding to interface %s", addr_str);
+
+ /* Create new interface. */
+ m = malloc(sizeof(iface_t));
+ unsigned size = s->handlers[IO_UDP].handler.unit->size;
+ if (server_init_iface(m, &addr, size) < 0) {
+ free(m);
+ m = 0;
+ }
+ }
+
+ /* Move to new list. */
+ if (m) {
+ add_tail(&newlist->l, (node_t *)m);
+ ++bound;
+ }
+
+ conf_val_next(&listen_val);
+ }
+ free(rundir);
+
+ /* Wait for readers that are reconfiguring right now. */
+ /*! \note This subsystem will be reworked in #239 */
+ for (unsigned proto = IO_UDP; proto <= IO_TCP; ++proto) {
+ dt_unit_t *tu = s->handlers[proto].handler.unit;
+ iohandler_t *ioh = &s->handlers[proto].handler;
+ for (unsigned i = 0; i < tu->size; ++i) {
+ while (ioh->thread_state[i] & ServerReload) {
+ sleep(1);
+ }
+ }
+ }
+
+ /* Publish new list. */
+ s->ifaces = newlist;
+
+ /* Update TCP+UDP ifacelist (reload all threads). */
+ unsigned thread_count = 0;
+ for (unsigned proto = IO_UDP; proto <= IO_TCP; ++proto) {
+ dt_unit_t *tu = s->handlers[proto].handler.unit;
+ for (unsigned i = 0; i < tu->size; ++i) {
+ ref_retain((ref_t *)newlist);
+ s->handlers[proto].handler.thread_state[i] |= ServerReload;
+ s->handlers[proto].handler.thread_id[i] = thread_count++;
+ if (s->state & ServerRunning) {
+ dt_activate(tu->threads[i]);
+ dt_signalize(tu->threads[i], SIGALRM);
+ }
+ }
+ }
+
+ ref_release(&oldlist->ref);
+
+ return bound;
+}
+
+int server_init(server_t *server, int bg_workers)
+{
+ if (server == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ /* Clear the structure. */
+ memset(server, 0, sizeof(server_t));
+
+ /* Initialize event scheduler. */
+ if (evsched_init(&server->sched, server) != KNOT_EOK) {
+ return KNOT_ENOMEM;
+ }
+
+ server->workers = worker_pool_create(bg_workers);
+ if (server->workers == NULL) {
+ evsched_deinit(&server->sched);
+ return KNOT_ENOMEM;
+ }
+
+ char *journal_dir = conf_journalfile(conf());
+ conf_val_t journal_size = conf_default_get(conf(), C_MAX_JOURNAL_DB_SIZE);
+ conf_val_t journal_mode = conf_default_get(conf(), C_JOURNAL_DB_MODE);
+ int ret = journal_db_init(&server->journal_db, journal_dir,
+ conf_int(&journal_size), conf_opt(&journal_mode));
+ free(journal_dir);
+ if (ret != KNOT_EOK) {
+ worker_pool_destroy(server->workers);
+ evsched_deinit(&server->sched);
+ return ret;
+ }
+
+ char *kasp_dir = conf_kaspdir(conf());
+ conf_val_t kasp_size = conf_default_get(conf(), C_MAX_KASP_DB_SIZE);
+ ret = kasp_db_init(kaspdb(), kasp_dir, conf_int(&kasp_size));
+ free(kasp_dir);
+ if (ret != KNOT_EOK) {
+ journal_db_close(&server->journal_db);
+ worker_pool_destroy(server->workers);
+ evsched_deinit(&server->sched);
+ return ret;
+ }
+
+ return KNOT_EOK;
+}
+
+void server_deinit(server_t *server)
+{
+ if (server == NULL) {
+ return;
+ }
+
+ /* Free remaining interfaces. */
+ if (server->ifaces) {
+ iface_t *n = NULL, *m = NULL;
+ WALK_LIST_DELSAFE(n, m, server->ifaces->l) {
+ server_remove_iface(n);
+ }
+ free(server->ifaces);
+ }
+
+ /* Free threads and event handlers. */
+ worker_pool_destroy(server->workers);
+
+ /* Free zone database. */
+ knot_zonedb_deep_free(&server->zone_db);
+
+ /* Free remaining events. */
+ evsched_deinit(&server->sched);
+
+ /* Close kasp_db. */
+ kasp_db_close(kaspdb());
+
+ /* Close journal database if open. */
+ journal_db_close(&server->journal_db);
+
+ /* Close persistent timers database. */
+ zone_timers_close(server->timers_db);
+
+ /* Clear the structure. */
+ memset(server, 0, sizeof(server_t));
+}
+
+static int server_init_handler(server_t *server, int index, int thread_count,
+ runnable_t runnable, runnable_t destructor)
+{
+ /* Initialize */
+ iohandler_t *h = &server->handlers[index].handler;
+ memset(h, 0, sizeof(iohandler_t));
+ h->server = server;
+ h->unit = dt_create(thread_count, runnable, destructor, h);
+ if (h->unit == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ h->thread_state = calloc(thread_count, sizeof(unsigned));
+ if (h->thread_state == NULL) {
+ dt_delete(&h->unit);
+ return KNOT_ENOMEM;
+ }
+
+ h->thread_id = calloc(thread_count, sizeof(unsigned));
+ if (h->thread_id == NULL) {
+ free(h->thread_state);
+ dt_delete(&h->unit);
+ return KNOT_ENOMEM;
+ }
+
+ return KNOT_EOK;
+}
+
+static void server_free_handler(iohandler_t *h)
+{
+ if (h == NULL || h->server == NULL) {
+ return;
+ }
+
+ /* Wait for threads to finish */
+ if (h->unit) {
+ dt_stop(h->unit);
+ dt_join(h->unit);
+ }
+
+ /* Destroy worker context. */
+ dt_delete(&h->unit);
+ free(h->thread_state);
+ free(h->thread_id);
+ memset(h, 0, sizeof(iohandler_t));
+}
+
+int server_start(server_t *server, bool async)
+{
+ if (server == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ /* Start workers. */
+ worker_pool_start(server->workers);
+
+ /* Wait for enqueued events if not asynchronous. */
+ if (!async) {
+ worker_pool_wait(server->workers);
+ }
+
+ /* Start evsched handler. */
+ evsched_start(&server->sched);
+
+ /* Start I/O handlers. */
+ server->state |= ServerRunning;
+ for (int proto = IO_UDP; proto <= IO_TCP; ++proto) {
+ if (server->handlers[proto].size > 0) {
+ int ret = dt_start(server->handlers[proto].handler.unit);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+void server_wait(server_t *server)
+{
+ if (server == NULL) {
+ return;
+ }
+
+ evsched_join(&server->sched);
+ worker_pool_join(server->workers);
+
+ for (int proto = IO_UDP; proto <= IO_TCP; ++proto) {
+ if (server->handlers[proto].size > 0) {
+ server_free_handler(&server->handlers[proto].handler);
+ }
+ }
+}
+
+static int reload_conf(conf_t *new_conf)
+{
+ yp_schema_purge_dynamic(new_conf->schema);
+
+ /* Re-load common modules. */
+ int ret = conf_mod_load_common(new_conf);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ /* Re-import zonefile if specified. */
+ const char *filename = conf()->filename;
+ if (filename != NULL) {
+ log_info("reloading configuration file '%s'", filename);
+
+ /* Import the configuration file. */
+ ret = conf_import(new_conf, filename, true);
+ if (ret != KNOT_EOK) {
+ log_error("failed to load configuration file (%s)",
+ knot_strerror(ret));
+ return ret;
+ }
+ } else {
+ log_info("reloading configuration database");
+
+ /* Re-load extra modules. */
+ for (conf_iter_t iter = conf_iter(new_conf, C_MODULE);
+ iter.code == KNOT_EOK; conf_iter_next(new_conf, &iter)) {
+ conf_val_t id = conf_iter_id(new_conf, &iter);
+ conf_val_t file = conf_id_get(new_conf, C_MODULE, C_FILE, &id);
+ ret = conf_mod_load_extra(new_conf, conf_str(&id), conf_str(&file), false);
+ if (ret != KNOT_EOK) {
+ conf_iter_finish(new_conf, &iter);
+ return ret;
+ }
+ }
+ }
+
+ conf_mod_load_purge(new_conf, false);
+
+ // Migrate from old schema.
+ ret = conf_migrate(new_conf);
+ if (ret != KNOT_EOK) {
+ log_error("failed to migrate configuration (%s)", knot_strerror(ret));
+ }
+
+ /* Refresh hostname. */
+ conf_refresh_hostname(new_conf);
+
+ return KNOT_EOK;
+}
+
+int server_reload(server_t *server)
+{
+ if (server == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ /* Check for no edit mode. */
+ if (conf()->io.txn != NULL) {
+ log_warning("reload aborted due to active configuration transaction");
+ return KNOT_TXN_EEXISTS;
+ }
+
+ conf_t *new_conf = NULL;
+ int ret = conf_clone(&new_conf);
+ if (ret != KNOT_EOK) {
+ log_error("failed to initialize configuration (%s)",
+ knot_strerror(ret));
+ return ret;
+ }
+
+ yp_flag_t flags = conf()->io.flags;
+ bool full = !(flags & CONF_IO_FACTIVE);
+ bool reuse_modules = !full && !(flags & CONF_IO_FRLD_MOD);
+
+ /* Reload configuration and modules if full reload or a module change. */
+ if (full || !reuse_modules) {
+ ret = reload_conf(new_conf);
+ if (ret != KNOT_EOK) {
+ conf_free(new_conf);
+ return ret;
+ }
+
+ conf_activate_modules(new_conf, NULL, new_conf->query_modules,
+ &new_conf->query_plan);
+ }
+
+ conf_update_flag_t upd_flags = CONF_UPD_FNOFREE;
+ if (!full) {
+ upd_flags |= CONF_UPD_FCONFIO;
+ }
+ if (reuse_modules) {
+ upd_flags |= CONF_UPD_FMODULES;
+ }
+
+ /* Update to the new config. */
+ conf_t *old_conf = conf_update(new_conf, upd_flags);
+
+ /* Reload each component if full reload or a specific one if required. */
+ if (full || (flags & CONF_IO_FRLD_LOG)) {
+ log_reconfigure(conf());
+ }
+ if (full || (flags & CONF_IO_FRLD_SRV)) {
+ server_reconfigure(conf(), server);
+ stats_reconfigure(conf(), server);
+ }
+ if (full || (flags & (CONF_IO_FRLD_ZONES | CONF_IO_FRLD_ZONE))) {
+ server_update_zones(conf(), server);
+ }
+
+ /* Free old config needed for module unload in zone reload. */
+ conf_free(old_conf);
+
+ if (full) {
+ log_info("configuration reloaded");
+ } else {
+ // Reset confio reload context.
+ conf()->io.flags = YP_FNONE;
+ if (conf()->io.zones != NULL) {
+ trie_clear(conf()->io.zones);
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+void server_stop(server_t *server)
+{
+ log_info("stopping server");
+
+ /* Stop scheduler. */
+ evsched_stop(&server->sched);
+ /* Interrupt background workers. */
+ worker_pool_stop(server->workers);
+
+ /* Clear 'running' flag. */
+ server->state &= ~ServerRunning;
+}
+
+static int reset_handler(server_t *server, int index, unsigned size, runnable_t run)
+{
+ if (server->handlers[index].size != size) {
+ /* Free old handlers */
+ if (server->handlers[index].size > 0) {
+ server_free_handler(&server->handlers[index].handler);
+ }
+
+ /* Initialize I/O handlers. */
+ int ret = server_init_handler(server, index, size, run, NULL);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ /* Start if server is running. */
+ if (server->state & ServerRunning) {
+ ret = dt_start(server->handlers[index].handler.unit);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+ server->handlers[index].size = size;
+ }
+
+ return KNOT_EOK;
+}
+
+/*! \brief Reconfigure UDP and TCP query processing threads. */
+static int reconfigure_threads(conf_t *conf, server_t *server)
+{
+ int ret = reset_handler(server, IO_UDP, conf_udp_threads(conf), udp_master);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ return reset_handler(server, IO_TCP, conf_tcp_threads(conf), tcp_master);
+}
+
+static int reconfigure_journal_db(conf_t *conf, server_t *server)
+{
+ char *journal_dir = conf_journalfile(conf);
+ conf_val_t journal_size = conf_default_get(conf, C_MAX_JOURNAL_DB_SIZE);
+ conf_val_t journal_mode = conf_default_get(conf, C_JOURNAL_DB_MODE);
+ bool changed_path = (strcmp(journal_dir, server->journal_db->path) != 0);
+ bool changed_size = (conf_int(&journal_size) != server->journal_db->fslimit);
+ bool changed_mode = (conf_opt(&journal_mode) != server->journal_db->mode);
+ int ret = KNOT_EOK;
+
+ if (server->journal_db->db != NULL) {
+ if (changed_path) {
+ log_warning("ignored reconfiguration of journal DB path (already open)");
+ }
+ if (changed_size) {
+ log_warning("ignored reconfiguration of journal DB max size (already open)");
+ }
+ if (changed_mode) {
+ log_warning("ignored reconfiguration of journal DB mode (already open)");
+ }
+ } else if (changed_path || changed_size || changed_mode) {
+ journal_db_t *newjdb = NULL;
+ ret = journal_db_init(&newjdb, journal_dir, conf_int(&journal_size),
+ conf_opt(&journal_mode));
+ if (ret == KNOT_EOK) {
+ journal_db_close(&server->journal_db);
+ server->journal_db = newjdb;
+ }
+ }
+ free(journal_dir);
+
+ return ret;
+}
+
+static int reconfigure_kasp_db(conf_t *conf, server_t *server)
+{
+ char *kasp_dir = conf_kaspdir(conf);
+ conf_val_t kasp_size = conf_default_get(conf, C_MAX_KASP_DB_SIZE);
+ int ret = kasp_db_reconfigure(kaspdb(), kasp_dir, conf_int(&kasp_size));
+ switch (ret) {
+ case KNOT_EBUSY:
+ log_warning("ignored reconfiguration of KASP DB path (already open)");
+ break;
+ case KNOT_EEXIST:
+ ret = KNOT_EBUSY;
+ log_warning("ignored reconfiguration of KASP DB max size (already open)");
+ break;
+ case KNOT_ENODIFF:
+ case KNOT_EOK:
+ ret = KNOT_EOK;
+ break;
+ default:
+ break;
+ }
+ free(kasp_dir);
+
+ return ret;
+}
+
+void server_reconfigure(conf_t *conf, server_t *server)
+{
+ if (conf == NULL || server == NULL) {
+ return;
+ }
+
+ /* First reconfiguration. */
+ if (!(server->state & ServerRunning)) {
+ log_info("Knot DNS %s starting", PACKAGE_VERSION);
+ }
+
+ /* Reconfigure server threads. */
+ int ret;
+ if ((ret = reconfigure_threads(conf, server)) < 0) {
+ log_error("failed to reconfigure server threads (%s)",
+ knot_strerror(ret));
+ }
+
+ /* Reconfigure journal DB. */
+ if ((ret = reconfigure_journal_db(conf, server)) < 0) {
+ log_error("failed to reconfigure journal DB (%s)",
+ knot_strerror(ret));
+ }
+
+ /* Reconfigure KASP DB. */
+ if ((ret = reconfigure_kasp_db(conf, server)) < 0) {
+ log_error("failed to reconfigure KASP DB (%s)",
+ knot_strerror(ret));
+ }
+
+ /* Update bound sockets. */
+ if ((ret = reconfigure_sockets(conf, server)) < 0) {
+ log_error("failed to reconfigure server sockets (%s)",
+ knot_strerror(ret));
+ }
+}
+
+static void reopen_timers_database(conf_t *conf, server_t *server)
+{
+ zone_timers_close(server->timers_db);
+ server->timers_db = NULL;
+
+ conf_val_t val = conf_default_get(conf, C_STORAGE);
+ char *storage = conf_abs_path(&val, NULL);
+ val = conf_default_get(conf, C_TIMER_DB);
+ char *timer_db = conf_abs_path(&val, storage);
+ free(storage);
+ val = conf_default_get(conf, C_MAX_TIMER_DB_SIZE);
+ size_t mapsize = conf_int(&val);
+
+ int ret = zone_timers_open(timer_db, &server->timers_db, mapsize);
+ if (ret != KNOT_EOK) {
+ log_warning("cannot open persistent timer DB '%s' (%s)",
+ timer_db, knot_strerror(ret));
+ }
+
+ free(timer_db);
+}
+
+void server_update_zones(conf_t *conf, server_t *server)
+{
+ if (conf == NULL || server == NULL) {
+ return;
+ }
+
+ /* Prevent emitting of new zone events. */
+ if (server->zone_db) {
+ knot_zonedb_foreach(server->zone_db, zone_events_freeze);
+ }
+
+ /* Suspend adding events to worker pool queue, wait for queued events. */
+ evsched_pause(&server->sched);
+ worker_pool_wait(server->workers);
+
+ /* Reload zone database and free old zones. */
+ reopen_timers_database(conf, server);
+ zonedb_reload(conf, server);
+
+ /* Trim extra heap. */
+ mem_trim();
+
+ /* Resume processing events on new zones. */
+ evsched_resume(&server->sched);
+ if (server->zone_db) {
+ knot_zonedb_foreach(server->zone_db, zone_events_start);
+ }
+}
+
+ref_t *server_set_ifaces(server_t *server, fdset_t *fds, int index, int thread_id)
+{
+ if (server == NULL || server->ifaces == NULL || fds == NULL) {
+ return NULL;
+ }
+
+ rcu_read_lock();
+ fdset_clear(fds);
+
+ iface_t *i = NULL;
+ WALK_LIST(i, server->ifaces->l) {
+#ifdef ENABLE_REUSEPORT
+ int udp_id = thread_id % i->fd_udp_count;
+#else
+ int udp_id = 0;
+#endif
+ switch(index) {
+ case IO_TCP:
+ fdset_add(fds, i->fd_tcp, POLLIN, NULL);
+ break;
+ case IO_UDP:
+ fdset_add(fds, i->fd_udp[udp_id], POLLIN, NULL);
+ break;
+ default:
+ assert(0);
+ }
+ }
+ rcu_read_unlock();
+
+ return &server->ifaces->ref;
+}
diff --git a/src/knot/server/server.h b/src/knot/server/server.h
new file mode 100644
index 0000000..76fcc86
--- /dev/null
+++ b/src/knot/server/server.h
@@ -0,0 +1,181 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "sys/socket.h"
+
+#include "knot/conf/conf.h"
+#include "knot/common/evsched.h"
+#include "knot/common/fdset.h"
+#include "knot/server/dthreads.h"
+#include "knot/common/ref.h"
+#include "knot/worker/pool.h"
+#include "knot/zone/zonedb.h"
+#include "contrib/ucw/lists.h"
+
+/* Forwad declarations. */
+struct server;
+
+/*! \brief I/O handler structure.
+ */
+typedef struct iohandler {
+ struct node n;
+ struct server *server; /*!< Reference to server */
+ dt_unit_t *unit; /*!< Threading unit */
+ unsigned *thread_state; /*!< Thread state */
+ unsigned *thread_id; /*!< Thread identifier. */
+} iohandler_t;
+
+/*! \brief Server state flags.
+ */
+typedef enum {
+ ServerIdle = 0 << 0, /*!< Server is idle. */
+ ServerRunning = 1 << 0, /*!< Server is running. */
+ ServerReload = 1 << 1 /*!< Server reload requested. */
+} server_state;
+
+/*!
+ * \brief Server interface structure.
+ */
+typedef struct iface {
+ struct node n;
+ int *fd_udp;
+ int fd_udp_count;
+ int fd_tcp;
+ struct sockaddr_storage addr;
+} iface_t;
+
+/* Handler indexes. */
+enum {
+ IO_UDP = 0,
+ IO_TCP = 1
+};
+
+typedef struct ifacelist {
+ ref_t ref;
+ list_t l;
+ list_t u;
+} ifacelist_t;
+
+/*!
+ * \brief Main server structure.
+ *
+ * Keeps references to all important structures needed for operation.
+ */
+typedef struct server {
+
+ /*! \brief Server state tracking. */
+ volatile unsigned state;
+
+ /*! \brief Zone database. */
+ knot_zonedb_t *zone_db;
+ knot_db_t *timers_db;
+ journal_db_t *journal_db;
+
+ /*! \brief I/O handlers. */
+ struct {
+ unsigned size;
+ iohandler_t handler;
+ } handlers[2];
+
+ /*! \brief Background jobs. */
+ worker_pool_t *workers;
+
+ /*! \brief Event scheduler. */
+ evsched_t sched;
+
+ /*! \brief List of interfaces. */
+ ifacelist_t *ifaces;
+
+} server_t;
+
+/*!
+ * \brief Initializes the server structure.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_EINVAL on invalid parameters.
+ */
+int server_init(server_t *server, int bg_workers);
+
+/*!
+ * \brief Properly destroys the server structure.
+ *
+ * \param server Server structure to be used for operation.
+ */
+void server_deinit(server_t *server);
+
+/*!
+ * \brief Starts the server.
+ *
+ * \param server Server structure to be used for operation.
+ * \param async Don't wait for zones to load if true.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_EINVAL on invalid parameters.
+ *
+ */
+int server_start(server_t *server, bool async);
+
+/*!
+ * \brief Waits for the server to finish.
+ *
+ * \param server Server structure to be used for operation.
+ *
+ */
+void server_wait(server_t *server);
+
+/*!
+ * \brief Reload server configuration.
+ *
+ * \param server Server instance.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int server_reload(server_t *server);
+
+/*!
+ * \brief Requests server to stop.
+ *
+ * \param server Server structure to be used for operation.
+ */
+void server_stop(server_t *server);
+
+/*!
+ * \brief Server reconfiguration routine.
+ *
+ * Routine for dynamic server reconfiguration.
+ */
+void server_reconfigure(conf_t *conf, server_t *server);
+
+/*!
+ * \brief Reconfigure zone database.
+ *
+ * Routine for dynamic server zones reconfiguration.
+ */
+void server_update_zones(conf_t *conf, server_t *server);
+
+/*!
+ * \brief Update fdsets from current interfaces list.
+ *
+ * \param server Server.
+ * \param fds File descriptor set.
+ * \param index I/O index (UDP/TCP).
+ * \param thread_id Thread ID used for geting UDP ID.
+ *
+ * \return new interface list
+ */
+ref_t *server_set_ifaces(server_t *server, fdset_t *fds, int index, int thread_id);
diff --git a/src/knot/server/tcp-handler.c b/src/knot/server/tcp-handler.c
new file mode 100644
index 0000000..2a0a6ff
--- /dev/null
+++ b/src/knot/server/tcp-handler.c
@@ -0,0 +1,373 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/tcp.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <urcu.h>
+#ifdef HAVE_SYS_UIO_H // struct iovec (OpenBSD)
+#include <sys/uio.h>
+#endif // HAVE_SYS_UIO_H
+
+#include "libdnssec/random.h"
+#include "knot/server/server.h"
+#include "knot/server/tcp-handler.h"
+#include "knot/common/log.h"
+#include "knot/nameserver/process_query.h"
+#include "knot/query/layer.h"
+#include "contrib/macros.h"
+#include "contrib/mempattern.h"
+#include "contrib/net.h"
+#include "contrib/sockaddr.h"
+#include "contrib/time.h"
+#include "contrib/ucw/mempool.h"
+
+/*! \brief TCP context data. */
+typedef struct tcp_context {
+ knot_layer_t layer; /*!< Query processing layer. */
+ server_t *server; /*!< Name server structure. */
+ struct iovec iov[2]; /*!< TX/RX buffers. */
+ unsigned client_threshold; /*!< Index of first TCP client. */
+ struct timespec last_poll_time; /*!< Time of the last socket poll. */
+ struct timespec throttle_end; /*!< End of accept() throttling. */
+ fdset_t set; /*!< Set of server/client sockets. */
+ unsigned thread_id; /*!< Thread identifier. */
+} tcp_context_t;
+
+#define TCP_SWEEP_INTERVAL 2 /*!< [secs] granularity of connection sweeping. */
+#define TCP_THROTTLE_LO 0 /*!< Minimum recovery time on errors. */
+#define TCP_THROTTLE_HI 2 /*!< Maximum recovery time on errors. */
+
+/*! \brief Calculate TCP throttle time (random). */
+static inline int tcp_throttle(void) {
+ return TCP_THROTTLE_LO + (dnssec_random_uint16_t() % TCP_THROTTLE_HI);
+}
+
+/*! \brief Sweep TCP connection. */
+static enum fdset_sweep_state tcp_sweep(fdset_t *set, int i, void *data)
+{
+ UNUSED(data);
+ assert(set && i < set->n && i >= 0);
+ int fd = set->pfd[i].fd;
+
+ /* Best-effort, name and shame. */
+ struct sockaddr_storage ss;
+ socklen_t len = sizeof(struct sockaddr_storage);
+ if (getpeername(fd, (struct sockaddr*)&ss, &len) == 0) {
+ char addr_str[SOCKADDR_STRLEN] = {0};
+ sockaddr_tostr(addr_str, sizeof(addr_str), (struct sockaddr *)&ss);
+ log_notice("TCP, terminated inactive client, address %s", addr_str);
+ }
+
+ close(fd);
+
+ return FDSET_SWEEP;
+}
+
+static bool tcp_active_state(int state)
+{
+ return (state == KNOT_STATE_PRODUCE || state == KNOT_STATE_FAIL);
+}
+
+static bool tcp_send_state(int state)
+{
+ return (state != KNOT_STATE_FAIL && state != KNOT_STATE_NOOP);
+}
+
+static int tcp_handle(tcp_context_t *tcp, int fd,
+ struct iovec *rx, struct iovec *tx)
+{
+ /* Get peer name. */
+ struct sockaddr_storage ss;
+ socklen_t addrlen = sizeof(struct sockaddr_storage);
+ if (getpeername(fd, (struct sockaddr *)&ss, &addrlen) != 0) {
+ return KNOT_EINVAL;
+ }
+
+ /* Create query processing parameter. */
+ knotd_qdata_params_t params = {
+ .remote = &ss,
+ .socket = fd,
+ .server = tcp->server,
+ .thread_id = tcp->thread_id
+ };
+
+ rx->iov_len = KNOT_WIRE_MAX_PKTSIZE;
+ tx->iov_len = KNOT_WIRE_MAX_PKTSIZE;
+
+ /* Timeout. */
+ rcu_read_lock();
+ int timeout = 1000 * conf()->cache.srv_tcp_reply_timeout;
+ rcu_read_unlock();
+
+ /* Receive data. */
+ int ret = net_dns_tcp_recv(fd, rx->iov_base, rx->iov_len, timeout);
+ if (ret <= 0) {
+ if (ret == KNOT_EAGAIN) {
+ char addr_str[SOCKADDR_STRLEN] = {0};
+ sockaddr_tostr(addr_str, sizeof(addr_str), (struct sockaddr *)&ss);
+ log_warning("TCP, connection timed out, address %s",
+ addr_str);
+ }
+ return KNOT_ECONNREFUSED;
+ } else {
+ rx->iov_len = ret;
+ }
+
+ /* Initialize processing layer. */
+ knot_layer_begin(&tcp->layer, &params);
+
+ /* Create packets. */
+ knot_pkt_t *ans = knot_pkt_new(tx->iov_base, tx->iov_len, tcp->layer.mm);
+ knot_pkt_t *query = knot_pkt_new(rx->iov_base, rx->iov_len, tcp->layer.mm);
+
+ /* Input packet. */
+ (void) knot_pkt_parse(query, 0);
+ knot_layer_consume(&tcp->layer, query);
+
+ /* Resolve until NOOP or finished. */
+ ret = KNOT_EOK;
+ while (tcp_active_state(tcp->layer.state)) {
+ knot_layer_produce(&tcp->layer, ans);
+ /* Send, if response generation passed and wasn't ignored. */
+ if (ans->size > 0 && tcp_send_state(tcp->layer.state)) {
+ if (net_dns_tcp_send(fd, ans->wire, ans->size, timeout) != ans->size) {
+ ret = KNOT_ECONNREFUSED;
+ break;
+ }
+ }
+ }
+
+ /* Reset after processing. */
+ knot_layer_finish(&tcp->layer);
+
+ /* Flush per-query memory (including query and answer packets). */
+ mp_flush(tcp->layer.mm->ctx);
+
+ return ret;
+}
+
+static int tcp_accept(int fd)
+{
+ /* Accept incoming connection. */
+ int incoming = net_accept(fd, NULL);
+
+ /* Evaluate connection. */
+ if (incoming >= 0) {
+#ifdef SO_RCVTIMEO
+ struct timeval tv;
+ rcu_read_lock();
+ tv.tv_sec = conf()->cache.srv_tcp_idle_timeout;
+ rcu_read_unlock();
+ tv.tv_usec = 0;
+ if (setsockopt(incoming, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
+ log_warning("TCP, failed to set up watchdog timer"
+ ", fd %d", incoming);
+ }
+#endif
+ }
+
+ return incoming;
+}
+
+static int tcp_event_accept(tcp_context_t *tcp, unsigned i)
+{
+ /* Accept client. */
+ int fd = tcp->set.pfd[i].fd;
+ int client = tcp_accept(fd);
+ if (client >= 0) {
+ /* Assign to fdset. */
+ int next_id = fdset_add(&tcp->set, client, POLLIN, NULL);
+ if (next_id < 0) {
+ close(client);
+ return next_id; /* Contains errno. */
+ }
+
+ /* Update watchdog timer. */
+ rcu_read_lock();
+ int timeout = conf()->cache.srv_tcp_hshake_timeout;
+ fdset_set_watchdog(&tcp->set, next_id, timeout);
+ rcu_read_unlock();
+
+ return KNOT_EOK;
+ }
+
+ return client;
+}
+
+static int tcp_event_serve(tcp_context_t *tcp, unsigned i)
+{
+ int fd = tcp->set.pfd[i].fd;
+ int ret = tcp_handle(tcp, fd, &tcp->iov[0], &tcp->iov[1]);
+ if (ret == KNOT_EOK) {
+ /* Update socket activity timer. */
+ rcu_read_lock();
+ int timeout = conf()->cache.srv_tcp_idle_timeout;
+ fdset_set_watchdog(&tcp->set, i, timeout);
+ rcu_read_unlock();
+ }
+
+ return ret;
+}
+
+static int tcp_wait_for_events(tcp_context_t *tcp)
+{
+ /* Wait for events. */
+ fdset_t *set = &tcp->set;
+ int nfds = poll(set->pfd, set->n, TCP_SWEEP_INTERVAL * 1000);
+
+ /* Mark the time of last poll call. */
+ tcp->last_poll_time = time_now();
+ bool is_throttled = (tcp->last_poll_time.tv_sec < tcp->throttle_end.tv_sec);
+ if (!is_throttled) {
+ /* Configuration limit, infer maximal pool size. */
+ rcu_read_lock();
+ int clients = conf()->cache.srv_max_tcp_clients;
+ unsigned max_per_set = MAX(clients / conf_tcp_threads(conf()), 1);
+ rcu_read_unlock();
+ /* Subtract master sockets check limits. */
+ is_throttled = (set->n - tcp->client_threshold) >= max_per_set;
+ }
+
+ /* Process events. */
+ unsigned i = 0;
+ while (nfds > 0 && i < set->n) {
+ bool should_close = false;
+ int fd = set->pfd[i].fd;
+ if (set->pfd[i].revents & (POLLERR|POLLHUP|POLLNVAL)) {
+ should_close = (i >= tcp->client_threshold);
+ --nfds;
+ } else if (set->pfd[i].revents & (POLLIN)) {
+ /* Master sockets */
+ if (i < tcp->client_threshold) {
+ if (!is_throttled && tcp_event_accept(tcp, i) == KNOT_EBUSY) {
+ tcp->throttle_end = time_now();
+ tcp->throttle_end.tv_sec += tcp_throttle();
+ }
+ /* Client sockets */
+ } else {
+ if (tcp_event_serve(tcp, i) != KNOT_EOK) {
+ should_close = true;
+ }
+ }
+ --nfds;
+ }
+
+ /* Evaluate */
+ if (should_close) {
+ fdset_remove(set, i);
+ close(fd);
+ } else {
+ ++i;
+ }
+ }
+
+ return nfds;
+}
+
+int tcp_master(dthread_t *thread)
+{
+ if (thread == NULL || thread->data == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ iohandler_t *handler = (iohandler_t *)thread->data;
+ unsigned *iostate = &handler->thread_state[dt_get_id(thread)];
+
+ int ret = KNOT_EOK;
+ ref_t *ref = NULL;
+
+ /* Create big enough memory cushion. */
+ knot_mm_t mm;
+ mm_ctx_mempool(&mm, 16 * MM_DEFAULT_BLKSIZE);
+
+ /* Create TCP answering context. */
+ tcp_context_t tcp = {
+ .server = handler->server,
+ .thread_id = handler->thread_id[dt_get_id(thread)]
+ };
+ knot_layer_init(&tcp.layer, &mm, process_query_layer());
+
+ /* Prepare structures for bound sockets. */
+ conf_val_t val = conf_get(conf(), C_SRV, C_LISTEN);
+ fdset_init(&tcp.set, conf_val_count(&val) + CONF_XFERS);
+
+ /* Create iovec abstraction. */
+ for (unsigned i = 0; i < 2; ++i) {
+ tcp.iov[i].iov_len = KNOT_WIRE_MAX_PKTSIZE;
+ tcp.iov[i].iov_base = malloc(tcp.iov[i].iov_len);
+ if (tcp.iov[i].iov_base == NULL) {
+ ret = KNOT_ENOMEM;
+ goto finish;
+ }
+ }
+
+ /* Initialize sweep interval. */
+ struct timespec next_sweep = time_now();
+ next_sweep.tv_sec += TCP_SWEEP_INTERVAL;
+
+ for(;;) {
+
+ /* Check handler state. */
+ if (unlikely(*iostate & ServerReload)) {
+ *iostate &= ~ServerReload;
+
+ /* Cancel client connections. */
+ for (unsigned i = tcp.client_threshold; i < tcp.set.n; ++i) {
+ close(tcp.set.pfd[i].fd);
+ }
+
+ ref_release(ref);
+ ref = server_set_ifaces(handler->server, &tcp.set, IO_TCP, tcp.thread_id);
+ if (tcp.set.n == 0) {
+ break; /* Terminate on zero interfaces. */
+ }
+
+ tcp.client_threshold = tcp.set.n;
+ }
+
+ /* Check for cancellation. */
+ if (dt_is_cancelled(thread)) {
+ break;
+ }
+
+ /* Serve client requests. */
+ tcp_wait_for_events(&tcp);
+
+ /* Sweep inactive clients. */
+ if (tcp.last_poll_time.tv_sec >= next_sweep.tv_sec) {
+ fdset_sweep(&tcp.set, &tcp_sweep, NULL);
+ next_sweep = time_now();
+ next_sweep.tv_sec += TCP_SWEEP_INTERVAL;
+ }
+ }
+
+finish:
+ free(tcp.iov[0].iov_base);
+ free(tcp.iov[1].iov_base);
+ mp_delete(mm.ctx);
+ fdset_clear(&tcp.set);
+ ref_release(ref);
+
+ return ret;
+}
diff --git a/src/knot/server/tcp-handler.h b/src/knot/server/tcp-handler.h
new file mode 100644
index 0000000..9d048d7
--- /dev/null
+++ b/src/knot/server/tcp-handler.h
@@ -0,0 +1,42 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \brief TCP sockets threading model.
+ *
+ * The master socket distributes incoming connections among
+ * the worker threads ("buckets"). Each threads processes it's own
+ * set of sockets, and eliminates mutual exclusion problem by doing so.
+ */
+
+#pragma once
+
+#include "knot/server/dthreads.h"
+
+#define TCP_BACKLOG_SIZE 10 /*!< TCP listen backlog size. */
+
+/*!
+ * \brief TCP handler thread runnable.
+ *
+ * Listens to both bound TCP sockets for client connections and
+ * serves TCP clients. This runnable is designed to be used as coherent
+ * and implements cancellation point.
+ *
+ * \param thread Associated thread from DThreads unit.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_EINVAL invalid parameters.
+ */
+int tcp_master(dthread_t *thread);
diff --git a/src/knot/server/udp-handler.c b/src/knot/server/udp-handler.c
new file mode 100644
index 0000000..5076094
--- /dev/null
+++ b/src/knot/server/udp-handler.c
@@ -0,0 +1,495 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define __APPLE_USE_RFC_3542
+
+#include <dlfcn.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/param.h>
+#include <urcu.h>
+#ifdef HAVE_SYS_UIO_H // struct iovec (OpenBSD)
+#include <sys/uio.h>
+#endif /* HAVE_SYS_UIO_H */
+
+#include "contrib/macros.h"
+#include "contrib/mempattern.h"
+#include "contrib/sockaddr.h"
+#include "contrib/ucw/mempool.h"
+#include "knot/nameserver/process_query.h"
+#include "knot/query/layer.h"
+#include "knot/server/server.h"
+#include "knot/server/udp-handler.h"
+
+/* Buffer identifiers. */
+enum {
+ RX = 0,
+ TX = 1,
+ NBUFS = 2
+};
+
+/*! \brief UDP context data. */
+typedef struct {
+ knot_layer_t layer; /*!< Query processing layer. */
+ server_t *server; /*!< Name server structure. */
+ unsigned thread_id; /*!< Thread identifier. */
+} udp_context_t;
+
+static bool udp_state_active(int state)
+{
+ return (state == KNOT_STATE_PRODUCE || state == KNOT_STATE_FAIL);
+}
+
+static void udp_handle(udp_context_t *udp, int fd, struct sockaddr_storage *ss,
+ struct iovec *rx, struct iovec *tx)
+{
+ /* Create query processing parameter. */
+ knotd_qdata_params_t params = {
+ .remote = ss,
+ .flags = KNOTD_QUERY_FLAG_NO_AXFR | KNOTD_QUERY_FLAG_NO_IXFR | /* No transfers. */
+ KNOTD_QUERY_FLAG_LIMIT_SIZE | /* Enforce UDP packet size limit. */
+ KNOTD_QUERY_FLAG_LIMIT_ANY, /* Limit ANY over UDP (depends on zone as well). */
+ .socket = fd,
+ .server = udp->server,
+ .thread_id = udp->thread_id
+ };
+
+ /* Start query processing. */
+ knot_layer_begin(&udp->layer, &params);
+
+ /* Create packets. */
+ knot_pkt_t *query = knot_pkt_new(rx->iov_base, rx->iov_len, udp->layer.mm);
+ knot_pkt_t *ans = knot_pkt_new(tx->iov_base, tx->iov_len, udp->layer.mm);
+
+ /* Input packet. */
+ (void) knot_pkt_parse(query, 0);
+ knot_layer_consume(&udp->layer, query);
+
+ /* Process answer. */
+ while (udp_state_active(udp->layer.state)) {
+ knot_layer_produce(&udp->layer, ans);
+ }
+
+ /* Send response only if finished successfully. */
+ if (udp->layer.state == KNOT_STATE_DONE) {
+ tx->iov_len = ans->size;
+ } else {
+ tx->iov_len = 0;
+ }
+
+ /* Reset after processing. */
+ knot_layer_finish(&udp->layer);
+
+ /* Flush per-query memory (including query and answer packets). */
+ mp_flush(udp->layer.mm->ctx);
+}
+
+/*! \brief Pointer to selected UDP master implementation. */
+static void* (*_udp_init)(void) = 0;
+static void (*_udp_deinit)(void *) = 0;
+static int (*_udp_recv)(int, void *) = 0;
+static int (*_udp_handle)(udp_context_t *, void *) = 0;
+static int (*_udp_send)(void *) = 0;
+
+/*! \brief Control message to fit IP_PKTINFO or IPv6_RECVPKTINFO. */
+typedef union {
+ struct cmsghdr cmsg;
+ uint8_t buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
+} cmsg_pktinfo_t;
+
+static void udp_pktinfo_handle(const struct msghdr *rx, struct msghdr *tx)
+{
+ tx->msg_controllen = rx->msg_controllen;
+ if (tx->msg_controllen > 0) {
+ tx->msg_control = rx->msg_control;
+ } else {
+ // BSD has problem with zero length and not-null pointer
+ tx->msg_control = NULL;
+ }
+
+#if defined(__linux__) || defined(__APPLE__)
+ struct cmsghdr *cmsg = CMSG_FIRSTHDR(tx);
+ if (cmsg == NULL) {
+ return;
+ }
+
+ /* Unset the ifindex to not bypass the routing tables. */
+ if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) {
+ struct in_pktinfo *info = (struct in_pktinfo *)CMSG_DATA(cmsg);
+ info->ipi_spec_dst = info->ipi_addr;
+ info->ipi_ifindex = 0;
+ } else if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
+ struct in6_pktinfo *info = (struct in6_pktinfo *)CMSG_DATA(cmsg);
+ info->ipi6_ifindex = 0;
+ }
+#endif
+}
+
+/* UDP recvfrom() request struct. */
+struct udp_recvfrom {
+ int fd;
+ struct sockaddr_storage addr;
+ struct msghdr msg[NBUFS];
+ struct iovec iov[NBUFS];
+ uint8_t buf[NBUFS][KNOT_WIRE_MAX_PKTSIZE];
+ cmsg_pktinfo_t pktinfo;
+};
+
+static void *udp_recvfrom_init(void)
+{
+ struct udp_recvfrom *rq = malloc(sizeof(struct udp_recvfrom));
+ if (rq == NULL) {
+ return NULL;
+ }
+ memset(rq, 0, sizeof(struct udp_recvfrom));
+
+ for (unsigned i = 0; i < NBUFS; ++i) {
+ rq->iov[i].iov_base = rq->buf + i;
+ rq->iov[i].iov_len = KNOT_WIRE_MAX_PKTSIZE;
+ rq->msg[i].msg_name = &rq->addr;
+ rq->msg[i].msg_namelen = sizeof(rq->addr);
+ rq->msg[i].msg_iov = &rq->iov[i];
+ rq->msg[i].msg_iovlen = 1;
+ rq->msg[i].msg_control = &rq->pktinfo.cmsg;
+ rq->msg[i].msg_controllen = sizeof(rq->pktinfo);
+ }
+ return rq;
+}
+
+static void udp_recvfrom_deinit(void *d)
+{
+ struct udp_recvfrom *rq = (struct udp_recvfrom *)d;
+ free(rq);
+}
+
+static int udp_recvfrom_recv(int fd, void *d)
+{
+ /* Reset max lengths. */
+ struct udp_recvfrom *rq = (struct udp_recvfrom *)d;
+ rq->iov[RX].iov_len = KNOT_WIRE_MAX_PKTSIZE;
+ rq->msg[RX].msg_namelen = sizeof(struct sockaddr_storage);
+ rq->msg[RX].msg_controllen = sizeof(rq->pktinfo);
+
+ int ret = recvmsg(fd, &rq->msg[RX], MSG_DONTWAIT);
+ if (ret > 0) {
+ rq->fd = fd;
+ rq->iov[RX].iov_len = ret;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int udp_recvfrom_handle(udp_context_t *ctx, void *d)
+{
+ struct udp_recvfrom *rq = (struct udp_recvfrom *)d;
+
+ /* Prepare TX address. */
+ rq->msg[TX].msg_namelen = rq->msg[RX].msg_namelen;
+ rq->iov[TX].iov_len = KNOT_WIRE_MAX_PKTSIZE;
+
+ udp_pktinfo_handle(&rq->msg[RX], &rq->msg[TX]);
+
+ /* Process received pkt. */
+ udp_handle(ctx, rq->fd, &rq->addr, &rq->iov[RX], &rq->iov[TX]);
+
+ return KNOT_EOK;
+}
+
+static int udp_recvfrom_send(void *d)
+{
+ struct udp_recvfrom *rq = (struct udp_recvfrom *)d;
+ int rc = 0;
+ if (rq->iov[TX].iov_len > 0) {
+ rc = sendmsg(rq->fd, &rq->msg[TX], 0);
+ }
+
+ /* Return number of packets sent. */
+ if (rc > 1) {
+ return 1;
+ }
+
+ return 0;
+}
+
+#ifdef ENABLE_RECVMMSG
+
+/* UDP recvmmsg() request struct. */
+struct udp_recvmmsg {
+ int fd;
+ struct sockaddr_storage addrs[RECVMMSG_BATCHLEN];
+ char *iobuf[NBUFS];
+ struct iovec *iov[NBUFS];
+ struct mmsghdr *msgs[NBUFS];
+ unsigned rcvd;
+ knot_mm_t mm;
+ cmsg_pktinfo_t pktinfo[RECVMMSG_BATCHLEN];
+};
+
+static void *udp_recvmmsg_init(void)
+{
+ knot_mm_t mm;
+ mm_ctx_mempool(&mm, sizeof(struct udp_recvmmsg));
+
+ struct udp_recvmmsg *rq = mm_alloc(&mm, sizeof(struct udp_recvmmsg));
+ memset(rq, 0, sizeof(*rq));
+ memcpy(&rq->mm, &mm, sizeof(knot_mm_t));
+
+ /* Initialize buffers. */
+ for (unsigned i = 0; i < NBUFS; ++i) {
+ rq->iobuf[i] = mm_alloc(&mm, KNOT_WIRE_MAX_PKTSIZE * RECVMMSG_BATCHLEN);
+ rq->iov[i] = mm_alloc(&mm, sizeof(struct iovec) * RECVMMSG_BATCHLEN);
+ rq->msgs[i] = mm_alloc(&mm, sizeof(struct mmsghdr) * RECVMMSG_BATCHLEN);
+ memset(rq->msgs[i], 0, sizeof(struct mmsghdr) * RECVMMSG_BATCHLEN);
+ for (unsigned k = 0; k < RECVMMSG_BATCHLEN; ++k) {
+ rq->iov[i][k].iov_base = rq->iobuf[i] + k * KNOT_WIRE_MAX_PKTSIZE;
+ rq->iov[i][k].iov_len = KNOT_WIRE_MAX_PKTSIZE;
+ rq->msgs[i][k].msg_hdr.msg_iov = rq->iov[i] + k;
+ rq->msgs[i][k].msg_hdr.msg_iovlen = 1;
+ rq->msgs[i][k].msg_hdr.msg_name = rq->addrs + k;
+ rq->msgs[i][k].msg_hdr.msg_namelen = sizeof(struct sockaddr_storage);
+ rq->msgs[i][k].msg_hdr.msg_control = &rq->pktinfo[k].cmsg;
+ rq->msgs[i][k].msg_hdr.msg_controllen = sizeof(cmsg_pktinfo_t);
+ }
+ }
+
+ return rq;
+}
+
+static void udp_recvmmsg_deinit(void *d)
+{
+ struct udp_recvmmsg *rq = (struct udp_recvmmsg *)d;
+ if (rq != NULL) {
+ mp_delete(rq->mm.ctx);
+ }
+}
+
+static int udp_recvmmsg_recv(int fd, void *d)
+{
+ struct udp_recvmmsg *rq = (struct udp_recvmmsg *)d;
+
+ int n = recvmmsg(fd, rq->msgs[RX], RECVMMSG_BATCHLEN, MSG_DONTWAIT, NULL);
+ if (n > 0) {
+ rq->fd = fd;
+ rq->rcvd = n;
+ }
+ return n;
+}
+
+static int udp_recvmmsg_handle(udp_context_t *ctx, void *d)
+{
+ struct udp_recvmmsg *rq = (struct udp_recvmmsg *)d;
+
+ /* Handle each received msg. */
+ for (unsigned i = 0; i < rq->rcvd; ++i) {
+ struct iovec *rx = rq->msgs[RX][i].msg_hdr.msg_iov;
+ struct iovec *tx = rq->msgs[TX][i].msg_hdr.msg_iov;
+ rx->iov_len = rq->msgs[RX][i].msg_len; /* Received bytes. */
+
+ udp_pktinfo_handle(&rq->msgs[RX][i].msg_hdr, &rq->msgs[TX][i].msg_hdr);
+
+ udp_handle(ctx, rq->fd, rq->addrs + i, rx, tx);
+ rq->msgs[TX][i].msg_len = tx->iov_len;
+ rq->msgs[TX][i].msg_hdr.msg_namelen = 0;
+ if (tx->iov_len > 0) {
+ /* @note sendmmsg() workaround to prevent sending the packet */
+ rq->msgs[TX][i].msg_hdr.msg_namelen = rq->msgs[RX][i].msg_hdr.msg_namelen;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+static int udp_recvmmsg_send(void *d)
+{
+ struct udp_recvmmsg *rq = (struct udp_recvmmsg *)d;
+ int rc = sendmmsg(rq->fd, rq->msgs[TX], rq->rcvd, 0);
+ for (unsigned i = 0; i < rq->rcvd; ++i) {
+ /* Reset buffer size and address len. */
+ struct iovec *rx = rq->msgs[RX][i].msg_hdr.msg_iov;
+ struct iovec *tx = rq->msgs[TX][i].msg_hdr.msg_iov;
+ rx->iov_len = KNOT_WIRE_MAX_PKTSIZE; /* Reset RX buflen */
+ tx->iov_len = KNOT_WIRE_MAX_PKTSIZE;
+
+ memset(rq->addrs + i, 0, sizeof(struct sockaddr_storage));
+ rq->msgs[RX][i].msg_hdr.msg_namelen = sizeof(struct sockaddr_storage);
+ rq->msgs[TX][i].msg_hdr.msg_namelen = sizeof(struct sockaddr_storage);
+ rq->msgs[RX][i].msg_hdr.msg_controllen = sizeof(cmsg_pktinfo_t);
+ }
+ return rc;
+}
+#endif /* ENABLE_RECVMMSG */
+
+/*! \brief Initialize UDP master routine on run-time. */
+void __attribute__ ((constructor)) udp_master_init(void)
+{
+ /* Initialize defaults. */
+ _udp_init = udp_recvfrom_init;
+ _udp_deinit = udp_recvfrom_deinit;
+ _udp_recv = udp_recvfrom_recv;
+ _udp_handle = udp_recvfrom_handle;
+ _udp_send = udp_recvfrom_send;
+
+#ifdef ENABLE_RECVMMSG
+ _udp_init = udp_recvmmsg_init;
+ _udp_deinit = udp_recvmmsg_deinit;
+ _udp_recv = udp_recvmmsg_recv;
+ _udp_handle = udp_recvmmsg_handle;
+ _udp_send = udp_recvmmsg_send;
+#endif /* ENABLE_RECVMMSG */
+}
+
+/*! \brief Get interface UDP descriptor for a given thread. */
+static int iface_udp_fd(const iface_t *iface, int thread_id)
+{
+#ifdef ENABLE_REUSEPORT
+ return iface->fd_udp[thread_id % iface->fd_udp_count];
+#else
+ return iface->fd_udp[0];
+#endif
+}
+
+/*! \brief Release the interface list reference and free watched descriptor set. */
+static void forget_ifaces(ifacelist_t *ifaces, struct pollfd **fds_ptr)
+{
+ ref_release((ref_t *)ifaces);
+ free(*fds_ptr);
+ *fds_ptr = NULL;
+}
+
+/*!
+ * \brief Make a set of watched descriptors based on the interface list.
+ *
+ * \param[in] ifaces New interface list.
+ * \param[in] thrid Thread ID.
+ * \param[out] fds_ptr Allocated set of descriptors.
+ *
+ * \return Number of watched descriptors, zero on error.
+ */
+static nfds_t track_ifaces(const ifacelist_t *ifaces, int thrid,
+ struct pollfd **fds_ptr)
+{
+ assert(ifaces && fds_ptr);
+
+ nfds_t nfds = list_size(&ifaces->l);
+ struct pollfd *fds = malloc(nfds * sizeof(*fds));
+ if (!fds) {
+ *fds_ptr = NULL;
+ return 0;
+ }
+
+ iface_t *iface = NULL;
+ int i = 0;
+ WALK_LIST(iface, ifaces->l) {
+ fds[i].fd = iface_udp_fd(iface, thrid);
+ fds[i].events = POLLIN;
+ fds[i].revents = 0;
+ i += 1;
+ }
+ assert(i == nfds);
+
+ *fds_ptr = fds;
+ return nfds;
+}
+
+int udp_master(dthread_t *thread)
+{
+ if (thread == NULL || thread->data == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ unsigned cpu = dt_online_cpus();
+ if (cpu > 1) {
+ unsigned cpu_mask = (dt_get_id(thread) % cpu);
+ dt_setaffinity(thread, &cpu_mask, 1);
+ }
+
+ /* Prepare structures for bound sockets. */
+ unsigned thr_id = dt_get_id(thread);
+ iohandler_t *handler = (iohandler_t *)thread->data;
+ unsigned *iostate = &handler->thread_state[thr_id];
+ void *rq = _udp_init();
+ ifacelist_t *ref = NULL;
+
+ /* Create big enough memory cushion. */
+ knot_mm_t mm;
+ mm_ctx_mempool(&mm, 16 * MM_DEFAULT_BLKSIZE);
+
+ /* Create UDP answering context. */
+ udp_context_t udp = {
+ .server = handler->server,
+ .thread_id = handler->thread_id[thr_id]
+ };
+ knot_layer_init(&udp.layer, &mm, process_query_layer());
+
+ /* Event source. */
+ struct pollfd *fds = NULL;
+ nfds_t nfds = 0;
+
+ /* Loop until all data is read. */
+ for (;;) {
+
+ /* Check handler state. */
+ if (unlikely(*iostate & ServerReload)) {
+ *iostate &= ~ServerReload;
+ udp.thread_id = handler->thread_id[thr_id];
+
+ rcu_read_lock();
+ forget_ifaces(ref, &fds);
+ ref = handler->server->ifaces;
+ nfds = track_ifaces(ref, udp.thread_id, &fds);
+ rcu_read_unlock();
+ if (nfds == 0) {
+ break;
+ }
+ }
+
+ /* Cancellation point. */
+ if (dt_is_cancelled(thread)) {
+ break;
+ }
+
+ /* Wait for events. */
+ int events = poll(fds, nfds, -1);
+ if (events <= 0) {
+ if (errno == EINTR) continue;
+ break;
+ }
+
+ /* Process the events. */
+ for (nfds_t i = 0; i < nfds && events > 0; i++) {
+ if (fds[i].revents == 0) {
+ continue;
+ }
+ events -= 1;
+ if (_udp_recv(fds[i].fd, rq) > 0) {
+ _udp_handle(&udp, rq);
+ _udp_send(rq);
+ }
+ }
+ }
+
+ _udp_deinit(rq);
+ forget_ifaces(ref, &fds);
+ mp_delete(mm.ctx);
+ return KNOT_EOK;
+}
diff --git a/src/knot/server/udp-handler.h b/src/knot/server/udp-handler.h
new file mode 100644
index 0000000..5555b98
--- /dev/null
+++ b/src/knot/server/udp-handler.h
@@ -0,0 +1,42 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \brief UDP sockets threading model.
+ *
+ * The master socket locks one worker thread at a time
+ * and saves events in it's own backing store for asynchronous processing.
+ * The worker threads work asynchronously in thread pool.
+ */
+
+#pragma once
+
+#include "knot/server/dthreads.h"
+
+#define RECVMMSG_BATCHLEN 10 /*!< Default recvmmsg() batch size. */
+
+/*!
+ * \brief UDP handler thread runnable.
+ *
+ * Listen to DNS datagrams in a loop on a UDP socket and
+ * reply to them. This runnable is designed to be used as coherent
+ * and implements cancellation point.
+ *
+ * \param thread Associated thread from DThreads unit.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_EINVAL invalid parameters.
+ */
+int udp_master(dthread_t *thread);
diff --git a/src/knot/updates/acl.c b/src/knot/updates/acl.c
new file mode 100644
index 0000000..28f9626
--- /dev/null
+++ b/src/knot/updates/acl.c
@@ -0,0 +1,104 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "knot/updates/acl.h"
+
+bool acl_allowed(conf_t *conf, conf_val_t *acl, acl_action_t action,
+ const struct sockaddr_storage *addr, knot_tsig_key_t *tsig)
+{
+ if (acl == NULL || addr == NULL || tsig == NULL) {
+ return NULL;
+ }
+
+ while (acl->code == KNOT_EOK) {
+ /* Check if the address matches the current acl address list. */
+ conf_val_t val = conf_id_get(conf, C_ACL, C_ADDR, acl);
+ if (val.code != KNOT_ENOENT && !conf_addr_range_match(&val, addr)) {
+ goto next_acl;
+ }
+
+ /* Check if the key matches the current acl key list. */
+ conf_val_t key_val = conf_id_get(conf, C_ACL, C_KEY, acl);
+ while (key_val.code == KNOT_EOK) {
+ /* No key provided, but required. */
+ if (tsig->name == NULL) {
+ conf_val_next(&key_val);
+ continue;
+ }
+
+ /* Compare key names (both in lower-case). */
+ const knot_dname_t *key_name = conf_dname(&key_val);
+ if (!knot_dname_is_equal(key_name, tsig->name)) {
+ conf_val_next(&key_val);
+ continue;
+ }
+
+ /* Compare key algorithms. */
+ conf_val_t alg_val = conf_id_get(conf, C_KEY, C_ALG,
+ &key_val);
+ if (conf_opt(&alg_val) != tsig->algorithm) {
+ conf_val_next(&key_val);
+ continue;
+ }
+
+ break;
+ }
+ /* Check for key match or empty list without key provided. */
+ if (key_val.code != KNOT_EOK &&
+ !(key_val.code == KNOT_ENOENT && tsig->name == NULL)) {
+ goto next_acl;
+ }
+
+ /* Check if the action is allowed. */
+ if (action != ACL_ACTION_NONE) {
+ val = conf_id_get(conf, C_ACL, C_ACTION, acl);
+ while (val.code == KNOT_EOK) {
+ if (conf_opt(&val) != action) {
+ conf_val_next(&val);
+ continue;
+ }
+
+ break;
+ }
+ switch (val.code) {
+ case KNOT_EOK: /* Check for action match. */
+ break;
+ case KNOT_ENOENT: /* Empty action list allowed with deny only. */
+ return false;
+ default: /* No match. */
+ goto next_acl;
+ }
+ }
+
+ /* Check if denied. */
+ val = conf_id_get(conf, C_ACL, C_DENY, acl);
+ if (conf_bool(&val)) {
+ return false;
+ }
+
+ /* Fill the output with tsig secret if provided. */
+ if (tsig->name != NULL) {
+ val = conf_id_get(conf, C_KEY, C_SECRET, &key_val);
+ tsig->secret.data = (uint8_t *)conf_bin(&val, &tsig->secret.size);
+ }
+
+ return true;
+next_acl:
+ conf_val_next(acl);
+ }
+
+ return false;
+}
diff --git a/src/knot/updates/acl.h b/src/knot/updates/acl.h
new file mode 100644
index 0000000..e15df39
--- /dev/null
+++ b/src/knot/updates/acl.h
@@ -0,0 +1,57 @@
+/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * Access control list.
+ *
+ * \addtogroup server
+ * @{
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <sys/socket.h>
+
+#include "libknot/tsig.h"
+#include "knot/conf/conf.h"
+
+/*! \brief ACL actions. */
+typedef enum {
+ ACL_ACTION_NONE = 0,
+ ACL_ACTION_NOTIFY = 1,
+ ACL_ACTION_TRANSFER = 2,
+ ACL_ACTION_UPDATE = 3
+} acl_action_t;
+
+/*!
+ * \brief Checks if the address and/or tsig key matches given ACL list.
+ *
+ * If a proper ACL rule is found and tsig.name is not empty, tsig.secret is filled.
+ *
+ * \param conf Configuration.
+ * \param acl Pointer to ACL config multivalued identifier.
+ * \param action ACL action.
+ * \param addr IP address.
+ * \param tsig TSIG parameters.
+ *
+ * \retval True if authenticated.
+ */
+bool acl_allowed(conf_t *conf, conf_val_t *acl, acl_action_t action,
+ const struct sockaddr_storage *addr, knot_tsig_key_t *tsig);
+
+/*! @} */
diff --git a/src/knot/updates/apply.c b/src/knot/updates/apply.c
new file mode 100644
index 0000000..1b4cf5b
--- /dev/null
+++ b/src/knot/updates/apply.c
@@ -0,0 +1,485 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "knot/common/log.h"
+#include "knot/updates/apply.h"
+#include "libknot/libknot.h"
+#include "contrib/macros.h"
+#include "contrib/mempattern.h"
+
+/* --------------------------- Update cleanup ------------------------------- */
+
+/*!
+ * \brief Post update cleanup: frees data that are in the tree that will not
+ * be used (old tree if success, new tree if failure).
+ * Freed data:
+ * - actual data inside knot_rrs_t. (the rest is part of the node)
+ */
+static void rrs_list_clear(list_t *l, knot_mm_t *mm)
+{
+ ptrnode_t *n;
+ node_t *nxt;
+ WALK_LIST_DELSAFE(n, nxt, *l) {
+ mm_free(mm, (void *)n->d);
+ mm_free(mm, n);
+ };
+}
+
+/*! \brief Frees additional data from single node */
+static int free_additional(zone_node_t **node, void *data)
+{
+ UNUSED(data);
+
+ for (uint16_t i = 0; i < (*node)->rrset_count; ++i) {
+ struct rr_data *data = &(*node)->rrs[i];
+ additional_clear(data->additional);
+ data->additional = NULL;
+ }
+
+ return KNOT_EOK;
+}
+
+/* -------------------- Changeset application helpers ----------------------- */
+
+/*! \brief Replaces rdataset of given type with a copy. */
+static int replace_rdataset_with_copy(zone_node_t *node, uint16_t type)
+{
+ // Find data to copy.
+ struct rr_data *data = NULL;
+ for (uint16_t i = 0; i < node->rrset_count; ++i) {
+ if (node->rrs[i].type == type) {
+ data = &node->rrs[i];
+ break;
+ }
+ }
+ assert(data);
+
+ // Create new data.
+ knot_rdataset_t *rrs = &data->rrs;
+ void *copy = malloc(knot_rdataset_size(rrs));
+ if (copy == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ memcpy(copy, rrs->rdata, knot_rdataset_size(rrs));
+
+ // Store new data into node RRS.
+ rrs->rdata = copy;
+
+ return KNOT_EOK;
+}
+
+/*! \brief Frees RR dataset. For use when a copy was made. */
+static void clear_new_rrs(zone_node_t *node, uint16_t type)
+{
+ knot_rdataset_t *new_rrs = node_rdataset(node, type);
+ if (new_rrs) {
+ knot_rdataset_clear(new_rrs, NULL);
+ }
+}
+
+/*! \brief Stores RR data for update cleanup. */
+static int add_old_data(apply_ctx_t *ctx, knot_rdata_t *old_data)
+{
+ if (ptrlist_add(&ctx->old_data, old_data, NULL) == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ return KNOT_EOK;
+}
+
+/*! \brief Stores RR data for update rollback. */
+static int add_new_data(apply_ctx_t *ctx, knot_rdata_t *new_data)
+{
+ if (ptrlist_add(&ctx->new_data, new_data, NULL) == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ return KNOT_EOK;
+}
+
+/*! \brief Returns true if given RR is present in node and can be removed. */
+static bool can_remove(const zone_node_t *node, const knot_rrset_t *rrset)
+{
+ if (node == NULL) {
+ // Node does not exist, cannot remove anything.
+ return false;
+ }
+ const knot_rdataset_t *node_rrs = node_rdataset(node, rrset->type);
+ if (node_rrs == NULL) {
+ // Node does not have this type at all.
+ return false;
+ }
+
+ knot_rdata_t *rr_cmp = rrset->rrs.rdata;
+ for (uint16_t i = 0; i < rrset->rrs.count; ++i) {
+ if (knot_rdataset_member(node_rrs, rr_cmp)) {
+ // At least one RR matches.
+ return true;
+ }
+ rr_cmp = knot_rdataset_next(rr_cmp);
+ }
+
+ // Node does have the type, but no RRs match.
+ return false;
+}
+
+/*! \brief Removes all RRs from changeset from zone contents. */
+static int apply_remove(apply_ctx_t *ctx, const changeset_t *chset)
+{
+ changeset_iter_t itt;
+ changeset_iter_rem(&itt, chset);
+
+ knot_rrset_t rr = changeset_iter_next(&itt);
+ while (!knot_rrset_empty(&rr)) {
+ int ret = apply_remove_rr(ctx, &rr);
+ if (ret != KNOT_EOK) {
+ changeset_iter_clear(&itt);
+ return ret;
+ }
+
+ rr = changeset_iter_next(&itt);
+ }
+ changeset_iter_clear(&itt);
+
+ return KNOT_EOK;
+}
+
+/*! \brief Adds all RRs from changeset into zone contents. */
+static int apply_add(apply_ctx_t *ctx, const changeset_t *chset)
+{
+ changeset_iter_t itt;
+ changeset_iter_add(&itt, chset);
+
+ knot_rrset_t rr = changeset_iter_next(&itt);
+ while(!knot_rrset_empty(&rr)) {
+ int ret = apply_add_rr(ctx, &rr);
+ if (ret != KNOT_EOK) {
+ changeset_iter_clear(&itt);
+ return ret;
+ }
+ rr = changeset_iter_next(&itt);
+ }
+ changeset_iter_clear(&itt);
+
+ return KNOT_EOK;
+}
+
+/*! \brief Apply single change to zone contents structure. */
+static int apply_single(apply_ctx_t *ctx, const changeset_t *chset)
+{
+ /*
+ * Applies one changeset to the zone. Checks if the changeset may be
+ * applied (i.e. the origin SOA (soa_from) has the same serial as
+ * SOA in the zone apex.
+ */
+
+ zone_contents_t *contents = ctx->contents;
+
+ // check if serial matches
+ const knot_rdataset_t *soa = node_rdataset(contents->apex, KNOT_RRTYPE_SOA);
+
+ // either we are in the mode of ignoring SOA (both NULL), or we shall be strict and apply SOA later
+ bool ignore_soa = (chset->soa_from == NULL && chset->soa_to == NULL);
+ bool soa_mismatch = (chset->soa_from == NULL || chset->soa_to == NULL || soa == NULL ||
+ knot_soa_serial(soa->rdata) != knot_soa_serial(chset->soa_from->rrs.rdata));
+
+ if (soa == NULL || (!ignore_soa && soa_mismatch)) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = apply_remove(ctx, chset);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = apply_add(ctx, chset);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ return (ignore_soa ? KNOT_EOK : apply_replace_soa(ctx, chset));
+}
+
+/* ------------------------------- API -------------------------------------- */
+
+void apply_init_ctx(apply_ctx_t *ctx, zone_contents_t *contents, uint32_t flags)
+{
+ assert(ctx);
+
+ ctx->contents = contents;
+
+ init_list(&ctx->old_data);
+ init_list(&ctx->new_data);
+
+ ctx->flags = flags;
+}
+
+int apply_prepare_zone_copy(zone_contents_t *old_contents,
+ zone_contents_t **new_contents)
+{
+ if (old_contents == NULL || new_contents == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ /*
+ * Create a shallow copy of the zone, so that the structures may be
+ * updated.
+ *
+ * This will create new zone contents structures (normal nodes' tree,
+ * NSEC3 tree), and copy all nodes.
+ * The data in the nodes (RRSets) remain the same though.
+ */
+ zone_contents_t *contents_copy = NULL;
+ int ret = zone_contents_shallow_copy(old_contents, &contents_copy);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ *new_contents = contents_copy;
+
+ return KNOT_EOK;
+}
+
+int apply_add_rr(apply_ctx_t *ctx, const knot_rrset_t *rr)
+{
+ zone_contents_t *contents = ctx->contents;
+
+ // Get or create node with this owner
+ zone_node_t *node = zone_contents_get_node_for_rr(contents, rr);
+ if (node == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ knot_rrset_t changed_rrset = node_rrset(node, rr->type);
+ if (!knot_rrset_empty(&changed_rrset)) {
+ // Modifying existing RRSet.
+ knot_rdata_t *old_data = changed_rrset.rrs.rdata;
+ int ret = replace_rdataset_with_copy(node, rr->type);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Store old RRS for cleanup.
+ ret = add_old_data(ctx, old_data);
+ if (ret != KNOT_EOK) {
+ clear_new_rrs(node, rr->type);
+ return ret;
+ }
+ }
+
+ // Insert new RR to RRSet, data will be copied.
+ int ret = node_add_rrset(node, rr, NULL);
+ if (ret == KNOT_EOK || ret == KNOT_ETTL) {
+ // RR added, store for possible rollback.
+ knot_rdataset_t *rrs = node_rdataset(node, rr->type);
+ int data_ret = add_new_data(ctx, rrs->rdata);
+ if (data_ret != KNOT_EOK) {
+ knot_rdataset_clear(rrs, NULL);
+ return data_ret;
+ }
+
+ if (ret == KNOT_ETTL) {
+ char buff[KNOT_DNAME_TXT_MAXLEN + 1];
+ char *owner = knot_dname_to_str(buff, rr->owner, sizeof(buff));
+ if (owner == NULL) {
+ owner = "";
+ }
+ char type[16] = { '\0' };
+ knot_rrtype_to_string(rr->type, type, sizeof(type));
+ log_zone_notice(contents->apex->owner,
+ "TTL mismatch, owner %s, type %s, "
+ "TTL set to %u", owner, type, rr->ttl);
+ return KNOT_EOK;
+ }
+ }
+
+ return ret;
+}
+
+int apply_remove_rr(apply_ctx_t *ctx, const knot_rrset_t *rr)
+{
+ zone_contents_t *contents = ctx->contents;
+
+ // Find node for this owner
+ zone_node_t *node = zone_contents_find_node_for_rr(contents, rr);
+ if (!can_remove(node, rr)) {
+ // Cannot be removed, either no node or nonexistent RR
+ if (ctx->flags & APPLY_STRICT) {
+ // Don't ignore missing RR if strict. Required for IXFR.
+ return KNOT_ENORECORD;
+ }
+ return KNOT_EOK;
+ }
+
+ zone_tree_t *tree = knot_rrset_is_nsec3rel(rr) ?
+ contents->nsec3_nodes : contents->nodes;
+
+ knot_rrset_t removed_rrset = node_rrset(node, rr->type);
+ knot_rdata_t *old_data = removed_rrset.rrs.rdata;
+ int ret = replace_rdataset_with_copy(node, rr->type);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Store old data for cleanup.
+ ret = add_old_data(ctx, old_data);
+ if (ret != KNOT_EOK) {
+ clear_new_rrs(node, rr->type);
+ return ret;
+ }
+
+ knot_rdataset_t *changed_rrs = node_rdataset(node, rr->type);
+ // Subtract changeset RRS from node RRS.
+ ret = knot_rdataset_subtract(changed_rrs, &rr->rrs, NULL);
+ if (ret != KNOT_EOK) {
+ clear_new_rrs(node, rr->type);
+ return ret;
+ }
+
+ if (changed_rrs->count > 0) {
+ // Subtraction left some data in RRSet, store it for rollback.
+ ret = add_new_data(ctx, changed_rrs->rdata);
+ if (ret != KNOT_EOK) {
+ knot_rdataset_clear(changed_rrs, NULL);
+ return ret;
+ }
+ } else {
+ // RRSet is empty now, remove it from node, all data freed, except additionals.
+ node_remove_rdataset(node, rr->type);
+ // If node is empty now, delete it from zone tree.
+ if (node->rrset_count == 0 && node != contents->apex) {
+ zone_tree_delete_empty(tree, node);
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+int apply_replace_soa(apply_ctx_t *ctx, const changeset_t *chset)
+{
+ zone_contents_t *contents = ctx->contents;
+
+ if (!knot_dname_is_equal(chset->soa_to->owner, contents->apex->owner)) {
+ return KNOT_EDENIED;
+ }
+
+ assert(chset->soa_from && chset->soa_to);
+ int ret = apply_remove_rr(ctx, chset->soa_from);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Check for SOA with proper serial but different rdata.
+ if (node_rrtype_exists(contents->apex, KNOT_RRTYPE_SOA)) {
+ return KNOT_ESOAINVAL;
+ }
+
+ return apply_add_rr(ctx, chset->soa_to);
+}
+
+int apply_prepare_to_sign(apply_ctx_t *ctx)
+{
+ return zone_contents_adjust_pointers(ctx->contents);
+}
+
+int apply_changesets_directly(apply_ctx_t *ctx, list_t *chsets)
+{
+ if (ctx == NULL || ctx->contents == NULL || chsets == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ changeset_t *set = NULL;
+ WALK_LIST(set, *chsets) {
+ int ret = apply_single(ctx, set);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ return zone_contents_adjust_full(ctx->contents);
+}
+
+int apply_changeset_directly(apply_ctx_t *ctx, const changeset_t *ch)
+{
+ if (ctx == NULL || ctx->contents == NULL || ch == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = apply_single(ctx, ch);
+ if (ret != KNOT_EOK) {
+ update_rollback(ctx);
+ return ret;
+ }
+
+ ret = zone_contents_adjust_full(ctx->contents);
+ if (ret != KNOT_EOK) {
+ update_rollback(ctx);
+ return ret;
+ }
+
+ return KNOT_EOK;
+}
+
+int apply_finalize(apply_ctx_t *ctx)
+{
+ return zone_contents_adjust_full(ctx->contents);
+}
+
+void update_cleanup(apply_ctx_t *ctx)
+{
+ if (ctx == NULL) {
+ return;
+ }
+
+ // Delete old RR data
+ rrs_list_clear(&ctx->old_data, NULL);
+ init_list(&ctx->old_data);
+ // Keep new RR data
+ ptrlist_free(&ctx->new_data, NULL);
+ init_list(&ctx->new_data);
+}
+
+void update_rollback(apply_ctx_t *ctx)
+{
+ if (ctx == NULL) {
+ return;
+ }
+
+ // Delete new RR data
+ rrs_list_clear(&ctx->new_data, NULL);
+ init_list(&ctx->new_data);
+ // Keep old RR data
+ ptrlist_free(&ctx->old_data, NULL);
+ init_list(&ctx->old_data);
+}
+
+void update_free_zone(zone_contents_t *contents)
+{
+ if (contents == NULL) {
+ return;
+ }
+
+ (void)zone_tree_apply(contents->nodes, free_additional, NULL);
+ zone_tree_deep_free(&contents->nodes);
+ zone_tree_deep_free(&contents->nsec3_nodes);
+
+ dnssec_nsec3_params_free(&contents->nsec3_params);
+
+ free(contents);
+}
diff --git a/src/knot/updates/apply.h b/src/knot/updates/apply.h
new file mode 100644
index 0000000..7908ca4
--- /dev/null
+++ b/src/knot/updates/apply.h
@@ -0,0 +1,150 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "knot/zone/contents.h"
+#include "knot/updates/changesets.h"
+#include "contrib/ucw/lists.h"
+
+enum {
+ APPLY_STRICT = 1 << 0, /* Apply strictly, don't ignore removing non-existent RRs. */
+};
+
+struct apply_ctx {
+ zone_contents_t *contents;
+ list_t old_data; /*!< Old data, to be freed after successful update. */
+ list_t new_data; /*!< New data, to be freed after failed update. */
+ uint32_t flags;
+};
+
+typedef struct apply_ctx apply_ctx_t;
+
+/*!
+ * \brief Initialize a new context structure.
+ *
+ * \param ctx Context to be initialized.
+ * \param contents Zone contents to apply changes onto.
+ * \param flags Flags to control the application process.
+ */
+void apply_init_ctx(apply_ctx_t *ctx, zone_contents_t *contents, uint32_t flags);
+
+/*!
+ * \brief Creates a shallow zone contents copy.
+ *
+ * \param old_contents Source.
+ * \param new_contents Target.
+ *
+ * \return KNOT_E*
+ */
+int apply_prepare_zone_copy(zone_contents_t *old_contents,
+ zone_contents_t **new_contents);
+
+/*!
+ * \brief Adds a single RR into zone contents.
+ *
+ * \param ctx Apply context.
+ * \param rr RRSet to add.
+ *
+ * \return KNOT_E*
+ */
+int apply_add_rr(apply_ctx_t *ctx, const knot_rrset_t *rr);
+
+/*!
+ * \brief Removes single RR from zone contents.
+ *
+ * \param ctx Apply context.
+ * \param rr RRSet to remove.
+ *
+ * \return KNOT_E*
+ */
+int apply_remove_rr(apply_ctx_t *ctx, const knot_rrset_t *rr);
+
+/*!
+ * \brief Adds a single RR into zone contents.
+ *
+ * \param ctx Apply context.
+ * \param ch Changeset to be applied to the zone.
+ *
+ * \return KNOT_E*
+ */
+int apply_replace_soa(apply_ctx_t *ctx, const changeset_t *ch);
+
+/*!
+ * \brief Prepares the new zone contents for signing.
+ *
+ * Adjusted pointers are required for DNSSEC.
+ *
+ * \param ctx Apply context.
+ *
+ * \return KNOT_E*
+ */
+int apply_prepare_to_sign(apply_ctx_t *ctx);
+
+/*!
+ * \brief Applies changesets directly to the zone, without copying it.
+ *
+ * \warning Modified zone is in inconsistent state after error and should be freed.
+ *
+ * \param ctx Apply context.
+ * \param chsets List of changesets to be applied to the zone.
+ *
+ * \return KNOT_E*
+ */
+int apply_changesets_directly(apply_ctx_t *ctx, list_t *chsets);
+
+/*!
+ * \brief Applies changeset directly to the zone, without copying it.
+ *
+ * \param ctx Apply context.
+ * \param ch Changeset to be applied to the zone.
+ *
+ * \return KNOT_E*
+ */
+int apply_changeset_directly(apply_ctx_t *ctx, const changeset_t *ch);
+
+/*!
+ * \brief Finalizes the zone contents for publishing.
+ *
+ * Fully adjusts the zone.
+ *
+ * \param ctx Apply context.
+ *
+ * \return KNOT_E*
+ */
+int apply_finalize(apply_ctx_t *ctx);
+
+/*!
+ * \brief Cleanups successful zone update.
+ *
+ * \param ctx Context used to create the update.
+ */
+void update_cleanup(apply_ctx_t *ctx);
+
+/*!
+ * \brief Rollbacks failed zone update.
+ *
+ * \param ctx Context used to create the update.
+ */
+void update_rollback(apply_ctx_t *ctx);
+
+/*!
+ * \brief Shallow frees zone contents - either shallow copy after failed update
+ * or original zone contents after successful update.
+ *
+ * \param contents Contents to free.
+ */
+void update_free_zone(zone_contents_t *contents);
diff --git a/src/knot/updates/changesets.c b/src/knot/updates/changesets.c
new file mode 100644
index 0000000..3c0c9dc
--- /dev/null
+++ b/src/knot/updates/changesets.c
@@ -0,0 +1,822 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "knot/updates/changesets.h"
+#include "knot/updates/apply.h"
+#include "libknot/libknot.h"
+#include "knot/zone/zone-dump.h"
+#include "contrib/macros.h"
+#include "contrib/mempattern.h"
+
+static int handle_soa(knot_rrset_t **soa, const knot_rrset_t *rrset)
+{
+ assert(soa);
+ assert(rrset);
+
+ if (*soa != NULL) {
+ knot_rrset_free(*soa, NULL);
+ }
+
+ *soa = knot_rrset_copy(rrset, NULL);
+ if (*soa == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ return KNOT_EOK;
+}
+
+/*! \brief Adds RRSet to given zone. */
+static int add_rr_to_contents(zone_contents_t *z, const knot_rrset_t *rrset)
+{
+ zone_node_t *n = NULL;
+ int ret = zone_contents_add_rr(z, rrset, &n);
+ UNUSED(n);
+
+ // We don't care of TTLs.
+ return ret == KNOT_ETTL ? KNOT_EOK : ret;
+}
+
+/*! \brief Cleans up trie iterations. */
+static void cleanup_iter_list(list_t *l)
+{
+ ptrnode_t *n, *nxt;
+ WALK_LIST_DELSAFE(n, nxt, *l) {
+ trie_it_t *it = (trie_it_t *)n->d;
+ trie_it_free(it);
+ rem_node(&n->n);
+ free(n);
+ }
+ init_list(l);
+}
+
+/*! \brief Inits changeset iterator with given tries. */
+static int changeset_iter_init(changeset_iter_t *ch_it, size_t tries, ...)
+{
+ memset(ch_it, 0, sizeof(*ch_it));
+ init_list(&ch_it->iters);
+
+ va_list args;
+ va_start(args, tries);
+
+ for (size_t i = 0; i < tries; ++i) {
+ trie_t *t = va_arg(args, trie_t *);
+ if (t == NULL) {
+ continue;
+ }
+
+ trie_it_t *it = trie_it_begin(t);
+ if (it == NULL) {
+ cleanup_iter_list(&ch_it->iters);
+ va_end(args);
+ return KNOT_ENOMEM;
+ }
+
+ if (ptrlist_add(&ch_it->iters, it, NULL) == NULL) {
+ cleanup_iter_list(&ch_it->iters);
+ va_end(args);
+ return KNOT_ENOMEM;
+ }
+ }
+
+ va_end(args);
+
+ return KNOT_EOK;
+}
+
+/*! \brief Gets next node from trie iterators. */
+static void iter_next_node(changeset_iter_t *ch_it, trie_it_t *t_it)
+{
+ assert(!trie_it_finished(t_it));
+ // Get next node, but not for the very first call.
+ if (ch_it->node) {
+ trie_it_next(t_it);
+ }
+ if (trie_it_finished(t_it)) {
+ ch_it->node = NULL;
+ return;
+ }
+
+ ch_it->node = (zone_node_t *)*trie_it_val(t_it);
+ assert(ch_it->node);
+ while (ch_it->node && ch_it->node->rrset_count == 0) {
+ // Skip empty non-terminals.
+ trie_it_next(t_it);
+ if (trie_it_finished(t_it)) {
+ ch_it->node = NULL;
+ } else {
+ ch_it->node = (zone_node_t *)*trie_it_val(t_it);
+ assert(ch_it->node);
+ }
+ }
+
+ ch_it->node_pos = 0;
+}
+
+/*! \brief Gets next RRSet from trie iterators. */
+static knot_rrset_t get_next_rr(changeset_iter_t *ch_it, trie_it_t *t_it)
+{
+ if (ch_it->node == NULL || ch_it->node_pos == ch_it->node->rrset_count) {
+ iter_next_node(ch_it, t_it);
+ if (ch_it->node == NULL) {
+ assert(trie_it_finished(t_it));
+ knot_rrset_t rr;
+ knot_rrset_init_empty(&rr);
+ return rr;
+ }
+ }
+
+ return node_rrset_at(ch_it->node, ch_it->node_pos++);
+}
+
+// removes from counterpart what is in rr.
+// fixed_rr is an output parameter, holding a copy of rr without what has been removed from counterpart
+static void check_redundancy(zone_contents_t *counterpart, const knot_rrset_t *rr, knot_rrset_t **fixed_rr)
+{
+ if (fixed_rr != NULL) {
+ *fixed_rr = knot_rrset_copy(rr, NULL);
+ }
+
+ zone_node_t *node = zone_contents_find_node_for_rr(counterpart, rr);
+ if (node == NULL) {
+ return;
+ }
+
+ if (!node_rrtype_exists(node, rr->type)) {
+ return;
+ }
+
+ // Subtract the data from node's RRSet.
+ knot_rdataset_t *rrs = node_rdataset(node, rr->type);
+ uint32_t rrs_ttl = node_rrset(node, rr->type).ttl;
+
+ if (fixed_rr != NULL && *fixed_rr != NULL && (*fixed_rr)->ttl == rrs_ttl) {
+ int ret = knot_rdataset_subtract(&(*fixed_rr)->rrs, rrs, NULL);
+ if (ret != KNOT_EOK) {
+ return;
+ }
+ }
+
+ if (rr->ttl == rrs_ttl) {
+ int ret = knot_rdataset_subtract(rrs, &rr->rrs, NULL);
+ if (ret != KNOT_EOK) {
+ return;
+ }
+ }
+
+ if (knot_rdataset_size(rrs) == 0) {
+ // Remove empty type.
+ node_remove_rdataset(node, rr->type);
+
+ if (node->rrset_count == 0 && node != counterpart->apex) {
+ // Remove empty node.
+ zone_tree_t *t = knot_rrset_is_nsec3rel(rr) ?
+ counterpart->nsec3_nodes : counterpart->nodes;
+ zone_tree_delete_empty(t, node);
+ }
+ }
+
+ return;
+}
+
+int changeset_init(changeset_t *ch, const knot_dname_t *apex)
+{
+ memset(ch, 0, sizeof(changeset_t));
+
+ // Init local changes
+ ch->add = zone_contents_new(apex);
+ if (ch->add == NULL) {
+ return KNOT_ENOMEM;
+ }
+ ch->remove = zone_contents_new(apex);
+ if (ch->remove == NULL) {
+ zone_contents_free(ch->add);
+ return KNOT_ENOMEM;
+ }
+
+ return KNOT_EOK;
+}
+
+changeset_t *changeset_new(const knot_dname_t *apex)
+{
+ changeset_t *ret = malloc(sizeof(changeset_t));
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ if (changeset_init(ret, apex) == KNOT_EOK) {
+ return ret;
+ } else {
+ free(ret);
+ return NULL;
+ }
+}
+
+bool changeset_empty(const changeset_t *ch)
+{
+ if (ch == NULL || ch->add == NULL || ch->remove == NULL) {
+ return true;
+ }
+
+ if (ch->soa_to) {
+ return false;
+ }
+
+ changeset_iter_t itt;
+ changeset_iter_all(&itt, ch);
+
+ knot_rrset_t rr = changeset_iter_next(&itt);
+ changeset_iter_clear(&itt);
+
+ return knot_rrset_empty(&rr);
+}
+
+size_t changeset_size(const changeset_t *ch)
+{
+ if (ch == NULL) {
+ return 0;
+ }
+
+ changeset_iter_t itt;
+ changeset_iter_all(&itt, ch);
+
+ size_t size = 0;
+ knot_rrset_t rr = changeset_iter_next(&itt);
+ while(!knot_rrset_empty(&rr)) {
+ ++size;
+ rr = changeset_iter_next(&itt);
+ }
+ changeset_iter_clear(&itt);
+
+ if (!knot_rrset_empty(ch->soa_from)) {
+ size += 1;
+ }
+ if (!knot_rrset_empty(ch->soa_to)) {
+ size += 1;
+ }
+
+ return size;
+}
+
+int changeset_add_addition(changeset_t *ch, const knot_rrset_t *rrset, changeset_flag_t flags)
+{
+ if (!ch || !rrset) {
+ return KNOT_EINVAL;
+ }
+
+ if (rrset->type == KNOT_RRTYPE_SOA) {
+ /* Do not add SOAs into actual contents. */
+ return handle_soa(&ch->soa_to, rrset);
+ }
+
+ knot_rrset_t *rrset_cancelout = NULL;
+
+ /* Check if there's any removal and remove that, then add this
+ * addition anyway. Required to change TTLs. */
+ if (flags & CHANGESET_CHECK) {
+ /* If we delete the rrset, we need to hold a copy to add it later */
+ rrset = knot_rrset_copy(rrset, NULL);
+ if (rrset == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ check_redundancy(ch->remove, rrset,
+ ((flags & CHANGESET_CHECK_CANCELOUT) ? &rrset_cancelout : NULL));
+ }
+
+ const knot_rrset_t *to_add = (rrset_cancelout == NULL ? rrset : rrset_cancelout);
+ int ret = knot_rrset_empty(to_add) ? KNOT_EOK : add_rr_to_contents(ch->add, to_add);
+
+ if (flags & CHANGESET_CHECK) {
+ knot_rrset_free((knot_rrset_t *)rrset, NULL);
+ }
+ knot_rrset_free(rrset_cancelout, NULL);
+
+ return ret;
+}
+
+int changeset_add_removal(changeset_t *ch, const knot_rrset_t *rrset, changeset_flag_t flags)
+{
+ if (!ch || !rrset) {
+ return KNOT_EINVAL;
+ }
+
+ if (rrset->type == KNOT_RRTYPE_SOA) {
+ /* Do not add SOAs into actual contents. */
+ return handle_soa(&ch->soa_from, rrset);
+ }
+
+ knot_rrset_t *rrset_cancelout = NULL;
+
+ /* Check if there's any addition and remove that, then add this
+ * removal anyway. */
+ if (flags & CHANGESET_CHECK) {
+ /* If we delete the rrset, we need to hold a copy to add it later */
+ rrset = knot_rrset_copy(rrset, NULL);
+ if (rrset == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ check_redundancy(ch->add, rrset,
+ ((flags & CHANGESET_CHECK_CANCELOUT) ? &rrset_cancelout : NULL));
+ }
+
+ const knot_rrset_t *to_remove = (rrset_cancelout == NULL ? rrset : rrset_cancelout);
+ int ret = knot_rrset_empty(to_remove) ? KNOT_EOK : add_rr_to_contents(ch->remove, to_remove);
+
+ if (flags & CHANGESET_CHECK) {
+ knot_rrset_free((knot_rrset_t *)rrset, NULL);
+ }
+ knot_rrset_free(rrset_cancelout, NULL);
+
+ return ret;
+}
+
+int changeset_remove_addition(changeset_t *ch, const knot_rrset_t *rrset)
+{
+ if (rrset->type == KNOT_RRTYPE_SOA) {
+ /* Do not add SOAs into actual contents. */
+ if (ch->soa_to != NULL) {
+ knot_rrset_free(ch->soa_to, NULL);
+ ch->soa_to = NULL;
+ }
+ return KNOT_EOK;
+ }
+
+ zone_node_t *n = NULL;
+ return zone_contents_remove_rr(ch->add, rrset, &n);
+}
+
+int changeset_remove_removal(changeset_t *ch, const knot_rrset_t *rrset)
+{
+ if (rrset->type == KNOT_RRTYPE_SOA) {
+ /* Do not add SOAs into actual contents. */
+ if (ch->soa_from != NULL) {
+ knot_rrset_free(ch->soa_from, NULL);
+ ch->soa_from = NULL;
+ }
+ return KNOT_EOK;
+ }
+
+ zone_node_t *n = NULL;
+ return zone_contents_remove_rr(ch->remove, rrset, &n);
+}
+
+int changeset_merge(changeset_t *ch1, const changeset_t *ch2, int flags)
+{
+ changeset_iter_t itt;
+ changeset_iter_rem(&itt, ch2);
+
+ knot_rrset_t rrset = changeset_iter_next(&itt);
+ while (!knot_rrset_empty(&rrset)) {
+ int ret = changeset_add_removal(ch1, &rrset, CHANGESET_CHECK | flags);
+ if (ret != KNOT_EOK) {
+ changeset_iter_clear(&itt);
+ return ret;
+ }
+ rrset = changeset_iter_next(&itt);
+ }
+ changeset_iter_clear(&itt);
+
+ changeset_iter_add(&itt, ch2);
+
+ rrset = changeset_iter_next(&itt);
+ while (!knot_rrset_empty(&rrset)) {
+ int ret = changeset_add_addition(ch1, &rrset, CHANGESET_CHECK | flags);
+ if (ret != KNOT_EOK) {
+ changeset_iter_clear(&itt);
+ return ret;
+ }
+ rrset = changeset_iter_next(&itt);
+ }
+ changeset_iter_clear(&itt);
+
+ // Use soa_to and serial from the second changeset
+ // soa_to from the first changeset is redundant, delete it
+ if (ch2->soa_to == NULL && ch2->soa_from == NULL) {
+ // but not if ch2 has no soa change
+ return KNOT_EOK;
+ }
+ knot_rrset_t *soa_copy = knot_rrset_copy(ch2->soa_to, NULL);
+ if (soa_copy == NULL && ch2->soa_to) {
+ return KNOT_ENOMEM;
+ }
+ knot_rrset_free(ch1->soa_to, NULL);
+ ch1->soa_to = soa_copy;
+
+ return KNOT_EOK;
+}
+
+typedef struct {
+ const zone_contents_t *zone;
+ changeset_t *fixing;
+ knot_mm_t *mm;
+} preapply_fix_ctx;
+
+static int preapply_fix_rrset(const knot_rrset_t *apply, bool adding, void *data)
+{
+ preapply_fix_ctx *ctx = (preapply_fix_ctx *)data;
+ const zone_node_t *znode = zone_contents_find_node(ctx->zone, apply->owner);
+ const knot_rdataset_t *zrdataset = node_rdataset(znode, apply->type);
+ if (adding && zrdataset == NULL) {
+ return KNOT_EOK;
+ }
+
+ knot_rrset_t *fixrrset;
+ if (adding) {
+ fixrrset = knot_rrset_new(apply->owner, apply->type, apply->rclass,
+ apply->ttl, ctx->mm);
+ } else {
+ fixrrset = knot_rrset_copy(apply, ctx->mm);
+ }
+ if (fixrrset == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ int ret = KNOT_EOK;
+ if (adding) {
+ ret = knot_rdataset_intersect(zrdataset, &apply->rrs, &fixrrset->rrs, ctx->mm);
+ } else {
+ uint32_t zrrset_ttl = node_rrset(znode, apply->type).ttl;
+ if (zrdataset != NULL && fixrrset->ttl == zrrset_ttl) {
+ ret = knot_rdataset_subtract(&fixrrset->rrs, zrdataset, ctx->mm);
+ }
+ }
+ if (ret == KNOT_EOK && !knot_rrset_empty(fixrrset)) {
+ if (adding) {
+ ret = changeset_add_removal(ctx->fixing, fixrrset, 0);
+ } else {
+ ret = changeset_add_addition(ctx->fixing, fixrrset, 0);
+ }
+ }
+
+ knot_rrset_free(fixrrset, ctx->mm);
+ return ret;
+}
+
+static int subtract_callback(const knot_rrset_t *rrset, bool addition, void *subtractfrom)
+{
+ changeset_t *chsf = (changeset_t *)subtractfrom;
+ if (addition) {
+ return changeset_remove_removal(chsf, rrset);
+ } else {
+ return changeset_remove_addition(chsf, rrset);
+ }
+}
+
+static int subtract(changeset_t *from, const changeset_t *what)
+{
+ return changeset_walk(what, subtract_callback, (void *)from);
+}
+
+int changeset_preapply_fix(const zone_contents_t *zone, changeset_t *ch)
+{
+ if (zone == NULL || ch == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ changeset_t fixing;
+ int ret = changeset_init(&fixing, zone->apex->owner);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ preapply_fix_ctx ctx = { .zone = zone, .fixing = &fixing, .mm = NULL };
+ ret = changeset_walk(ch, preapply_fix_rrset, (void *)&ctx);
+ if (ret == KNOT_EOK) {
+ ret = subtract(ch, &fixing);
+ }
+ changeset_clear(&fixing);
+ return ret;
+}
+
+int changeset_cancelout(changeset_t *ch)
+{
+ if (ch == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ changeset_t fixing;
+ int ret = changeset_init(&fixing, ch->add->apex->owner);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ preapply_fix_ctx ctx = { .zone = ch->remove, .fixing = &fixing, .mm = NULL };
+ ret = changeset_walk(ch, preapply_fix_rrset, (void *)&ctx);
+ if (ret == KNOT_EOK) {
+ assert(zone_contents_is_empty(fixing.add));
+ zone_contents_t *fixing_add_bck = fixing.add;
+ fixing.add = fixing.remove;
+ ret = subtract(ch, &fixing);
+ fixing.add = fixing_add_bck;
+ }
+ changeset_clear(&fixing);
+ return ret;
+}
+
+bool changeset_differs_just_serial(const changeset_t *ch)
+{
+ if (ch == NULL || ch->soa_from == NULL || ch->soa_to == NULL) {
+ return false;
+ }
+
+ knot_rrset_t *soa_to_cpy = knot_rrset_copy(ch->soa_to, NULL);
+ knot_soa_serial_set(soa_to_cpy->rrs.rdata, knot_soa_serial(ch->soa_from->rrs.rdata));
+
+ bool ret = knot_rrset_equal(ch->soa_from, soa_to_cpy, KNOT_RRSET_COMPARE_WHOLE);
+ knot_rrset_free(soa_to_cpy, NULL);
+
+ changeset_iter_t itt;
+ changeset_iter_all(&itt, ch);
+
+ knot_rrset_t rrset = changeset_iter_next(&itt);
+ while (!knot_rrset_empty(&rrset) && ret) {
+ if (rrset.type != KNOT_RRTYPE_RRSIG || rrset.rrs.count != 1 ||
+ knot_rrsig_type_covered(rrset.rrs.rdata) != KNOT_RRTYPE_SOA) {
+ ret = false;
+ }
+ rrset = changeset_iter_next(&itt);
+ }
+ changeset_iter_clear(&itt);
+
+ return ret;
+}
+
+int changeset_to_contents(changeset_t *ch, zone_contents_t **out)
+{
+ assert(ch->soa_from == NULL);
+ assert(zone_contents_is_empty(ch->remove));
+ assert(out != NULL);
+
+ *out = ch->add;
+ int ret = add_rr_to_contents(*out, ch->soa_to);
+ knot_rrset_free(ch->soa_to, NULL);
+ if (ret != KNOT_EOK) {
+ zone_contents_deep_free(*out);
+ }
+
+ zone_contents_deep_free(ch->remove);
+ free(ch->data);
+ free(ch);
+ return ret;
+}
+
+changeset_t *changeset_from_contents(const zone_contents_t *contents)
+{
+ zone_contents_t *copy = NULL;
+ if (zone_contents_shallow_copy(contents, &copy) != KNOT_EOK) {
+ return NULL;
+ }
+
+ changeset_t *res = changeset_new(copy->apex->owner);
+
+ knot_rrset_t soa_rr = node_rrset(copy->apex, KNOT_RRTYPE_SOA);;
+ res->soa_to = knot_rrset_copy(&soa_rr, NULL);
+
+ node_remove_rdataset(copy->apex, KNOT_RRTYPE_SOA);
+
+ zone_contents_deep_free(res->add);
+ res->add = copy;
+ return res;
+}
+
+void changeset_from_contents_free(changeset_t *ch)
+{
+ assert(ch);
+ assert(ch->soa_from == NULL);
+ assert(zone_contents_is_empty(ch->remove));
+
+ update_free_zone(ch->add);
+
+ zone_contents_deep_free(ch->remove);
+ knot_rrset_free(ch->soa_from, NULL);
+ knot_rrset_free(ch->soa_to, NULL);
+ free(ch->data);
+ free(ch);
+}
+
+void changesets_clear(list_t *chgs)
+{
+ if (chgs) {
+ changeset_t *chg, *nxt;
+ WALK_LIST_DELSAFE(chg, nxt, *chgs) {
+ changeset_clear(chg);
+ rem_node(&chg->n);
+ }
+ init_list(chgs);
+ }
+}
+
+void changesets_free(list_t *chgs)
+{
+ if (chgs) {
+ changeset_t *chg, *nxt;
+ WALK_LIST_DELSAFE(chg, nxt, *chgs) {
+ rem_node(&chg->n);
+ changeset_free(chg);
+ }
+ init_list(chgs);
+ }
+}
+
+void changeset_clear(changeset_t *ch)
+{
+ if (ch == NULL) {
+ return;
+ }
+
+ // Delete RRSets in lists, in case there are any left
+ zone_contents_deep_free(ch->add);
+ zone_contents_deep_free(ch->remove);
+ ch->add = NULL;
+ ch->remove = NULL;
+
+ knot_rrset_free(ch->soa_from, NULL);
+ knot_rrset_free(ch->soa_to, NULL);
+ ch->soa_from = NULL;
+ ch->soa_to = NULL;
+
+ // Delete binary data
+ free(ch->data);
+}
+
+changeset_t *changeset_clone(const changeset_t *ch)
+{
+ if (ch == NULL) {
+ return NULL;
+ }
+
+ changeset_t *res = changeset_new(ch->add->apex->owner);
+ if (res == NULL) {
+ return NULL;
+ }
+
+ res->soa_from = knot_rrset_copy(ch->soa_from, NULL);
+ res->soa_to = knot_rrset_copy(ch->soa_to, NULL);
+
+ int ret = KNOT_EOK;
+ changeset_iter_t itt;
+
+ changeset_iter_rem(&itt, ch);
+ knot_rrset_t rr = changeset_iter_next(&itt);
+ while (!knot_rrset_empty(&rr) && ret == KNOT_EOK) {
+ ret = changeset_add_removal(res, &rr, 0);
+ rr = changeset_iter_next(&itt);
+ }
+ changeset_iter_clear(&itt);
+
+ changeset_iter_add(&itt, ch);
+ rr = changeset_iter_next(&itt);
+ while (!knot_rrset_empty(&rr) && ret == KNOT_EOK) {
+ ret = changeset_add_addition(res, &rr, 0);
+ rr = changeset_iter_next(&itt);
+ }
+ changeset_iter_clear(&itt);
+
+ if ((ch->soa_from != NULL && res->soa_from == NULL) ||
+ (ch->soa_to != NULL && res->soa_to == NULL) ||
+ ret != KNOT_EOK) {
+ changeset_free(res);
+ return NULL;
+ }
+
+ return res;
+}
+
+void changeset_free(changeset_t *ch)
+{
+ changeset_clear(ch);
+ free(ch);
+}
+
+int changeset_iter_add(changeset_iter_t *itt, const changeset_t *ch)
+{
+ return changeset_iter_init(itt, 2, ch->add->nodes, ch->add->nsec3_nodes);
+}
+
+int changeset_iter_rem(changeset_iter_t *itt, const changeset_t *ch)
+{
+ return changeset_iter_init(itt, 2, ch->remove->nodes, ch->remove->nsec3_nodes);
+}
+
+int changeset_iter_all(changeset_iter_t *itt, const changeset_t *ch)
+{
+ return changeset_iter_init(itt, 4, ch->add->nodes, ch->add->nsec3_nodes,
+ ch->remove->nodes, ch->remove->nsec3_nodes);
+}
+
+knot_rrset_t changeset_iter_next(changeset_iter_t *it)
+{
+ assert(it);
+ ptrnode_t *n = NULL;
+ knot_rrset_t rr;
+ knot_rrset_init_empty(&rr);
+ WALK_LIST(n, it->iters) {
+ trie_it_t *t_it = (trie_it_t *)n->d;
+ if (trie_it_finished(t_it)) {
+ continue;
+ }
+
+ rr = get_next_rr(it, t_it);
+ if (!knot_rrset_empty(&rr)) {
+ // Got valid RRSet.
+ return rr;
+ }
+ }
+
+ return rr;
+}
+
+void changeset_iter_clear(changeset_iter_t *it)
+{
+ if (it) {
+ cleanup_iter_list(&it->iters);
+ it->node = NULL;
+ it->node_pos = 0;
+ }
+}
+
+int changeset_walk(const changeset_t *changeset, changeset_walk_callback callback, void *ctx)
+{
+ changeset_iter_t it;
+ int ret = changeset_iter_rem(&it, changeset);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ knot_rrset_t rrset = changeset_iter_next(&it);
+ while (!knot_rrset_empty(&rrset)) {
+ ret = callback(&rrset, false, ctx);
+ if (ret != KNOT_EOK) {
+ changeset_iter_clear(&it);
+ return ret;
+ }
+ rrset = changeset_iter_next(&it);
+ }
+ changeset_iter_clear(&it);
+
+ ret = changeset_iter_add(&it, changeset);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ rrset = changeset_iter_next(&it);
+ while (!knot_rrset_empty(&rrset)) {
+ ret = callback(&rrset, true, ctx);
+ if (ret != KNOT_EOK) {
+ changeset_iter_clear(&it);
+ return ret;
+ }
+ rrset = changeset_iter_next(&it);
+ }
+ changeset_iter_clear(&it);
+
+ return KNOT_EOK;
+}
+
+void changeset_print(const changeset_t *changeset, FILE *outfile, bool color)
+{
+ const char * RED = "\x1B[31m", * GRN = "\x1B[32m", * RESET = "\x1B[0m";
+ size_t buflen = 1024;
+ char *buff = malloc(buflen);
+
+ if (changeset->soa_from != NULL || !zone_contents_is_empty(changeset->remove)) {
+ fprintf(outfile, "%s;;Removed\n", color ? RED : "");
+ }
+ if (changeset->soa_from != NULL && buff != NULL) {
+ (void)knot_rrset_txt_dump(changeset->soa_from, &buff, &buflen, &KNOT_DUMP_STYLE_DEFAULT);
+ fprintf(outfile, "%s", buff);
+ }
+ (void)zone_dump_text(changeset->remove, outfile, false);
+
+ if (changeset->soa_to != NULL || !zone_contents_is_empty(changeset->add)) {
+ fprintf(outfile, "%s;;Added\n", color ? GRN : "");
+ }
+ if (changeset->soa_to != NULL && buff != NULL) {
+ (void)knot_rrset_txt_dump(changeset->soa_to, &buff, &buflen, &KNOT_DUMP_STYLE_DEFAULT);
+ fprintf(outfile, "%s", buff);
+ }
+ (void)zone_dump_text(changeset->add, outfile, false);
+
+ if (color) {
+ printf("%s", RESET);
+ }
+ free(buff);
+}
diff --git a/src/knot/updates/changesets.h b/src/knot/updates/changesets.h
new file mode 100644
index 0000000..8002712
--- /dev/null
+++ b/src/knot/updates/changesets.h
@@ -0,0 +1,314 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <stdio.h>
+
+#include "libknot/rrset.h"
+#include "knot/zone/contents.h"
+#include "contrib/ucw/lists.h"
+
+/*! \brief Changeset addition/removal flags */
+typedef enum {
+ CHANGESET_NONE = 0,
+ CHANGESET_CHECK = 1 << 0, /*! Perform redundancy check on additions/removals */
+ CHANGESET_CHECK_CANCELOUT = 1 << 1, /*! Do the complete cancelout on addition/removal/merge (depends on CHANGESET_CHECK */
+} changeset_flag_t;
+
+/*! \brief One zone change, from 'soa_from' to 'soa_to'. */
+typedef struct {
+ node_t n; /*!< List node. */
+ knot_rrset_t *soa_from; /*!< Start SOA. */
+ knot_rrset_t *soa_to; /*!< Destination SOA. */
+ zone_contents_t *add; /*!< Change additions. */
+ zone_contents_t *remove; /*!< Change removals. */
+ size_t size; /*!< Size of serialized changeset. \todo Remove after old_journal removal! */
+ uint8_t *data; /*!< Serialized changeset. */
+} changeset_t;
+
+/*! \brief Changeset iteration structure. */
+typedef struct {
+ list_t iters; /*!< List of pending zone iterators. */
+ const zone_node_t *node; /*!< Current zone node. */
+ uint16_t node_pos; /*!< Position in node. */
+} changeset_iter_t;
+
+/*!
+ * \brief Inits changeset structure.
+ *
+ * \param ch Changeset to init.
+ * \param apex Zone apex DNAME.
+ *
+ * \return KNOT_E*
+ */
+int changeset_init(changeset_t *ch, const knot_dname_t *apex);
+
+/*!
+ * \brief Creates new changeset structure and inits it.
+ *
+ * \param apex Zone apex DNAME.
+ *
+ * \return Changeset structure on success, NULL on errors.
+ */
+changeset_t *changeset_new(const knot_dname_t *apex);
+
+/*!
+ * \brief Checks whether changeset is empty, i.e. no change will happen after its application.
+ *
+ * \param ch Changeset to be checked.
+ *
+ * \retval true if changeset is empty.
+ * \retval false if changeset is not empty.
+ */
+bool changeset_empty(const changeset_t *ch);
+
+/*!
+ * \brief Get number of changes (additions and removals) in the changeset.
+ *
+ * \param ch Changeset to be checked.
+ *
+ * \return Number of changes in the changeset.
+ */
+size_t changeset_size(const changeset_t *ch);
+
+/*!
+ * \brief Add RRSet to 'add' part of changeset.
+ *
+ * \param ch Changeset to add RRSet into.
+ * \param rrset RRSet to be added.
+ * \param flags Changeset flags.
+ *
+ * \return KNOT_E*
+ */
+int changeset_add_addition(changeset_t *ch, const knot_rrset_t *rrset, changeset_flag_t flags);
+
+/*!
+ * \brief Add RRSet to 'remove' part of changeset.
+ *
+ * \param ch Changeset to add RRSet into.
+ * \param rrset RRSet to be added.
+ * \param flags Changeset flags.
+ *
+ * \return KNOT_E*
+ */
+int changeset_add_removal(changeset_t *ch, const knot_rrset_t *rrset, changeset_flag_t flags);
+
+
+/*!
+ * \brief Remove an RRSet from the 'add' part of changeset.
+ *
+ * \param ch Changeset to add RRSet into.
+ * \param rrset RRSet to be added.
+ *
+ * \return KNOT_E*
+ */
+int changeset_remove_addition(changeset_t *ch, const knot_rrset_t *rrset);
+
+/*!
+ * \brief Remove an RRSet from the 'remove' part of changeset.
+ *
+ * \param ch Changeset to add RRSet into.
+ * \param rrset RRSet to be added.
+ *
+ * \return KNOT_E*
+ */
+int changeset_remove_removal(changeset_t *ch, const knot_rrset_t *rrset);
+
+/*!
+ * \brief Merges two changesets together.
+ *
+ * \param ch1 Merge into this changeset.
+ * \param ch2 Merge this changeset.
+ * \param flags Flags how to handle rendundancies.
+ *
+ * \return KNOT_E*
+ */
+int changeset_merge(changeset_t *ch1, const changeset_t *ch2, int flags);
+
+/*!
+ * \brief Remove from changeset those rdata which won't be added/removed from zone.
+ *
+ * \param zone The zone the changeset is going to be applied on.
+ * \param ch The cheangeset to be fixed.
+ *
+ * \return KNOT_E*
+ */
+int changeset_preapply_fix(const zone_contents_t *zone, changeset_t *ch);
+
+/*!
+ * \brief Remove from changeset records which are removed and added the same.
+ *
+ * \param ch Changeset to be fixed.
+ *
+ * \return KNOT_E*
+ */
+int changeset_cancelout(changeset_t *ch);
+
+/*!
+ * \brief Check the changes and SOA, ignoring possibly updated SOA serial.
+ *
+ * \note Also tolerates changed RRSIG of SOA.
+ *
+ * \param ch Changeset in question.
+ *
+ * \retval false If the changeset changes other records than SOA, or some SOA field
+ * other than serial changed.
+ * \retval true Otherwise.
+ */
+bool changeset_differs_just_serial(const changeset_t *ch);
+
+/*!
+ * \brief Loads zone contents from botstrap changeset.
+ *
+ * \param ch Changeset to load from, will be freed!
+ * \param out Zone contents.
+ *
+ * \return KNOT_E*
+ */
+int changeset_to_contents(changeset_t *ch, zone_contents_t **out);
+
+/*!
+ * \brief Creates a bootstrap changeset from zone.
+ *
+ * \param contents Contents to include, will be freed!
+ *
+ * \return Changeset, which shall be freed with changeset_from_contents_free()
+ */
+changeset_t *changeset_from_contents(const zone_contents_t *contents);
+
+/*!
+ * \brief Frees single changeset.
+ *
+ * \param ch Changeset from changeset_from_contents() to free.
+ */
+void changeset_from_contents_free(changeset_t *ch);
+
+/*!
+ * \brief Clears changesets in list. Changesets are not free'd. Legacy.
+ *
+ * \param chgs Changeset list to clear.
+ */
+void changesets_clear(list_t *chgs);
+
+/*!
+ * \brief Free changesets in list. Legacy.
+ *
+ * \param chgs Changeset list to free.
+ */
+void changesets_free(list_t *chgs);
+
+/*!
+ * \brief Clear single changeset.
+ *
+ * \param ch Changeset to clear.
+ */
+void changeset_clear(changeset_t *ch);
+
+/*!
+ * \brief Copy changeset to newly allocated space, all rrsigs are copied.
+ *
+ * \param ch Changeset to be copied.
+ *
+ * \return a copy, or NULL if error.
+ */
+changeset_t *changeset_clone(const changeset_t *ch);
+
+/*!
+ * \brief Frees single changeset.
+ *
+ * \param ch Changeset to free.
+ */
+void changeset_free(changeset_t *ch);
+
+/*!
+ * \brief Inits changeset iteration structure with changeset additions.
+ *
+ * \param itt Iterator to init.
+ * \param ch Changeset to use.
+ *
+ * \return KNOT_E*
+ */
+int changeset_iter_add(changeset_iter_t *itt, const changeset_t *ch);
+
+/*!
+ * \brief Inits changeset iteration structure with changeset removals.
+ *
+ * \param itt Iterator to init.
+ * \param ch Changeset to use.
+ *
+ * \return KNOT_E*
+ */
+int changeset_iter_rem(changeset_iter_t *itt, const changeset_t *ch);
+
+/*!
+ * \brief Inits changeset iteration structure with changeset additions and removals.
+ *
+ * \param itt Iterator to init.
+ * \param ch Changeset to use.
+ *
+ * \return KNOT_E*
+ */
+int changeset_iter_all(changeset_iter_t *itt, const changeset_t *ch);
+
+/*!
+ * \brief Gets next RRSet from changeset iterator.
+ *
+ * \param it Changeset iterator.
+ *
+ * \return Next RRSet in iterator, empty RRSet if iteration done.
+ */
+knot_rrset_t changeset_iter_next(changeset_iter_t *it);
+
+/*!
+ * \brief Free resources allocated by changeset iterator.
+ *
+ * \param it Iterator to clear.
+ */
+void changeset_iter_clear(changeset_iter_t *it);
+
+/*!
+ * \brief A pointer type for callback for changeset_walk() function.
+ *
+ * \param rrset An actual removal/addition inside the changeset.
+ * \param addition Indicates addition against removal.
+ * \param ctx A context passed to the changeset_walk() function.
+ *
+ * \retval KNOT_EOK if all ok, iteration will continue
+ * \return KNOT_E* if error, iteration will stop immediately and changeset_walk() returns this error.
+ */
+typedef int (*changeset_walk_callback)(const knot_rrset_t *rrset, bool addition, void *ctx);
+
+/*!
+ * \brief Calls a callback for each removal/addition in the changeset.
+ *
+ * \param changeset Changeset.
+ * \param callback Callback.
+ * \param ctx Arbitrary context passed to the callback.
+ *
+ * \return KNOT_E*
+ */
+int changeset_walk(const changeset_t *changeset, changeset_walk_callback callback, void *ctx);
+
+/*!
+ *
+ * \brief Dumps the changeset into text file.
+ *
+ * \param changeset Changeset.
+ * \param outfile File to write into.
+ * \param color Use unix tty color metacharacters.
+ */
+void changeset_print(const changeset_t *changeset, FILE *outfile, bool color);
diff --git a/src/knot/updates/ddns.c b/src/knot/updates/ddns.c
new file mode 100644
index 0000000..cd2952e
--- /dev/null
+++ b/src/knot/updates/ddns.c
@@ -0,0 +1,769 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "knot/common/log.h"
+#include "knot/updates/ddns.h"
+#include "knot/updates/changesets.h"
+#include "knot/updates/zone-update.h"
+#include "knot/zone/serial.h"
+#include "libknot/libknot.h"
+#include "contrib/ucw/lists.h"
+
+/* ----------------------------- prereq check ------------------------------- */
+
+/*!< \brief Clears prereq RRSet list. */
+static void rrset_list_clear(list_t *l)
+{
+ node_t *n, *nxt;
+ WALK_LIST_DELSAFE(n, nxt, *l) {
+ ptrnode_t *ptr_n = (ptrnode_t *)n;
+ knot_rrset_t *rrset = (knot_rrset_t *)ptr_n->d;
+ knot_rrset_free(rrset, NULL);
+ free(n);
+ };
+}
+
+/*!< \brief Adds RR to prereq RRSet list, merges RRs into RRSets. */
+static int add_rr_to_list(list_t *l, const knot_rrset_t *rr)
+{
+ node_t *n;
+ WALK_LIST(n, *l) {
+ ptrnode_t *ptr_n = (ptrnode_t *)n;
+ knot_rrset_t *rrset = (knot_rrset_t *)ptr_n->d;
+ if (knot_rrset_equal(rr, rrset, KNOT_RRSET_COMPARE_HEADER)) {
+ return knot_rdataset_merge(&rrset->rrs, &rr->rrs, NULL);
+ }
+ };
+
+ knot_rrset_t *rr_copy = knot_rrset_copy(rr, NULL);
+ if (rr_copy == NULL) {
+ return KNOT_ENOMEM;
+ }
+ return ptrlist_add(l, rr_copy, NULL) != NULL ? KNOT_EOK : KNOT_ENOMEM;
+}
+
+/*!< \brief Checks whether RRSet exists in the zone. */
+static int check_rrset_exists(zone_update_t *update, const knot_rrset_t *rrset,
+ uint16_t *rcode)
+{
+ assert(rrset->type != KNOT_RRTYPE_ANY);
+
+ const zone_node_t *node = zone_update_get_node(update, rrset->owner);
+ if (node == NULL || !node_rrtype_exists(node, rrset->type)) {
+ *rcode = KNOT_RCODE_NXRRSET;
+ return KNOT_EPREREQ;
+ } else {
+ knot_rrset_t found = node_rrset(node, rrset->type);
+ assert(!knot_rrset_empty(&found));
+ if (knot_rrset_equal(&found, rrset, KNOT_RRSET_COMPARE_WHOLE)) {
+ return KNOT_EOK;
+ } else {
+ *rcode = KNOT_RCODE_NXRRSET;
+ return KNOT_EPREREQ;
+ }
+ }
+}
+
+/*!< \brief Checks whether RRSets in the list exist in the zone. */
+static int check_stored_rrsets(list_t *l, zone_update_t *update,
+ uint16_t *rcode)
+{
+ node_t *n;
+ WALK_LIST(n, *l) {
+ ptrnode_t *ptr_n = (ptrnode_t *)n;
+ knot_rrset_t *rrset = (knot_rrset_t *)ptr_n->d;
+ int ret = check_rrset_exists(update, rrset, rcode);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ };
+
+ return KNOT_EOK;
+}
+
+/*!< \brief Checks whether node of given owner, with given type exists. */
+static bool check_type(zone_update_t *update, const knot_rrset_t *rrset)
+{
+ assert(rrset->type != KNOT_RRTYPE_ANY);
+ const zone_node_t *node = zone_update_get_node(update, rrset->owner);
+ if (node == NULL || !node_rrtype_exists(node, rrset->type)) {
+ return false;
+ }
+
+ return true;
+}
+
+/*!< \brief Checks whether RR type exists in the zone. */
+static int check_type_exist(zone_update_t *update,
+ const knot_rrset_t *rrset, uint16_t *rcode)
+{
+ assert(rrset->rclass == KNOT_CLASS_ANY);
+ if (check_type(update, rrset)) {
+ return KNOT_EOK;
+ } else {
+ *rcode = KNOT_RCODE_NXRRSET;
+ return KNOT_EPREREQ;
+ }
+}
+
+/*!< \brief Checks whether RR type is not in the zone. */
+static int check_type_not_exist(zone_update_t *update,
+ const knot_rrset_t *rrset, uint16_t *rcode)
+{
+ assert(rrset->rclass == KNOT_CLASS_NONE);
+ if (check_type(update, rrset)) {
+ *rcode = KNOT_RCODE_YXRRSET;
+ return KNOT_EPREREQ;
+ } else {
+ return KNOT_EOK;
+ }
+}
+
+/*!< \brief Checks whether DNAME is in the zone. */
+static int check_in_use(zone_update_t *update,
+ const knot_dname_t *dname, uint16_t *rcode)
+{
+ const zone_node_t *node = zone_update_get_node(update, dname);
+ if (node == NULL || node->rrset_count == 0) {
+ *rcode = KNOT_RCODE_NXDOMAIN;
+ return KNOT_EPREREQ;
+ } else {
+ return KNOT_EOK;
+ }
+}
+
+/*!< \brief Checks whether DNAME is not in the zone. */
+static int check_not_in_use(zone_update_t *update,
+ const knot_dname_t *dname, uint16_t *rcode)
+{
+ const zone_node_t *node = zone_update_get_node(update, dname);
+ if (node == NULL || node->rrset_count == 0) {
+ return KNOT_EOK;
+ } else {
+ *rcode = KNOT_RCODE_YXDOMAIN;
+ return KNOT_EPREREQ;
+ }
+}
+
+/*!< \brief Returns true if rrset has 0 data or RDATA of size 0 (we need TTL). */
+static bool rrset_empty(const knot_rrset_t *rrset)
+{
+ switch (rrset->rrs.count) {
+ case 0:
+ return true;
+ case 1:
+ return rrset->rrs.rdata->len == 0;
+ default:
+ return false;
+ }
+}
+
+/*< \brief Returns true if DDNS should deny updating DNSSEC-related record. */
+static bool is_dnssec_protected(uint16_t type, bool is_apex)
+{
+ switch (type) {
+ case KNOT_RRTYPE_RRSIG:
+ case KNOT_RRTYPE_NSEC:
+ case KNOT_RRTYPE_NSEC3:
+ case KNOT_RRTYPE_CDNSKEY:
+ case KNOT_RRTYPE_CDS:
+ return true;
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_NSEC3PARAM:
+ return is_apex;
+ default:
+ return false;
+ }
+}
+
+/*!< \brief Checks prereq for given packet RR. */
+static int process_prereq(const knot_rrset_t *rrset, uint16_t qclass,
+ zone_update_t *update, uint16_t *rcode,
+ list_t *rrset_list)
+{
+ if (rrset->ttl != 0) {
+ *rcode = KNOT_RCODE_FORMERR;
+ return KNOT_EMALF;
+ }
+
+ if (knot_dname_in_bailiwick(rrset->owner, update->zone->name) < 0) {
+ *rcode = KNOT_RCODE_NOTZONE;
+ return KNOT_EOUTOFZONE;
+ }
+
+ if (rrset->rclass == KNOT_CLASS_ANY) {
+ if (!rrset_empty(rrset)) {
+ *rcode = KNOT_RCODE_FORMERR;
+ return KNOT_EMALF;
+ }
+ if (rrset->type == KNOT_RRTYPE_ANY) {
+ return check_in_use(update, rrset->owner, rcode);
+ } else {
+ return check_type_exist(update, rrset, rcode);
+ }
+ } else if (rrset->rclass == KNOT_CLASS_NONE) {
+ if (!rrset_empty(rrset)) {
+ *rcode = KNOT_RCODE_FORMERR;
+ return KNOT_EMALF;
+ }
+ if (rrset->type == KNOT_RRTYPE_ANY) {
+ return check_not_in_use(update, rrset->owner, rcode);
+ } else {
+ return check_type_not_exist(update, rrset, rcode);
+ }
+ } else if (rrset->rclass == qclass) {
+ // Store RRs for full check into list
+ int ret = add_rr_to_list(rrset_list, rrset);
+ if (ret != KNOT_EOK) {
+ *rcode = KNOT_RCODE_SERVFAIL;
+ }
+ return ret;
+ } else {
+ *rcode = KNOT_RCODE_FORMERR;
+ return KNOT_EMALF;
+ }
+}
+
+/* --------------------------- DDNS processing ------------------------------ */
+
+/* --------------------- true/false helper functions ------------------------ */
+
+static inline bool is_addition(const knot_rrset_t *rr)
+{
+ return rr->rclass == KNOT_CLASS_IN;
+}
+
+static inline bool is_removal(const knot_rrset_t *rr)
+{
+ return rr->rclass == KNOT_CLASS_NONE || rr->rclass == KNOT_CLASS_ANY;
+}
+
+static inline bool is_rr_removal(const knot_rrset_t *rr)
+{
+ return rr->rclass == KNOT_CLASS_NONE;
+}
+
+static inline bool is_rrset_removal(const knot_rrset_t *rr)
+{
+ return rr->rclass == KNOT_CLASS_ANY && rr->type != KNOT_RRTYPE_ANY;
+}
+
+static inline bool is_node_removal(const knot_rrset_t *rr)
+{
+ return rr->rclass == KNOT_CLASS_ANY && rr->type == KNOT_RRTYPE_ANY;
+}
+
+/*!< \brief Returns true if last addition of certain types is to be replaced. */
+static bool should_replace(const knot_rrset_t *rrset)
+{
+ return rrset->type == KNOT_RRTYPE_CNAME ||
+ rrset->type == KNOT_RRTYPE_NSEC3PARAM;
+}
+
+/*!< \brief Returns true if node contains given RR in its RRSets. */
+static bool node_contains_rr(const zone_node_t *node,
+ const knot_rrset_t *rrset)
+{
+ const knot_rdataset_t *zone_rrs = node_rdataset(node, rrset->type);
+ if (zone_rrs != NULL) {
+ assert(rrset->rrs.count == 1);
+ return knot_rdataset_member(zone_rrs, rrset->rrs.rdata);
+ } else {
+ return false;
+ }
+}
+
+/*!< \brief Returns true if CNAME is in this node. */
+static bool adding_to_cname(const knot_dname_t *owner,
+ const zone_node_t *node)
+{
+ if (node == NULL) {
+ // Node did not exist before update.
+ return false;
+ }
+
+ knot_rrset_t cname = node_rrset(node, KNOT_RRTYPE_CNAME);
+ if (knot_rrset_empty(&cname)) {
+ // Node did not contain CNAME before update.
+ return false;
+ }
+
+ // CNAME present
+ return true;
+}
+
+/*!< \brief Used to ignore SOA deletions and SOAs with lower serial than zone. */
+static bool skip_soa(const knot_rrset_t *rr, int64_t sn)
+{
+ if (rr->type == KNOT_RRTYPE_SOA &&
+ (rr->rclass == KNOT_CLASS_NONE || rr->rclass == KNOT_CLASS_ANY ||
+ (serial_compare(knot_soa_serial(rr->rrs.rdata), sn) != SERIAL_GREATER))) {
+ return true;
+ }
+
+ return false;
+}
+
+/* ---------------------- changeset manipulation ---------------------------- */
+
+/*!< \brief Replaces possible singleton RR type in changeset. */
+static bool singleton_replaced(changeset_t *changeset,
+ const knot_rrset_t *rr)
+{
+ if (!should_replace(rr)) {
+ return false;
+ }
+
+ zone_node_t *n = zone_contents_find_node_for_rr(changeset->add, rr);
+ if (n == NULL) {
+ return false;
+ }
+
+ knot_rdataset_t *rrs = node_rdataset(n, rr->type);
+ if (rrs == NULL) {
+ return false;
+ }
+
+ // Replace singleton RR.
+ knot_rdataset_clear(rrs, NULL);
+ node_remove_rdataset(n, rr->type);
+ node_add_rrset(n, rr, NULL);
+
+ return true;
+}
+
+/*!< \brief Adds RR into add section of changeset if it is deemed worthy. */
+static int add_rr_to_chgset(const knot_rrset_t *rr,
+ zone_update_t *update)
+{
+ if (singleton_replaced(&update->change, rr)) {
+ return KNOT_EOK;
+ }
+
+ return zone_update_add(update, rr);
+}
+
+/* ------------------------ RR processing logic ----------------------------- */
+
+/* --------------------------- RR additions --------------------------------- */
+
+/*!< \brief Processes CNAME addition (replace or ignore) */
+static int process_add_cname(const zone_node_t *node,
+ const knot_rrset_t *rr,
+ zone_update_t *update)
+{
+ knot_rrset_t cname = node_rrset(node, KNOT_RRTYPE_CNAME);
+ if (!knot_rrset_empty(&cname)) {
+ // If they are identical, ignore.
+ if (knot_rrset_equal(&cname, rr, KNOT_RRSET_COMPARE_WHOLE)) {
+ return KNOT_EOK;
+ }
+
+ int ret = zone_update_remove(update, &cname);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ return add_rr_to_chgset(rr, update);
+ } else if (!node_empty(node)) {
+ // Other occupied node => ignore.
+ return KNOT_EOK;
+ } else {
+ // Can add.
+ return add_rr_to_chgset(rr, update);
+ }
+}
+
+/*!< \brief Processes NSEC3PARAM addition (ignore when not removed, or non-apex) */
+static int process_add_nsec3param(const zone_node_t *node,
+ const knot_rrset_t *rr,
+ zone_update_t *update)
+{
+ if (node == NULL || !node_rrtype_exists(node, KNOT_RRTYPE_SOA)) {
+ // Ignore non-apex additions
+ char *owner = knot_dname_to_str_alloc(rr->owner);
+ log_warning("DDNS, refusing to add NSEC3PARAM to non-apex "
+ "node '%s'", owner);
+ free(owner);
+ return KNOT_EDENIED;
+ }
+ knot_rrset_t param = node_rrset(node, KNOT_RRTYPE_NSEC3PARAM);
+ if (knot_rrset_empty(&param)) {
+ return add_rr_to_chgset(rr, update);
+ }
+
+ char *owner = knot_dname_to_str_alloc(rr->owner);
+ log_warning("DDNS, refusing to add second NSEC3PARAM to node '%s'", owner);
+ free(owner);
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Processes SOA addition (ignore when non-apex), lower serials
+ * dropped before.
+ */
+static int process_add_soa(const zone_node_t *node,
+ const knot_rrset_t *rr,
+ zone_update_t *update)
+{
+ if (node == NULL || !node_rrtype_exists(node, KNOT_RRTYPE_SOA)) {
+ // Adding SOA to non-apex node, ignore.
+ return KNOT_EOK;
+ }
+
+ // Get current SOA RR.
+ knot_rrset_t removed = node_rrset(node, KNOT_RRTYPE_SOA);
+ if (knot_rrset_equal(&removed, rr, KNOT_RRSET_COMPARE_WHOLE)) {
+ // If they are identical, ignore.
+ return KNOT_EOK;
+ }
+
+ return add_rr_to_chgset(rr, update);
+}
+
+/*!< \brief Adds normal RR, ignores when CNAME exists in node. */
+static int process_add_normal(const zone_node_t *node,
+ const knot_rrset_t *rr,
+ zone_update_t *update)
+{
+ if (adding_to_cname(rr->owner, node)) {
+ // Adding RR to CNAME node, ignore.
+ return KNOT_EOK;
+ }
+
+ if (node && node_contains_rr(node, rr)) {
+ // Adding existing RR, ignore.
+ return KNOT_EOK;
+ }
+
+ return add_rr_to_chgset(rr, update);
+}
+
+/*!< \brief Decides what to do with RR addition. */
+static int process_add(const knot_rrset_t *rr,
+ const zone_node_t *node,
+ zone_update_t *update)
+{
+ switch(rr->type) {
+ case KNOT_RRTYPE_CNAME:
+ return process_add_cname(node, rr, update);
+ case KNOT_RRTYPE_SOA:
+ return process_add_soa(node, rr, update);
+ case KNOT_RRTYPE_NSEC3PARAM:
+ return process_add_nsec3param(node, rr, update);
+ default:
+ return process_add_normal(node, rr, update);
+ }
+}
+
+/* --------------------------- RR deletions --------------------------------- */
+
+/*!< \brief Removes single RR from zone. */
+static int process_rem_rr(const knot_rrset_t *rr,
+ const zone_node_t *node,
+ zone_update_t *update)
+{
+ if (node == NULL) {
+ // Removing from node that does not exist
+ return KNOT_EOK;
+ }
+
+ const bool apex_ns = node_rrtype_exists(node, KNOT_RRTYPE_SOA) &&
+ rr->type == KNOT_RRTYPE_NS;
+ if (apex_ns) {
+ const knot_rdataset_t *ns_rrs =
+ node_rdataset(node, KNOT_RRTYPE_NS);
+ if (ns_rrs == NULL) {
+ // Zone without apex NS.
+ return KNOT_EOK;
+ }
+ if (ns_rrs->count == 1) {
+ // Cannot remove last apex NS RR.
+ return KNOT_EOK;
+ }
+ }
+
+ knot_rrset_t to_modify = node_rrset(node, rr->type);
+ if (knot_rrset_empty(&to_modify)) {
+ // No such RRSet
+ return KNOT_EOK;
+ }
+
+ knot_rdataset_t *rrs = node_rdataset(node, rr->type);
+ if (!knot_rdataset_member(rrs, rr->rrs.rdata)) {
+ // Node does not contain this RR
+ return KNOT_EOK;
+ }
+
+ return zone_update_remove(update, rr);
+}
+
+/*!< \brief Removes RRSet from zone. */
+static int process_rem_rrset(const knot_rrset_t *rrset,
+ const zone_node_t *node,
+ zone_update_t *update)
+{
+ bool is_apex = node_rrtype_exists(node, KNOT_RRTYPE_SOA);
+
+ if (rrset->type == KNOT_RRTYPE_SOA || is_dnssec_protected(rrset->type, is_apex)) {
+ // Ignore SOA and DNSSEC removals.
+ return KNOT_EOK;
+ }
+
+ if (is_apex && rrset->type == KNOT_RRTYPE_NS) {
+ // Ignore NS apex RRSet removals.
+ return KNOT_EOK;
+ }
+
+ if (node == NULL) {
+ // no such node in zone, ignore
+ return KNOT_EOK;
+ }
+
+ if (!node_rrtype_exists(node, rrset->type)) {
+ // no such RR, ignore
+ return KNOT_EOK;
+ }
+
+ knot_rrset_t to_remove = node_rrset(node, rrset->type);
+ return zone_update_remove(update, &to_remove);
+}
+
+/*!< \brief Removes node from zone. */
+static int process_rem_node(const knot_rrset_t *rr,
+ const zone_node_t *node, zone_update_t *update)
+{
+ if (node == NULL) {
+ return KNOT_EOK;
+ }
+
+ zone_node_t *node_copy = node_shallow_copy(node, NULL);
+ if (node_copy == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ // Remove all RRSets from node
+ size_t rrset_count = node_copy->rrset_count;
+ for (int i = 0; i < rrset_count; ++i) {
+ knot_rrset_t rrset = node_rrset_at(node_copy, rrset_count - i - 1);
+ int ret = process_rem_rrset(&rrset, node_copy, update);
+ if (ret != KNOT_EOK) {
+ node_free(node_copy, NULL);
+ return ret;
+ }
+ }
+
+ node_free(node_copy, NULL);
+
+ return KNOT_EOK;
+}
+
+/*!< \brief Decides what to with removal. */
+static int process_remove(const knot_rrset_t *rr,
+ const zone_node_t *node,
+ zone_update_t *update)
+{
+ if (is_rr_removal(rr)) {
+ return process_rem_rr(rr, node, update);
+ } else if (is_rrset_removal(rr)) {
+ return process_rem_rrset(rr, node, update);
+ } else if (is_node_removal(rr)) {
+ return process_rem_node(rr, node, update);
+ } else {
+ return KNOT_EINVAL;
+ }
+}
+
+/* --------------------------- validity checks ------------------------------ */
+
+/*!< \brief Checks whether addition has not violated DNAME rules. */
+static bool sem_check(const knot_rrset_t *rr, const zone_node_t *zone_node,
+ zone_update_t *update)
+{
+ // Check that we have not added DNAME child
+ const knot_dname_t *parent_dname = knot_wire_next_label(rr->owner, NULL);
+ const zone_node_t *parent = zone_update_get_node(update, parent_dname);
+ if (parent == NULL) {
+ return true;
+ }
+
+ if (node_rrtype_exists(parent, KNOT_RRTYPE_DNAME)) {
+ // Parent has DNAME RRSet, refuse update
+ return false;
+ }
+
+ if (rr->type != KNOT_RRTYPE_DNAME || zone_node == NULL) {
+ return true;
+ }
+
+ // Check that we have not created node with DNAME children.
+ if (zone_node->children > 0) {
+ // Updated node has children and DNAME was added, refuse update
+ return false;
+ }
+
+ return true;
+}
+
+/*!< \brief Checks whether we can accept this RR. */
+static int check_update(const knot_rrset_t *rrset, const knot_pkt_t *query,
+ uint16_t *rcode)
+{
+ /* Accept both subdomain and dname match. */
+ const knot_dname_t *owner = rrset->owner;
+ const knot_dname_t *qname = knot_pkt_qname(query);
+ const int in_bailiwick = knot_dname_in_bailiwick(owner, qname);
+ if (in_bailiwick < 0) {
+ *rcode = KNOT_RCODE_NOTZONE;
+ return KNOT_EOUTOFZONE;
+ }
+ const bool is_apex = in_bailiwick == 0;
+
+ if (is_dnssec_protected(rrset->type, is_apex)) {
+ *rcode = KNOT_RCODE_REFUSED;
+ log_warning("DDNS, refusing to update DNSSEC-related record");
+ return KNOT_EDENIED;
+ }
+
+ if (rrset->rclass == knot_pkt_qclass(query)) {
+ if (knot_rrtype_is_metatype(rrset->type)) {
+ *rcode = KNOT_RCODE_FORMERR;
+ return KNOT_EMALF;
+ }
+ } else if (rrset->rclass == KNOT_CLASS_ANY) {
+ if (!rrset_empty(rrset) ||
+ (knot_rrtype_is_metatype(rrset->type) &&
+ rrset->type != KNOT_RRTYPE_ANY)) {
+ *rcode = KNOT_RCODE_FORMERR;
+ return KNOT_EMALF;
+ }
+ } else if (rrset->rclass == KNOT_CLASS_NONE) {
+ if (rrset->ttl != 0 || knot_rrtype_is_metatype(rrset->type)) {
+ *rcode = KNOT_RCODE_FORMERR;
+ return KNOT_EMALF;
+ }
+ } else {
+ *rcode = KNOT_RCODE_FORMERR;
+ return KNOT_EMALF;
+ }
+
+ return KNOT_EOK;
+}
+
+/*!< \brief Checks RR and decides what to do with it. */
+static int process_rr(const knot_rrset_t *rr, zone_update_t *update)
+{
+ const zone_node_t *node = zone_update_get_node(update, rr->owner);
+
+ if (is_addition(rr)) {
+ int ret = process_add(rr, node, update);
+ if (ret == KNOT_EOK) {
+ if (!sem_check(rr, node, update)) {
+ return KNOT_EDENIED;
+ }
+ }
+ return ret;
+ } else if (is_removal(rr)) {
+ return process_remove(rr, node, update);
+ } else {
+ return KNOT_EMALF;
+ }
+}
+
+/*!< \brief Maps Knot return code to RCODE. */
+static uint16_t ret_to_rcode(int ret)
+{
+ if (ret == KNOT_EMALF) {
+ return KNOT_RCODE_FORMERR;
+ } else if (ret == KNOT_EDENIED) {
+ return KNOT_RCODE_REFUSED;
+ } else {
+ return KNOT_RCODE_SERVFAIL;
+ }
+}
+
+/* ---------------------------------- API ----------------------------------- */
+
+int ddns_process_prereqs(const knot_pkt_t *query, zone_update_t *update,
+ uint16_t *rcode)
+{
+ if (query == NULL || rcode == NULL || update == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = KNOT_EOK;
+ list_t rrset_list; // List used to store merged RRSets
+ init_list(&rrset_list);
+
+ const knot_pktsection_t *answer = knot_pkt_section(query, KNOT_ANSWER);
+ const knot_rrset_t *answer_rr = knot_pkt_rr(answer, 0);
+ for (int i = 0; i < answer->count; ++i) {
+ // Check what can be checked, store full RRs into list
+ ret = process_prereq(&answer_rr[i], knot_pkt_qclass(query),
+ update, rcode, &rrset_list);
+ if (ret != KNOT_EOK) {
+ rrset_list_clear(&rrset_list);
+ return ret;
+ }
+ }
+
+ // Check stored RRSets
+ ret = check_stored_rrsets(&rrset_list, update, rcode);
+ rrset_list_clear(&rrset_list);
+ return ret;
+}
+
+int ddns_process_update(const zone_t *zone, const knot_pkt_t *query,
+ zone_update_t *update, uint16_t *rcode)
+{
+ if (zone == NULL || query == NULL || update == NULL || rcode == NULL) {
+ if (rcode) {
+ *rcode = ret_to_rcode(KNOT_EINVAL);
+ }
+ return KNOT_EINVAL;
+ }
+
+ uint32_t sn_old = knot_soa_serial(zone_update_from(update)->rdata);
+
+ // Process all RRs in the authority section.
+ const knot_pktsection_t *authority = knot_pkt_section(query, KNOT_AUTHORITY);
+ const knot_rrset_t *authority_rr = knot_pkt_rr(authority, 0);
+ for (uint16_t i = 0; i < authority->count; ++i) {
+ const knot_rrset_t *rr = &authority_rr[i];
+ // Check if RR is correct.
+ int ret = check_update(rr, query, rcode);
+ if (ret != KNOT_EOK) {
+ assert(*rcode != KNOT_RCODE_NOERROR);
+ return ret;
+ }
+
+ if (skip_soa(rr, sn_old)) {
+ continue;
+ }
+
+ ret = process_rr(rr, update);
+ if (ret != KNOT_EOK) {
+ *rcode = ret_to_rcode(ret);
+ return ret;
+ }
+ }
+
+ *rcode = KNOT_RCODE_NOERROR;
+ return KNOT_EOK;
+}
diff --git a/src/knot/updates/ddns.h b/src/knot/updates/ddns.h
new file mode 100644
index 0000000..171245d
--- /dev/null
+++ b/src/knot/updates/ddns.h
@@ -0,0 +1,57 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief Dynamic updates processing.
+ *
+ * \addtogroup ddns
+ * @{
+ */
+
+#pragma once
+
+#include "knot/updates/zone-update.h"
+#include "knot/zone/zone.h"
+#include "libknot/packet/pkt.h"
+
+/*!
+ * \brief Checks update prerequisite section.
+ *
+ * \param query DNS message containing the update.
+ * \param update Zone to be checked.
+ * \param rcode Returned DNS RCODE.
+ *
+ * \return KNOT_E*
+ */
+int ddns_process_prereqs(const knot_pkt_t *query, zone_update_t *update,
+ uint16_t *rcode);
+
+/*!
+ * \brief Processes DNS update and creates a changeset out of it. Zone is left
+ * intact.
+ *
+ * \param zone Zone to be updated.
+ * \param query DNS message containing the update.
+ * \param update Output changeset.
+ * \param rcode Output DNS RCODE.
+ *
+ * \return KNOT_E*
+ */
+int ddns_process_update(const zone_t *zone, const knot_pkt_t *query,
+ zone_update_t *update, uint16_t *rcode);
+
+/*! @} */
diff --git a/src/knot/updates/zone-update.c b/src/knot/updates/zone-update.c
new file mode 100644
index 0000000..7905a33
--- /dev/null
+++ b/src/knot/updates/zone-update.c
@@ -0,0 +1,895 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "knot/common/log.h"
+#include "knot/dnssec/zone-events.h"
+#include "knot/updates/zone-update.h"
+#include "knot/zone/serial.h"
+#include "knot/zone/zone-diff.h"
+#include "contrib/mempattern.h"
+#include "contrib/trim.h"
+#include "contrib/ucw/lists.h"
+#include "contrib/ucw/mempool.h"
+
+#include <urcu.h>
+
+static int init_incremental(zone_update_t *update, zone_t *zone, zone_contents_t *old_contents, bool deep_copy)
+{
+ if (old_contents == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = changeset_init(&update->change, zone->name);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ if (deep_copy) {
+ update->new_cont_deep_copy = true;
+ update->new_cont = old_contents;
+ } else {
+ update->new_cont_deep_copy = false;
+ ret = apply_prepare_zone_copy(old_contents, &update->new_cont);
+ if (ret != KNOT_EOK) {
+ changeset_clear(&update->change);
+ return ret;
+ }
+ }
+
+ uint32_t apply_flags = update->flags & UPDATE_STRICT ? APPLY_STRICT : 0;
+ apply_init_ctx(update->a_ctx, update->new_cont, apply_flags);
+
+ /* Copy base SOA RR. */
+ update->change.soa_from =
+ node_create_rrset(old_contents->apex, KNOT_RRTYPE_SOA);
+ if (update->change.soa_from == NULL) {
+ zone_contents_free(update->new_cont);
+ changeset_clear(&update->change);
+ return KNOT_ENOMEM;
+ }
+
+ return KNOT_EOK;
+}
+
+static int init_full(zone_update_t *update, zone_t *zone)
+{
+ update->new_cont = zone_contents_new(zone->name);
+ if (update->new_cont == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ update->new_cont_deep_copy = true;
+
+ apply_init_ctx(update->a_ctx, update->new_cont, 0);
+
+ return KNOT_EOK;
+}
+
+static int replace_soa(zone_contents_t *contents, const knot_rrset_t *rr)
+{
+ /* SOA possible only within apex. */
+ if (!knot_dname_is_equal(rr->owner, contents->apex->owner)) {
+ return KNOT_EDENIED;
+ }
+
+ knot_rrset_t old_soa = node_rrset(contents->apex, KNOT_RRTYPE_SOA);
+ zone_node_t *n = contents->apex;
+ int ret = zone_contents_remove_rr(contents, &old_soa, &n);
+ if (ret != KNOT_EOK && ret != KNOT_EINVAL) {
+ return ret;
+ }
+
+ ret = zone_contents_add_rr(contents, rr, &n);
+ if (ret == KNOT_ETTL) {
+ return KNOT_EOK;
+ }
+
+ return ret;
+}
+
+int init_base(zone_update_t *update, zone_t *zone, zone_contents_t *old_contents,
+ zone_update_flags_t flags)
+{
+ if (update == NULL || zone == NULL || (old_contents == NULL && (flags & UPDATE_INCREMENTAL))) {
+ return KNOT_EINVAL;
+ }
+
+ memset(update, 0, sizeof(*update));
+ update->zone = zone;
+
+ mm_ctx_mempool(&update->mm, MM_DEFAULT_BLKSIZE);
+ update->flags = flags;
+
+ update->a_ctx = calloc(1, sizeof(*update->a_ctx));
+ if (update->a_ctx == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ int ret = KNOT_EINVAL;
+ if (flags & UPDATE_INCREMENTAL) {
+ ret = init_incremental(update, zone, old_contents, flags & UPDATE_JOURNAL);
+ } else if (flags & UPDATE_FULL) {
+ ret = init_full(update, zone);
+ }
+ if (ret != KNOT_EOK) {
+ free(update->a_ctx);
+ }
+
+ return ret;
+}
+
+/* ------------------------------- API -------------------------------------- */
+
+int zone_update_init(zone_update_t *update, zone_t *zone, zone_update_flags_t flags)
+{
+ return init_base(update, zone, zone->contents, flags);
+}
+
+int zone_update_from_differences(zone_update_t *update, zone_t *zone, zone_contents_t *old_cont,
+ zone_contents_t *new_cont, zone_update_flags_t flags, bool ignore_dnssec)
+{
+ if (update == NULL || zone == NULL || new_cont == NULL ||
+ !(flags & UPDATE_INCREMENTAL) || (flags & UPDATE_FULL)) {
+ return KNOT_EINVAL;
+ }
+
+ changeset_t diff;
+ int ret = changeset_init(&diff, zone->name);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = zone_contents_diff(old_cont, new_cont, &diff, ignore_dnssec);
+ if (ret != KNOT_EOK && ret != KNOT_ENODIFF && ret != KNOT_ESEMCHECK) {
+ changeset_clear(&diff);
+ return ret;
+ }
+
+ // True if nonempty changes were made but the serial
+ // remained the same and has to be incremented.
+ bool diff_semcheck = (ret == KNOT_ESEMCHECK);
+
+ ret = init_base(update, zone, old_cont, flags);
+ if (ret != KNOT_EOK) {
+ changeset_clear(&diff);
+ return ret;
+ }
+
+ ret = zone_update_apply_changeset(update, &diff);
+ changeset_clear(&diff);
+ if (ret != KNOT_EOK) {
+ zone_update_clear(update);
+ return ret;
+ }
+
+ if (diff_semcheck) {
+ ret = zone_update_increment_soa(update, conf());
+ if (ret != KNOT_EOK) {
+ zone_update_clear(update);
+ return ret;
+ }
+ log_zone_info(zone->name, "automatic SOA serial increment");
+ }
+
+ return KNOT_EOK;
+}
+
+int zone_update_from_contents(zone_update_t *update, zone_t *zone_without_contents,
+ zone_contents_t *new_cont, zone_update_flags_t flags)
+{
+ if (update == NULL || zone_without_contents == NULL || new_cont == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ memset(update, 0, sizeof(*update));
+ update->zone = zone_without_contents;
+
+ mm_ctx_mempool(&update->mm, MM_DEFAULT_BLKSIZE);
+ update->flags = flags;
+
+ update->new_cont = new_cont;
+ update->new_cont_deep_copy = true;
+
+ update->a_ctx = calloc(1, sizeof(*update->a_ctx));
+ if (update->a_ctx == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ if (flags & UPDATE_INCREMENTAL) {
+ int ret = changeset_init(&update->change, zone_without_contents->name);
+ if (ret != KNOT_EOK) {
+ free(update->a_ctx);
+ return ret;
+ }
+
+ update->change.soa_from = node_create_rrset(new_cont->apex, KNOT_RRTYPE_SOA);
+ if (update->change.soa_from == NULL) {
+ changeset_clear(&update->change);
+ free(update->a_ctx);
+ return KNOT_ENOMEM;
+ }
+ }
+
+ uint32_t apply_flags = update->flags & UPDATE_STRICT ? APPLY_STRICT : 0;
+ apply_init_ctx(update->a_ctx, update->new_cont, apply_flags);
+
+ return KNOT_EOK;
+}
+
+const zone_node_t *zone_update_get_node(zone_update_t *update, const knot_dname_t *dname)
+{
+ if (update == NULL || dname == NULL) {
+ return NULL;
+ }
+
+ return zone_contents_find_node(update->new_cont, dname);
+}
+
+const zone_node_t *zone_update_get_apex(zone_update_t *update)
+{
+ if (update == NULL) {
+ return NULL;
+ }
+
+ return zone_update_get_node(update, update->zone->name);
+}
+
+uint32_t zone_update_current_serial(zone_update_t *update)
+{
+ const zone_node_t *apex = zone_update_get_apex(update);
+ if (apex != NULL) {
+ return knot_soa_serial(node_rdataset(apex, KNOT_RRTYPE_SOA)->rdata);
+ } else {
+ return 0;
+ }
+}
+
+const knot_rdataset_t *zone_update_from(zone_update_t *update)
+{
+ if (update == NULL) {
+ return NULL;
+ }
+
+ if (update->flags & UPDATE_INCREMENTAL) {
+ const zone_node_t *apex = update->zone->contents->apex;
+ return node_rdataset(apex, KNOT_RRTYPE_SOA);
+ }
+
+ return NULL;
+}
+
+const knot_rdataset_t *zone_update_to(zone_update_t *update)
+{
+ if (update == NULL) {
+ return NULL;
+ }
+
+ if (update->flags & UPDATE_FULL) {
+ const zone_node_t *apex = update->new_cont->apex;
+ return node_rdataset(apex, KNOT_RRTYPE_SOA);
+ } else if (update->flags & UPDATE_INCREMENTAL) {
+ if (update->change.soa_to == NULL) {
+ return NULL;
+ }
+ return &update->change.soa_to->rrs;
+ }
+
+ return NULL;
+}
+
+void zone_update_clear(zone_update_t *update)
+{
+ if (update == NULL) {
+ return;
+ }
+
+ if (update->flags & UPDATE_INCREMENTAL) {
+ /* Revert any changes on error, do nothing on success. */
+ if (update->new_cont_deep_copy) {
+ update_cleanup(update->a_ctx);
+ zone_contents_deep_free(update->new_cont);
+ } else {
+ update_rollback(update->a_ctx);
+ update_free_zone(update->new_cont);
+ }
+ changeset_clear(&update->change);
+ } else if (update->flags & UPDATE_FULL) {
+ assert(update->new_cont_deep_copy);
+ zone_contents_deep_free(update->new_cont);
+ }
+ free(update->a_ctx);
+ mp_delete(update->mm.ctx);
+ memset(update, 0, sizeof(*update));
+}
+
+int zone_update_add(zone_update_t *update, const knot_rrset_t *rrset)
+{
+ if (update == NULL || rrset == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ if (update->flags & UPDATE_INCREMENTAL) {
+ int ret = changeset_add_addition(&update->change, rrset, CHANGESET_CHECK);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ if (rrset->type == KNOT_RRTYPE_SOA) {
+ /* replace previous SOA */
+ ret = apply_replace_soa(update->a_ctx, &update->change);
+ if (ret != KNOT_EOK) {
+ changeset_remove_addition(&update->change, rrset);
+ }
+ return ret;
+ }
+
+ ret = apply_add_rr(update->a_ctx, rrset);
+ if (ret != KNOT_EOK) {
+ changeset_remove_addition(&update->change, rrset);
+ return ret;
+ }
+
+ return KNOT_EOK;
+ } else if (update->flags & UPDATE_FULL) {
+ if (rrset->type == KNOT_RRTYPE_SOA) {
+ /* replace previous SOA */
+ return replace_soa(update->new_cont, rrset);
+ }
+
+ zone_node_t *n = NULL;
+ int ret = zone_contents_add_rr(update->new_cont, rrset, &n);
+ if (ret == KNOT_ETTL) {
+ char buff[KNOT_DNAME_TXT_MAXLEN + 1];
+ char *owner = knot_dname_to_str(buff, rrset->owner, sizeof(buff));
+ if (owner == NULL) {
+ owner = "";
+ }
+ char type[16] = { '\0' };
+ knot_rrtype_to_string(rrset->type, type, sizeof(type));
+ log_zone_notice(update->new_cont->apex->owner,
+ "TTL mismatch, owner %s, type %s, "
+ "TTL set to %u", owner, type, rrset->ttl);
+ return KNOT_EOK;
+ }
+
+ return ret;
+ } else {
+ return KNOT_EINVAL;
+ }
+}
+
+int zone_update_remove(zone_update_t *update, const knot_rrset_t *rrset)
+{
+ if (update == NULL || rrset == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ if (update->flags & UPDATE_INCREMENTAL) {
+ int ret = changeset_add_removal(&update->change, rrset, CHANGESET_CHECK);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ if (rrset->type == KNOT_RRTYPE_SOA) {
+ /* SOA is replaced with addition */
+ return KNOT_EOK;
+ }
+
+ ret = apply_remove_rr(update->a_ctx, rrset);
+ if (ret != KNOT_EOK) {
+ changeset_remove_removal(&update->change, rrset);
+ return ret;
+ }
+
+ return KNOT_EOK;
+ } else if (update->flags & UPDATE_FULL) {
+ zone_node_t *n = NULL;
+ knot_rrset_t *rrs_copy = knot_rrset_copy(rrset, &update->mm);
+ int ret = zone_contents_remove_rr(update->new_cont, rrs_copy, &n);
+ knot_rrset_free(rrs_copy, &update->mm);
+ return ret;
+ } else {
+ return KNOT_EINVAL;
+ }
+}
+
+int zone_update_remove_rrset(zone_update_t *update, knot_dname_t *owner, uint16_t type)
+{
+ if (update == NULL || owner == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ if (update->flags & UPDATE_INCREMENTAL) {
+ /* Remove the RRSet from the original node */
+ const zone_node_t *node = zone_contents_find_node(update->new_cont, owner);
+ if (node != NULL) {
+ knot_rrset_t rrset = node_rrset(node, type);
+ if (rrset.owner == NULL) {
+ return KNOT_ENOENT;
+ }
+ int ret = changeset_add_removal(&update->change, &rrset,
+ CHANGESET_CHECK);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ if (type == KNOT_RRTYPE_SOA) {
+ /* SOA is replaced with addition */
+ return KNOT_EOK;
+ }
+
+ ret = apply_remove_rr(update->a_ctx, &rrset);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ } else {
+ return KNOT_ENONODE;
+ }
+ } else if (update->flags & UPDATE_FULL) {
+ /* Remove the RRSet from the non-synthesized new node */
+ const zone_node_t *node = zone_contents_find_node(update->new_cont, owner);
+ if (node == NULL) {
+ return KNOT_ENONODE;
+ }
+
+ knot_rrset_t rrset = node_rrset(node, type);
+ int ret = zone_update_remove(update, &rrset);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+int zone_update_remove_node(zone_update_t *update, const knot_dname_t *owner)
+{
+ if (update == NULL || owner == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ if (update->flags & UPDATE_INCREMENTAL) {
+ /* Remove all RRSets from the new node */
+ const zone_node_t *node = zone_contents_find_node(update->new_cont, owner);
+ if (node != NULL) {
+ size_t rrset_count = node->rrset_count;
+ for (int i = 0; i < rrset_count; ++i) {
+ knot_rrset_t rrset = node_rrset_at(node, rrset_count - 1 - i);
+ int ret = changeset_add_removal(&update->change, &rrset,
+ CHANGESET_CHECK);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ if (rrset.type == KNOT_RRTYPE_SOA) {
+ /* SOA is replaced with addition */
+ continue;
+ }
+
+ ret = apply_remove_rr(update->a_ctx, &rrset);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+ } else {
+ return KNOT_ENONODE;
+ }
+ } else if (update->flags & UPDATE_FULL) {
+ /* Remove all RRSets from the non-synthesized new node */
+ const zone_node_t *node = zone_contents_find_node(update->new_cont, owner);
+ if (node == NULL) {
+ return KNOT_ENONODE;
+ }
+
+ size_t rrset_count = node->rrset_count;
+ for (int i = 0; i < rrset_count; ++i) {
+ knot_rrset_t rrset = node_rrset_at(node, rrset_count - 1 - i);
+ int ret = zone_update_remove(update, &rrset);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+int zone_update_apply_changeset(zone_update_t *update, const changeset_t *changes)
+{
+ int ret = KNOT_EOK;
+ if (update->flags & UPDATE_INCREMENTAL) {
+ ret = changeset_merge(&update->change, changes, CHANGESET_CHECK_CANCELOUT);
+ }
+ if (ret == KNOT_EOK) {
+ ret = apply_changeset_directly(update->a_ctx, changes);
+ }
+ return ret;
+}
+
+int zone_update_apply_changeset_fix(zone_update_t *update, changeset_t *changes)
+{
+ int ret = changeset_cancelout(changes);
+ if (ret == KNOT_EOK) {
+ ret = changeset_preapply_fix(update->new_cont, changes);
+ }
+ if (ret == KNOT_EOK) {
+ ret = zone_update_apply_changeset(update, changes);
+ }
+ return ret;
+}
+
+int zone_update_apply_changeset_reverse(zone_update_t *update, const changeset_t *changes)
+{
+ changeset_t reverse;
+ reverse.remove = changes->add;
+ reverse.add = changes->remove;
+ reverse.soa_from = changes->soa_to;
+ reverse.soa_to = changes->soa_from;
+ return zone_update_apply_changeset(update, &reverse);
+}
+
+static int set_new_soa(zone_update_t *update, unsigned serial_policy)
+{
+ assert(update);
+
+ knot_rrset_t *soa_cpy = node_create_rrset(zone_update_get_apex(update),
+ KNOT_RRTYPE_SOA);
+ if (soa_cpy == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ int ret = zone_update_remove(update, soa_cpy);
+ if (ret != KNOT_EOK) {
+ knot_rrset_free(soa_cpy, NULL);
+ return ret;
+ }
+
+ uint32_t old_serial = knot_soa_serial(soa_cpy->rrs.rdata);
+ uint32_t new_serial = serial_next(old_serial, serial_policy);
+ if (serial_compare(old_serial, new_serial) != SERIAL_LOWER) {
+ log_zone_warning(update->zone->name, "updated SOA serial is lower "
+ "than current, serial %u -> %u",
+ old_serial, new_serial);
+ ret = KNOT_ESOAINVAL;
+ } else {
+ knot_soa_serial_set(soa_cpy->rrs.rdata, new_serial);
+
+ ret = zone_update_add(update, soa_cpy);
+ }
+ knot_rrset_free(soa_cpy, NULL);
+
+ return ret;
+}
+
+int zone_update_increment_soa(zone_update_t *update, conf_t *conf)
+{
+ if (update == NULL || conf == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ conf_val_t val = conf_zone_get(conf, C_SERIAL_POLICY, update->zone->name);
+ return set_new_soa(update, conf_opt(&val));
+}
+
+static int commit_incremental(conf_t *conf, zone_update_t *update,
+ zone_contents_t **contents_out)
+{
+ assert(update);
+ assert(contents_out);
+
+ if (changeset_empty(&update->change)) {
+ changeset_clear(&update->change);
+ if (update->zone->contents == NULL || update->new_cont_deep_copy) {
+ *contents_out = update->new_cont;
+ }
+ return KNOT_EOK;
+ }
+
+ zone_contents_t *new_contents = update->new_cont;
+ int ret = KNOT_EOK;
+ if (zone_update_to(update) == NULL) {
+ /* No SOA in the update, create one according to the current policy */
+ ret = zone_update_increment_soa(update, conf);
+ if (ret != KNOT_EOK) {
+ zone_update_clear(update);
+ return ret;
+ }
+ }
+
+ ret = apply_finalize(update->a_ctx);
+ if (ret != KNOT_EOK) {
+ zone_update_clear(update);
+ return ret;
+ }
+
+ /* Write changes to journal if all went well. */
+ conf_val_t val = conf_zone_get(conf, C_JOURNAL_CONTENT, update->zone->name);
+ if (conf_opt(&val) != JOURNAL_CONTENT_NONE) {
+ ret = zone_change_store(conf, update->zone, &update->change);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ *contents_out = new_contents;
+
+ return KNOT_EOK;
+}
+
+static int commit_full(conf_t *conf, zone_update_t *update, zone_contents_t **contents_out)
+{
+ assert(update);
+ assert(contents_out);
+
+ /* Check if we have SOA. We might consider adding full semantic check here.
+ * But if we wanted full sem-check I'd consider being it controlled by a flag
+ * - to enable/disable it on demand. */
+ if (!node_rrtype_exists(update->new_cont->apex, KNOT_RRTYPE_SOA)) {
+ return KNOT_ESEMCHECK;
+ }
+
+ int ret = zone_contents_adjust_full(update->new_cont);
+ if (ret != KNOT_EOK) {
+ zone_update_clear(update);
+ return ret;
+ }
+
+ /* Store new zone contents in journal. */
+ conf_val_t val = conf_zone_get(conf, C_JOURNAL_CONTENT, update->zone->name);
+ unsigned content = conf_opt(&val);
+ if (content == JOURNAL_CONTENT_ALL) {
+ ret = zone_in_journal_store(conf, update->zone, update->new_cont);
+ } else if (content != JOURNAL_CONTENT_NONE) { // zone_in_journal_store does this automatically
+ ret = zone_changes_clear(conf, update->zone);
+ }
+
+ *contents_out = update->new_cont;
+
+ return ret;
+}
+
+/*! \brief Routine for calling call_rcu() easier way.
+ *
+ * Consider moving elsewhere, as it has no direct relation to zone-update.
+ */
+typedef struct {
+ struct rcu_head rcuhead;
+ void (*callback)(void *);
+ void *ctx;
+ bool free_ctx;
+} callrcu_wrapper_t;
+
+static void callrcu_wrapper_cb(struct rcu_head *param)
+{
+ callrcu_wrapper_t *wrap = (callrcu_wrapper_t *)param;
+ wrap->callback(wrap->ctx);
+ if (wrap->free_ctx) {
+ free(wrap->ctx);
+ }
+ free(wrap);
+
+ // Trim extra heap.
+ mem_trim();
+}
+
+/* NOTE: Does nothing if not enough memory. */
+static void callrcu_wrapper(void *ctx, void *callback, bool free_ctx)
+{
+ callrcu_wrapper_t *wrap = calloc(1, sizeof(callrcu_wrapper_t));
+ if (wrap != NULL) {
+ wrap->callback = callback;
+ wrap->ctx = ctx;
+ wrap->free_ctx = free_ctx;
+ call_rcu((struct rcu_head *)wrap, callrcu_wrapper_cb);
+ }
+}
+
+int zone_update_commit(conf_t *conf, zone_update_t *update)
+{
+ if (conf == NULL || update == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = KNOT_EOK;
+ zone_contents_t *new_contents = NULL;
+ if (update->flags & UPDATE_INCREMENTAL) {
+ ret = commit_incremental(conf, update, &new_contents);
+ } else {
+ ret = commit_full(conf, update, &new_contents);
+ }
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ /* If there is anything to change. */
+ if (new_contents == NULL) {
+ return KNOT_EOK;
+ }
+
+ /* Check the zone size. */
+ conf_val_t val = conf_zone_get(conf, C_MAX_ZONE_SIZE, update->zone->name);
+ size_t size_limit = conf_int(&val);
+
+ if (new_contents->size > size_limit) {
+ /* Recoverable error. */
+ return KNOT_EZONESIZE;
+ }
+
+ /* Check if the zone was re-signed upon zone load to ensure proper flush
+ * even if the SOA serial wasn't incremented by re-signing. */
+ val = conf_zone_get(conf, C_DNSSEC_SIGNING, update->zone->name);
+ bool dnssec = conf_bool(&val);
+ if (!changeset_empty(&update->change) && dnssec) {
+ update->zone->zonefile.resigned = true;
+ }
+
+ /* Switch zone contents. */
+ zone_contents_t *old_contents;
+ old_contents = zone_switch_contents(update->zone, new_contents);
+
+ /* Sync RCU. */
+ if (update->flags & UPDATE_FULL) {
+ assert(update->new_cont_deep_copy);
+ callrcu_wrapper(old_contents, zone_contents_deep_free, false);
+ } else if (update->flags & UPDATE_INCREMENTAL) {
+ if (update->new_cont_deep_copy) {
+ callrcu_wrapper(old_contents, zone_contents_deep_free, false);
+ } else {
+ callrcu_wrapper(old_contents, update_free_zone, false);
+ }
+ changeset_clear(&update->change);
+ }
+ callrcu_wrapper(update->a_ctx, update_cleanup, true);
+ update->a_ctx = NULL;
+ update->new_cont = NULL;
+
+ /* Sync zonefile immediately if configured. */
+ val = conf_zone_get(conf, C_ZONEFILE_SYNC, update->zone->name);
+ if (conf_int(&val) == 0) {
+ zone_events_schedule_now(update->zone, ZONE_EVENT_FLUSH);
+ }
+
+ return KNOT_EOK;
+}
+
+static int iter_init_tree_iters(zone_update_iter_t *it, zone_update_t *update,
+ bool nsec3)
+{
+ /* Set zone iterator. */
+ zone_contents_t *_contents = update->new_cont;
+
+ /* Begin iteration. We can safely assume _contents is a valid pointer. */
+ zone_tree_t *tree = nsec3 ? _contents->nsec3_nodes : _contents->nodes;
+ it->tree_it = trie_it_begin(tree);
+ if (it->tree_it == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ it->cur_node = (zone_node_t *)(*trie_it_val(it->tree_it));
+
+ return KNOT_EOK;
+}
+
+static int iter_get_next_node(zone_update_iter_t *it)
+{
+ trie_it_next(it->tree_it);
+ if (trie_it_finished(it->tree_it)) {
+ trie_it_free(it->tree_it);
+ it->tree_it = NULL;
+ it->cur_node = NULL;
+ return KNOT_ENOENT;
+ }
+
+ it->cur_node = (zone_node_t *)(*trie_it_val(it->tree_it));
+
+ return KNOT_EOK;
+}
+
+static int iter_init(zone_update_iter_t *it, zone_update_t *update, const bool nsec3)
+{
+ memset(it, 0, sizeof(*it));
+
+ it->update = update;
+ it->nsec3 = nsec3;
+ int ret = iter_init_tree_iters(it, update, nsec3);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ it->cur_node = (zone_node_t *)(*trie_it_val(it->tree_it));
+
+ return KNOT_EOK;
+}
+
+int zone_update_iter(zone_update_iter_t *it, zone_update_t *update)
+{
+ if (it == NULL || update == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ return iter_init(it, update, false);
+}
+
+int zone_update_iter_nsec3(zone_update_iter_t *it, zone_update_t *update)
+{
+ if (it == NULL || update == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ if (update->flags & UPDATE_FULL) {
+ if (update->new_cont->nsec3_nodes == NULL) {
+ /* No NSEC3 tree. */
+ return KNOT_ENOENT;
+ }
+ } else {
+ if (update->change.add->nsec3_nodes == NULL &&
+ update->change.remove->nsec3_nodes == NULL) {
+ /* No NSEC3 changes. */
+ return KNOT_ENOENT;
+ }
+ }
+
+ return iter_init(it, update, true);
+}
+
+int zone_update_iter_next(zone_update_iter_t *it)
+{
+ if (it == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ if (it->tree_it != NULL) {
+ int ret = iter_get_next_node(it);
+ if (ret != KNOT_EOK && ret != KNOT_ENOENT) {
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+const zone_node_t *zone_update_iter_val(zone_update_iter_t *it)
+{
+ if (it != NULL) {
+ return it->cur_node;
+ } else {
+ return NULL;
+ }
+}
+
+void zone_update_iter_finish(zone_update_iter_t *it)
+{
+ if (it == NULL) {
+ return;
+ }
+
+ trie_it_free(it->tree_it);
+}
+
+bool zone_update_no_change(zone_update_t *update)
+{
+ if (update == NULL) {
+ return true;
+ }
+
+ if (update->flags & UPDATE_INCREMENTAL) {
+ return changeset_empty(&update->change);
+ } else {
+ /* This branch does not make much sense and FULL update will most likely
+ * be a change every time anyway, just return false. */
+ return false;
+ }
+}
diff --git a/src/knot/updates/zone-update.h b/src/knot/updates/zone-update.h
new file mode 100644
index 0000000..b5d7a9a
--- /dev/null
+++ b/src/knot/updates/zone-update.h
@@ -0,0 +1,321 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "knot/updates/apply.h"
+#include "knot/conf/conf.h"
+#include "knot/updates/changesets.h"
+#include "knot/zone/contents.h"
+#include "knot/zone/zone.h"
+#include "libknot/mm_ctx.h"
+
+/*! \brief Structure for zone contents updating / querying. */
+typedef struct zone_update {
+ zone_t *zone; /*!< Zone being updated. */
+ zone_contents_t *new_cont; /*!< New zone contents for full updates. */
+ bool new_cont_deep_copy; /*!< On update_clear, perform deep free instead of shallow. */
+ changeset_t change; /*!< Changes we want to apply. */
+ apply_ctx_t *a_ctx; /*!< Context for applying changesets. */
+ uint32_t flags; /*!< Zone update flags. */
+ knot_mm_t mm; /*!< Memory context used for intermediate nodes. */
+} zone_update_t;
+
+typedef struct {
+ zone_update_t *update; /*!< The update we're iterating over. */
+ trie_it_t *tree_it; /*!< Iterator for the new zone. */
+ const zone_node_t *cur_node; /*!< Current node in the new zone. */
+ bool nsec3; /*!< Set when we're using the NSEC3 node tree. */
+} zone_update_iter_t;
+
+typedef enum {
+ UPDATE_FULL = 1 << 0, /*!< Replace the old zone by a complete new one. */
+ UPDATE_INCREMENTAL = 1 << 1, /*!< Apply changes to the old zone. */
+ UPDATE_SIGN = 1 << 2, /*!< Sign the resulting zone. */
+ UPDATE_JOURNAL = 1 << 3, /*!< Using zone-in-journal for a diff update. */
+ UPDATE_STRICT = 1 << 4, /*!< Apply changes strictly, i.e. fail when removing nonexistent RR. */
+} zone_update_flags_t;
+
+/*!
+ * \brief Inits given zone update structure, new memory context is created.
+ *
+ * \param update Zone update structure to init.
+ * \param zone Init with this zone.
+ * \param flags Flags to control the behavior of the update.
+ *
+ * \return KNOT_E*
+ */
+int zone_update_init(zone_update_t *update, zone_t *zone, zone_update_flags_t flags);
+
+/*!
+ * \brief Inits update structure, the update is built like IXFR from differences.
+ *
+ * The existing zone with its own contents is taken as a base,
+ * the new candidate zone contents are taken as new contents,
+ * the diff is calculated, so that this update is INCREMENTAL.
+ *
+ * \param update Zone update structure to init.
+ * \param zone Init with this zone.
+ * \param old_cont The current zone contents the diff will be against. Probably zone->contents.
+ * \param new_cont New zone contents. Will be taken over (and later freed) by zone update.
+ * \param flags Flags for update. Must be UPDATE_INCREMENTAL.
+ *
+ * \return KNOT_E*
+ */
+int zone_update_from_differences(zone_update_t *update, zone_t *zone, zone_contents_t *old_cont,
+ zone_contents_t *new_cont, zone_update_flags_t flags, bool ignore_dnssec);
+
+/*!
+ * \brief Inits a zone update based on new zone contents.
+ *
+ * \param update Zone update structure to init.
+ * \param zone_without_contents Init with this zone. Its contents may be NULL.
+ * \param new_cont New zone contents. Will be taken over (and later freed) by zone update.
+ * \param flags Flags for update.
+ *
+ * \return KNOT_E*
+ */
+int zone_update_from_contents(zone_update_t *update, zone_t *zone_without_contents,
+ zone_contents_t *new_cont, zone_update_flags_t flags);
+
+/*!
+ * \brief Returns node that would be in the zone after updating it.
+ *
+ * \note Returned node is either zone original or synthesized, do *not* free
+ * or modify. Returned node is allocated on local mempool.
+ *
+ * \param update Zone update.
+ * \param dname Dname to search for.
+ *
+ * \return Node after zone update.
+ */
+const zone_node_t *zone_update_get_node(zone_update_t *update,
+ const knot_dname_t *dname);
+
+/*!
+ * \brief Returns updated zone apex.
+ *
+ * \note Returned node is either zone original or synthesized, do *not* free
+ * or modify.
+ *
+ * \param update Zone update.
+ *
+ * \return Returns apex after update.
+ */
+const zone_node_t *zone_update_get_apex(zone_update_t *update);
+
+/*!
+ * \brief Returns the serial from the current apex.
+ *
+ * \param update Zone update.
+ *
+ * \return 0 if no apex was found, its serial otherwise.
+ */
+uint32_t zone_update_current_serial(zone_update_t *update);
+
+/*!
+ * \brief Returns the SOA rdataset we're updating from.
+ *
+ * \param update Zone update.
+ *
+ * \return The original SOA rdataset.
+ */
+const knot_rdataset_t *zone_update_from(zone_update_t *update);
+
+/*!
+ * \brief Returns the SOA rdataset we're updating to.
+ *
+ * \param update Zone update.
+ *
+ * \return NULL if no new SOA has been added, new SOA otherwise.
+ */
+const knot_rdataset_t *zone_update_to(zone_update_t *update);
+
+/*!
+ * \brief Clear data allocated by given zone update structure.
+ *
+ * \param update Zone update to clear.
+ */
+void zone_update_clear(zone_update_t *update);
+
+/*!
+ * \brief Adds an RRSet to the zone.
+ *
+ * \warning Do not edit the zone_update when any iterator is active. Any
+ * zone_update modifications will invalidate the trie iterators
+ * in the zone_update iterator(s).
+ *
+ * \param update Zone update.
+ * \param rrset RRSet to add.
+ *
+ * \return KNOT_E*
+ */
+int zone_update_add(zone_update_t *update, const knot_rrset_t *rrset);
+
+/*!
+ * \brief Removes an RRSet from the zone.
+ *
+ * \warning Do not edit the zone_update when any iterator is active. Any
+ * zone_update modifications will invalidate the trie iterators
+ * in the zone_update iterator(s).
+ *
+ * \param update Zone update.
+ * \param rrset RRSet to remove.
+ *
+ * \return KNOT_E*
+ */
+int zone_update_remove(zone_update_t *update, const knot_rrset_t *rrset);
+
+/*!
+ * \brief Removes a whole RRSet of specified type from the zone.
+ *
+ * \warning Do not edit the zone_update when any iterator is active. Any
+ * zone_update modifications will invalidate the trie iterators
+ * in the zone_update iterator(s).
+ *
+ * \param update Zone update.
+ * \param owner Node name to remove.
+ * \param type RRSet type to remove.
+ *
+ * \return KNOT_E*
+ */
+int zone_update_remove_rrset(zone_update_t *update, knot_dname_t *owner, uint16_t type);
+
+/*!
+ * \brief Removes a whole node from the zone.
+ *
+ * \warning Do not edit the zone_update when any iterator is active. Any
+ * zone_update modifications will invalidate the trie iterators
+ * in the zone_update iterator(s).
+ *
+ * \param update Zone update.
+ * \param owner Node name to remove.
+ *
+ * \return KNOT_E*
+ */
+int zone_update_remove_node(zone_update_t *update, const knot_dname_t *owner);
+
+/*!
+ * \brief Adds and removes RRsets to/from the zone according to the changeset.
+ *
+ * \param update Zone update.
+ * \param changes Changes to be made in zone.
+ *
+ * \return KNOT_E*
+ */
+int zone_update_apply_changeset(zone_update_t *update, const changeset_t *changes);
+
+/*!
+ * \brief Applies a changeset to zone, the changeset is modified to contain only really added/removed rdata.
+ *
+ * \param update Zone update.
+ * \param changes In: changes to be made in zone; out: changes really made in zone.
+ *
+ * \return KNOT_E*
+ */
+int zone_update_apply_changeset_fix(zone_update_t *update, changeset_t *changes);
+
+/*!
+ * \brief Applies the changeset in reverse, rsets from REM section are added and from ADD section removed.
+ *
+ * \param update Zone update.
+ * \param changes Changes to be un-done.
+ *
+ * \return KNOT_E*
+ */
+int zone_update_apply_changeset_reverse(zone_update_t *update, const changeset_t *changes);
+
+/*!
+ * \brief Increment SOA serial (according to cofigured policy) in the update.
+ *
+ * \param update Update to be modified.
+ * \param conf Configuration.
+ *
+ * \return KNOT_E*
+ */
+int zone_update_increment_soa(zone_update_t *update, conf_t *conf);
+
+/*!
+ * \brief Commits all changes to the zone, signs it, saves changes to journal.
+ *
+ * \param conf Configuration.
+ * \param update Zone update.
+ *
+ * \return KNOT_E*
+ */
+int zone_update_commit(conf_t *conf, zone_update_t *update);
+
+/*!
+ * \brief Setup a zone_update iterator for both FULL and INCREMENTAL updates.
+ *
+ * \warning Do not init or use iterators when the zone is edited. Any
+ * zone_update modifications will invalidate the trie iterators
+ * in the zone_update iterator.
+ *
+ * \param it Iterator.
+ * \param update Zone update.
+ *
+ * \return KNOT_E*
+ */
+int zone_update_iter(zone_update_iter_t *it, zone_update_t *update);
+
+/*!
+ * \brief Setup a zone_update iterator for both FULL and INCREMENTAL updates.
+ * Version for iterating over nsec3 nodes.
+ *
+ * \warning Do not init or use iterators when the zone is edited. Any
+ * zone_update modifications will invalidate the trie iterators
+ * in the zone_update iterator.
+ *
+ *
+ * \param it Iterator.
+ * \param update Zone update.
+ *
+ * \return KNOT_E*
+ */
+int zone_update_iter_nsec3(zone_update_iter_t *it, zone_update_t *update);
+
+/*!
+ * \brief Move the iterator to the next item.
+ *
+ * \param it Iterator.
+ *
+ * \return KNOT_E*
+ */
+int zone_update_iter_next(zone_update_iter_t *it);
+
+/*!
+ * \brief Get the value of the iterator.
+ *
+ * \param it Iterator.
+ *
+ * \return A (synthesized or added) node with all its current data.
+ */
+const zone_node_t *zone_update_iter_val(zone_update_iter_t *it);
+
+/*!
+ * \brief Finish the iterator and clean it up.
+ *
+ * \param it Iterator.
+ */
+void zone_update_iter_finish(zone_update_iter_t *it);
+
+/*!
+ * \brief Returns bool whether there are any changes at all.
+ *
+ * \param update Zone update.
+ */
+bool zone_update_no_change(zone_update_t *update);
diff --git a/src/knot/worker/pool.c b/src/knot/worker/pool.c
new file mode 100644
index 0000000..9d8413a
--- /dev/null
+++ b/src/knot/worker/pool.c
@@ -0,0 +1,242 @@
+/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libknot/libknot.h"
+#include "knot/server/dthreads.h"
+#include "knot/worker/pool.h"
+
+/*!
+ * \brief Worker pool state.
+ */
+struct worker_pool {
+ dt_unit_t *threads;
+
+ pthread_mutex_t lock;
+ pthread_cond_t wake;
+
+ bool terminating; /*!< Is the pool terminating? .*/
+ bool suspended; /*!< Is execution temporarily suspended? .*/
+ int running; /*!< Number of running threads. */
+ worker_queue_t tasks;
+};
+
+/*!
+ * \brief Worker thread.
+ *
+ * The thread takes a task from the tasks queue and runs it, while checking
+ * if the dispatching of new tasks is allowed by the thread pool.
+ *
+ * An execution of a running thread cannot be enforced.
+ *
+ */
+static int worker_main(dthread_t *thread)
+{
+ assert(thread);
+
+ worker_pool_t *pool = thread->data;
+
+ pthread_mutex_lock(&pool->lock);
+
+ for (;;) {
+ if (pool->terminating) {
+ break;
+ }
+
+ task_t *task = NULL;
+ if (!pool->suspended) {
+ task = worker_queue_dequeue(&pool->tasks);
+ }
+
+ if (task == NULL) {
+ pthread_cond_wait(&pool->wake, &pool->lock);
+ continue;
+ }
+
+ assert(task->run);
+ pool->running += 1;
+
+ pthread_mutex_unlock(&pool->lock);
+ task->run(task);
+ pthread_mutex_lock(&pool->lock);
+
+ pool->running -= 1;
+ pthread_cond_broadcast(&pool->wake);
+ }
+
+ pthread_mutex_unlock(&pool->lock);
+
+ return KNOT_EOK;
+}
+
+/* -- public API ------------------------------------------------------------ */
+
+worker_pool_t *worker_pool_create(unsigned threads)
+{
+ worker_pool_t *pool = malloc(sizeof(worker_pool_t));
+ if (pool == NULL) {
+ return NULL;
+ }
+
+ memset(pool, 0, sizeof(worker_pool_t));
+ pool->threads = dt_create(threads, worker_main, NULL, pool);
+ if (pool->threads == NULL) {
+ goto fail;
+ }
+
+ if (pthread_mutex_init(&pool->lock, NULL) != 0) {
+ goto fail;
+ }
+
+ if (pthread_cond_init(&pool->wake, NULL) != 0) {
+ goto fail;
+ }
+
+ worker_queue_init(&pool->tasks);
+
+ return pool;
+
+fail:
+ dt_delete(&pool->threads);
+ free(pool);
+ return NULL;
+}
+
+void worker_pool_destroy(worker_pool_t *pool)
+{
+ if (!pool) {
+ return;
+ }
+
+ dt_delete(&pool->threads);
+
+ pthread_mutex_destroy(&pool->lock);
+ pthread_cond_destroy(&pool->wake);
+
+ worker_queue_deinit(&pool->tasks);
+
+ free(pool);
+}
+
+void worker_pool_start(worker_pool_t *pool)
+{
+ if (!pool) {
+ return;
+ }
+
+ dt_start(pool->threads);
+}
+
+void worker_pool_stop(worker_pool_t *pool)
+{
+ if (!pool) {
+ return;
+ }
+
+ pthread_mutex_lock(&pool->lock);
+ pool->terminating = true;
+ pthread_cond_broadcast(&pool->wake);
+ pthread_mutex_unlock(&pool->lock);
+
+ dt_stop(pool->threads);
+}
+
+void worker_pool_suspend(worker_pool_t *pool)
+{
+ if (!pool) {
+ return;
+ }
+
+ pthread_mutex_lock(&pool->lock);
+ pool->suspended = true;
+ pthread_mutex_unlock(&pool->lock);
+}
+
+void worker_pool_resume(worker_pool_t *pool)
+{
+ if (!pool) {
+ return;
+ }
+
+ pthread_mutex_lock(&pool->lock);
+ pool->suspended = false;
+ pthread_cond_broadcast(&pool->wake);
+ pthread_mutex_unlock(&pool->lock);
+}
+
+void worker_pool_join(worker_pool_t *pool)
+{
+ if (!pool) {
+ return;
+ }
+
+ dt_join(pool->threads);
+}
+
+void worker_pool_wait(worker_pool_t *pool)
+{
+ if (!pool) {
+ return;
+ }
+
+ pthread_mutex_lock(&pool->lock);
+ while (!EMPTY_LIST(pool->tasks.list) || pool->running > 0) {
+ pthread_cond_wait(&pool->wake, &pool->lock);
+ }
+ pthread_mutex_unlock(&pool->lock);
+}
+
+void worker_pool_assign(worker_pool_t *pool, struct task *task)
+{
+ if (!pool || !task) {
+ return;
+ }
+
+ pthread_mutex_lock(&pool->lock);
+ worker_queue_enqueue(&pool->tasks, task);
+ pthread_cond_signal(&pool->wake);
+ pthread_mutex_unlock(&pool->lock);
+}
+
+void worker_pool_clear(worker_pool_t *pool)
+{
+ if (!pool) {
+ return;
+ }
+
+ pthread_mutex_lock(&pool->lock);
+ worker_queue_deinit(&pool->tasks);
+ worker_queue_init(&pool->tasks);
+ pthread_mutex_unlock(&pool->lock);
+}
+
+void worker_pool_status(worker_pool_t *pool, int *running, int *queued)
+{
+ if (!pool) {
+ *running = *queued = 0;
+ return;
+ }
+
+ pthread_mutex_lock(&pool->lock);
+ *running = pool->running;
+ *queued = worker_queue_length(&pool->tasks);
+ pthread_mutex_unlock(&pool->lock);
+}
diff --git a/src/knot/worker/pool.h b/src/knot/worker/pool.h
new file mode 100644
index 0000000..4f8b3dc
--- /dev/null
+++ b/src/knot/worker/pool.h
@@ -0,0 +1,82 @@
+/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include "knot/worker/queue.h"
+
+struct worker_pool;
+typedef struct worker_pool worker_pool_t;
+
+/*!
+ * \brief Initialize worker pool.
+ *
+ * \param threads Number of threads to be created.
+ *
+ * \return Thread pool or NULL in case of error.
+ */
+worker_pool_t *worker_pool_create(unsigned threads);
+
+/*!
+ * \brief Destroy the worker pool.
+ */
+void worker_pool_destroy(worker_pool_t *pool);
+
+/*!
+ * \brief Start all threads in the worker pool.
+ */
+void worker_pool_start(worker_pool_t *pool);
+
+/*!
+ * \brief Stop processing of new tasks, start stopping worker threads when possible.
+ */
+void worker_pool_stop(worker_pool_t *pool);
+
+/*!
+ * \brief Temporarily suspend the execution of worker pool.
+ */
+void worker_pool_suspend(worker_pool_t *pool);
+
+/*!
+ * \brief Resume the execution of worker pool.
+ */
+void worker_pool_resume(worker_pool_t *pool);
+
+/*!
+ * \brief Wait for all threads to terminate.
+ */
+void worker_pool_join(worker_pool_t *pool);
+
+/*!
+ * \brief Wait till the number of pending tasks is zero.
+ *
+ */
+void worker_pool_wait(worker_pool_t *pool);
+
+/*!
+ * \brief Assign a task to be performed by a worker in the pool.
+ */
+void worker_pool_assign(worker_pool_t *pool, struct task *task);
+
+/*!
+ * \brief Clear all tasks enqueued in pool processing queue.
+ */
+void worker_pool_clear(worker_pool_t *pool);
+
+/*!
+ * \brief Obtain info regarding how the pool is busy.
+ */
+void worker_pool_status(worker_pool_t *pool, int *running, int *queued);
diff --git a/src/knot/worker/queue.c b/src/knot/worker/queue.c
new file mode 100644
index 0000000..c5c4cf7
--- /dev/null
+++ b/src/knot/worker/queue.c
@@ -0,0 +1,67 @@
+/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "knot/worker/queue.h"
+#include "contrib/mempattern.h"
+
+void worker_queue_init(worker_queue_t *queue)
+{
+ if (!queue) {
+ return;
+ }
+
+ memset(queue, 0, sizeof(worker_queue_t));
+
+ init_list(&queue->list);
+ mm_ctx_init(&queue->mm_ctx);
+}
+
+void worker_queue_deinit(worker_queue_t *queue)
+{
+ ptrlist_free(&queue->list, &queue->mm_ctx);
+}
+
+void worker_queue_enqueue(worker_queue_t *queue, task_t *task)
+{
+ if (!queue || !task) {
+ return;
+ }
+
+ ptrlist_add(&queue->list, task, &queue->mm_ctx);
+}
+
+task_t *worker_queue_dequeue(worker_queue_t *queue)
+{
+ if (!queue) {
+ return NULL;
+ }
+
+ task_t *task = NULL;
+
+ if (!EMPTY_LIST(queue->list)) {
+ ptrnode_t *node = HEAD(queue->list);
+ task = (void *)node->d;
+ rem_node(&node->n);
+ queue->mm_ctx.free(&node->n);
+ }
+
+ return task;
+}
+
+size_t worker_queue_length(worker_queue_t *queue)
+{
+ return queue ? list_size(&queue->list) : 0;
+}
diff --git a/src/knot/worker/queue.h b/src/knot/worker/queue.h
new file mode 100644
index 0000000..2507919
--- /dev/null
+++ b/src/knot/worker/queue.h
@@ -0,0 +1,65 @@
+/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include "contrib/ucw/lists.h"
+
+struct task;
+typedef void (*task_cb)(struct task *);
+
+/*!
+ * \brief Task executable by a worker.
+ */
+typedef struct task {
+ void *ctx;
+ task_cb run;
+} task_t;
+
+/*!
+ * \brief Worker queue.
+ */
+typedef struct worker_queue {
+ knot_mm_t mm_ctx;
+ list_t list;
+} worker_queue_t;
+
+/*!
+ * \brief Initialize worker queue.
+ */
+void worker_queue_init(worker_queue_t *queue);
+
+/*!
+ * \brief Deinitialize worker queue.
+ */
+void worker_queue_deinit(worker_queue_t *queue);
+
+/*!
+ * \brief Insert new item into the queue.
+ */
+void worker_queue_enqueue(worker_queue_t *queue, task_t *task);
+
+/*!
+ * \brief Remove item from the queue.
+ *
+ * \return Task or NULL if the queue is empty.
+ */
+task_t *worker_queue_dequeue(worker_queue_t *queue);
+
+/*!
+ * \brief Return number of tasks in worker queue.
+ */
+size_t worker_queue_length(worker_queue_t *queue);
diff --git a/src/knot/zone/contents.c b/src/knot/zone/contents.c
new file mode 100644
index 0000000..e99cb48
--- /dev/null
+++ b/src/knot/zone/contents.c
@@ -0,0 +1,1197 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "libdnssec/error.h"
+#include "knot/zone/contents.h"
+#include "knot/common/log.h"
+#include "knot/dnssec/zone-nsec.h"
+#include "libknot/libknot.h"
+#include "contrib/qp-trie/trie.h"
+#include "contrib/macros.h"
+
+typedef struct {
+ zone_contents_apply_cb_t func;
+ void *data;
+} zone_tree_func_t;
+
+typedef struct {
+ zone_node_t *first_node;
+ zone_contents_t *zone;
+ zone_node_t *previous_node;
+} zone_adjust_arg_t;
+
+static int tree_apply_cb(zone_node_t **node, void *data)
+{
+ if (node == NULL || data == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ zone_tree_func_t *f = (zone_tree_func_t *)data;
+ return f->func(*node, f->data);
+}
+
+/*!
+ * \brief Checks if the given node can be inserted into the given zone.
+ *
+ * Checks if both the arguments are non-NULL and if the owner of the node
+ * belongs to the zone (i.e. is a subdomain of the zone apex).
+ *
+ * \param zone Zone to which the node is going to be inserted.
+ * \param node Node to check.
+ *
+ * \retval KNOT_EOK if both arguments are non-NULL and the node belongs to the
+ * zone.
+ * \retval KNOT_EINVAL if either of the arguments is NULL.
+ * \retval KNOT_EOUTOFZONE if the node does not belong to the zone.
+ */
+static int check_node(const zone_contents_t *contents, const zone_node_t *node)
+{
+ assert(contents);
+ assert(contents->apex != NULL);
+ assert(node);
+
+ if (knot_dname_in_bailiwick(node->owner, contents->apex->owner) <= 0) {
+ return KNOT_EOUTOFZONE;
+ }
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Destroys all RRSets in a node.
+ *
+ * This function is designed to be used in the tree-iterating functions.
+ *
+ * \param node Node to destroy RRSets from.
+ * \param data Unused parameter.
+ */
+static int destroy_node_rrsets_from_tree(zone_node_t **node, void *data)
+{
+ assert(node);
+ UNUSED(data);
+
+ if (*node != NULL) {
+ node_free_rrsets(*node, NULL);
+ node_free(*node, NULL);
+ }
+
+ return KNOT_EOK;
+}
+
+static int create_nsec3_name(uint8_t *out, size_t out_size,
+ const zone_contents_t *zone,
+ const knot_dname_t *name)
+{
+ assert(out);
+ assert(zone);
+ assert(name);
+
+ if (!knot_is_nsec3_enabled(zone)) {
+ return KNOT_ENSEC3PAR;
+ }
+
+ return knot_create_nsec3_owner(out, out_size, name, zone->apex->owner,
+ &zone->nsec3_params);
+}
+
+/*! \brief Link pointers to additional nodes for this RRSet. */
+static int discover_additionals(const knot_dname_t *owner, struct rr_data *rr_data,
+ zone_contents_t *zone)
+{
+ assert(rr_data != NULL);
+
+ /* Drop possible previous additional nodes. */
+ additional_clear(rr_data->additional);
+ rr_data->additional = NULL;
+
+ const knot_rdataset_t *rrs = &rr_data->rrs;
+ uint16_t rdcount = rrs->count;
+
+ uint16_t mandatory_count = 0;
+ uint16_t others_count = 0;
+ glue_t mandatory[rdcount];
+ glue_t others[rdcount];
+
+ /* Scan new additional nodes. */
+ for (uint16_t i = 0; i < rdcount; i++) {
+ knot_rdata_t *rdata = knot_rdataset_at(rrs, i);
+ const knot_dname_t *dname = knot_rdata_name(rdata, rr_data->type);
+ const zone_node_t *node = NULL, *encloser = NULL, *prev = NULL;
+
+ /* Try to find node for the dname in the RDATA. */
+ zone_contents_find_dname(zone, dname, &node, &encloser, &prev);
+ if (node == NULL && encloser != NULL
+ && (encloser->flags & NODE_FLAGS_WILDCARD_CHILD)) {
+ /* Find wildcard child in the zone. */
+ node = zone_contents_find_wildcard_child(zone, encloser);
+ assert(node != NULL);
+ }
+
+ if (node == NULL) {
+ continue;
+ }
+
+ glue_t *glue;
+ if ((node->flags & (NODE_FLAGS_DELEG | NODE_FLAGS_NONAUTH)) &&
+ rr_data->type == KNOT_RRTYPE_NS &&
+ knot_dname_in_bailiwick(node->owner, owner) >= 0) {
+ glue = &mandatory[mandatory_count++];
+ glue->optional = false;
+ } else {
+ glue = &others[others_count++];
+ glue->optional = true;
+ }
+ glue->node = node;
+ glue->ns_pos = i;
+ }
+
+ /* Store sorted additionals by the type, mandatory first. */
+ size_t total_count = mandatory_count + others_count;
+ if (total_count > 0) {
+ rr_data->additional = malloc(sizeof(additional_t));
+ if (rr_data->additional == NULL) {
+ return KNOT_ENOMEM;
+ }
+ rr_data->additional->count = total_count;
+
+ size_t size = total_count * sizeof(glue_t);
+ rr_data->additional->glues = malloc(size);
+ if (rr_data->additional->glues == NULL) {
+ free(rr_data->additional);
+ return KNOT_ENOMEM;
+ }
+
+ size_t mandatory_size = mandatory_count * sizeof(glue_t);
+ memcpy(rr_data->additional->glues, mandatory, mandatory_size);
+ memcpy(rr_data->additional->glues + mandatory_count, others,
+ size - mandatory_size);
+ }
+
+ return KNOT_EOK;
+}
+
+static int adjust_pointers(zone_node_t **tnode, void *data)
+{
+ assert(tnode != NULL);
+ assert(data != NULL);
+
+ zone_adjust_arg_t *args = (zone_adjust_arg_t *)data;
+ zone_node_t *node = *tnode;
+
+ // remember first node
+ if (args->first_node == NULL) {
+ args->first_node = node;
+ }
+
+ // check if this node is not a wildcard child of its parent
+ if (knot_dname_is_wildcard(node->owner)) {
+ assert(node->parent != NULL);
+ node->parent->flags |= NODE_FLAGS_WILDCARD_CHILD;
+ }
+
+ // set flags (delegation point, non-authoritative)
+ if (node->parent &&
+ (node->parent->flags & NODE_FLAGS_DELEG ||
+ node->parent->flags & NODE_FLAGS_NONAUTH)) {
+ node->flags |= NODE_FLAGS_NONAUTH;
+ } else if (node_rrtype_exists(node, KNOT_RRTYPE_NS) && node != args->zone->apex) {
+ node->flags |= NODE_FLAGS_DELEG;
+ } else {
+ // Default.
+ node->flags = NODE_FLAGS_AUTH;
+ }
+
+ // set pointer to previous node
+ node->prev = args->previous_node;
+
+ // update remembered previous pointer only if authoritative
+ if (!(node->flags & NODE_FLAGS_NONAUTH) && node->rrset_count > 0) {
+ args->previous_node = node;
+ }
+
+ return KNOT_EOK;
+}
+
+static int adjust_nsec3_pointers(zone_node_t **tnode, void *data)
+{
+ assert(data != NULL);
+ assert(tnode != NULL);
+
+ zone_adjust_arg_t *args = (zone_adjust_arg_t *)data;
+ zone_node_t *node = *tnode;
+ const zone_node_t *ignored;
+
+ // Connect to NSEC3 node (only if NSEC3 tree is not empty)
+ node->nsec3_wildcard_prev = NULL;
+ uint8_t nsec3_name[KNOT_DNAME_MAXLEN];
+ int ret = create_nsec3_name(nsec3_name, sizeof(nsec3_name), args->zone,
+ node->owner);
+ if (ret == KNOT_EOK) {
+ node->nsec3_node = zone_tree_get(args->zone->nsec3_nodes, nsec3_name);
+
+ // Connect to NSEC3 node proving nonexistence of wildcard.
+ size_t wildcard_size = knot_dname_size(node->owner) + 2;
+ if (wildcard_size <= KNOT_DNAME_MAXLEN) {
+ assert(wildcard_size > 2);
+ knot_dname_t wildcard[wildcard_size];
+ memcpy(wildcard, "\x01""*", 2);
+ memcpy(wildcard + 2, node->owner, wildcard_size - 2);
+ ret = zone_contents_find_nsec3_for_name(args->zone, wildcard, &ignored,
+ (const zone_node_t **)&node->nsec3_wildcard_prev);
+ if (ret == ZONE_NAME_FOUND) {
+ node->nsec3_wildcard_prev = NULL;
+ ret = KNOT_EOK;
+ }
+ }
+ } else if (ret == KNOT_ENSEC3PAR) {
+ node->nsec3_node = NULL;
+ ret = KNOT_EOK;
+ }
+
+ return ret;
+}
+
+static int measure_size(zone_node_t *node, void *data){
+
+ size_t *size = data;
+ int rrset_count = node->rrset_count;
+ for (int i = 0; i < rrset_count; i++) {
+ knot_rrset_t rrset = node_rrset_at(node, i);
+ *size += knot_rrset_size(&rrset);
+ }
+ return KNOT_EOK;
+}
+
+static int measure_max_ttl(zone_node_t *node, void *data){
+
+ uint32_t *max = data;
+ int rrset_count = node->rrset_count;
+ for (int i = 0; i < rrset_count; i++) {
+ *max = MAX(*max, node->rrs[i].ttl);
+ }
+ return KNOT_EOK;
+}
+
+static bool nsec3_params_match(const knot_rdataset_t *rrs,
+ const dnssec_nsec3_params_t *params,
+ size_t rdata_pos)
+{
+ assert(rrs != NULL);
+ assert(params != NULL);
+
+ knot_rdata_t *rdata = knot_rdataset_at(rrs, rdata_pos);
+
+ return (knot_nsec3_alg(rdata) == params->algorithm
+ && knot_nsec3_iters(rdata) == params->iterations
+ && knot_nsec3_salt_len(rdata) == params->salt.size
+ && memcmp(knot_nsec3_salt(rdata), params->salt.data,
+ params->salt.size) == 0);
+}
+
+/*!
+ * \brief Adjust normal (non NSEC3) node.
+ *
+ * Set:
+ * - pointer to wildcard childs in parent nodes if applicable
+ * - flags (delegation point, non-authoritative)
+ * - pointer to previous node
+ * - parent pointers
+ *
+ * \param tnode Zone node to adjust.
+ * \param data Adjusting parameters (zone_adjust_arg_t *).
+ */
+static int adjust_normal_node(zone_node_t **tnode, void *data)
+{
+ assert(tnode != NULL && *tnode);
+ assert(data != NULL);
+
+ // Do cheap operations first
+ int ret = adjust_pointers(tnode, data);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ zone_adjust_arg_t *arg = data;
+ measure_size(*tnode, &arg->zone->size);
+ measure_max_ttl(*tnode, &arg->zone->max_ttl);
+
+ // Connect nodes to their NSEC3 nodes
+ return adjust_nsec3_pointers(tnode, data);
+}
+
+/*!
+ * \brief Adjust NSEC3 node.
+ *
+ * Set:
+ * - pointer to previous node
+ * - pointer to node stored in owner dname
+ *
+ * \param tnode Zone node to adjust.
+ * \param data Adjusting parameters (zone_adjust_arg_t *).
+ */
+static int adjust_nsec3_node(zone_node_t **tnode, void *data)
+{
+ assert(data != NULL);
+ assert(tnode != NULL);
+
+ zone_adjust_arg_t *args = (zone_adjust_arg_t *)data;
+ zone_node_t *node = *tnode;
+
+ // remember first node
+ if (args->first_node == NULL) {
+ args->first_node = node;
+ }
+
+ // set previous node
+ node->prev = args->previous_node;
+ args->previous_node = node;
+
+ measure_size(*tnode, &args->zone->size);
+ measure_max_ttl(*tnode, &args->zone->max_ttl);
+
+ // check if this node belongs to correct chain
+ const knot_rdataset_t *nsec3_rrs = node_rdataset(node, KNOT_RRTYPE_NSEC3);
+ for (uint16_t i = 0; nsec3_rrs != NULL && i < nsec3_rrs->count; i++) {
+ if (nsec3_params_match(nsec3_rrs, &args->zone->nsec3_params, i)) {
+ node->flags |= NODE_FLAGS_IN_NSEC3_CHAIN;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+/*! \brief Discover additional records for affected nodes. */
+static int adjust_additional(zone_node_t **tnode, void *data)
+{
+ assert(data != NULL);
+ assert(tnode != NULL);
+
+ zone_adjust_arg_t *args = (zone_adjust_arg_t *)data;
+ zone_node_t *node = *tnode;
+
+ /* Lookup additional records for specific nodes. */
+ for(uint16_t i = 0; i < node->rrset_count; ++i) {
+ struct rr_data *rr_data = &node->rrs[i];
+ if (knot_rrtype_additional_needed(rr_data->type)) {
+ int ret = discover_additionals(node->owner, rr_data, args->zone);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Tries to find the given domain name in the zone tree.
+ *
+ * \param zone Zone to search in.
+ * \param name Domain name to find.
+ * \param node Found node.
+ * \param previous Previous node in canonical order (i.e. the one directly
+ * preceding \a name in canonical order, regardless if the name
+ * is in the zone or not).
+ *
+ * \retval true if the domain name was found. In such case \a node holds the
+ * zone node with \a name as its owner. \a previous is set
+ * properly.
+ * \retval false if the domain name was not found. \a node may hold any (or none)
+ * node. \a previous is set properly.
+ */
+static bool find_in_tree(zone_tree_t *tree, const knot_dname_t *name,
+ zone_node_t **node, zone_node_t **previous)
+{
+ assert(tree != NULL);
+ assert(name != NULL);
+ assert(node != NULL);
+ assert(previous != NULL);
+
+ zone_node_t *found = NULL, *prev = NULL;
+
+ int match = zone_tree_get_less_or_equal(tree, name, &found, &prev);
+ if (match < 0) {
+ assert(0);
+ return false;
+ }
+
+ *node = found;
+ *previous = prev;
+
+ return match > 0;
+}
+
+zone_contents_t *zone_contents_new(const knot_dname_t *apex_name)
+{
+ if (apex_name == NULL) {
+ return NULL;
+ }
+
+ zone_contents_t *contents = malloc(sizeof(zone_contents_t));
+ if (contents == NULL) {
+ return NULL;
+ }
+
+ memset(contents, 0, sizeof(zone_contents_t));
+ contents->apex = node_new(apex_name, NULL);
+ if (contents->apex == NULL) {
+ goto cleanup;
+ }
+
+ contents->nodes = zone_tree_create();
+ if (contents->nodes == NULL) {
+ goto cleanup;
+ }
+
+ if (zone_tree_insert(contents->nodes, contents->apex) != KNOT_EOK) {
+ goto cleanup;
+ }
+
+ return contents;
+
+cleanup:
+ free(contents->nodes);
+ free(contents->nsec3_nodes);
+ free(contents);
+ return NULL;
+}
+
+static zone_node_t *get_node(const zone_contents_t *zone, const knot_dname_t *name)
+{
+ assert(zone);
+ assert(name);
+
+ return zone_tree_get(zone->nodes, name);
+}
+
+static int add_node(zone_contents_t *zone, zone_node_t *node, bool create_parents)
+{
+ if (zone == NULL || node == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = check_node(zone, node);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = zone_tree_insert(zone->nodes, node);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ if (!create_parents) {
+ return KNOT_EOK;
+ }
+
+ /* No parents for root domain. */
+ if (*node->owner == '\0') {
+ return KNOT_EOK;
+ }
+
+ zone_node_t *next_node = NULL;
+ const uint8_t *parent = knot_wire_next_label(node->owner, NULL);
+
+ if (knot_dname_is_equal(zone->apex->owner, parent)) {
+ node_set_parent(node, zone->apex);
+
+ // check if the node is not wildcard child of the parent
+ if (knot_dname_is_wildcard(node->owner)) {
+ zone->apex->flags |= NODE_FLAGS_WILDCARD_CHILD;
+ }
+ } else {
+ while (parent != NULL && !(next_node = get_node(zone, parent))) {
+
+ /* Create a new node. */
+ next_node = node_new(parent, NULL);
+ if (next_node == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ /* Insert node to a tree. */
+ ret = zone_tree_insert(zone->nodes, next_node);
+ if (ret != KNOT_EOK) {
+ node_free(next_node, NULL);
+ return ret;
+ }
+
+ /* Update node pointers. */
+ node_set_parent(node, next_node);
+ if (knot_dname_is_wildcard(node->owner)) {
+ next_node->flags |= NODE_FLAGS_WILDCARD_CHILD;
+ }
+
+ node = next_node;
+ parent = knot_wire_next_label(parent, NULL);
+ }
+
+ // set the found parent (in the zone) as the parent of the last
+ // inserted node
+ assert(node->parent == NULL);
+ node_set_parent(node, next_node);
+ }
+
+ return KNOT_EOK;
+}
+
+static int add_nsec3_node(zone_contents_t *zone, zone_node_t *node)
+{
+ if (zone == NULL || node == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = check_node(zone, node);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ /* Create NSEC3 tree if not exists. */
+ if (zone->nsec3_nodes == NULL) {
+ zone->nsec3_nodes = zone_tree_create();
+ if (zone->nsec3_nodes == NULL) {
+ return KNOT_ENOMEM;
+ }
+ }
+
+ // how to know if this is successful??
+ ret = zone_tree_insert(zone->nsec3_nodes, node);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // no parents to be created, the only parent is the zone apex
+ // set the apex as the parent of the node
+ node_set_parent(node, zone->apex);
+
+ // cannot be wildcard child, so nothing to be done
+
+ return KNOT_EOK;
+}
+
+static zone_node_t *get_nsec3_node(const zone_contents_t *zone,
+ const knot_dname_t *name)
+{
+ assert(zone);
+ assert(name);
+
+ return zone_tree_get(zone->nsec3_nodes, name);
+}
+
+static int insert_rr(zone_contents_t *z, const knot_rrset_t *rr,
+ zone_node_t **n, bool nsec3)
+{
+ if (knot_rrset_empty(rr)) {
+ return KNOT_EINVAL;
+ }
+
+ // check if the RRSet belongs to the zone
+ if (knot_dname_in_bailiwick(rr->owner, z->apex->owner) < 0) {
+ return KNOT_EOUTOFZONE;
+ }
+
+ if (*n == NULL) {
+ *n = nsec3 ? get_nsec3_node(z, rr->owner) : get_node(z, rr->owner);
+ if (*n == NULL) {
+ // Create new, insert
+ *n = node_new(rr->owner, NULL);
+ if (*n == NULL) {
+ return KNOT_ENOMEM;
+ }
+ int ret = nsec3 ? add_nsec3_node(z, *n) : add_node(z, *n, true);
+ if (ret != KNOT_EOK) {
+ node_free(*n, NULL);
+ *n = NULL;
+ }
+ }
+ }
+
+ return node_add_rrset(*n, rr, NULL);
+}
+
+static int remove_rr(zone_contents_t *z, const knot_rrset_t *rr,
+ zone_node_t **n, bool nsec3)
+{
+ if (knot_rrset_empty(rr)) {
+ return KNOT_EINVAL;
+ }
+
+ // check if the RRSet belongs to the zone
+ if (knot_dname_in_bailiwick(rr->owner, z->apex->owner) < 0) {
+ return KNOT_EOUTOFZONE;
+ }
+
+ zone_node_t *node;
+ if (*n == NULL) {
+ node = nsec3 ? get_nsec3_node(z, rr->owner) : get_node(z, rr->owner);
+ if (node == NULL) {
+ return KNOT_ENONODE;
+ }
+ } else {
+ node = *n;
+ }
+
+ knot_rdataset_t *node_rrs = node_rdataset(node, rr->type);
+ // Subtract changeset RRS from node RRS.
+ int ret = knot_rdataset_subtract(node_rrs, &rr->rrs, NULL);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ if (node_rrs->count == 0) {
+ // RRSet is empty now, remove it from node, all data freed.
+ node_remove_rdataset(node, rr->type);
+ // If node is empty now, delete it from zone tree.
+ if (node->rrset_count == 0 && node != z->apex) {
+ zone_tree_delete_empty(nsec3 ? z->nsec3_nodes : z->nodes, node);
+ }
+ }
+
+ *n = node;
+ return KNOT_EOK;
+}
+
+static int recreate_normal_tree(const zone_contents_t *z, zone_contents_t *out)
+{
+ out->nodes = trie_create(NULL);
+ if (out->nodes == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ // Insert APEX first.
+ zone_node_t *apex_cpy = node_shallow_copy(z->apex, NULL);
+ if (apex_cpy == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ // Normal additions need apex ... so we need to insert directly.
+ int ret = zone_tree_insert(out->nodes, apex_cpy);
+ if (ret != KNOT_EOK) {
+ node_free(apex_cpy, NULL);
+ return ret;
+ }
+
+ out->apex = apex_cpy;
+
+ trie_it_t *itt = trie_it_begin(z->nodes);
+ if (itt == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ while (!trie_it_finished(itt)) {
+ const zone_node_t *to_cpy = (zone_node_t *)*trie_it_val(itt);
+ if (to_cpy == z->apex) {
+ // Inserted already.
+ trie_it_next(itt);
+ continue;
+ }
+ zone_node_t *to_add = node_shallow_copy(to_cpy, NULL);
+ if (to_add == NULL) {
+ trie_it_free(itt);
+ return KNOT_ENOMEM;
+ }
+
+ int ret = add_node(out, to_add, true);
+ if (ret != KNOT_EOK) {
+ node_free(to_add, NULL);
+ trie_it_free(itt);
+ return ret;
+ }
+ trie_it_next(itt);
+ }
+
+ trie_it_free(itt);
+
+ return KNOT_EOK;
+}
+
+static int recreate_nsec3_tree(const zone_contents_t *z, zone_contents_t *out)
+{
+ out->nsec3_nodes = trie_create(NULL);
+ if (out->nsec3_nodes == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ trie_it_t *itt = trie_it_begin(z->nsec3_nodes);
+ if (itt == NULL) {
+ return KNOT_ENOMEM;
+ }
+ while (!trie_it_finished(itt)) {
+ const zone_node_t *to_cpy = (zone_node_t *)*trie_it_val(itt);
+ zone_node_t *to_add = node_shallow_copy(to_cpy, NULL);
+ if (to_add == NULL) {
+ trie_it_free(itt);
+ return KNOT_ENOMEM;
+ }
+
+ int ret = add_nsec3_node(out, to_add);
+ if (ret != KNOT_EOK) {
+ trie_it_free(itt);
+ node_free(to_add, NULL);
+ return ret;
+ }
+
+ trie_it_next(itt);
+ }
+
+ trie_it_free(itt);
+
+ return KNOT_EOK;
+}
+
+// Public API
+
+int zone_contents_add_rr(zone_contents_t *z, const knot_rrset_t *rr,
+ zone_node_t **n)
+{
+ if (z == NULL || rr == NULL || n == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ return insert_rr(z, rr, n, knot_rrset_is_nsec3rel(rr));
+}
+
+int zone_contents_remove_rr(zone_contents_t *z, const knot_rrset_t *rr,
+ zone_node_t **n)
+{
+ if (z == NULL || rr == NULL || n == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ return remove_rr(z, rr, n, knot_rrset_is_nsec3rel(rr));
+}
+
+zone_node_t *zone_contents_get_node_for_rr(zone_contents_t *zone, const knot_rrset_t *rrset)
+{
+ if (zone == NULL || rrset == NULL) {
+ return NULL;
+ }
+
+ const bool nsec3 = knot_rrset_is_nsec3rel(rrset);
+ zone_node_t *node = nsec3 ? get_nsec3_node(zone, rrset->owner) :
+ get_node(zone, rrset->owner);
+ if (node == NULL) {
+ node = node_new(rrset->owner, NULL);
+ int ret = nsec3 ? add_nsec3_node(zone, node) : add_node(zone, node, true);
+ if (ret != KNOT_EOK) {
+ node_free(node, NULL);
+ return NULL;
+ }
+
+ return node;
+ } else {
+ return node;
+ }
+}
+
+const zone_node_t *zone_contents_find_node(const zone_contents_t *zone, const knot_dname_t *name)
+{
+ if (zone == NULL || name == NULL) {
+ return NULL;
+ }
+
+ return get_node(zone, name);
+}
+
+zone_node_t *zone_contents_find_node_for_rr(zone_contents_t *contents, const knot_rrset_t *rrset)
+{
+ if (contents == NULL || rrset == NULL) {
+ return NULL;
+ }
+
+ const bool nsec3 = knot_rrset_is_nsec3rel(rrset);
+ return nsec3 ? get_nsec3_node(contents, rrset->owner) :
+ get_node(contents, rrset->owner);
+}
+
+int zone_contents_find_dname(const zone_contents_t *zone,
+ const knot_dname_t *name,
+ const zone_node_t **match,
+ const zone_node_t **closest,
+ const zone_node_t **previous)
+{
+ if (!zone || !name || !match || !closest || !previous) {
+ return KNOT_EINVAL;
+ }
+
+ if (knot_dname_in_bailiwick(name, zone->apex->owner) < 0) {
+ return KNOT_EOUTOFZONE;
+ }
+
+ zone_node_t *node = NULL;
+ zone_node_t *prev = NULL;
+
+ int found = zone_tree_get_less_or_equal(zone->nodes, name, &node, &prev);
+ if (found < 0) {
+ // error
+ return found;
+ } else if (found == 1) {
+ // exact match
+
+ assert(node && prev);
+
+ *match = node;
+ *closest = node;
+ *previous = prev;
+
+ return ZONE_NAME_FOUND;
+ } else {
+ // closest match
+
+ assert(!node && prev);
+
+ node = prev;
+ size_t matched_labels = knot_dname_matched_labels(node->owner, name);
+ while (matched_labels < knot_dname_labels(node->owner, NULL)) {
+ node = node->parent;
+ assert(node);
+ }
+
+ *match = NULL;
+ *closest = node;
+ *previous = prev;
+
+ return ZONE_NAME_NOT_FOUND;
+ }
+}
+
+const zone_node_t *zone_contents_find_nsec3_node(const zone_contents_t *zone,
+ const knot_dname_t *name)
+{
+ if (zone == NULL || name == NULL) {
+ return NULL;
+ }
+
+ return get_nsec3_node(zone, name);
+}
+
+int zone_contents_find_nsec3_for_name(const zone_contents_t *zone,
+ const knot_dname_t *name,
+ const zone_node_t **nsec3_node,
+ const zone_node_t **nsec3_previous)
+{
+ if (zone == NULL || name == NULL || nsec3_node == NULL ||
+ nsec3_previous == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ // check if the NSEC3 tree is not empty
+ if (zone_tree_is_empty(zone->nsec3_nodes)) {
+ return KNOT_ENSEC3CHAIN;
+ }
+
+ uint8_t nsec3_name[KNOT_DNAME_MAXLEN];
+ int ret = create_nsec3_name(nsec3_name, sizeof(nsec3_name), zone, name);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ zone_node_t *found = NULL, *prev = NULL;
+ bool match = find_in_tree(zone->nsec3_nodes, nsec3_name, &found, &prev);
+
+ *nsec3_node = found;
+
+ if (prev == NULL) {
+ // either the returned node is the root of the tree, or it is
+ // the leftmost node in the tree; in both cases node was found
+ // set the previous node of the found node
+ assert(match);
+ assert(*nsec3_node != NULL);
+ *nsec3_previous = (*nsec3_node)->prev;
+ } else {
+ *nsec3_previous = prev;
+ }
+
+ // The previous may be from wrong NSEC3 chain. Search for previous from the right chain.
+ const zone_node_t *original_prev = *nsec3_previous;
+ while (!((*nsec3_previous)->flags & NODE_FLAGS_IN_NSEC3_CHAIN)) {
+ *nsec3_previous = (*nsec3_previous)->prev;
+ if (*nsec3_previous == original_prev || *nsec3_previous == NULL) {
+ // cycle
+ *nsec3_previous = NULL;
+ break;
+ }
+ }
+
+ return (match ? ZONE_NAME_FOUND : ZONE_NAME_NOT_FOUND);
+}
+
+const zone_node_t *zone_contents_find_wildcard_child(const zone_contents_t *contents,
+ const zone_node_t *parent)
+{
+ if (contents == NULL || parent == NULL || parent->owner == NULL) {
+ return NULL;
+ }
+
+ knot_dname_t wildcard[KNOT_DNAME_MAXLEN] = { 0x01, '*' };
+ knot_dname_to_wire(wildcard + 2, parent->owner, KNOT_DNAME_MAXLEN - 2);
+
+ return zone_contents_find_node(contents, wildcard);
+}
+
+static int adjust_nodes(zone_tree_t *nodes, zone_adjust_arg_t *adjust_arg,
+ zone_tree_apply_cb_t callback)
+{
+ assert(adjust_arg);
+ assert(callback);
+
+ if (zone_tree_is_empty(nodes)) {
+ return KNOT_EOK;
+ }
+
+ adjust_arg->first_node = NULL;
+ adjust_arg->previous_node = NULL;
+
+ int ret = zone_tree_apply(nodes, callback, adjust_arg);
+
+ if (adjust_arg->first_node) {
+ adjust_arg->first_node->prev = adjust_arg->previous_node;
+ }
+
+ return ret;
+}
+
+static int load_nsec3param(zone_contents_t *contents)
+{
+ assert(contents);
+ assert(contents->apex);
+
+ const knot_rdataset_t *rrs = NULL;
+ rrs = node_rdataset(contents->apex, KNOT_RRTYPE_NSEC3PARAM);
+ if (rrs == NULL) {
+ dnssec_nsec3_params_free(&contents->nsec3_params);
+ return KNOT_EOK;
+ }
+
+ if (rrs->count < 1) {
+ return KNOT_EINVAL;
+ }
+
+ dnssec_binary_t rdata = {
+ .size = rrs->rdata->len,
+ .data = rrs->rdata->data,
+ };
+
+ dnssec_nsec3_params_t new_params = { 0 };
+ int r = dnssec_nsec3_params_from_rdata(&new_params, &rdata);
+ if (r != DNSSEC_EOK) {
+ return KNOT_EMALF;
+ }
+
+ dnssec_nsec3_params_free(&contents->nsec3_params);
+ contents->nsec3_params = new_params;
+ return KNOT_EOK;
+}
+
+static int contents_adjust(zone_contents_t *contents, bool normal)
+{
+ if (contents == NULL || contents->apex == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = load_nsec3param(contents);
+ if (ret != KNOT_EOK) {
+ log_zone_error(contents->apex->owner,
+ "failed to load NSEC3 parameters (%s)",
+ knot_strerror(ret));
+ return ret;
+ }
+
+ zone_adjust_arg_t arg = {
+ .zone = contents
+ };
+
+ contents->size = 0;
+ contents->dnssec = node_rrtype_is_signed(contents->apex, KNOT_RRTYPE_SOA);
+
+ // NSEC3 nodes must be adjusted first, because we already need the NSEC3 chain
+ // to be closed before we adjust NSEC3 pointers in adjust_normal_node
+ ret = adjust_nodes(contents->nsec3_nodes, &arg, adjust_nsec3_node);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = adjust_nodes(contents->nodes, &arg,
+ normal ? adjust_normal_node : adjust_pointers);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ return adjust_nodes(contents->nodes, &arg, adjust_additional);
+}
+
+int zone_contents_adjust_pointers(zone_contents_t *contents)
+{
+ return contents_adjust(contents, false);
+}
+
+int zone_contents_adjust_full(zone_contents_t *contents)
+{
+ return contents_adjust(contents, true);
+}
+
+int zone_contents_apply(zone_contents_t *contents,
+ zone_contents_apply_cb_t function, void *data)
+{
+ if (contents == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ zone_tree_func_t f = {
+ .func = function,
+ .data = data
+ };
+
+ return zone_tree_apply(contents->nodes, tree_apply_cb, &f);
+}
+
+int zone_contents_nsec3_apply(zone_contents_t *contents,
+ zone_contents_apply_cb_t function, void *data)
+{
+ if (contents == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ zone_tree_func_t f = {
+ .func = function,
+ .data = data
+ };
+
+ return zone_tree_apply(contents->nsec3_nodes, tree_apply_cb, &f);
+}
+
+int zone_contents_shallow_copy(const zone_contents_t *from, zone_contents_t **to)
+{
+ if (from == NULL || to == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ /* Copy to same destination as source. */
+ if (from == *to) {
+ return KNOT_EINVAL;
+ }
+
+ zone_contents_t *contents = calloc(1, sizeof(zone_contents_t));
+ if (contents == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ int ret = recreate_normal_tree(from, contents);
+ if (ret != KNOT_EOK) {
+ zone_tree_free(&contents->nodes);
+ free(contents);
+ return ret;
+ }
+
+ if (from->nsec3_nodes) {
+ ret = recreate_nsec3_tree(from, contents);
+ if (ret != KNOT_EOK) {
+ zone_tree_free(&contents->nodes);
+ zone_tree_free(&contents->nsec3_nodes);
+ free(contents);
+ return ret;
+ }
+ } else {
+ contents->nsec3_nodes = NULL;
+ }
+
+ *to = contents;
+ return KNOT_EOK;
+}
+
+void zone_contents_free(zone_contents_t *contents)
+{
+ if (contents == NULL) {
+ return;
+ }
+
+ // free the zone tree, but only the structure
+ zone_tree_free(&contents->nodes);
+ zone_tree_free(&contents->nsec3_nodes);
+
+ dnssec_nsec3_params_free(&contents->nsec3_params);
+
+ free(contents);
+}
+
+void zone_contents_deep_free(zone_contents_t *contents)
+{
+ if (contents == NULL) {
+ return;
+ }
+
+ if (contents != NULL) {
+ // Delete NSEC3 tree.
+ (void)zone_tree_apply(contents->nsec3_nodes,
+ destroy_node_rrsets_from_tree, NULL);
+
+ // Delete the normal tree.
+ (void)zone_tree_apply(contents->nodes,
+ destroy_node_rrsets_from_tree, NULL);
+ }
+
+ zone_contents_free(contents);
+}
+
+uint32_t zone_contents_serial(const zone_contents_t *zone)
+{
+ if (zone == NULL) {
+ return 0;
+ }
+
+ const knot_rdataset_t *soa = node_rdataset(zone->apex, KNOT_RRTYPE_SOA);
+ if (soa == NULL) {
+ return 0;
+ }
+
+ return knot_soa_serial(soa->rdata);
+}
+
+void zone_contents_set_soa_serial(zone_contents_t *zone, uint32_t new_serial)
+{
+ knot_rdataset_t *soa;
+ if (zone != NULL && (soa = node_rdataset(zone->apex, KNOT_RRTYPE_SOA)) != NULL) {
+ knot_soa_serial_set(soa->rdata, new_serial);
+ }
+}
+
+bool zone_contents_is_empty(const zone_contents_t *zone)
+{
+ if (zone == NULL) {
+ return true;
+ }
+
+ bool apex_empty = (zone->apex == NULL || zone->apex->rrset_count == 0);
+ bool no_non_apex = (zone_tree_count(zone->nodes) <= (zone->apex != NULL ? 1 : 0));
+ bool no_nsec3 = zone_tree_is_empty(zone->nsec3_nodes);
+
+ return (apex_empty && no_non_apex && no_nsec3);
+}
+
+size_t zone_contents_measure_size(zone_contents_t *zone)
+{
+ zone->size = 0;
+ zone_contents_apply(zone, measure_size, &zone->size);
+ return zone->size;
+}
+
+uint32_t zone_contents_max_ttl(zone_contents_t *zone)
+{
+ zone->max_ttl = 0;
+ zone_contents_apply(zone, measure_max_ttl, &zone->size);
+ return zone->max_ttl;
+}
diff --git a/src/knot/zone/contents.h b/src/knot/zone/contents.h
new file mode 100644
index 0000000..9ccf3c0
--- /dev/null
+++ b/src/knot/zone/contents.h
@@ -0,0 +1,288 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * Zone contents structure and API for manipulating it.
+ *
+ * \addtogroup zone
+ * @{
+ */
+
+#pragma once
+
+#include "libdnssec/nsec.h"
+#include "libknot/rrtype/nsec3param.h"
+#include "knot/zone/node.h"
+#include "knot/zone/zone-tree.h"
+
+enum zone_contents_find_dname_result {
+ ZONE_NAME_NOT_FOUND = 0,
+ ZONE_NAME_FOUND = 1
+};
+
+typedef struct zone_contents {
+ zone_node_t *apex; /*!< Apex node of the zone (holding SOA) */
+
+ zone_tree_t *nodes;
+ zone_tree_t *nsec3_nodes;
+
+ dnssec_nsec3_params_t nsec3_params;
+ size_t size;
+ uint32_t max_ttl;
+ bool dnssec;
+} zone_contents_t;
+
+/*!
+ * \brief Signature of callback for zone contents apply functions.
+ */
+typedef int (*zone_contents_apply_cb_t)(zone_node_t *node, void *data);
+
+/*!
+ * \brief Allocate and create new zone contents.
+ *
+ * \param apex_name Name of the root node.
+ *
+ * \return New contents or NULL on error.
+ */
+zone_contents_t *zone_contents_new(const knot_dname_t *apex_name);
+
+/*!
+ * \brief Add an RR to contents.
+ *
+ * \param z Contents to add to.
+ * \param rr The RR to add.
+ * \param n Node to which the RR has been added to on success, unchanged otherwise.
+ *
+ * \return KNOT_E*
+ */
+int zone_contents_add_rr(zone_contents_t *z, const knot_rrset_t *rr, zone_node_t **n);
+
+/*!
+ * \brief Remove an RR from contents.
+ *
+ * \param z Contents to remove from.
+ * \param rr The RR to remove.
+ * \param n Node from which the RR to be removed from on success, unchanged otherwise.
+ *
+ * \return KNOT_E*
+ */
+int zone_contents_remove_rr(zone_contents_t *z, const knot_rrset_t *rr, zone_node_t **n);
+
+/*!
+ * \brief Get the node with this RR (the RR's owner).
+ *
+ * \param zone Contents to add to.
+ * \param rrset The RR to add.
+ *
+ * \return The searched node if it exists, a new added empty node or NULL on error.
+ */
+zone_node_t *zone_contents_get_node_for_rr(zone_contents_t *zone, const knot_rrset_t *rrset);
+
+/*!
+ * \brief Tries to find a node with the specified name in the zone.
+ *
+ * \param contents Zone where the name should be searched for.
+ * \param name Name to find.
+ *
+ * \return Corresponding node if found, NULL otherwise.
+ */
+const zone_node_t *zone_contents_find_node(const zone_contents_t *contents, const knot_dname_t *name);
+
+zone_node_t *zone_contents_find_node_for_rr(zone_contents_t *contents, const knot_rrset_t *rrset);
+
+/*!
+ * \brief Tries to find a node by owner in the zone contents.
+ *
+ * \param[in] contents Zone to search for the name.
+ * \param[in] name Domain name to search for.
+ * \param[out] match Matching node or NULL.
+ * \param[out] closest Closest matching name in the zone.
+ * May match \a match if found exactly.
+ * \param[out] previous Previous domain name in canonical order.
+ * Always previous, won't match \a match.
+ *
+ * \note The encloser and previous mustn't be used directly for DNSSEC proofs.
+ * These nodes may be empty non-terminals or not authoritative.
+ *
+ * \retval ZONE_NAME_FOUND if node with owner \a name was found.
+ * \retval ZONE_NAME_NOT_FOUND if it was not found.
+ * \retval KNOT_EINVAL
+ * \retval KNOT_EOUTOFZONE
+ */
+int zone_contents_find_dname(const zone_contents_t *contents,
+ const knot_dname_t *name,
+ const zone_node_t **match,
+ const zone_node_t **closest,
+ const zone_node_t **previous);
+
+/*!
+ * \brief Tries to find a node with the specified name among the NSEC3 nodes
+ * of the zone.
+ *
+ * \note This function is identical to zone_contents_get_nsec3_node(), only it
+ * returns constant reference.
+ *
+ * \param contents Zone where the name should be searched for.
+ * \param name Name to find.
+ *
+ * \return Corresponding node if found, NULL otherwise.
+ */
+const zone_node_t *zone_contents_find_nsec3_node(const zone_contents_t *contents,
+ const knot_dname_t *name);
+
+/*!
+ * \brief Finds NSEC3 node and previous NSEC3 node in canonical order,
+ * corresponding to the given domain name.
+ *
+ * This functions creates a NSEC3 hash of \a name and tries to find NSEC3 node
+ * with the hashed domain name as owner.
+ *
+ * \param[in] contents Zone to search in.
+ * \param[in] name Domain name to get the corresponding NSEC3 nodes for.
+ * \param[out] nsec3_node NSEC3 node corresponding to \a name (if found,
+ * otherwise this may be an arbitrary NSEC3 node).
+ * \param[out] nsec3_previous The NSEC3 node immediately preceding hashed domain
+ * name corresponding to \a name in canonical order.
+ *
+ * \retval ZONE_NAME_FOUND if the corresponding NSEC3 node was found.
+ * \retval ZONE_NAME_NOT_FOUND if it was not found.
+ * \retval KNOT_EINVAL
+ * \retval KNOT_ENSEC3PAR
+ * \retval KNOT_ECRYPTO
+ * \retval KNOT_ERROR
+ */
+int zone_contents_find_nsec3_for_name(const zone_contents_t *contents,
+ const knot_dname_t *name,
+ const zone_node_t **nsec3_node,
+ const zone_node_t **nsec3_previous);
+
+const zone_node_t *zone_contents_find_wildcard_child(const zone_contents_t *contents,
+ const zone_node_t *parent);
+
+/*!
+ * \brief Sets parent and previous pointers and node flags. (cheap operation)
+ * For both normal and NSEC3 tree
+ *
+ * \param contents Zone contents to be adjusted.
+ */
+int zone_contents_adjust_pointers(zone_contents_t *contents);
+
+/*!
+ * \brief Sets parent and previous pointers, sets node flags and NSEC3 links.
+ * This has to be called before the zone can be served.
+ *
+ * \param contents Zone contents to be adjusted.
+ */
+int zone_contents_adjust_full(zone_contents_t *contents);
+
+/*!
+ * \brief Applies the given function to each regular node in the zone.
+ *
+ * \param contents Nodes of this zone will be used as parameters for the function.
+ * \param function Function to be applied to each node of the zone.
+ * \param data Arbitrary data to be passed to the function.
+ */
+int zone_contents_apply(zone_contents_t *contents,
+ zone_contents_apply_cb_t function, void *data);
+
+/*!
+ * \brief Applies the given function to each NSEC3 node in the zone.
+ *
+ * \param contents NSEC3 nodes of this zone will be used as parameters for the
+ * function.
+ * \param function Function to be applied to each node of the zone.
+ * \param data Arbitrary data to be passed to the function.
+ */
+int zone_contents_nsec3_apply(zone_contents_t *contents,
+ zone_contents_apply_cb_t function, void *data);
+
+/*!
+ * \brief Creates a shallow copy of the zone (no stored data are copied).
+ *
+ * This function creates a new zone structure in \a to, creates new trees for
+ * regular nodes and for NSEC3 nodes, creates new hash table and a new domain
+ * table. It also fills these structures with the exact same data as the
+ * original zone is - no copying of stored data is done, just pointers are
+ * copied.
+ *
+ * \param from Original zone.
+ * \param to Copy of the zone.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EINVAL
+ * \retval KNOT_ENOMEM
+ */
+int zone_contents_shallow_copy(const zone_contents_t *from, zone_contents_t **to);
+
+/*!
+ * \brief Deallocate directly owned data of zone contents.
+ *
+ * \param contents Zone contents to free.
+ */
+void zone_contents_free(zone_contents_t *contents);
+
+/*!
+ * \brief Deallocate node RRSets inside the trees, then call zone_contents_free.
+ *
+ * \param contents Zone contents to free.
+ */
+void zone_contents_deep_free(zone_contents_t *contents);
+
+/*!
+ * \brief Fetch zone serial.
+ *
+ * \param zone Zone.
+ *
+ * \return serial or 0
+ */
+uint32_t zone_contents_serial(const zone_contents_t *zone);
+
+/*!
+ * \brief Adjust zone serial.
+ *
+ * Works only if there is a SOA in given contents.
+ *
+ * \param zone Zone.
+ * \param new_serial New serial to be set.
+ */
+void zone_contents_set_soa_serial(zone_contents_t *zone, uint32_t new_serial);
+
+/*!
+ * \brief Return true if zone is empty.
+ */
+bool zone_contents_is_empty(const zone_contents_t *zone);
+
+/*!
+ * \brief Measure zone contents size.
+ *
+ * Size is measured in uncompressed wire format. Measured size is saved into
+ * zone contents structure.
+ * \return Measured size
+ */
+size_t zone_contents_measure_size(zone_contents_t *zone);
+
+/*!
+ * \brief Obtain maximal TTL above all the records in zone.
+ *
+ * The value is also stored in zone_contents structure.
+ *
+ * \param zone Zone in question.
+ * \return Maximal TTL.
+ */
+uint32_t zone_contents_max_ttl(zone_contents_t *zone);
+
+/*! @} */
diff --git a/src/knot/zone/node.c b/src/knot/zone/node.c
new file mode 100644
index 0000000..2d593b9
--- /dev/null
+++ b/src/knot/zone/node.c
@@ -0,0 +1,312 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "knot/zone/node.h"
+#include "libknot/libknot.h"
+#include "contrib/mempattern.h"
+
+void additional_clear(additional_t *additional)
+{
+ if (additional == NULL) {
+ return;
+ }
+
+ free(additional->glues);
+ free(additional);
+}
+
+/*! \brief Clears allocated data in RRSet entry. */
+static void rr_data_clear(struct rr_data *data, knot_mm_t *mm)
+{
+ knot_rdataset_clear(&data->rrs, mm);
+ additional_clear(data->additional);
+}
+
+/*! \brief Clears allocated data in RRSet entry. */
+static int rr_data_from(const knot_rrset_t *rrset, struct rr_data *data, knot_mm_t *mm)
+{
+ int ret = knot_rdataset_copy(&data->rrs, &rrset->rrs, mm);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ data->ttl = rrset->ttl;
+ data->type = rrset->type;
+ data->additional = NULL;
+
+ return KNOT_EOK;
+}
+
+/*! \brief Adds RRSet to node directly. */
+static int add_rrset_no_merge(zone_node_t *node, const knot_rrset_t *rrset,
+ knot_mm_t *mm)
+{
+ if (node == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ const size_t prev_nlen = node->rrset_count * sizeof(struct rr_data);
+ const size_t nlen = (node->rrset_count + 1) * sizeof(struct rr_data);
+ void *p = mm_realloc(mm, node->rrs, nlen, prev_nlen);
+ if (p == NULL) {
+ return KNOT_ENOMEM;
+ }
+ node->rrs = p;
+ int ret = rr_data_from(rrset, node->rrs + node->rrset_count, mm);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ ++node->rrset_count;
+
+ return KNOT_EOK;
+}
+
+/*! \brief Checks if the added RR has the same TTL as the first RR in the node. */
+static bool ttl_changed(struct rr_data *node_data, const knot_rrset_t *rrset)
+{
+ if (rrset->type == KNOT_RRTYPE_RRSIG || node_data->rrs.count == 0) {
+ return false;
+ }
+
+ return rrset->ttl != node_data->ttl;
+}
+
+zone_node_t *node_new(const knot_dname_t *owner, knot_mm_t *mm)
+{
+ zone_node_t *ret = mm_alloc(mm, sizeof(zone_node_t));
+ if (ret == NULL) {
+ return NULL;
+ }
+ memset(ret, 0, sizeof(*ret));
+
+ if (owner) {
+ ret->owner = knot_dname_copy(owner, mm);
+ if (ret->owner == NULL) {
+ mm_free(mm, ret);
+ return NULL;
+ }
+ }
+
+ // Node is authoritative by default.
+ ret->flags = NODE_FLAGS_AUTH;
+
+ return ret;
+}
+
+void node_free_rrsets(zone_node_t *node, knot_mm_t *mm)
+{
+ if (node == NULL) {
+ return;
+ }
+
+ for (uint16_t i = 0; i < node->rrset_count; ++i) {
+ rr_data_clear(&node->rrs[i], mm);
+ }
+
+ mm_free(mm, node->rrs);
+ node->rrs = NULL;
+ node->rrset_count = 0;
+}
+
+void node_free(zone_node_t *node, knot_mm_t *mm)
+{
+ if (node == NULL) {
+ return;
+ }
+
+ knot_dname_free(node->owner, mm);
+
+ if (node->rrs != NULL) {
+ mm_free(mm, node->rrs);
+ }
+
+ mm_free(mm, node);
+}
+
+zone_node_t *node_shallow_copy(const zone_node_t *src, knot_mm_t *mm)
+{
+ if (src == NULL) {
+ return NULL;
+ }
+
+ // create new node
+ zone_node_t *dst = node_new(src->owner, mm);
+ if (dst == NULL) {
+ return NULL;
+ }
+
+ dst->flags = src->flags;
+
+ // copy RRSets
+ dst->rrset_count = src->rrset_count;
+ size_t rrlen = sizeof(struct rr_data) * src->rrset_count;
+ dst->rrs = mm_alloc(mm, rrlen);
+ if (dst->rrs == NULL) {
+ node_free(dst, mm);
+ return NULL;
+ }
+ memcpy(dst->rrs, src->rrs, rrlen);
+
+ for (uint16_t i = 0; i < src->rrset_count; ++i) {
+ // Clear additionals in the copy.
+ dst->rrs[i].additional = NULL;
+ }
+
+ return dst;
+}
+
+int node_add_rrset(zone_node_t *node, const knot_rrset_t *rrset, knot_mm_t *mm)
+{
+ if (node == NULL || rrset == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ for (uint16_t i = 0; i < node->rrset_count; ++i) {
+ if (node->rrs[i].type == rrset->type) {
+ struct rr_data *node_data = &node->rrs[i];
+ const bool ttl_change = ttl_changed(node_data, rrset);
+ if (ttl_change) {
+ node_data->ttl = rrset->ttl;
+ }
+
+ int ret = knot_rdataset_merge(&node_data->rrs,
+ &rrset->rrs, mm);
+ if (ret != KNOT_EOK) {
+ return ret;
+ } else {
+ return ttl_change ? KNOT_ETTL : KNOT_EOK;
+ }
+ }
+ }
+
+ // New RRSet (with one RR)
+ return add_rrset_no_merge(node, rrset, mm);
+}
+
+void node_remove_rdataset(zone_node_t *node, uint16_t type)
+{
+ if (node == NULL) {
+ return;
+ }
+
+ for (int i = 0; i < node->rrset_count; ++i) {
+ if (node->rrs[i].type == type) {
+ // We need to free additionals from this rr_data before it gets overwritten.
+ additional_clear(node->rrs[i].additional);
+ memmove(node->rrs + i, node->rrs + i + 1,
+ (node->rrset_count - i - 1) * sizeof(struct rr_data));
+ --node->rrset_count;
+ return;
+ }
+ }
+}
+
+knot_rrset_t *node_create_rrset(const zone_node_t *node, uint16_t type)
+{
+ if (node == NULL) {
+ return NULL;
+ }
+
+ for (uint16_t i = 0; i < node->rrset_count; ++i) {
+ if (node->rrs[i].type == type) {
+ knot_rrset_t rrset = node_rrset_at(node, i);
+ return knot_rrset_copy(&rrset, NULL);
+ }
+ }
+
+ return NULL;
+}
+
+knot_rdataset_t *node_rdataset(const zone_node_t *node, uint16_t type)
+{
+ if (node == NULL) {
+ return NULL;
+ }
+
+ for (uint16_t i = 0; i < node->rrset_count; ++i) {
+ if (node->rrs[i].type == type) {
+ return &node->rrs[i].rrs;
+ }
+ }
+
+ return NULL;
+}
+
+void node_set_parent(zone_node_t *node, zone_node_t *parent)
+{
+ if (node == NULL || node->parent == parent) {
+ return;
+ }
+
+ // decrease number of children of previous parent
+ if (node->parent != NULL) {
+ --node->parent->children;
+ }
+ // set the parent
+ node->parent = parent;
+
+ // increase the count of children of the new parent
+ if (parent != NULL) {
+ ++parent->children;
+ }
+}
+
+bool node_rrtype_is_signed(const zone_node_t *node, uint16_t type)
+{
+ if (node == NULL) {
+ return false;
+ }
+
+ const knot_rdataset_t *rrsigs = node_rdataset(node, KNOT_RRTYPE_RRSIG);
+ if (rrsigs == NULL) {
+ return false;
+ }
+
+ uint16_t rrsigs_rdata_count = rrsigs->count;
+ knot_rdata_t *rrsig = rrsigs->rdata;
+ for (uint16_t i = 0; i < rrsigs_rdata_count; ++i) {
+ if (knot_rrsig_type_covered(rrsig) == type) {
+ return true;
+ }
+ rrsig = knot_rdataset_next(rrsig);
+ }
+
+ return false;
+}
+
+bool node_bitmap_equal(const zone_node_t *a, const zone_node_t *b)
+{
+ if (a == NULL || b == NULL || a->rrset_count != b->rrset_count) {
+ return false;
+ }
+
+ uint16_t i;
+ // heuristics: try if they are equal including order
+ for (i = 0; i < a->rrset_count; i++) {
+ if (a->rrs[i].type != b->rrs[i].type) {
+ break;
+ }
+ }
+ if (i == a->rrset_count) {
+ return true;
+ }
+
+ for (i = 0; i < a->rrset_count; i++) {
+ if (node_rdataset(b, a->rrs[i].type) == NULL) {
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/src/knot/zone/node.h b/src/knot/zone/node.h
new file mode 100644
index 0000000..07b4678
--- /dev/null
+++ b/src/knot/zone/node.h
@@ -0,0 +1,276 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "libknot/descriptor.h"
+#include "libknot/dname.h"
+#include "libknot/rrset.h"
+#include "libknot/rdataset.h"
+
+struct rr_data;
+
+/*!
+ * \brief Structure representing one node in a domain name tree, i.e. one domain
+ * name in a zone.
+ */
+typedef struct zone_node {
+ knot_dname_t *owner; /*!< Domain name being the owner of this node. */
+ struct zone_node *parent; /*!< Parent node in the name hierarchy. */
+
+ /*! \brief Array with data of RRSets belonging to this node. */
+ struct rr_data *rrs;
+
+ /*!
+ * \brief Previous node in canonical order. Only authoritative
+ * nodes or delegation points are referenced by this.
+ */
+ struct zone_node *prev;
+ struct zone_node *nsec3_node; /*! NSEC3 node corresponding to this node. */
+ struct zone_node *nsec3_wildcard_prev; /*! NSEC3 node for proof of wildcard non-existence. */
+ uint32_t children; /*!< Count of children nodes in DNS hierarchy. */
+ uint16_t rrset_count; /*!< Number of RRSets stored in the node. */
+ uint8_t flags; /*!< \ref node_flags enum. */
+} zone_node_t;
+
+/*!< \brief Glue node context. */
+typedef struct {
+ const zone_node_t *node; /*!< Glue node. */
+ uint16_t ns_pos; /*!< Corresponding NS record position (for compression). */
+ bool optional; /*!< Optional glue indicator. */
+} glue_t;
+
+/*!< \brief Additional data. */
+typedef struct {
+ glue_t *glues; /*!< Glue data. */
+ uint16_t count; /*!< Number of glue nodes. */
+} additional_t;
+
+/*!< \brief Structure storing RR data. */
+struct rr_data {
+ uint32_t ttl; /*!< RRSet TTL. */
+ uint16_t type; /*!< RR type of data. */
+ knot_rdataset_t rrs; /*!< Data of given type. */
+ additional_t *additional; /*!< Additional nodes with glues. */
+};
+
+/*! \brief Flags used to mark nodes with some property. */
+enum node_flags {
+ /*! \brief Node is authoritative, default. */
+ NODE_FLAGS_AUTH = 0 << 0,
+ /*! \brief Node is a delegation point (i.e. marking a zone cut). */
+ NODE_FLAGS_DELEG = 1 << 0,
+ /*! \brief Node is not authoritative (i.e. below a zone cut). */
+ NODE_FLAGS_NONAUTH = 1 << 1,
+ /*! \brief Node is empty and will be deleted after update. */
+ NODE_FLAGS_EMPTY = 1 << 3,
+ /*! \brief Node has a wildcard child. */
+ NODE_FLAGS_WILDCARD_CHILD = 1 << 4,
+ /*! \brief Is this NSEC3 node compatible with zone's NSEC3PARAMS ? */
+ NODE_FLAGS_IN_NSEC3_CHAIN = 1 << 5,
+};
+
+/*!
+ * \brief Clears additional structure.
+ *
+ * \param additional Additional to clear.
+ */
+void additional_clear(additional_t *additional);
+
+/*!
+ * \brief Creates and initializes new node structure.
+ *
+ * \param owner Node's owner, will be duplicated.
+ * \param mm Memory context to use.
+ *
+ * \return Newly created node or NULL if an error occurred.
+ */
+zone_node_t *node_new(const knot_dname_t *owner, knot_mm_t *mm);
+
+/*!
+ * \brief Destroys allocated data within the node
+ * structure, but not the node itself.
+ *
+ * \param node Node that contains data to be destroyed.
+ * \param mm Memory context to use.
+ */
+void node_free_rrsets(zone_node_t *node, knot_mm_t *mm);
+
+/*!
+ * \brief Destroys the node structure.
+ *
+ * Does not destroy the data within the node.
+ *
+ * \param node Node to be destroyed.
+ * \param mm Memory context to use.
+ */
+void node_free(zone_node_t *node, knot_mm_t *mm);
+
+/*!
+ * \brief Creates a shallow copy of node structure, RR data are shared.
+ *
+ * \param src Source of the copy.
+ * \param mm Memory context to use.
+ *
+ * \return Copied node if success, NULL otherwise.
+ */
+zone_node_t *node_shallow_copy(const zone_node_t *src, knot_mm_t *mm);
+
+/*!
+ * \brief Adds an RRSet to the node. All data are copied. Owner and class are
+ * not used at all.
+ *
+ * \param node Node to add the RRSet to.
+ * \param rrset RRSet to add.
+ * \param mm Memory context to use.
+ *
+ * \return KNOT_E*
+ * \retval KNOT_ETTL RRSet TTL was updated.
+ */
+int node_add_rrset(zone_node_t *node, const knot_rrset_t *rrset, knot_mm_t *mm);
+
+/*!
+ * \brief Removes data for given RR type from node.
+ *
+ * \param node Node we want to delete from.
+ * \param type RR type to delete.
+ */
+void node_remove_rdataset(zone_node_t *node, uint16_t type);
+
+/*!
+ * \brief Returns the RRSet of the given type from the node. RRSet is allocated.
+ *
+ * \param node Node to get the RRSet from.
+ * \param type RR type of the RRSet to retrieve.
+ *
+ * \return RRSet from node \a node having type \a type, or NULL if no such
+ * RRSet exists in this node.
+ */
+knot_rrset_t *node_create_rrset(const zone_node_t *node, uint16_t type);
+
+/*!
+ * \brief Gets rdata set structure of given type from node.
+ *
+ * \param node Node to get data from.
+ * \param type RR type of data to get.
+ *
+ * \return Pointer to data if found, NULL otherwise.
+ */
+knot_rdataset_t *node_rdataset(const zone_node_t *node, uint16_t type);
+
+/*!
+ * \brief Sets the parent of the node. Also adjusts children count of parent.
+ *
+ * \param node Node to set the parent of.
+ * \param parent Parent to set to the node.
+ */
+void node_set_parent(zone_node_t *node, zone_node_t *parent);
+
+/*!
+ * \brief Checks whether node contains any RRSIG for given type.
+ *
+ * \param node Node to check in.
+ * \param type Type to check for.
+ *
+ * \return True/False.
+ */
+bool node_rrtype_is_signed(const zone_node_t *node, uint16_t type);
+
+/*!
+ * \brief Checks whether node contains RRSet for given type.
+ *
+ * \param node Node to check in.
+ * \param type Type to check for.
+ *
+ * \return True/False.
+ */
+inline static bool node_rrtype_exists(const zone_node_t *node, uint16_t type)
+{
+ return node_rdataset(node, type) != NULL;
+}
+
+/*!
+ * \brief Checks whether node is empty. Node is empty when NULL or when no
+ * RRSets are in it.
+ *
+ * \param node Node to check in.
+ *
+ * \return True/False.
+ */
+inline static bool node_empty(const zone_node_t *node)
+{
+ return node == NULL || node->rrset_count == 0;
+}
+
+/*!
+ * \brief Check whether two nodes have equal set of rrtypes.
+ *
+ * \param a A node.
+ * \param b Another node.
+ *
+ * \return True/False.
+ */
+bool node_bitmap_equal(const zone_node_t *a, const zone_node_t *b);
+
+/*!
+ * \brief Returns RRSet structure initialized with data from node.
+ *
+ * \param node Node containing RRSet.
+ * \param type RRSet type we want to get.
+ *
+ * \return RRSet structure with wanted type, or empty RRSet.
+ */
+static inline knot_rrset_t node_rrset(const zone_node_t *node, uint16_t type)
+{
+ knot_rrset_t rrset;
+ for (uint16_t i = 0; node && i < node->rrset_count; ++i) {
+ if (node->rrs[i].type == type) {
+ struct rr_data *rr_data = &node->rrs[i];
+ knot_rrset_init(&rrset, node->owner, type, KNOT_CLASS_IN,
+ rr_data->ttl);
+ rrset.rrs = rr_data->rrs;
+ rrset.additional = rr_data->additional;
+ return rrset;
+ }
+ }
+ knot_rrset_init_empty(&rrset);
+ return rrset;
+}
+
+/*!
+ * \brief Returns RRSet structure initialized with data from node at position
+ * equal to \a pos.
+ *
+ * \param node Node containing RRSet.
+ * \param pos RRSet position we want to get.
+ *
+ * \return RRSet structure with data from wanted position, or empty RRSet.
+ */
+static inline knot_rrset_t node_rrset_at(const zone_node_t *node, size_t pos)
+{
+ knot_rrset_t rrset;
+ if (node == NULL || pos >= node->rrset_count) {
+ knot_rrset_init_empty(&rrset);
+ return rrset;
+ }
+
+ struct rr_data *rr_data = &node->rrs[pos];
+ knot_rrset_init(&rrset, node->owner, rr_data->type, KNOT_CLASS_IN,
+ rr_data->ttl);
+ rrset.rrs = rr_data->rrs;
+ rrset.additional = rr_data->additional;
+ return rrset;
+}
diff --git a/src/knot/zone/semantic-check.c b/src/knot/zone/semantic-check.c
new file mode 100644
index 0000000..e7e9129
--- /dev/null
+++ b/src/knot/zone/semantic-check.c
@@ -0,0 +1,1193 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "libdnssec/error.h"
+#include "contrib/base32hex.h"
+#include "contrib/string.h"
+#include "libknot/libknot.h"
+#include "knot/zone/semantic-check.h"
+#include "knot/dnssec/rrset-sign.h"
+#include "knot/dnssec/zone-nsec.h"
+
+static const char *error_messages[SEM_ERR_UNKNOWN + 1] = {
+ [SEM_ERR_SOA_NONE] =
+ "missing SOA at the zone apex",
+
+ [SEM_ERR_CNAME_EXTRA_RECORDS] =
+ "more records exist at CNAME",
+ [SEM_ERR_CNAME_MULTIPLE] =
+ "multiple CNAME records",
+
+ [SEM_ERR_DNAME_CHILDREN] =
+ "child record exists under DNAME",
+
+ [SEM_ERR_NS_APEX] =
+ "missing NS at the zone apex",
+ [SEM_ERR_NS_GLUE] =
+ "missing glue record",
+
+ [SEM_ERR_RRSIG_RDATA_TYPE_COVERED] =
+ "wrong type covered in RRSIG",
+ [SEM_ERR_RRSIG_RDATA_TTL] =
+ "wrong original TTL in RRSIG",
+ [SEM_ERR_RRSIG_RDATA_EXPIRATION] =
+ "expired RRSIG",
+ [SEM_ERR_RRSIG_RDATA_INCEPTION] =
+ "RRSIG inception in the future",
+ [SEM_ERR_RRSIG_RDATA_LABELS] =
+ "wrong labels in RRSIG",
+ [SEM_ERR_RRSIG_RDATA_OWNER] =
+ "wrong signer's name in RRSIG",
+ [SEM_ERR_RRSIG_NO_RRSIG] =
+ "missing RRSIG",
+ [SEM_ERR_RRSIG_SIGNED] =
+ "signed RRSIG",
+ [SEM_ERR_RRSIG_UNVERIFIABLE] =
+ "unverifiable signature",
+
+ [SEM_ERR_NSEC_NONE] =
+ "missing NSEC",
+ [SEM_ERR_NSEC_RDATA_BITMAP] =
+ "incorrect type bitmap in NSEC",
+ [SEM_ERR_NSEC_RDATA_MULTIPLE] =
+ "multiple NSEC records",
+ [SEM_ERR_NSEC_RDATA_CHAIN] =
+ "incoherent NSEC chain",
+
+ [SEM_ERR_NSEC3_NONE] =
+ "missing NSEC3",
+ [SEM_ERR_NSEC3_INSECURE_DELEGATION_OPT] =
+ "insecure delegation outside NSEC3 opt-out",
+ [SEM_ERR_NSEC3_EXTRA_RECORD] =
+ "invalid record type in NSEC3 chain",
+ [SEM_ERR_NSEC3_RDATA_TTL] =
+ "inconsistent TTL for NSEC3 and minimum TTL in SOA",
+ [SEM_ERR_NSEC3_RDATA_CHAIN] =
+ "incoherent NSEC3 chain",
+ [SEM_ERR_NSEC3_RDATA_BITMAP] =
+ "incorrect type bitmap in NSEC3",
+ [SEM_ERR_NSEC3_RDATA_FLAGS] =
+ "incorrect flags in NSEC3",
+ [SEM_ERR_NSEC3_RDATA_SALT] =
+ "incorrect salt in NSEC3",
+ [SEM_ERR_NSEC3_RDATA_ALG] =
+ "incorrect algorithm in NSEC3",
+ [SEM_ERR_NSEC3_RDATA_ITERS] =
+ "incorrect number of iterations in NSEC3",
+
+ [SEM_ERR_NSEC3PARAM_RDATA_FLAGS] =
+ "invalid flags in NSEC3PARAM",
+ [SEM_ERR_NSEC3PARAM_RDATA_ALG] =
+ "invalid algorithm in NSEC3PARAM",
+
+ [SEM_ERR_DS_RDATA_ALG] =
+ "invalid algorithm in DS",
+ [SEM_ERR_DS_RDATA_DIGLEN] =
+ "invalid digest length in DS",
+
+ [SEM_ERR_DNSKEY_NONE] =
+ "missing DNSKEY",
+ [SEM_ERR_DNSKEY_INVALID] =
+ "invalid DNSKEY",
+ [SEM_ERR_DNSKEY_RDATA_PROTOCOL] =
+ "invalid protocol in DNSKEY",
+
+ [SEM_ERR_CDS_NONE] =
+ "missing CDS",
+ [SEM_ERR_CDS_MULTIPLE] =
+ "multiple CDS records",
+ [SEM_ERR_CDS_NOT_MATCH] =
+ "CDS not match CDNSKEY",
+
+ [SEM_ERR_CDNSKEY_NONE] =
+ "missing CDNSKEY",
+ [SEM_ERR_CDNSKEY_MULTIPLE] =
+ "multiple CDNSKEY records",
+ [SEM_ERR_CDNSKEY_NO_DNSKEY] =
+ "CDNSKEY not match DNSKEY",
+
+ [SEM_ERR_UNKNOWN] =
+ "unknown error"
+};
+
+const char *sem_error_msg(sem_error_t code)
+{
+ if (code > SEM_ERR_UNKNOWN) {
+ code = SEM_ERR_UNKNOWN;
+ }
+ return error_messages[code];
+}
+
+typedef enum {
+ MANDATORY = 1 << 0,
+ OPTIONAL = 1 << 1,
+ NSEC = 1 << 2,
+ NSEC3 = 1 << 3,
+} check_level_t;
+
+typedef struct {
+ zone_contents_t *zone;
+ sem_handler_t *handler;
+ const zone_node_t *next_nsec;
+ check_level_t level;
+ time_t time;
+} semchecks_data_t;
+
+static int check_cname(const zone_node_t *node, semchecks_data_t *data);
+static int check_dname(const zone_node_t *node, semchecks_data_t *data);
+static int check_delegation(const zone_node_t *node, semchecks_data_t *data);
+static int check_submission(const zone_node_t *node, semchecks_data_t *data);
+static int check_ds(const zone_node_t *node, semchecks_data_t *data);
+static int check_nsec(const zone_node_t *node, semchecks_data_t *data);
+static int check_nsec3(const zone_node_t *node, semchecks_data_t *data);
+static int check_nsec3_opt_out(const zone_node_t *node, semchecks_data_t *data);
+static int check_rrsig(const zone_node_t *node, semchecks_data_t *data);
+static int check_rrsig_signed(const zone_node_t *node, semchecks_data_t *data);
+static int check_nsec_bitmap(const zone_node_t *node, semchecks_data_t *data);
+static int check_nsec3_presence(const zone_node_t *node, semchecks_data_t *data);
+
+struct check_function {
+ int (*function)(const zone_node_t *, semchecks_data_t *);
+ check_level_t level;
+};
+
+/* List of function callbacks for defined check_level */
+static const struct check_function CHECK_FUNCTIONS[] = {
+ { check_cname, MANDATORY },
+ { check_dname, MANDATORY },
+ { check_delegation, OPTIONAL },
+ { check_submission, OPTIONAL },
+ { check_ds, OPTIONAL },
+ { check_rrsig, NSEC | NSEC3 },
+ { check_rrsig_signed, NSEC | NSEC3 },
+ { check_nsec_bitmap, NSEC | NSEC3 },
+ { check_nsec, NSEC },
+ { check_nsec3, NSEC3 },
+ { check_nsec3_presence, NSEC3 },
+ { check_nsec3_opt_out, NSEC3 },
+};
+
+static const int CHECK_FUNCTIONS_LEN = sizeof(CHECK_FUNCTIONS)
+ / sizeof(struct check_function);
+
+static int dnssec_key_from_rdata(dnssec_key_t **key, const knot_dname_t *owner,
+ const uint8_t *rdata, size_t rdlen)
+{
+ if (!key || !rdata || rdlen == 0) {
+ return KNOT_EINVAL;
+ }
+
+ const dnssec_binary_t binary_key = {
+ .size = rdlen,
+ .data = (uint8_t *)rdata
+ };
+
+ dnssec_key_t *new_key = NULL;
+ int ret = dnssec_key_new(&new_key);
+ if (ret != DNSSEC_EOK) {
+ return KNOT_ENOMEM;
+ }
+ ret = dnssec_key_set_rdata(new_key, &binary_key);
+ if (ret != DNSSEC_EOK) {
+ dnssec_key_free(new_key);
+ return KNOT_ENOMEM;
+ }
+ if (owner) {
+ ret = dnssec_key_set_dname(new_key, owner);
+ if (ret != DNSSEC_EOK) {
+ dnssec_key_free(new_key);
+ return KNOT_ENOMEM;
+ }
+ }
+
+ *key = new_key;
+ return KNOT_EOK;
+}
+
+static int check_signature(const knot_rdata_t *rrsig, const dnssec_key_t *key,
+ const knot_rrset_t *covered)
+{
+ if (!rrsig || !key || !dnssec_key_can_verify(key)) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = KNOT_EOK;
+ dnssec_sign_ctx_t *sign_ctx = NULL;
+
+ dnssec_binary_t signature = {
+ .size = knot_rrsig_signature_len(rrsig),
+ .data = (uint8_t *)knot_rrsig_signature(rrsig)
+ };
+ if (!signature.data || !signature.size) {
+ ret = KNOT_EINVAL;
+ goto fail;
+ }
+
+ if (dnssec_sign_new(&sign_ctx, key) != KNOT_EOK) {
+ ret = KNOT_ENOMEM;
+ goto fail;
+ }
+
+ if (knot_sign_ctx_add_data(sign_ctx, rrsig->data, covered) != KNOT_EOK) {
+ ret = KNOT_ENOMEM;
+ goto fail;
+ }
+
+ if (dnssec_sign_verify(sign_ctx, &signature) != KNOT_EOK) {
+ ret = KNOT_EINVAL;
+ goto fail;
+ }
+
+fail:
+ dnssec_sign_free(sign_ctx);
+ return ret;
+}
+
+/*!
+ * \brief Semantic check - RRSIG rdata.
+ *
+ * \param handler Pointer on function to be called in case of negative check.
+ * \param zone The zone the rrset is in.
+ * \param node The node in the zone contents.
+ * \param rrsig RRSIG rdata.
+ * \param rrset RRSet signed by the RRSIG.
+ * \param context The time stamp we check the rrsig validity according to.
+ * \param level Level of the check.
+ * \param verified Out: the RRSIG has been verified to be signed by existing DNSKEY.
+ *
+ * \retval KNOT_EOK on success.
+ * \return Appropriate error code if error was found.
+ */
+static int check_rrsig_rdata(sem_handler_t *handler,
+ const zone_contents_t *zone,
+ const zone_node_t *node,
+ const knot_rdata_t *rrsig,
+ const knot_rrset_t *rrset,
+ time_t context,
+ check_level_t level,
+ bool *verified)
+{
+ /* Prepare additional info string. */
+ char info_str[50] = { '\0' };
+ char type_str[16] = { '\0' };
+ knot_rrtype_to_string(rrset->type, type_str, sizeof(type_str));
+ int ret = snprintf(info_str, sizeof(info_str), "(record type %s)", type_str);
+ if (ret < 0 || ret >= sizeof(info_str)) {
+ return KNOT_ENOMEM;
+ }
+
+ if (knot_rrsig_type_covered(rrsig) != rrset->type) {
+ handler->cb(handler, zone, node, SEM_ERR_RRSIG_RDATA_TYPE_COVERED,
+ info_str);
+ }
+
+ /* label number at the 2nd index should be same as owner's */
+ uint8_t labels_rdata = knot_rrsig_labels(rrsig);
+
+ size_t tmp = knot_dname_labels(rrset->owner, NULL) - labels_rdata;
+ if (tmp != 0) {
+ /* if name has wildcard, label must not be included */
+ if (!knot_dname_is_wildcard(rrset->owner)) {
+ handler->cb(handler, zone, node, SEM_ERR_RRSIG_RDATA_LABELS,
+ info_str);
+ } else if (tmp != 1) {
+ handler->cb(handler, zone, node, SEM_ERR_RRSIG_RDATA_LABELS,
+ info_str);
+ }
+ }
+
+ /* Check original TTL. */
+ uint32_t original_ttl = knot_rrsig_original_ttl(rrsig);
+ if (original_ttl != rrset->ttl) {
+ handler->cb(handler, zone, node, SEM_ERR_RRSIG_RDATA_TTL,
+ info_str);
+ }
+
+ /* Check for expired signature. */
+ if (knot_rrsig_sig_expiration(rrsig) < context) {
+ handler->cb(handler, zone, node, SEM_ERR_RRSIG_RDATA_EXPIRATION,
+ info_str);
+ }
+
+ /* Check inception */
+ if (knot_rrsig_sig_inception(rrsig) > context) {
+ handler->cb(handler, zone, node, SEM_ERR_RRSIG_RDATA_INCEPTION,
+ info_str);
+ }
+
+ /* Check signer name. */
+ const knot_dname_t *signer = knot_rrsig_signer_name(rrsig);
+ if (!knot_dname_is_equal(signer, zone->apex->owner)) {
+ handler->cb(handler, zone, node, SEM_ERR_RRSIG_RDATA_OWNER,
+ info_str);
+ }
+
+ /* Verify with public key - only one RRSIG of covered record needed */
+ if (level & OPTIONAL && !*verified) {
+ const knot_rdataset_t *dnskeys = node_rdataset(zone->apex, KNOT_RRTYPE_DNSKEY);
+ if (dnskeys == NULL) {
+ return KNOT_EOK;
+ }
+
+ for (int i = 0; i < dnskeys->count; i++) {
+ knot_rdata_t *dnskey = knot_rdataset_at(dnskeys, i);
+ uint16_t flags = knot_dnskey_flags(dnskey);
+ uint8_t proto = knot_dnskey_proto(dnskey);
+ /* RFC 4034 2.1.1 & 2.1.2 */
+ if (flags & DNSKEY_FLAGS_ZSK && proto == 3) {
+ dnssec_key_t *key;
+
+ ret = dnssec_key_from_rdata(&key, zone->apex->owner,
+ dnskey->data, dnskey->len);
+ if (ret != KNOT_EOK) {
+ continue;
+ }
+
+ ret = check_signature(rrsig, key, rrset);
+ dnssec_key_free(key);
+ if (ret == KNOT_EOK) {
+ *verified = true;
+ break;
+ }
+ }
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+static int check_rrsig_signed(const zone_node_t *node, semchecks_data_t *data)
+{
+ /* signed rrsig - nonsense */
+ if (node_rrtype_is_signed(node, KNOT_RRTYPE_RRSIG)) {
+ data->handler->cb(data->handler, data->zone, node,
+ SEM_ERR_RRSIG_SIGNED, NULL);
+ }
+
+ return KNOT_EOK;
+}
+/*!
+ * \brief Semantic check - RRSet's RRSIG.
+ *
+ * \param handler Pointer on function to be called in case of negative check.
+ * \param zone The zone the rrset is in.
+ * \param node The node in the zone contents.
+ * \param rrset RRSet signed by the RRSIG.
+ * \param context The time stamp we check the rrsig validity according to.
+ * \param level Level of the check.
+ *
+ * \retval KNOT_EOK on success.
+ * \return Appropriate error code if error was found.
+ */
+static int check_rrsig_in_rrset(sem_handler_t *handler,
+ const zone_contents_t *zone,
+ const zone_node_t *node,
+ const knot_rrset_t *rrset,
+ time_t context,
+ check_level_t level)
+{
+ if (handler == NULL || node == NULL || rrset == NULL) {
+ return KNOT_EINVAL;
+ }
+ /* Prepare additional info string. */
+ char info_str[50] = { '\0' };
+ char type_str[16] = { '\0' };
+ knot_rrtype_to_string(rrset->type, type_str, sizeof(type_str));
+ int ret = snprintf(info_str, sizeof(info_str), "(record type %s)", type_str);
+ if (ret < 0 || ret >= sizeof(info_str)) {
+ return KNOT_ENOMEM;
+ }
+
+ knot_rrset_t node_rrsigs = node_rrset(node, KNOT_RRTYPE_RRSIG);
+
+ knot_rdataset_t rrsigs;
+ knot_rdataset_init(&rrsigs);
+ ret = knot_synth_rrsig(rrset->type, &node_rrsigs.rrs, &rrsigs, NULL);
+ if (ret != KNOT_EOK && ret != KNOT_ENOENT) {
+ return ret;
+ }
+ if (ret == KNOT_ENOENT) {
+ handler->cb(handler, zone, node, SEM_ERR_RRSIG_NO_RRSIG, info_str);
+ return KNOT_EOK;
+ }
+
+ bool verified = false;
+ knot_rdata_t *rrsig = rrsigs.rdata;
+ for (uint16_t i = 0; ret == KNOT_EOK && i < rrsigs.count; ++i) {
+ ret = check_rrsig_rdata(handler, zone, node, rrsig, rrset,
+ context, level, &verified);
+ rrsig = knot_rdataset_next(rrsig);
+ }
+ /* Only one rrsig of covered record needs to be verified by DNSKEY. */
+ if (!verified) {
+ handler->cb(handler, zone, node, SEM_ERR_RRSIG_UNVERIFIABLE,
+ info_str);
+ }
+
+ knot_rdataset_clear(&rrsigs, NULL);
+ return KNOT_EOK;;
+}
+
+/*!
+ * \brief Check if glue record for delegation is present.
+ *
+ * Also check if there is NS record in the zone.
+ * \param node Node to check
+ * \param data Semantic checks context data
+ */
+static int check_delegation(const zone_node_t *node, semchecks_data_t *data)
+{
+ if (!((node->flags & NODE_FLAGS_DELEG) || data->zone->apex == node)) {
+ return KNOT_EOK;
+ }
+
+ const knot_rdataset_t *ns_rrs = node_rdataset(node, KNOT_RRTYPE_NS);
+ if (ns_rrs == NULL) {
+ assert(data->zone->apex == node);
+ data->handler->cb(data->handler, data->zone, node,
+ SEM_ERR_NS_APEX, NULL);
+ return KNOT_EOK;
+ }
+
+ // check glue record for delegation
+ for (int i = 0; i < ns_rrs->count; ++i) {
+ knot_rdata_t *ns_rr = knot_rdataset_at(ns_rrs, i);
+ const knot_dname_t *ns_dname = knot_ns_name(ns_rr);
+ if (knot_dname_in_bailiwick(ns_dname, node->owner) <= 0) {
+ continue;
+ }
+
+ const zone_node_t *glue_node =
+ zone_contents_find_node(data->zone, ns_dname);
+
+ if (glue_node == NULL) {
+ /* Try wildcard ([1]* + suffix). */
+ knot_dname_t wildcard[KNOT_DNAME_MAXLEN];
+ memcpy(wildcard, "\x1""*", 2);
+ knot_dname_to_wire(wildcard + 2,
+ knot_wire_next_label(ns_dname, NULL),
+ sizeof(wildcard) - 2);
+ glue_node = zone_contents_find_node(data->zone, wildcard);
+ }
+ if (!node_rrtype_exists(glue_node, KNOT_RRTYPE_A) &&
+ !node_rrtype_exists(glue_node, KNOT_RRTYPE_AAAA)) {
+ data->handler->cb(data->handler, data->zone, node,
+ SEM_ERR_NS_GLUE, NULL);
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief check_submission_records Check CDS and CDNSKEY
+ */
+static int check_submission(const zone_node_t *node, semchecks_data_t *data)
+{
+ const knot_rdataset_t *cdss = node_rdataset(node, KNOT_RRTYPE_CDS);
+ const knot_rdataset_t *cdnskeys = node_rdataset(node, KNOT_RRTYPE_CDNSKEY);
+ if (cdss == NULL && cdnskeys == NULL) {
+ return KNOT_EOK;
+ } else if (cdss == NULL) {
+ data->handler->cb(data->handler, data->zone, node,
+ SEM_ERR_CDS_NONE, NULL);
+ return KNOT_EOK;
+ } else if (cdnskeys == NULL) {
+ data->handler->cb(data->handler, data->zone, node,
+ SEM_ERR_CDNSKEY_NONE, NULL);
+ return KNOT_EOK;
+ }
+
+ if (cdss->count != 1) {
+ data->handler->cb(data->handler, data->zone, node,
+ SEM_ERR_CDS_MULTIPLE, NULL);
+ }
+ if (cdnskeys->count != 1) {
+ data->handler->cb(data->handler, data->zone, node,
+ SEM_ERR_CDNSKEY_MULTIPLE, NULL);
+ }
+
+ knot_rdata_t *cdnskey = cdnskeys->rdata;
+ knot_rdata_t *cds = cdss->rdata;
+ uint8_t digest_type = knot_ds_digest_type(cdss->rdata);
+
+ const knot_rdataset_t *dnskeys = node_rdataset(data->zone->apex,
+ KNOT_RRTYPE_DNSKEY);
+ for (int i = 0; dnskeys != NULL && i < dnskeys->count; i++) {
+ knot_rdata_t *dnskey = knot_rdataset_at(dnskeys, i);
+ if (knot_rdata_cmp(dnskey, cdnskey) != 0) {
+ continue;
+ }
+
+ dnssec_key_t *key;
+ int ret = dnssec_key_from_rdata(&key, data->zone->apex->owner,
+ dnskey->data, dnskey->len);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ dnssec_binary_t cds_calc = { 0 };
+ dnssec_binary_t cds_orig = { .size = cds->len, .data = cds->data };
+ ret = dnssec_key_create_ds(key, digest_type, &cds_calc);
+ if (ret != KNOT_EOK) {
+ dnssec_key_free(key);
+ return ret;
+ }
+
+ ret = dnssec_binary_cmp(&cds_orig, &cds_calc);
+ dnssec_binary_free(&cds_calc);
+ dnssec_key_free(key);
+ if (ret == 0) {
+ return KNOT_EOK;
+ } else {
+ data->handler->cb(data->handler, data->zone, node,
+ SEM_ERR_CDS_NOT_MATCH, NULL);
+ }
+ }
+
+ if (dnskeys != NULL) {
+ data->handler->cb(data->handler, data->zone, node,
+ SEM_ERR_CDNSKEY_NO_DNSKEY, NULL);
+ }
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Semantic check - DS record.
+ *
+ * \param node Node to check
+ * \param data Semantic checks context data
+ *
+ * \retval KNOT_EOK on success.
+ * \return Appropriate error code if error was found.
+ */
+static int check_ds(const zone_node_t *node, semchecks_data_t *data)
+{
+ const knot_rdataset_t *dss = node_rdataset(node, KNOT_RRTYPE_DS);
+ if (dss == NULL) {
+ return KNOT_EOK;
+ }
+
+ for (int i = 0; i < dss->count; i++) {
+ knot_rdata_t *ds = knot_rdataset_at(dss, i);
+ uint16_t keytag = knot_ds_key_tag(ds);
+ uint8_t digest_type = knot_ds_digest_type(ds);
+
+ char info[100] = "";
+ (void)snprintf(info, sizeof(info), "(keytag %d)", keytag);
+
+ if (!dnssec_algorithm_digest_support(digest_type)) {
+ data->handler->cb(data->handler, data->zone, node,
+ SEM_ERR_DS_RDATA_ALG, info);
+ } else {
+ // Sizes for different digest algorithms.
+ const uint16_t digest_sizes [] = { 0, 20, 32, 32, 48};
+
+ uint16_t digest_size = knot_ds_digest_len(ds);
+
+ if (digest_sizes[digest_type] != digest_size) {
+ data->handler->cb(data->handler, data->zone, node,
+ SEM_ERR_DS_RDATA_DIGLEN, info);
+ }
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Run all semantic check related to RRSIG record
+ *
+ * \param node Node to check
+ * \param data Semantic checks context data
+ */
+static int check_rrsig(const zone_node_t *node, semchecks_data_t *data)
+{
+ assert(node);
+ if (node->flags & NODE_FLAGS_NONAUTH) {
+ return KNOT_EOK;
+ }
+
+ bool deleg = node->flags & NODE_FLAGS_DELEG;
+
+ int ret = KNOT_EOK;
+
+ int rrset_count = node->rrset_count;
+ for (int i = 0; ret == KNOT_EOK && i < rrset_count; i++) {
+ knot_rrset_t rrset = node_rrset_at(node, i);
+ if (rrset.type == KNOT_RRTYPE_RRSIG) {
+ continue;
+ }
+ if (deleg && rrset.type != KNOT_RRTYPE_NSEC &&
+ rrset.type != KNOT_RRTYPE_DS ) {
+ continue;
+ }
+
+ ret = check_rrsig_in_rrset(data->handler, data->zone, node, &rrset,
+ data->time, data->level);
+ }
+ return ret;
+}
+
+/*!
+ * \brief Add all RR types from a node into the bitmap.
+ */
+static void bitmap_add_all_node_rrsets(dnssec_nsec_bitmap_t *bitmap,
+ const zone_node_t *node)
+{
+ bool deleg = node->flags & NODE_FLAGS_DELEG;
+ for (int i = 0; i < node->rrset_count; i++) {
+ knot_rrset_t rr = node_rrset_at(node, i);
+ if (deleg && (rr.type != KNOT_RRTYPE_NS &&
+ rr.type != KNOT_RRTYPE_DS &&
+ rr.type != KNOT_RRTYPE_NSEC &&
+ rr.type != KNOT_RRTYPE_RRSIG)) {
+ continue;
+ }
+ dnssec_nsec_bitmap_add(bitmap, rr.type);
+ }
+}
+
+static char *nsec3_info(const knot_dname_t *owner, char *out, size_t out_len)
+{
+ char buff[KNOT_DNAME_TXT_MAXLEN + 1];
+ char *str = knot_dname_to_str(buff, owner, sizeof(buff));
+ if (str == NULL) {
+ return NULL;
+ }
+
+ int ret = snprintf(out, out_len, "(NSEC3 owner=%s)", str);
+ if (ret <= 0 || ret >= out_len) {
+ return NULL;
+ }
+
+ return out;
+}
+
+/*!
+ * \brief Check NSEC and NSEC3 type bitmap
+ *
+ * \param node Node to check
+ * \param data Semantic checks context data
+ */
+static int check_nsec_bitmap(const zone_node_t *node, semchecks_data_t *data)
+{
+ assert(node);
+ if (node->flags & NODE_FLAGS_NONAUTH) {
+ return KNOT_EOK;
+ }
+
+ bool nsec = data->level & NSEC;
+ knot_rdataset_t *nsec_rrs = NULL;
+
+ if (nsec) {
+ nsec_rrs = node_rdataset(node, KNOT_RRTYPE_NSEC);
+ } else if (node->nsec3_node != NULL) {
+ nsec_rrs = node_rdataset(node->nsec3_node, KNOT_RRTYPE_NSEC3);
+ }
+ if (nsec_rrs == NULL) {
+ return KNOT_EOK;
+ }
+
+ // create NSEC bitmap from node
+ dnssec_nsec_bitmap_t *node_bitmap = dnssec_nsec_bitmap_new();
+ if (node_bitmap == NULL) {
+ return KNOT_ENOMEM;
+ }
+ bitmap_add_all_node_rrsets(node_bitmap, node);
+
+ uint16_t node_wire_size = dnssec_nsec_bitmap_size(node_bitmap);
+ uint8_t *node_wire = malloc(node_wire_size);
+ if (node_wire == NULL) {
+ dnssec_nsec_bitmap_free(node_bitmap);
+ return KNOT_ENOMEM;
+ }
+ dnssec_nsec_bitmap_write(node_bitmap, node_wire);
+ dnssec_nsec_bitmap_free(node_bitmap);
+
+ // get NSEC bitmap from NSEC node
+ const uint8_t *nsec_wire = NULL;
+ uint16_t nsec_wire_size = 0;
+ if (nsec) {
+ nsec_wire = knot_nsec_bitmap(nsec_rrs->rdata);
+ nsec_wire_size = knot_nsec_bitmap_len(nsec_rrs->rdata);
+ } else {
+ nsec_wire = knot_nsec3_bitmap(nsec_rrs->rdata);
+ nsec_wire_size = knot_nsec3_bitmap_len(nsec_rrs->rdata);
+ }
+
+ if (node_wire_size != nsec_wire_size ||
+ memcmp(node_wire, nsec_wire, node_wire_size) != 0) {
+ char buff[50 + KNOT_DNAME_TXT_MAXLEN];
+ char *info = nsec ? NULL : nsec3_info(node->nsec3_node->owner,
+ buff, sizeof(buff));
+ data->handler->cb(data->handler, data->zone, node,
+ (nsec ? SEM_ERR_NSEC_RDATA_BITMAP : SEM_ERR_NSEC3_RDATA_BITMAP),
+ info);
+ }
+
+ free(node_wire);
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Run NSEC related semantic checks
+ *
+ * \param node Node to check
+ * \param data Semantic checks context data
+ */
+static int check_nsec(const zone_node_t *node, semchecks_data_t *data)
+{
+ assert(node);
+ if (node->flags & NODE_FLAGS_NONAUTH) {
+ return KNOT_EOK;
+ }
+
+ if (node->rrset_count == 0) { // empty nonterminal
+ return KNOT_EOK;
+ }
+
+ /* check for NSEC record */
+ const knot_rdataset_t *nsec_rrs = node_rdataset(node, KNOT_RRTYPE_NSEC);
+ if (nsec_rrs == NULL) {
+ data->handler->cb(data->handler, data->zone, node,
+ SEM_ERR_NSEC_NONE, NULL);
+ return KNOT_EOK;
+ }
+
+ /* Test that only one record is in the NSEC RRSet */
+ if (nsec_rrs->count != 1) {
+ data->handler->cb(data->handler, data->zone, node,
+ SEM_ERR_NSEC_RDATA_MULTIPLE, NULL);
+ }
+
+ if (data->next_nsec != node) {
+ data->handler->cb(data->handler, data->zone, node,
+ SEM_ERR_NSEC_RDATA_CHAIN, NULL);
+ }
+
+ /*
+ * Test that NSEC chain is coherent.
+ * We have already checked that every
+ * authoritative node contains NSEC record
+ * so checking should only be matter of testing
+ * the next link in each node.
+ */
+ const knot_dname_t *next_domain = knot_nsec_next(nsec_rrs->rdata);
+
+ data->next_nsec = zone_contents_find_node(data->zone, next_domain);
+ if (data->next_nsec == NULL) {
+ data->handler->cb(data->handler, data->zone, node,
+ SEM_ERR_NSEC_RDATA_CHAIN, NULL);
+ }
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Check if node has NSEC3 node.
+ *
+ * \param node Node to check
+ * \param data Semantic checks context data
+ */
+static int check_nsec3_presence(const zone_node_t *node, semchecks_data_t *data)
+{
+ bool auth = (node->flags & NODE_FLAGS_NONAUTH) == 0;
+ bool deleg = (node->flags & NODE_FLAGS_DELEG) != 0;
+
+ if ((deleg && node_rrtype_exists(node, KNOT_RRTYPE_DS)) || (auth && !deleg)) {
+ if (node->nsec3_node == NULL) {
+ data->handler->cb(data->handler, data->zone, node,
+ SEM_ERR_NSEC3_NONE, NULL);
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Check NSEC3 opt-out.
+ *
+ * \param node Node to check
+ * \param data Semantic checks context data
+ */
+static int check_nsec3_opt_out(const zone_node_t *node, semchecks_data_t *data)
+{
+ if (!(node->nsec3_node == NULL && node->flags & NODE_FLAGS_DELEG)) {
+ return KNOT_EOK;
+ }
+ /* Insecure delegation, check whether it is part of opt-out span. */
+
+ const zone_node_t *nsec3_previous = NULL;
+ const zone_node_t *nsec3_node;
+ zone_contents_find_nsec3_for_name(data->zone, node->owner, &nsec3_node,
+ &nsec3_previous);
+
+ if (nsec3_previous == NULL) {
+ data->handler->cb(data->handler, data->zone, node,
+ SEM_ERR_NSEC3_NONE, NULL);
+ return KNOT_EOK;
+ }
+
+ const knot_rdataset_t *previous_rrs;
+ previous_rrs = node_rdataset(nsec3_previous, KNOT_RRTYPE_NSEC3);
+ assert(previous_rrs);
+
+ /* Check for opt-out flag. */
+ uint8_t flags = knot_nsec3_flags(previous_rrs->rdata);
+ if (!(flags & 1)) {
+ data->handler->cb(data->handler, data->zone, node,
+ SEM_ERR_NSEC3_INSECURE_DELEGATION_OPT, NULL);
+ }
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Run checks related to NSEC3.
+ *
+ * Check NSEC3 node for given node.
+ * Check if NSEC3 chain is coherent and cyclic.
+ * \param node Node to check
+ * \param data Semantic checks context data
+ */
+static int check_nsec3(const zone_node_t *node, semchecks_data_t *data)
+{
+ assert(node);
+ bool auth = (node->flags & NODE_FLAGS_NONAUTH) == 0;
+ bool deleg = (node->flags & NODE_FLAGS_DELEG) != 0;
+
+ if (!auth && !deleg) {
+ return KNOT_EOK;
+ }
+ if (node->nsec3_node == NULL) {
+ return KNOT_EOK;
+ }
+
+ dnssec_nsec3_params_t params_apex = { 0 };
+ int ret = KNOT_EOK;
+
+ char buff[50 + KNOT_DNAME_TXT_MAXLEN];
+ char *info = nsec3_info(node->nsec3_node->owner, buff, sizeof(buff));
+
+ knot_rrset_t nsec3_rrs = node_rrset(node->nsec3_node, KNOT_RRTYPE_NSEC3);
+ if (knot_rrset_empty(&nsec3_rrs)) {
+ data->handler->cb(data->handler, data->zone, node,
+ SEM_ERR_NSEC3_NONE, info);
+ goto nsec3_cleanup;
+ }
+
+ const knot_rdataset_t *soa_rrs = node_rdataset(data->zone->apex, KNOT_RRTYPE_SOA);
+ assert(soa_rrs);
+ uint32_t minimum_ttl = knot_soa_minimum(soa_rrs->rdata);
+ if (nsec3_rrs.ttl != minimum_ttl) {
+ data->handler->cb(data->handler, data->zone, node,
+ SEM_ERR_NSEC3_RDATA_TTL, info);
+ }
+
+ // Check parameters.
+ const knot_rdataset_t *nsec3param = node_rdataset(data->zone->apex,
+ KNOT_RRTYPE_NSEC3PARAM);
+ dnssec_binary_t rdata = {
+ .size = nsec3param->rdata->len,
+ .data = nsec3param->rdata->data
+ };
+ ret = dnssec_nsec3_params_from_rdata(&params_apex, &rdata);
+ if (ret != DNSSEC_EOK) {
+ ret = knot_error_from_libdnssec(ret);
+ goto nsec3_cleanup;
+ }
+
+ if (knot_nsec3_flags(nsec3_rrs.rrs.rdata) > 1) {
+ data->handler->cb(data->handler, data->zone, node,
+ SEM_ERR_NSEC3_RDATA_FLAGS, info);
+ }
+
+ dnssec_binary_t salt = {
+ .size = knot_nsec3_salt_len(nsec3_rrs.rrs.rdata),
+ .data = (uint8_t *)knot_nsec3_salt(nsec3_rrs.rrs.rdata),
+ };
+
+ if (dnssec_binary_cmp(&salt, &params_apex.salt)) {
+ data->handler->cb(data->handler, data->zone, node,
+ SEM_ERR_NSEC3_RDATA_SALT, info);
+ }
+
+ if (knot_nsec3_alg(nsec3_rrs.rrs.rdata) != params_apex.algorithm) {
+ data->handler->cb(data->handler, data->zone, node,
+ SEM_ERR_NSEC3_RDATA_ALG, info);
+ }
+
+ if (knot_nsec3_iters(nsec3_rrs.rrs.rdata) != params_apex.iterations) {
+ data->handler->cb(data->handler, data->zone, node,
+ SEM_ERR_NSEC3_RDATA_ITERS, info);
+ }
+
+ // Get next nsec3 node.
+ const zone_node_t *apex = data->zone->apex;
+ const uint8_t *next_dname_str = knot_nsec3_next(nsec3_rrs.rrs.rdata);
+ uint8_t next_dname_str_size = knot_nsec3_next_len(nsec3_rrs.rrs.rdata);
+ uint8_t next_dname[KNOT_DNAME_MAXLEN];
+ ret = knot_nsec3_hash_to_dname(next_dname, sizeof(next_dname),
+ next_dname_str, next_dname_str_size,
+ apex->owner);
+ if (ret != KNOT_EOK) {
+ goto nsec3_cleanup;
+ }
+
+ const zone_node_t *next_nsec3 = zone_contents_find_nsec3_node(data->zone,
+ next_dname);
+ if (next_nsec3 == NULL || next_nsec3->prev != node->nsec3_node) {
+ uint8_t *next = NULL;
+ int32_t next_len = base32hex_encode_alloc(next_dname_str,
+ next_dname_str_size,
+ &next);
+ char *hash_info = NULL;
+ if (next != NULL) {
+ hash_info = sprintf_alloc("(next hash %.*s)", next_len, next);
+ free(next);
+ }
+ data->handler->cb(data->handler, data->zone, node,
+ SEM_ERR_NSEC3_RDATA_CHAIN, hash_info);
+ free(hash_info);
+ }
+
+ ret = check_rrsig(node->nsec3_node, data);
+ if (ret != KNOT_EOK) {
+ goto nsec3_cleanup;
+ }
+
+ // Check that the node only contains NSEC3 and RRSIG.
+ for (int i = 0; ret == KNOT_EOK && i < node->nsec3_node->rrset_count; i++) {
+ knot_rrset_t rrset = node_rrset_at(node->nsec3_node, i);
+ uint16_t type = rrset.type;
+ if (type != KNOT_RRTYPE_NSEC3 && type != KNOT_RRTYPE_RRSIG) {
+ data->handler->cb(data->handler, data->zone, node->nsec3_node,
+ SEM_ERR_NSEC3_EXTRA_RECORD, NULL);
+ }
+ }
+
+nsec3_cleanup:
+ dnssec_nsec3_params_free(&params_apex);
+
+ return ret;
+}
+
+/*!
+ * \brief Check if CNAME record contains other records
+ *
+ * \param node Node to check
+ * \param data Semantic checks context data
+ */
+static int check_cname(const zone_node_t *node, semchecks_data_t *data)
+{
+ const knot_rdataset_t *cname_rrs = node_rdataset(node, KNOT_RRTYPE_CNAME);
+ if (cname_rrs == NULL) {
+ return KNOT_EOK;
+ }
+
+ unsigned rrset_limit = 1;
+ /* With DNSSEC node can contain RRSIGs or NSEC */
+ if (node_rrtype_exists(node, KNOT_RRTYPE_NSEC)) {
+ rrset_limit += 1;
+ }
+ if (node_rrtype_exists(node, KNOT_RRTYPE_RRSIG)) {
+ rrset_limit += 1;
+ }
+
+ if (node->rrset_count > rrset_limit) {
+ data->handler->fatal_error = true;
+ data->handler->cb(data->handler, data->zone, node,
+ SEM_ERR_CNAME_EXTRA_RECORDS, NULL);
+ }
+ if (cname_rrs->count != 1) {
+ data->handler->fatal_error = true;
+ data->handler->cb(data->handler, data->zone, node,
+ SEM_ERR_CNAME_MULTIPLE, NULL);
+ }
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Check if DNAME record has children.
+ *
+ * \param node Node to check
+ * \param data Semantic checks context data
+ */
+static int check_dname(const zone_node_t *node, semchecks_data_t *data)
+{
+ if (node->parent != NULL && node_rrtype_exists(node->parent, KNOT_RRTYPE_DNAME)) {
+ data->handler->fatal_error = true;
+ data->handler->cb(data->handler, data->zone, node,
+ SEM_ERR_DNAME_CHILDREN, NULL);
+ }
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Check that NSEC chain is cyclic.
+ *
+ * Run only once per zone. Check that last NSEC node points to first one.
+ * \param data Semantic checks context data
+ */
+static int check_nsec_cyclic(semchecks_data_t *data)
+{
+ if (data->next_nsec == NULL) {
+ data->handler->cb(data->handler, data->zone, data->zone->apex,
+ SEM_ERR_NSEC_RDATA_CHAIN, NULL);
+ return KNOT_EOK;
+ }
+ if (!knot_dname_is_equal(data->next_nsec->owner, data->zone->apex->owner)) {
+ data->handler->cb(data->handler, data->zone, data->next_nsec,
+ SEM_ERR_NSEC_RDATA_CHAIN, NULL);
+ }
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Call all semantic checks for each node.
+ *
+ * This function is called as callback from zone_contents_tree_apply_inorder.
+ * Checks are functions from global const array check_functions.
+ *
+ * \param node Node to be checked
+ * \param data Semantic checks context data
+ */
+static int do_checks_in_tree(zone_node_t *node, void *data)
+{
+ semchecks_data_t *s_data = (semchecks_data_t *)data;
+
+ int ret = KNOT_EOK;
+
+ for (int i = 0; ret == KNOT_EOK && i < CHECK_FUNCTIONS_LEN; ++i) {
+ if (CHECK_FUNCTIONS[i].level & s_data->level) {
+ ret = CHECK_FUNCTIONS[i].function(node, s_data);
+ }
+ }
+
+
+ return ret;
+}
+
+static void check_nsec3param(knot_rdataset_t *nsec3param, zone_contents_t *zone,
+ sem_handler_t *handler, semchecks_data_t *data)
+{
+ assert(nsec3param);
+
+ data->level |= NSEC3;
+ uint8_t param = knot_nsec3param_flags(nsec3param->rdata);
+ if ((param & ~1) != 0) {
+ handler->cb(handler, zone, zone->apex, SEM_ERR_NSEC3PARAM_RDATA_FLAGS,
+ NULL);
+ }
+
+ param = knot_nsec3param_alg(nsec3param->rdata);
+ if (param != DNSSEC_NSEC3_ALGORITHM_SHA1) {
+ handler->cb(handler, zone, zone->apex, SEM_ERR_NSEC3PARAM_RDATA_ALG,
+ NULL);
+ }
+}
+
+static void check_dnskey(zone_contents_t *zone, sem_handler_t *handler)
+{
+ const knot_rdataset_t *dnskeys = node_rdataset(zone->apex, KNOT_RRTYPE_DNSKEY);
+ if (dnskeys == NULL) {
+ handler->cb(handler, zone, zone->apex, SEM_ERR_DNSKEY_NONE, NULL);
+ return;
+ }
+
+ for (int i = 0; i < dnskeys->count; i++) {
+ knot_rdata_t *dnskey = knot_rdataset_at(dnskeys, i);
+ dnssec_key_t *key;
+ int ret = dnssec_key_from_rdata(&key, zone->apex->owner,
+ dnskey->data, dnskey->len);
+ if (ret == KNOT_EOK) {
+ dnssec_key_free(key);
+ } else {
+ handler->cb(handler, zone, zone->apex, SEM_ERR_DNSKEY_INVALID, NULL);
+ }
+
+ if (knot_dnskey_proto(dnskey) != 3) {
+ handler->cb(handler, zone, zone->apex, SEM_ERR_DNSKEY_RDATA_PROTOCOL,
+ NULL);
+ }
+
+ dnssec_key_algorithm_t alg = knot_dnskey_alg(dnskey);
+ if (!dnssec_algorithm_key_support(alg)) {
+ char *info = sprintf_alloc("(unsupported algorithm %d)", alg);
+ handler->cb(handler, zone, zone->apex, SEM_ERR_DNSKEY_INVALID, info);
+ free(info);
+ }
+ }
+}
+
+int sem_checks_process(zone_contents_t *zone, bool optional, sem_handler_t *handler,
+ time_t time)
+{
+ if (zone == NULL || handler == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ semchecks_data_t data = {
+ .handler = handler,
+ .zone = zone,
+ .next_nsec = zone->apex,
+ .level = MANDATORY,
+ .time = time,
+ };
+
+ if (optional) {
+ data.level |= OPTIONAL;
+ if (zone->dnssec) {
+ knot_rdataset_t *nsec3param = node_rdataset(zone->apex,
+ KNOT_RRTYPE_NSEC3PARAM);
+ if (nsec3param != NULL) {
+ data.level |= NSEC3;
+ check_nsec3param(nsec3param, zone, handler, &data);
+ } else {
+ data.level |= NSEC;
+ }
+ check_dnskey(zone, handler);
+ }
+ }
+
+ int ret = zone_contents_apply(zone, do_checks_in_tree, &data);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ if (data.handler->fatal_error) {
+ return KNOT_ESEMCHECK;
+ }
+
+ // check cyclic chain after every node was checked
+ if (data.level & NSEC) {
+ check_nsec_cyclic(&data);
+ }
+ if (data.handler->fatal_error) {
+ return KNOT_ESEMCHECK;
+ }
+
+ return KNOT_EOK;
+}
diff --git a/src/knot/zone/semantic-check.h b/src/knot/zone/semantic-check.h
new file mode 100644
index 0000000..2010ec9
--- /dev/null
+++ b/src/knot/zone/semantic-check.h
@@ -0,0 +1,123 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "knot/zone/node.h"
+#include "knot/zone/contents.h"
+
+/*!
+ *\brief Internal error constants.
+ */
+typedef enum {
+ // Mandatory checks.
+ SEM_ERR_SOA_NONE,
+
+ SEM_ERR_CNAME_EXTRA_RECORDS,
+ SEM_ERR_CNAME_MULTIPLE,
+
+ SEM_ERR_DNAME_CHILDREN,
+
+ // Optional checks.
+ SEM_ERR_NS_APEX,
+ SEM_ERR_NS_GLUE,
+
+ SEM_ERR_RRSIG_RDATA_TYPE_COVERED,
+ SEM_ERR_RRSIG_RDATA_TTL,
+ SEM_ERR_RRSIG_RDATA_EXPIRATION,
+ SEM_ERR_RRSIG_RDATA_INCEPTION,
+ SEM_ERR_RRSIG_RDATA_LABELS,
+ SEM_ERR_RRSIG_RDATA_OWNER,
+ SEM_ERR_RRSIG_NO_RRSIG,
+ SEM_ERR_RRSIG_SIGNED,
+ SEM_ERR_RRSIG_TTL,
+ SEM_ERR_RRSIG_UNVERIFIABLE,
+
+ SEM_ERR_NSEC_NONE,
+ SEM_ERR_NSEC_RDATA_BITMAP,
+ SEM_ERR_NSEC_RDATA_MULTIPLE,
+ SEM_ERR_NSEC_RDATA_CHAIN,
+
+ SEM_ERR_NSEC3_NONE,
+ SEM_ERR_NSEC3_INSECURE_DELEGATION_OPT,
+ SEM_ERR_NSEC3_EXTRA_RECORD,
+ SEM_ERR_NSEC3_RDATA_TTL,
+ SEM_ERR_NSEC3_RDATA_CHAIN,
+ SEM_ERR_NSEC3_RDATA_BITMAP,
+ SEM_ERR_NSEC3_RDATA_FLAGS,
+ SEM_ERR_NSEC3_RDATA_SALT,
+ SEM_ERR_NSEC3_RDATA_ALG,
+ SEM_ERR_NSEC3_RDATA_ITERS,
+
+ SEM_ERR_NSEC3PARAM_RDATA_FLAGS,
+ SEM_ERR_NSEC3PARAM_RDATA_ALG,
+
+ SEM_ERR_DS_RDATA_ALG,
+ SEM_ERR_DS_RDATA_DIGLEN,
+
+ SEM_ERR_DNSKEY_NONE,
+ SEM_ERR_DNSKEY_INVALID,
+ SEM_ERR_DNSKEY_RDATA_PROTOCOL,
+
+ SEM_ERR_CDS_NONE,
+ SEM_ERR_CDS_MULTIPLE,
+ SEM_ERR_CDS_NOT_MATCH,
+
+ SEM_ERR_CDNSKEY_NONE,
+ SEM_ERR_CDNSKEY_MULTIPLE,
+ SEM_ERR_CDNSKEY_NO_DNSKEY,
+
+ // General error!
+ SEM_ERR_UNKNOWN
+} sem_error_t;
+
+const char *sem_error_msg(sem_error_t code);
+
+/*!
+ * \brief Structure for handling semantic errors.
+ */
+typedef struct sem_handler sem_handler_t;
+
+/*!
+ * \brief Callback for handle error.
+ *
+ * Return KNOT_EOK to continue in semantic checks.
+ * Return other KNOT_E* to stop semantic check with error.
+ */
+typedef void (*sem_callback) (sem_handler_t *ctx, const zone_contents_t *zone,
+ const zone_node_t *node, sem_error_t error, const char *data);
+
+struct sem_handler {
+ sem_callback cb;
+ bool fatal_error;
+};
+
+/*!
+ * \brief Check zone for semantic errors.
+ *
+ * Errors are logged in error handler.
+ *
+ * \param zone Zone to be searched / checked.
+ * \param optional To do also optional check.
+ * \param handler Semantic error handler.
+ * \param time Check zone at given time (rrsig expiration).
+ *
+ * \retval KNOT_EOK no error found
+ * \retval KNOT_ESEMCHECK found semantic error
+ * \retval KNOT_EINVAL or other error
+ */
+int sem_checks_process(zone_contents_t *zone, bool optional, sem_handler_t *handler,
+ time_t time);
diff --git a/src/knot/zone/serial.c b/src/knot/zone/serial.c
new file mode 100644
index 0000000..9846f92
--- /dev/null
+++ b/src/knot/zone/serial.c
@@ -0,0 +1,84 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <time.h>
+
+#include "knot/conf/conf.h"
+#include "knot/zone/serial.h"
+
+static const serial_cmp_result_t diffbrief2result[4] = {
+ [0] = SERIAL_EQUAL,
+ [1] = SERIAL_GREATER,
+ [2] = SERIAL_INCOMPARABLE,
+ [3] = SERIAL_LOWER,
+};
+
+serial_cmp_result_t serial_compare(uint32_t s1, uint32_t s2)
+{
+ uint64_t diff = ((uint64_t)s1 + ((uint64_t)1 << 32) - s2) & 0xffffffff;
+ int diffbrief = (diff >> 31 << 1) | ((diff & 0x7fffffff) ? 1 : 0);
+ assert(diffbrief > -1 && diffbrief < 4);
+ return diffbrief2result[diffbrief];
+}
+
+static uint32_t serial_next_date(uint32_t current)
+{
+ uint32_t next = current + 1;
+
+ struct tm now;
+ time_t current_time = time(NULL);
+ struct tm *gmtime_result = gmtime_r(&current_time, &now);
+ if (gmtime_result == NULL) {
+ return next;
+ }
+
+ uint32_t yyyyMMdd00 = (1900 + now.tm_year) * 1000000 +
+ ( 1 + now.tm_mon ) * 10000 +
+ ( now.tm_mday) * 100;
+
+ if (next < yyyyMMdd00) {
+ next = yyyyMMdd00;
+ }
+
+ return next;
+}
+
+uint32_t serial_next(uint32_t current, int policy)
+{
+ uint32_t candidate;
+ switch (policy) {
+ case SERIAL_POLICY_INCREMENT:
+ return current + 1;
+ case SERIAL_POLICY_UNIXTIME:
+ candidate = time(NULL);
+ if (serial_compare(candidate, current) != SERIAL_GREATER) {
+ return current + 1;
+ } else {
+ return candidate;
+ }
+ case SERIAL_POLICY_DATESERIAL:
+ return serial_next_date(current);
+ default:
+ assert(0);
+ return 0;
+ }
+}
+
+serial_cmp_result_t kserial_cmp(kserial_t a, kserial_t b)
+{
+ return ((a.valid && b.valid) ? serial_compare(a.serial, b.serial) : SERIAL_INCOMPARABLE);
+}
diff --git a/src/knot/zone/serial.h b/src/knot/zone/serial.h
new file mode 100644
index 0000000..3453de8
--- /dev/null
+++ b/src/knot/zone/serial.h
@@ -0,0 +1,72 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/*!
+ * \brief result of serial comparison. LOWER means that the first serial is lower that the second.
+ *
+ * Example: (serial_compare(a, b) & SERIAL_MASK_LEQ) means "a <= b".
+ */
+typedef enum {
+ SERIAL_INCOMPARABLE = 0x0,
+ SERIAL_LOWER = 0x1,
+ SERIAL_GREATER = 0x2,
+ SERIAL_EQUAL = 0x3,
+ SERIAL_MASK_LEQ = SERIAL_LOWER,
+ SERIAL_MASK_GEQ = SERIAL_GREATER,
+} serial_cmp_result_t;
+
+/*!
+ * \brief Compares two zone serials.
+ */
+serial_cmp_result_t serial_compare(uint32_t s1, uint32_t s2);
+
+inline static bool serial_equal(uint32_t a, uint32_t b)
+{
+ return serial_compare(a, b) == SERIAL_EQUAL;
+}
+
+/*!
+ * \brief Get next serial for given serial update policy.
+ *
+ * \param current Current SOA serial.
+ * \param policy SERIAL_POLICY_INCREMENT, SERIAL_POLICY_UNIXTIME or
+ * SERIAL_POLICY_DATESERIAL.
+ *
+ * \return New serial.
+ */
+uint32_t serial_next(uint32_t current, int policy);
+
+typedef struct {
+ uint32_t serial;
+ bool valid;
+} kserial_t;
+
+/*!
+ * \brief Compares two kserials.
+ *
+ * If any of them is invalid, they are INCOMPARABLE.
+ */
+serial_cmp_result_t kserial_cmp(kserial_t a, kserial_t b);
+
+inline static bool kserial_equal(kserial_t a, kserial_t b)
+{
+ return kserial_cmp(a, b) == SERIAL_EQUAL;
+}
diff --git a/src/knot/zone/timers.c b/src/knot/zone/timers.c
new file mode 100644
index 0000000..0ff8aed
--- /dev/null
+++ b/src/knot/zone/timers.c
@@ -0,0 +1,288 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "knot/zone/timers.h"
+
+#include "contrib/wire_ctx.h"
+#include "libknot/db/db.h"
+#include "libknot/db/db_lmdb.h"
+
+/*
+ * # Timer database
+ *
+ * Timer database stores timestaps of events which need to be retained
+ * across server restarts. The key in the database is the zone name in
+ * wire format. The value contains serialized timers.
+ *
+ * # Serialization format
+ *
+ * The value is a sequence of timers. Each timer consists of the timer
+ * identifier (1 byte, unsigned integer) and timer value (8 bytes, unsigned
+ * integer, network order).
+ *
+ * For example, the following byte sequence:
+ *
+ * 81 00 00 00 00 57 e3 e8 0a 82 00 00 00 00 57 e3 e9 a1
+ *
+ * Encodes the following timers:
+ *
+ * last_flush = 1474553866
+ * last_refresh = 1474554273
+ */
+
+/**
+ * \brief Timer database fields identifiers.
+ *
+ * Valid ID starts with '1' in MSB to avoid conflicts with "old timers".
+ */
+enum timer_id {
+ TIMER_INVALID = 0,
+ TIMER_SOA_EXPIRE = 0x80,
+ TIMER_LAST_FLUSH,
+ TIMER_LAST_REFRESH,
+ TIMER_NEXT_REFRESH,
+ TIMER_LAST_RESALT,
+ TIMER_NEXT_PARENT_DS_Q
+};
+
+#define TIMER_COUNT 6
+#define TIMER_SIZE (sizeof(uint8_t) + sizeof(uint64_t))
+#define SERIALIZED_SIZE (TIMER_COUNT * TIMER_SIZE)
+
+/*!
+ * \brief Serialize timers into a binary buffer.
+ */
+static int serialize_timers(const zone_timers_t *timers, uint8_t *data, size_t size)
+{
+ if (!timers || !data || size != SERIALIZED_SIZE) {
+ return KNOT_EINVAL;
+ }
+
+ wire_ctx_t wire = wire_ctx_init(data, size);
+
+ wire_ctx_write_u8(&wire, TIMER_SOA_EXPIRE);
+ wire_ctx_write_u64(&wire, timers->soa_expire);
+ wire_ctx_write_u8(&wire, TIMER_LAST_FLUSH);
+ wire_ctx_write_u64(&wire, timers->last_flush);
+ wire_ctx_write_u8(&wire, TIMER_LAST_REFRESH);
+ wire_ctx_write_u64(&wire, timers->last_refresh);
+ wire_ctx_write_u8(&wire, TIMER_NEXT_REFRESH);
+ wire_ctx_write_u64(&wire, timers->next_refresh);
+ wire_ctx_write_u8(&wire, TIMER_LAST_RESALT);
+ wire_ctx_write_u64(&wire, timers->last_resalt);
+ wire_ctx_write_u8(&wire, TIMER_NEXT_PARENT_DS_Q);
+ wire_ctx_write_u64(&wire, timers->next_parent_ds_q);
+
+ assert(wire.error == KNOT_EOK);
+ assert(wire_ctx_available(&wire) == 0);
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Deserialize timers from a binary buffer.
+ *
+ * \note Unknown timers are ignored.
+ */
+static int deserialize_timers(zone_timers_t *timers_ptr,
+ const uint8_t *data, size_t size)
+{
+ if (!timers_ptr || !data) {
+ return KNOT_EINVAL;
+ }
+
+ zone_timers_t timers = { 0 };
+
+ wire_ctx_t wire = wire_ctx_init_const(data, size);
+ while (wire_ctx_available(&wire) >= TIMER_SIZE) {
+ uint8_t id = wire_ctx_read_u8(&wire);
+ uint64_t value = wire_ctx_read_u64(&wire);
+ switch (id) {
+ case TIMER_SOA_EXPIRE: timers.soa_expire = value; break;
+ case TIMER_LAST_FLUSH: timers.last_flush = value; break;
+ case TIMER_LAST_REFRESH: timers.last_refresh = value; break;
+ case TIMER_NEXT_REFRESH: timers.next_refresh = value; break;
+ case TIMER_LAST_RESALT: timers.last_resalt = value; break;
+ case TIMER_NEXT_PARENT_DS_Q: timers.next_parent_ds_q = value; break;
+ default: break; // ignore
+ }
+ }
+
+ if (wire_ctx_available(&wire) != 0) {
+ return KNOT_EMALF;
+ }
+
+ assert(wire.error == KNOT_EOK);
+
+ *timers_ptr = timers;
+ return KNOT_EOK;
+}
+
+static int txn_write_timers(knot_db_txn_t *txn, const knot_dname_t *zone,
+ const zone_timers_t *timers)
+{
+ uint8_t data[SERIALIZED_SIZE] = { 0 };
+ int ret = serialize_timers(timers, data, sizeof(data));
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ knot_db_val_t key = { (uint8_t *)zone, knot_dname_size(zone) };
+ knot_db_val_t val = { data, sizeof(data) };
+
+ return knot_db_lmdb_api()->insert(txn, &key, &val, 0);
+}
+
+static int txn_read_timers(knot_db_txn_t *txn, const knot_dname_t *zone,
+ zone_timers_t *timers)
+{
+ knot_db_val_t key = { (uint8_t *)zone, knot_dname_size(zone) };
+ knot_db_val_t val = { 0 };
+ int ret = knot_db_lmdb_api()->find(txn, &key, &val, 0);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ return deserialize_timers(timers, val.data, val.len);
+}
+
+int zone_timers_open(const char *path, knot_db_t **db, size_t mapsize)
+{
+ if (path == NULL || db == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ struct knot_db_lmdb_opts opts = KNOT_DB_LMDB_OPTS_INITIALIZER;
+ opts.mapsize = mapsize;
+ opts.path = path;
+
+ return knot_db_lmdb_api()->init(db, NULL, &opts);
+}
+
+void zone_timers_close(knot_db_t *db)
+{
+ if (db == NULL) {
+ return;
+ }
+
+ knot_db_lmdb_api()->deinit(db);
+}
+
+int zone_timers_read(knot_db_t *db, const knot_dname_t *zone,
+ zone_timers_t *timers)
+{
+ if (!db || !zone || !timers) {
+ return KNOT_EINVAL;
+ }
+
+ const knot_db_api_t *db_api = knot_db_lmdb_api();
+ assert(db_api);
+
+ knot_db_txn_t txn = { 0 };
+ int ret = db_api->txn_begin(db, &txn, KNOT_DB_RDONLY);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = txn_read_timers(&txn, zone, timers);
+ db_api->txn_abort(&txn);
+
+ return ret;
+}
+
+int zone_timers_write_begin(knot_db_t *db, knot_db_txn_t *txn)
+{
+ memset(txn, 0, sizeof(*txn));
+ return knot_db_lmdb_api()->txn_begin(db, txn, KNOT_DB_SORTED);
+}
+
+int zone_timers_write_end(knot_db_txn_t *txn)
+{
+ return knot_db_lmdb_api()->txn_commit(txn);
+}
+
+int zone_timers_write(knot_db_t *db, const knot_dname_t *zone,
+ const zone_timers_t *timers, knot_db_txn_t *txn)
+{
+ if (!zone || !timers || (!db && !txn)) {
+ return KNOT_EINVAL;
+ }
+
+ const knot_db_api_t *db_api = knot_db_lmdb_api();
+ assert(db_api);
+
+ knot_db_txn_t static_txn, *mytxn = txn;
+ if (txn == NULL) {
+ mytxn = &static_txn;
+ int ret = db_api->txn_begin(db, mytxn, KNOT_DB_SORTED);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ int ret = txn_write_timers(mytxn, zone, timers);
+ if (ret != KNOT_EOK) {
+ db_api->txn_abort(mytxn);
+ return ret;
+ }
+
+ if (txn == NULL) {
+ db_api->txn_commit(mytxn);
+ }
+
+ return KNOT_EOK;
+}
+
+int zone_timers_sweep(knot_db_t *db, sweep_cb keep_zone, void *cb_data)
+{
+ if (!db || !keep_zone) {
+ return KNOT_EINVAL;
+ }
+
+ const knot_db_api_t *db_api = knot_db_lmdb_api();
+ assert(db_api);
+
+ knot_db_txn_t txn = { 0 };
+ int ret = db_api->txn_begin(db, &txn, KNOT_DB_SORTED);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ knot_db_iter_t *it = NULL;
+ for (it = db_api->iter_begin(&txn, 0); it != NULL; it = db_api->iter_next(it)) {
+ knot_db_val_t key = { 0 };
+ ret = db_api->iter_key(it, &key);
+ if (ret != KNOT_EOK) {
+ break;
+ }
+
+ const knot_dname_t *zone = (const knot_dname_t *)key.data;
+ if (!keep_zone(zone, cb_data)) {
+ ret = db_api->del(&txn, &key);
+ if (ret != KNOT_EOK) {
+ break;
+ }
+ }
+ }
+ db_api->iter_finish(it);
+
+ if (ret != KNOT_EOK) {
+ db_api->txn_abort(&txn);
+ return ret;
+ }
+
+ return db_api->txn_commit(&txn);
+}
diff --git a/src/knot/zone/timers.h b/src/knot/zone/timers.h
new file mode 100644
index 0000000..4c8d0fa
--- /dev/null
+++ b/src/knot/zone/timers.h
@@ -0,0 +1,119 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <time.h>
+
+#include "libknot/db/db.h"
+#include "libknot/dname.h"
+
+/*!
+ * \brief Persistent zone timers.
+ */
+struct zone_timers {
+ uint32_t soa_expire; //!< SOA expire value.
+ time_t last_flush; //!< Last zone file synchronization.
+ time_t last_refresh; //!< Last successful zone refresh attempt.
+ time_t next_refresh; //!< Next zone refresh attempt.
+ time_t last_resalt; //!< Last NSEC3 resalt
+ time_t next_parent_ds_q; //!< Next parent ds query
+};
+
+typedef struct zone_timers zone_timers_t;
+
+/*!
+ * \brief Open zone timers database.
+ *
+ * \param[in] path Path to a directory with the database.
+ * \param[out] db Created database.
+ * \param[in] mapsize LMDB mapsize.
+ *
+ * \return KNOT_E*
+ */
+int zone_timers_open(const char *path, knot_db_t **db, size_t mapsize);
+
+/*!
+ * \brief Closes zone timers database.
+ *
+ * \param db Timer database.
+ */
+void zone_timers_close(knot_db_t *db);
+
+/*!
+ * \brief Load timers for one zone.
+ *
+ * \param[in] db Timer database.
+ * \param[in] zone Zone name.
+ * \param[out] timers Loaded timers
+ *
+ * \return KNOT_E*
+ * \retval KNOT_ENOENT Zone not found in the database.
+ */
+int zone_timers_read(knot_db_t *db, const knot_dname_t *zone,
+ zone_timers_t *timers);
+
+/*!
+ * \brief Init txn for zone_timers_write()
+ *
+ * \param db Timer database.
+ * \param txn Handler to be initialized.
+ *
+ * \return KNOT_E*
+ */
+int zone_timers_write_begin(knot_db_t *db, knot_db_txn_t *txn);
+
+/*!
+ * \brief Close txn for zone_timers_write()
+ *
+ * \param txn Handler to be closed.
+ *
+ * \return KNOT_E*
+ */
+int zone_timers_write_end(knot_db_txn_t *txn);
+
+/*!
+ * \brief Write timers for one zone.
+ *
+ * \param db Timer database.
+ * \param zone Zone name.
+ * \param timers Loaded timers
+ * \param txn Transaction handler obtained from zone_timers_write_begin()
+ *
+ * \return KNOT_E*
+ */
+int zone_timers_write(knot_db_t *db, const knot_dname_t *zone,
+ const zone_timers_t *timers, knot_db_txn_t *txn);
+
+/*!
+ * \brief Callback used in \ref zone_timers_sweep.
+ *
+ * \retval true for zones to preserve.
+ * \retval false for zones to remove.
+ */
+typedef bool (*sweep_cb)(const knot_dname_t *zone, void *data);
+
+/*!
+ * \brief Selectively delete zones from the database.
+ *
+ * \param db Timer dababase.
+ * \param keep_zone Filtering callback.
+ * \param cb_data Data passed to callback function.
+ *
+ * \return KNOT_E*
+ */
+int zone_timers_sweep(knot_db_t *db, sweep_cb keep_zone, void *cb_data);
diff --git a/src/knot/zone/zone-diff.c b/src/knot/zone/zone-diff.c
new file mode 100644
index 0000000..6022d4e
--- /dev/null
+++ b/src/knot/zone/zone-diff.c
@@ -0,0 +1,389 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include "libknot/libknot.h"
+#include "knot/zone/zone-diff.h"
+#include "knot/zone/serial.h"
+
+struct zone_diff_param {
+ zone_tree_t *nodes;
+ changeset_t *changeset;
+ bool ignore_dnssec;
+};
+
+static bool rrset_is_dnssec(const knot_rrset_t *rrset)
+{
+ switch (rrset->type) {
+ case KNOT_RRTYPE_RRSIG:
+ case KNOT_RRTYPE_NSEC:
+ case KNOT_RRTYPE_NSEC3:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int load_soas(const zone_contents_t *zone1, const zone_contents_t *zone2,
+ changeset_t *changeset)
+{
+ assert(zone1);
+ assert(zone2);
+ assert(changeset);
+
+ const zone_node_t *apex1 = zone1->apex;
+ const zone_node_t *apex2 = zone2->apex;
+ if (apex1 == NULL || apex2 == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ knot_rrset_t soa_rrset1 = node_rrset(apex1, KNOT_RRTYPE_SOA);
+ knot_rrset_t soa_rrset2 = node_rrset(apex2, KNOT_RRTYPE_SOA);
+ if (knot_rrset_empty(&soa_rrset1) || knot_rrset_empty(&soa_rrset2)) {
+ return KNOT_EINVAL;
+ }
+
+ if (soa_rrset1.rrs.count == 0 ||
+ soa_rrset2.rrs.count == 0) {
+ return KNOT_EINVAL;
+ }
+
+ uint32_t soa_serial1 = knot_soa_serial(soa_rrset1.rrs.rdata);
+ uint32_t soa_serial2 = knot_soa_serial(soa_rrset2.rrs.rdata);
+
+ if (serial_compare(soa_serial1, soa_serial2) == SERIAL_EQUAL) {
+ return KNOT_ENODIFF;
+ }
+
+ if (serial_compare(soa_serial1, soa_serial2) != SERIAL_LOWER) {
+ return KNOT_ERANGE;
+ }
+
+ changeset->soa_from = knot_rrset_copy(&soa_rrset1, NULL);
+ if (changeset->soa_from == NULL) {
+ return KNOT_ENOMEM;
+ }
+ changeset->soa_to = knot_rrset_copy(&soa_rrset2, NULL);
+ if (changeset->soa_to == NULL) {
+ knot_rrset_free(changeset->soa_from, NULL);
+ return KNOT_ENOMEM;
+ }
+
+ return KNOT_EOK;
+}
+
+static int add_node(const zone_node_t *node, changeset_t *changeset, bool ignore_dnssec)
+{
+ /* Add all rrsets from node. */
+ for (unsigned i = 0; i < node->rrset_count; i++) {
+ knot_rrset_t rrset = node_rrset_at(node, i);
+
+ if (ignore_dnssec && rrset_is_dnssec(&rrset)) {
+ continue;
+ }
+
+ int ret = changeset_add_addition(changeset, &rrset, 0);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+static int remove_node(const zone_node_t *node, changeset_t *changeset, bool ignore_dnssec)
+{
+ /* Remove all the RRSets of the node. */
+ for (unsigned i = 0; i < node->rrset_count; i++) {
+ knot_rrset_t rrset = node_rrset_at(node, i);
+
+ if (ignore_dnssec && rrset_is_dnssec(&rrset)) {
+ continue;
+ }
+
+ int ret = changeset_add_removal(changeset, &rrset, 0);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+static int rdata_return_changes(const knot_rrset_t *rrset1,
+ const knot_rrset_t *rrset2,
+ knot_rrset_t *changes)
+{
+ if (rrset1 == NULL || rrset2 == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ /* Create fake RRSet, it will be easier to handle. */
+ knot_rrset_init(changes, rrset1->owner, rrset1->type, rrset1->rclass, rrset1->ttl);
+
+ /*
+ * Take one rdata from first list and search through the second list
+ * looking for an exact match. If no match occurs, it means that this
+ * particular RR has changed.
+ * After the list has been traversed, we have a list of
+ * changed/removed rdatas. This has awful computation time.
+ */
+ bool ttl_differ = rrset1->ttl != rrset2->ttl && rrset1->type != KNOT_RRTYPE_RRSIG;
+ knot_rdata_t *rr1 = rrset1->rrs.rdata;
+ for (uint16_t i = 0; i < rrset1->rrs.count; ++i) {
+ if (ttl_differ || !knot_rdataset_member(&rrset2->rrs, rr1)) {
+ /*
+ * No such RR is present in 'rrset2'. We'll copy
+ * index 'i' into 'changes' RRSet.
+ */
+ int ret = knot_rdataset_add(&changes->rrs, rr1, NULL);
+ if (ret != KNOT_EOK) {
+ knot_rdataset_clear(&changes->rrs, NULL);
+ return ret;
+ }
+ }
+ rr1 = knot_rdataset_next(rr1);
+ }
+
+ return KNOT_EOK;
+}
+
+static int diff_rrsets(const knot_rrset_t *rrset1, const knot_rrset_t *rrset2,
+ changeset_t *changeset)
+{
+ if (changeset == NULL || (rrset1 == NULL && rrset2 == NULL)) {
+ return KNOT_EINVAL;
+ }
+ /*
+ * The easiest solution is to remove all the RRs that had no match and
+ * to add all RRs that had no match, but those from second RRSet. */
+
+ /* Get RRs to add to zone and to remove from zone. */
+ knot_rrset_t to_remove;
+ knot_rrset_t to_add;
+ if (rrset1 != NULL && rrset2 != NULL) {
+ int ret = rdata_return_changes(rrset1, rrset2, &to_remove);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = rdata_return_changes(rrset2, rrset1, &to_add);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ if (!knot_rrset_empty(&to_remove)) {
+ int ret = changeset_add_removal(changeset, &to_remove, 0);
+ knot_rdataset_clear(&to_remove.rrs, NULL);
+ if (ret != KNOT_EOK) {
+ knot_rdataset_clear(&to_add.rrs, NULL);
+ return ret;
+ }
+ }
+
+ if (!knot_rrset_empty(&to_add)) {
+ int ret = changeset_add_addition(changeset, &to_add, 0);
+ knot_rdataset_clear(&to_add.rrs, NULL);
+ return ret;
+ }
+
+ return KNOT_EOK;
+}
+
+/*!< \todo this could be generic function for adding / removing. */
+static int knot_zone_diff_node(zone_node_t **node_ptr, void *data)
+{
+ if (node_ptr == NULL || *node_ptr == NULL || data == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ zone_node_t *node = *node_ptr;
+
+ struct zone_diff_param *param = (struct zone_diff_param *)data;
+ if (param->changeset == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ /*
+ * First, we have to search the second tree to see if there's according
+ * node, if not, the whole node has been removed.
+ */
+ zone_node_t *node_in_second_tree = zone_tree_get(param->nodes, node->owner);
+ if (node_in_second_tree == NULL) {
+ return remove_node(node, param->changeset, param->ignore_dnssec);
+ }
+
+ assert(node_in_second_tree != node);
+
+ /* The nodes are in both trees, we have to diff each RRSet. */
+ if (node->rrset_count == 0) {
+ /*
+ * If there are no RRs in the first tree, all of the RRs
+ * in the second tree will have to be inserted to ADD section.
+ */
+ return add_node(node_in_second_tree, param->changeset, param->ignore_dnssec);
+ }
+
+ for (unsigned i = 0; i < node->rrset_count; i++) {
+ /* Search for the RRSet in the node from the second tree. */
+ knot_rrset_t rrset = node_rrset_at(node, i);
+
+ /* SOAs are handled explicitly. */
+ if (rrset.type == KNOT_RRTYPE_SOA) {
+ continue;
+ }
+
+ if (param->ignore_dnssec && rrset_is_dnssec(&rrset)) {
+ continue;
+ }
+
+ knot_rrset_t rrset_from_second_node =
+ node_rrset(node_in_second_tree, rrset.type);
+ if (knot_rrset_empty(&rrset_from_second_node)) {
+ /* RRSet has been removed. Make a copy and remove. */
+ int ret = changeset_add_removal(
+ param->changeset, &rrset, 0);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ } else {
+ /* Diff RRSets. */
+ int ret = diff_rrsets(&rrset, &rrset_from_second_node,
+ param->changeset);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+ }
+
+ for (unsigned i = 0; i < node_in_second_tree->rrset_count; i++) {
+ /* Search for the RRSet in the node from the second tree. */
+ knot_rrset_t rrset = node_rrset_at(node_in_second_tree, i);
+
+ /* SOAs are handled explicitly. */
+ if (rrset.type == KNOT_RRTYPE_SOA) {
+ continue;
+ }
+
+ if (param->ignore_dnssec && rrset_is_dnssec(&rrset)) {
+ continue;
+ }
+
+ knot_rrset_t rrset_from_first_node = node_rrset(node, rrset.type);
+ if (knot_rrset_empty(&rrset_from_first_node)) {
+ /* RRSet has been added. Make a copy and add. */
+ int ret = changeset_add_addition(
+ param->changeset, &rrset, 0);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+/*!< \todo possibly not needed! */
+static int add_new_nodes(zone_node_t **node_ptr, void *data)
+{
+ if (node_ptr == NULL || *node_ptr == NULL || data == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ zone_node_t *node = *node_ptr;
+
+ struct zone_diff_param *param = (struct zone_diff_param *)data;
+ if (param->changeset == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ /*
+ * If a node is not present in the second zone, it is a new node
+ * and has to be added to changeset. Differencies on the RRSet level are
+ * already handled.
+ */
+ zone_node_t *new_node = zone_tree_get(param->nodes, node->owner);
+ if (new_node == NULL) {
+ assert(node);
+ return add_node(node, param->changeset, param->ignore_dnssec);
+ }
+
+ return KNOT_EOK;
+}
+
+static int load_trees(zone_tree_t *nodes1, zone_tree_t *nodes2,
+ changeset_t *changeset, bool ignore_dnssec)
+{
+ assert(changeset);
+
+ struct zone_diff_param param = {
+ .changeset = changeset,
+ .ignore_dnssec = ignore_dnssec,
+ };
+
+ // Traverse one tree, compare every node, each RRSet with its rdata.
+ param.nodes = nodes2;
+ int ret = zone_tree_apply(nodes1, knot_zone_diff_node, &param);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Some nodes may have been added. Add missing nodes to changeset.
+ param.nodes = nodes1;
+ return zone_tree_apply(nodes2, add_new_nodes, &param);
+}
+
+int zone_contents_diff(const zone_contents_t *zone1, const zone_contents_t *zone2,
+ changeset_t *changeset, bool ignore_dnssec)
+{
+ if (zone1 == NULL || zone2 == NULL || changeset == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int ret_soa = load_soas(zone1, zone2, changeset);
+ if (ret_soa != KNOT_EOK && ret_soa != KNOT_ENODIFF) {
+ return ret_soa;
+ }
+
+ int ret = load_trees(zone1->nodes, zone2->nodes, changeset, ignore_dnssec);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = load_trees(zone1->nsec3_nodes, zone2->nsec3_nodes, changeset, ignore_dnssec);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ if (ret_soa == KNOT_ENODIFF && !changeset_empty(changeset)) {
+ return KNOT_ESEMCHECK;
+ }
+
+ return ret_soa;
+}
+
+int zone_tree_add_diff(zone_tree_t *t1, zone_tree_t *t2, changeset_t *changeset)
+{
+ if (changeset == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ return load_trees(t1, t2, changeset, false);
+}
diff --git a/src/knot/zone/zone-diff.h b/src/knot/zone/zone-diff.h
new file mode 100644
index 0000000..5f467aa
--- /dev/null
+++ b/src/knot/zone/zone-diff.h
@@ -0,0 +1,31 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "knot/zone/contents.h"
+#include "knot/updates/changesets.h"
+
+/*!
+ * \brief Create diff between two zone trees.
+ * */
+int zone_contents_diff(const zone_contents_t *zone1, const zone_contents_t *zone2,
+ changeset_t *changeset, bool ignore_dnssec);
+
+/*!
+ * \brief Add diff between two zone trees into the changeset.
+ */
+int zone_tree_add_diff(zone_tree_t *t1, zone_tree_t *t2, changeset_t *changeset);
diff --git a/src/knot/zone/zone-dump.c b/src/knot/zone/zone-dump.c
new file mode 100644
index 0000000..9729cbc
--- /dev/null
+++ b/src/knot/zone/zone-dump.c
@@ -0,0 +1,226 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <inttypes.h>
+
+#include "knot/dnssec/zone-nsec.h"
+#include "knot/zone/zone-dump.h"
+#include "libknot/libknot.h"
+
+/*! \brief Size of auxiliary buffer. */
+#define DUMP_BUF_LEN (70 * 1024)
+
+/*! \brief Dump parameters. */
+typedef struct {
+ FILE *file;
+ char *buf;
+ size_t buflen;
+ uint64_t rr_count;
+ bool dump_rrsig;
+ bool dump_nsec;
+ const knot_dname_t *origin;
+ const knot_dump_style_t *style;
+ const char *first_comment;
+} dump_params_t;
+
+static int apex_node_dump_text(zone_node_t *node, dump_params_t *params)
+{
+ knot_rrset_t soa = node_rrset(node, KNOT_RRTYPE_SOA);
+ knot_dump_style_t soa_style = *params->style;
+
+ // Dump SOA record as a first.
+ if (!params->dump_nsec) {
+ int ret = knot_rrset_txt_dump(&soa, &params->buf, &params->buflen,
+ &soa_style);
+ if (ret < 0) {
+ return ret;
+ }
+ params->rr_count += soa.rrs.count;
+ fprintf(params->file, "%s", params->buf);
+ params->buf[0] = '\0';
+ }
+
+ // Dump other records.
+ for (uint16_t i = 0; i < node->rrset_count; i++) {
+ knot_rrset_t rrset = node_rrset_at(node, i);
+ switch (rrset.type) {
+ case KNOT_RRTYPE_NSEC:
+ continue;
+ case KNOT_RRTYPE_RRSIG:
+ continue;
+ case KNOT_RRTYPE_SOA:
+ continue;
+ default:
+ break;
+ }
+
+ int ret = knot_rrset_txt_dump(&rrset, &params->buf, &params->buflen,
+ params->style);
+ if (ret < 0) {
+ return ret;
+ }
+ params->rr_count += rrset.rrs.count;
+ fprintf(params->file, "%s", params->buf);
+ params->buf[0] = '\0';
+ }
+
+ return KNOT_EOK;
+}
+
+static int node_dump_text(zone_node_t *node, void *data)
+{
+ dump_params_t *params = (dump_params_t *)data;
+
+ // Zone apex rrsets.
+ if (node->owner == params->origin && !params->dump_rrsig &&
+ !params->dump_nsec) {
+ apex_node_dump_text(node, params);
+ return KNOT_EOK;
+ }
+
+ // Dump non-apex rrsets.
+ for (uint16_t i = 0; i < node->rrset_count; i++) {
+ knot_rrset_t rrset = node_rrset_at(node, i);
+ switch (rrset.type) {
+ case KNOT_RRTYPE_RRSIG:
+ if (params->dump_rrsig) {
+ break;
+ }
+ continue;
+ case KNOT_RRTYPE_NSEC:
+ if (params->dump_nsec) {
+ break;
+ }
+ continue;
+ case KNOT_RRTYPE_NSEC3:
+ if (params->dump_nsec) {
+ break;
+ }
+ continue;
+ default:
+ if (params->dump_nsec || params->dump_rrsig) {
+ continue;
+ }
+ break;
+ }
+
+ // Dump block comment if available.
+ if (params->first_comment != NULL) {
+ fprintf(params->file, "%s", params->first_comment);
+ params->first_comment = NULL;
+ }
+
+ int ret = knot_rrset_txt_dump(&rrset, &params->buf, &params->buflen,
+ params->style);
+ if (ret < 0) {
+ return ret;
+ }
+ params->rr_count += rrset.rrs.count;
+ fprintf(params->file, "%s", params->buf);
+ params->buf[0] = '\0';
+ }
+
+ return KNOT_EOK;
+}
+
+int zone_dump_text(zone_contents_t *zone, FILE *file, bool comments)
+{
+ if (zone == NULL || file == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ // Allocate auxiliary buffer for dumping operations.
+ char *buf = malloc(DUMP_BUF_LEN);
+ if (buf == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ if (comments) {
+ fprintf(file, ";; Zone dump (Knot DNS %s)\n", PACKAGE_VERSION);
+ }
+
+ // Set structure with parameters.
+ zone_node_t *apex = zone->apex;
+ dump_params_t params = {
+ .file = file,
+ .buf = buf,
+ .buflen = DUMP_BUF_LEN,
+ .rr_count = 0,
+ .origin = apex->owner,
+ .style = &KNOT_DUMP_STYLE_DEFAULT,
+ .dump_rrsig = false,
+ .dump_nsec = false
+ };
+
+ // Dump standard zone records without RRSIGS.
+ int ret = zone_contents_apply(zone, node_dump_text, &params);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Dump RRSIG records if available.
+ params.dump_rrsig = true;
+ params.dump_nsec = false;
+ params.first_comment = comments ? ";; DNSSEC signatures\n" : NULL;
+ ret = zone_contents_apply(zone, node_dump_text, &params);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Dump NSEC chain if available.
+ params.dump_rrsig = false;
+ params.dump_nsec = true;
+ params.first_comment = comments ? ";; DNSSEC NSEC chain\n" : NULL;
+ ret = zone_contents_apply(zone, node_dump_text, &params);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Dump NSEC3 chain if available.
+ params.dump_rrsig = false;
+ params.dump_nsec = true;
+ params.first_comment = comments ? ";; DNSSEC NSEC3 chain\n" : NULL;
+ ret = zone_contents_nsec3_apply(zone, node_dump_text, &params);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ params.dump_rrsig = true;
+ params.dump_nsec = false;
+ params.first_comment = comments ? ";; DNSSEC NSEC3 signatures\n" : NULL;
+ ret = zone_contents_nsec3_apply(zone, node_dump_text, &params);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ if (comments) {
+ // Create formatted date-time string.
+ time_t now = time(NULL);
+ struct tm tm;
+ localtime_r(&now, &tm);
+ char date[64];
+ strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S %Z", &tm);
+
+ // Dump trailing statistics.
+ fprintf(file, ";; Written %"PRIu64" records\n"
+ ";; Time %s\n",
+ params.rr_count, date);
+ }
+
+ free(params.buf); // params.buf may be != buf because of knot_rrset_txt_dump_dynamic()
+
+ return KNOT_EOK;
+}
diff --git a/src/knot/zone/zone-dump.h b/src/knot/zone/zone-dump.h
new file mode 100644
index 0000000..e9d8be8
--- /dev/null
+++ b/src/knot/zone/zone-dump.h
@@ -0,0 +1,41 @@
+/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief Zone text dump facility.
+ *
+ * \addtogroup zone
+ * @{
+ */
+
+#pragma once
+
+#include "knot/zone/zone.h"
+
+/*!
+ * \brief Dumps given zone to text file.
+ *
+ * \param zone Zone to be saved.
+ * \param file File to write to.
+ * \param comments Add separating comments indicator.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval < 0 if error.
+ */
+int zone_dump_text(zone_contents_t *zone, FILE *file, bool comments);
+
+/*! @} */
diff --git a/src/knot/zone/zone-load.c b/src/knot/zone/zone-load.c
new file mode 100644
index 0000000..6b1c68e
--- /dev/null
+++ b/src/knot/zone/zone-load.c
@@ -0,0 +1,154 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "knot/common/log.h"
+#include "knot/journal/journal.h"
+#include "knot/zone/zone-diff.h"
+#include "knot/zone/zone-load.h"
+#include "knot/zone/zonefile.h"
+#include "knot/dnssec/key-events.h"
+#include "knot/dnssec/zone-events.h"
+#include "knot/updates/apply.h"
+#include "libknot/libknot.h"
+
+int zone_load_contents(conf_t *conf, const knot_dname_t *zone_name,
+ zone_contents_t **contents)
+{
+ if (conf == NULL || zone_name == NULL || contents == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ char *zonefile = conf_zonefile(conf, zone_name);
+ conf_val_t val = conf_zone_get(conf, C_SEM_CHECKS, zone_name);
+
+ zloader_t zl;
+ int ret = zonefile_open(&zl, zonefile, zone_name, conf_bool(&val), time(NULL));
+ free(zonefile);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ sem_handler_t handler = {
+ .cb = err_handler_logger
+ };
+
+ zl.err_handler = &handler;
+ zl.creator->master = !zone_load_can_bootstrap(conf, zone_name);
+
+ *contents = zonefile_load(&zl);
+ zonefile_close(&zl);
+ if (*contents == NULL) {
+ return KNOT_ERROR;
+ }
+
+ return KNOT_EOK;
+}
+
+int zone_load_journal(conf_t *conf, zone_t *zone, zone_contents_t *contents)
+{
+ if (conf == NULL || zone == NULL || contents == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ /* Check if journal is used (later in zone_changes_load() and zone is not empty. */
+ if (zone_contents_is_empty(contents)) {
+ return KNOT_EOK;
+ }
+
+ /* Fetch SOA serial. */
+ uint32_t serial = zone_contents_serial(contents);
+
+ /* Load journal */
+ list_t chgs;
+ init_list(&chgs);
+ int ret = zone_changes_load(conf, zone, &chgs, serial);
+ if (ret != KNOT_EOK && ret != KNOT_ENOENT) {
+ changesets_free(&chgs);
+ return ret;
+ }
+ if (EMPTY_LIST(chgs)) {
+ return KNOT_EOK;
+ }
+
+ /* Apply changesets. */
+ apply_ctx_t a_ctx = { 0 };
+ apply_init_ctx(&a_ctx, contents, 0);
+
+ ret = apply_changesets_directly(&a_ctx, &chgs);
+ if (ret == KNOT_EOK) {
+ log_zone_info(zone->name, "changes from journal applied %u -> %u",
+ serial, zone_contents_serial(contents));
+ } else {
+ log_zone_error(zone->name, "failed to apply journal changes %u -> %u (%s)",
+ serial, zone_contents_serial(contents),
+ knot_strerror(ret));
+ }
+
+ update_cleanup(&a_ctx);
+ changesets_free(&chgs);
+
+ return ret;
+}
+
+int zone_load_from_journal(conf_t *conf, zone_t *zone, zone_contents_t **contents)
+{
+ if (conf == NULL || zone == NULL || contents == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ list_t chgs;
+ init_list(&chgs);
+ int ret = zone_in_journal_load(conf, zone, &chgs);
+ if (ret != KNOT_EOK) {
+ changesets_free(&chgs);
+ return ret; // include ENOENT, which is normal operation
+ }
+
+ changeset_t *boo_ch = (changeset_t *)HEAD(chgs);
+ rem_node(&boo_ch->n);
+ ret = changeset_to_contents(boo_ch, contents);
+ if (ret != KNOT_EOK) {
+ changesets_free(&chgs);
+ return ret;
+ }
+
+ apply_ctx_t a_ctx = { 0 };
+ apply_init_ctx(&a_ctx, *contents, 0);
+ ret = apply_changesets_directly(&a_ctx, &chgs);
+ if (ret == KNOT_EOK) {
+ log_zone_info(zone->name, "zone loaded from journal, serial %u",
+ zone_contents_serial(*contents));
+ } else {
+ log_zone_error(zone->name, "failed to load zone from journal (%s)",
+ knot_strerror(ret));
+ }
+ update_cleanup(&a_ctx);
+ changesets_free(&chgs);
+
+ return ret;
+}
+
+bool zone_load_can_bootstrap(conf_t *conf, const knot_dname_t *zone_name)
+{
+ if (conf == NULL || zone_name == NULL) {
+ return false;
+ }
+
+ conf_val_t val = conf_zone_get(conf, C_MASTER, zone_name);
+ size_t count = conf_val_count(&val);
+
+ return count > 0;
+}
diff --git a/src/knot/zone/zone-load.h b/src/knot/zone/zone-load.h
new file mode 100644
index 0000000..3210476
--- /dev/null
+++ b/src/knot/zone/zone-load.h
@@ -0,0 +1,63 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include "knot/conf/conf.h"
+#include "knot/zone/zone.h"
+#include "knot/dnssec/zone-events.h" // zone_sign_reschedule_t
+
+/*!
+ * \brief Load zone contents according to the configuration.
+ *
+ * \param conf
+ * \param zone_name
+ * \param contents
+ * \return KNOT_EOK or an error
+ */
+int zone_load_contents(conf_t *conf, const knot_dname_t *zone_name,
+ zone_contents_t **contents);
+
+/*!
+ * \brief Update zone contents from the journal.
+ *
+ * \warning If error, the zone is in inconsistent state and should be freed.
+ *
+ * \param conf
+ * \param zone
+ * \param contents
+ * \return KNOT_EOK or an error
+ */
+int zone_load_journal(conf_t *conf, zone_t *zone, zone_contents_t *contents);
+
+/*!
+ * \brief Load zone contents from journal (headless).
+ *
+ * \param conf
+ * \param zone
+ * \param contents
+ * \return KNOT_EOK or an error
+ */
+int zone_load_from_journal(conf_t *conf, zone_t *zone,
+ zone_contents_t **contents);
+
+/*!
+ * \brief Check if zone can be bootstrapped.
+ *
+ * \param conf
+ * \param zone_name
+ */
+bool zone_load_can_bootstrap(conf_t *conf, const knot_dname_t *zone_name);
diff --git a/src/knot/zone/zone-tree.c b/src/knot/zone/zone-tree.c
new file mode 100644
index 0000000..d46b5ae
--- /dev/null
+++ b/src/knot/zone/zone-tree.c
@@ -0,0 +1,209 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "knot/zone/zone-tree.h"
+#include "libknot/consts.h"
+#include "libknot/errcode.h"
+#include "contrib/macros.h"
+
+zone_tree_t *zone_tree_create(void)
+{
+ return trie_create(NULL);
+}
+
+int zone_tree_insert(zone_tree_t *tree, zone_node_t *node)
+{
+ if (tree == NULL || node == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ assert(node->owner);
+ knot_dname_storage_t lf_storage;
+ uint8_t *lf = knot_dname_lf(node->owner, lf_storage);
+ assert(lf);
+
+ *trie_get_ins(tree, (char *)lf + 1, *lf) = node;
+
+ return KNOT_EOK;
+}
+
+zone_node_t *zone_tree_get(zone_tree_t *tree, const knot_dname_t *owner)
+{
+ if (owner == NULL) {
+ return NULL;
+ }
+
+ if (zone_tree_is_empty(tree)) {
+ return NULL;
+ }
+
+ knot_dname_storage_t lf_storage;
+ uint8_t *lf = knot_dname_lf(owner, lf_storage);
+ assert(lf);
+
+ trie_val_t *val = trie_get_try(tree, (char *)lf + 1, *lf);
+ if (val == NULL) {
+ return NULL;
+ }
+
+ return *val;
+}
+
+int zone_tree_get_less_or_equal(zone_tree_t *tree,
+ const knot_dname_t *owner,
+ zone_node_t **found,
+ zone_node_t **previous)
+{
+ if (owner == NULL || found == NULL || previous == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ if (zone_tree_is_empty(tree)) {
+ return KNOT_ENONODE;
+ }
+
+ knot_dname_storage_t lf_storage;
+ uint8_t *lf = knot_dname_lf(owner, lf_storage);
+ assert(lf);
+
+ trie_val_t *fval = NULL;
+ int ret = trie_get_leq(tree, (char *)lf + 1, *lf, &fval);
+ if (fval != NULL) {
+ *found = (zone_node_t *)(*fval);
+ }
+
+ int exact_match = 0;
+ if (ret == KNOT_EOK) {
+ if (fval != NULL) {
+ *previous = (*found)->prev;
+ }
+ exact_match = 1;
+ } else if (ret == 1) {
+ *previous = *found;
+ *found = NULL;
+ } else {
+ /* Previous should be the rightmost node.
+ * For regular zone it is the node left of apex, but for some
+ * cases like NSEC3, there is no such sort of thing (name wise).
+ */
+ /*! \todo We could store rightmost node in zonetree probably. */
+ trie_it_t *i = trie_it_begin(tree);
+ *previous = *(zone_node_t **)trie_it_val(i); /* leftmost */
+ *previous = (*previous)->prev; /* rightmost */
+ *found = NULL;
+ trie_it_free(i);
+ }
+
+ return exact_match;
+}
+
+/*! \brief Removes node with the given owner from the zone tree. */
+static void remove_node(zone_tree_t *tree, const knot_dname_t *owner)
+{
+ assert(owner);
+
+ if (zone_tree_is_empty(tree)) {
+ return;
+ }
+
+ knot_dname_storage_t lf_storage;
+ uint8_t *lf = knot_dname_lf(owner, lf_storage);
+ assert(lf);
+
+ trie_val_t *rval = trie_get_try(tree, (char *)lf + 1, *lf);
+ if (rval != NULL) {
+ trie_del(tree, (char *)lf + 1, *lf, NULL);
+ }
+}
+
+/*! \brief Clears wildcard child if set in parent node. */
+static void fix_wildcard_child(zone_node_t *node, const knot_dname_t *owner)
+{
+ if ((node->flags & NODE_FLAGS_WILDCARD_CHILD)
+ && knot_dname_is_wildcard(owner)) {
+ node->flags &= ~NODE_FLAGS_WILDCARD_CHILD;
+ }
+}
+
+void zone_tree_delete_empty(zone_tree_t *tree, zone_node_t *node)
+{
+ if (tree == NULL || node == NULL) {
+ return;
+ }
+
+ if (node->rrset_count == 0 && node->children == 0) {
+ zone_node_t *parent_node = node->parent;
+ if (parent_node != NULL) {
+ parent_node->children--;
+ fix_wildcard_child(parent_node, node->owner);
+ if (parent_node->parent != NULL) { /* Is not apex */
+ // Recurse using the parent node, do not delete possibly empty parent.
+ zone_tree_delete_empty(tree, parent_node);
+ }
+ }
+
+ // Delete node
+ remove_node(tree, node->owner);
+ node_free(node, NULL);
+ }
+}
+
+int zone_tree_apply(zone_tree_t *tree, zone_tree_apply_cb_t function, void *data)
+{
+ if (function == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ if (zone_tree_is_empty(tree)) {
+ return KNOT_EOK;
+ }
+
+ return trie_apply(tree, (int (*)(trie_val_t *, void *))function, data);
+}
+
+void zone_tree_free(zone_tree_t **tree)
+{
+ if (tree == NULL || *tree == NULL) {
+ return;
+ }
+
+ trie_free(*tree);
+ *tree = NULL;
+}
+
+static int zone_tree_free_node(zone_node_t **node, void *data)
+{
+ UNUSED(data);
+
+ if (node) {
+ node_free(*node, NULL);
+ }
+
+ return KNOT_EOK;
+}
+
+void zone_tree_deep_free(zone_tree_t **tree)
+{
+ if (tree == NULL || *tree == NULL) {
+ return;
+ }
+
+ (void)zone_tree_apply(*tree, zone_tree_free_node, NULL);
+ zone_tree_free(tree);
+}
diff --git a/src/knot/zone/zone-tree.h b/src/knot/zone/zone-tree.h
new file mode 100644
index 0000000..d3cc909
--- /dev/null
+++ b/src/knot/zone/zone-tree.h
@@ -0,0 +1,142 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "contrib/qp-trie/trie.h"
+#include "knot/zone/node.h"
+
+typedef trie_t zone_tree_t;
+
+/*!
+ * \brief Signature of callback for zone apply functions.
+ */
+typedef int (*zone_tree_apply_cb_t)(zone_node_t **node, void *data);
+
+/*!
+ * \brief Creates the zone tree.
+ *
+ * \return created zone tree structure.
+ */
+zone_tree_t *zone_tree_create(void);
+
+/*!
+ * \brief Return number of nodes in the zone tree.
+ *
+ * \param tree Zone tree.
+ *
+ * \return number of nodes in tree.
+ */
+inline static size_t zone_tree_count(const zone_tree_t *tree)
+{
+ if (tree == NULL) {
+ return 0;
+ }
+
+ return trie_weight(tree);
+}
+
+/*!
+ * \brief Checks if the zone tree is empty.
+ *
+ * \param tree Zone tree to check.
+ *
+ * \return Nonzero if the zone tree is empty.
+ */
+inline static bool zone_tree_is_empty(const zone_tree_t *tree)
+{
+ return zone_tree_count(tree) == 0;
+}
+
+/*!
+ * \brief Inserts the given node into the zone tree.
+ *
+ * \param tree Zone tree to insert the node into.
+ * \param node Node to insert.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EINVAL
+ * \retval KNOT_ENOMEM
+ */
+int zone_tree_insert(zone_tree_t *tree, zone_node_t *node);
+
+/*!
+ * \brief Finds node with the given owner in the zone tree.
+ *
+ * \param tree Zone tree to search in.
+ * \param owner Owner of the node to find.
+ *
+ * \retval Found node or NULL.
+ */
+zone_node_t *zone_tree_get(zone_tree_t *tree, const knot_dname_t *owner);
+
+/*!
+ * \brief Tries to find the given domain name in the zone tree and returns the
+ * associated node and previous node in canonical order.
+ *
+ * \param tree Zone to search in.
+ * \param owner Owner of the node to find.
+ * \param found Found node.
+ * \param previous Previous node in canonical order (i.e. the one directly
+ * preceding \a owner in canonical order, regardless if the name
+ * is in the zone or not).
+ *
+ * \retval > 0 if the domain name was found. In such case \a found holds the
+ * zone node with \a owner as its owner.
+ * \a previous is set properly.
+ * \retval 0 if the domain name was not found. \a found may hold any (or none)
+ * node. \a previous is set properly.
+ * \retval KNOT_EINVAL
+ * \retval KNOT_ENOMEM
+ */
+int zone_tree_get_less_or_equal(zone_tree_t *tree,
+ const knot_dname_t *owner,
+ zone_node_t **found,
+ zone_node_t **previous);
+
+/*!
+ * \brief Delete a node that has no RRSets and no children.
+ *
+ * \param tree The tree to remove from.
+ * \param node The node to remove.
+ */
+void zone_tree_delete_empty(zone_tree_t *tree, zone_node_t *node);
+
+/*!
+ * \brief Applies the given function to each node in the zone in order.
+ *
+ * \param tree Zone tree to apply the function to.
+ * \param function Function to be applied to each node of the zone.
+ * \param data Arbitrary data to be passed to the function.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EINVAL
+ */
+int zone_tree_apply(zone_tree_t *tree, zone_tree_apply_cb_t function, void *data);
+
+/*!
+ * \brief Destroys the zone tree, not touching the saved data.
+ *
+ * \param tree Zone tree to be destroyed.
+ */
+void zone_tree_free(zone_tree_t **tree);
+
+/*!
+ * \brief Destroys the zone tree, together with the saved data.
+ *
+ * \param tree Zone tree to be destroyed.
+ */
+void zone_tree_deep_free(zone_tree_t **tree);
diff --git a/src/knot/zone/zone.c b/src/knot/zone/zone.c
new file mode 100644
index 0000000..efc0caa
--- /dev/null
+++ b/src/knot/zone/zone.c
@@ -0,0 +1,731 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <urcu.h>
+
+#include "knot/common/log.h"
+#include "knot/conf/module.h"
+#include "knot/dnssec/kasp/kasp_db.h"
+#include "knot/nameserver/process_query.h"
+#include "knot/query/requestor.h"
+#include "knot/updates/zone-update.h"
+#include "knot/zone/contents.h"
+#include "knot/zone/serial.h"
+#include "knot/zone/zone.h"
+#include "knot/zone/zonefile.h"
+#include "libknot/libknot.h"
+#include "contrib/sockaddr.h"
+#include "contrib/trim.h"
+#include "contrib/mempattern.h"
+#include "contrib/ucw/lists.h"
+#include "contrib/ucw/mempool.h"
+
+#define JOURNAL_LOCK_MUTEX (&zone->journal_lock)
+#define JOURNAL_LOCK_RW pthread_mutex_lock(JOURNAL_LOCK_MUTEX);
+#define JOURNAL_UNLOCK_RW pthread_mutex_unlock(JOURNAL_LOCK_MUTEX);
+
+static void free_ddns_queue(zone_t *zone)
+{
+ ptrnode_t *node = NULL, *nxt = NULL;
+ WALK_LIST_DELSAFE(node, nxt, zone->ddns_queue) {
+ knot_request_free(node->d, NULL);
+ }
+ ptrlist_free(&zone->ddns_queue, NULL);
+}
+
+/*! \brief Open journal for zone. */
+static int open_journal(zone_t *zone)
+{
+ assert(zone);
+
+ int ret = journal_open(zone->journal, zone->journal_db, zone->name);
+ if (ret != KNOT_EOK) {
+ log_zone_error(zone->name, "failed to open journal '%s'",
+ (*zone->journal_db)->path);
+ }
+
+ return ret;
+}
+
+/*! \brief Close the zone journal. */
+static void close_journal(zone_t *zone)
+{
+ assert(zone);
+ journal_close(zone->journal);
+}
+
+/*!
+ * \param allow_empty_zone useful when need to flush journal but zone is not yet loaded
+ * ...in this case we actually don't have to do anything because the zonefile is current,
+ * but we must mark the journal as flushed
+ */
+static int flush_journal(conf_t *conf, zone_t *zone, bool allow_empty_zone)
+{
+ /*! @note Function expects nobody will change zone contents meanwile. */
+
+ assert(zone);
+
+ int ret = KNOT_EOK;
+
+ bool force = zone->flags & ZONE_FORCE_FLUSH;
+ zone->flags &= ~ZONE_FORCE_FLUSH;
+
+ if (zone_contents_is_empty(zone->contents)) {
+ if (allow_empty_zone && zone->journal && journal_exists(zone->journal_db, zone->name)) {
+ ret = journal_flush(zone->journal);
+ } else {
+ ret = KNOT_EINVAL;
+ }
+ goto flush_journal_replan;
+ }
+
+ /* Check for disabled zonefile synchronization. */
+ conf_val_t val = conf_zone_get(conf, C_ZONEFILE_SYNC, zone->name);
+ if (conf_int(&val) < 0 && !force) {
+ log_zone_warning(zone->name, "zonefile synchronization disabled, "
+ "use force command to override it");
+ return KNOT_EOK;
+ }
+
+ /* Check for updated zone. */
+ zone_contents_t *contents = zone->contents;
+ uint32_t serial_to = zone_contents_serial(contents);
+ if (!force && zone->zonefile.exists && zone->zonefile.serial == serial_to &&
+ !zone->zonefile.resigned) {
+ ret = KNOT_EOK; /* No differences. */
+ goto flush_journal_replan;
+ }
+
+ char *zonefile = conf_zonefile(conf, zone->name);
+
+ /* Synchronize journal. */
+ ret = zonefile_write(zonefile, contents);
+ if (ret != KNOT_EOK) {
+ log_zone_warning(zone->name, "failed to update zone file (%s)",
+ knot_strerror(ret));
+ free(zonefile);
+ goto flush_journal_replan;
+ }
+
+ if (zone->zonefile.exists) {
+ log_zone_info(zone->name, "zone file updated, serial %u -> %u",
+ zone->zonefile.serial, serial_to);
+ } else {
+ log_zone_info(zone->name, "zone file updated, serial %u",
+ serial_to);
+ }
+
+ /* Update zone version. */
+ struct stat st;
+ if (stat(zonefile, &st) < 0) {
+ log_zone_warning(zone->name, "failed to update zone file (%s)",
+ knot_strerror(knot_map_errno()));
+ free(zonefile);
+ ret = KNOT_EACCES;
+ goto flush_journal_replan;
+ }
+
+ free(zonefile);
+
+ /* Update zone file attributes. */
+ zone->zonefile.exists = true;
+ zone->zonefile.mtime = st.st_mtime;
+ zone->zonefile.serial = serial_to;
+ zone->zonefile.resigned = false;
+
+ /* Flush journal. */
+ if (zone->journal && journal_exists(zone->journal_db, zone->name)) {
+ ret = open_journal(zone);
+ if (ret != KNOT_EOK) {
+ goto flush_journal_replan;
+ }
+
+ ret = journal_flush(zone->journal);
+ if (ret != KNOT_EOK) {
+ goto flush_journal_replan;
+ }
+ }
+
+ /* Trim extra heap. */
+ mem_trim();
+
+flush_journal_replan:
+ /* Plan next journal flush after proper period. */
+ zone->timers.last_flush = time(NULL);
+ val = conf_zone_get(conf, C_ZONEFILE_SYNC, zone->name);
+ int64_t sync_timeout = conf_int(&val);
+ if (sync_timeout > 0) {
+ time_t next_flush = zone->timers.last_flush + sync_timeout;
+ zone_events_schedule_at(zone, ZONE_EVENT_FLUSH, 0,
+ ZONE_EVENT_FLUSH, next_flush);
+ }
+
+ return ret;
+}
+
+zone_t* zone_new(const knot_dname_t *name)
+{
+ zone_t *zone = malloc(sizeof(zone_t));
+ if (zone == NULL) {
+ return NULL;
+ }
+ memset(zone, 0, sizeof(zone_t));
+
+ zone->name = knot_dname_copy(name, NULL);
+ if (zone->name == NULL) {
+ free(zone);
+ return NULL;
+ }
+
+ // Journal
+ zone->journal = journal_new();
+ if (zone->journal == NULL) {
+ knot_dname_free(zone->name, NULL);
+ free(zone);
+ return NULL;
+ }
+
+ // DDNS
+ pthread_mutex_init(&zone->ddns_lock, NULL);
+ zone->ddns_queue_size = 0;
+ init_list(&zone->ddns_queue);
+
+ // Journal lock
+ pthread_mutex_init(&zone->journal_lock, NULL);
+
+ // Preferred master lock
+ pthread_mutex_init(&zone->preferred_lock, NULL);
+
+ // Initialize events
+ zone_events_init(zone);
+
+ // Initialize query modules list.
+ init_list(&zone->query_modules);
+
+ return zone;
+}
+
+void zone_control_clear(zone_t *zone)
+{
+ if (zone == NULL) {
+ return;
+ }
+
+ zone_update_clear(zone->control_update);
+ free(zone->control_update);
+ zone->control_update = NULL;
+}
+
+void zone_free(zone_t **zone_ptr)
+{
+ if (zone_ptr == NULL || *zone_ptr == NULL) {
+ return;
+ }
+
+ zone_t *zone = *zone_ptr;
+
+ close_journal(zone);
+
+ zone_events_deinit(zone);
+
+ knot_dname_free(zone->name, NULL);
+
+ journal_free(&zone->journal);
+
+ free_ddns_queue(zone);
+ pthread_mutex_destroy(&zone->ddns_lock);
+ pthread_mutex_destroy(&zone->journal_lock);
+
+ /* Control update. */
+ zone_control_clear(zone);
+
+ /* Free preferred master. */
+ pthread_mutex_destroy(&zone->preferred_lock);
+ free(zone->preferred_master);
+
+ /* Free zone contents. */
+ zone_contents_deep_free(zone->contents);
+
+ conf_deactivate_modules(&zone->query_modules, &zone->query_plan);
+
+ free(zone);
+ *zone_ptr = NULL;
+}
+
+int zone_change_store(conf_t *conf, zone_t *zone, changeset_t *change)
+{
+ if (conf == NULL || zone == NULL || change == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ JOURNAL_LOCK_RW
+
+ int ret = open_journal(zone);
+ if (ret == KNOT_EOK) {
+ ret = journal_store_changeset(zone->journal, change);
+ if (ret == KNOT_EBUSY) {
+ log_zone_notice(zone->name, "journal is full, flushing");
+
+ /* Transaction rolled back, journal released, we may flush. */
+ ret = flush_journal(conf, zone, true);
+ if (ret == KNOT_EOK) {
+ ret = journal_store_changeset(zone->journal, change);
+ }
+ }
+ }
+
+ JOURNAL_UNLOCK_RW
+
+ return ret;
+}
+
+int zone_changes_clear(conf_t *conf, zone_t *zone)
+{
+ if (conf == NULL || zone == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ JOURNAL_LOCK_RW
+
+ int ret = KNOT_EOK;
+
+ if (journal_exists(zone->journal_db, zone->name)) {
+ ret = open_journal(zone);
+ if (ret == KNOT_EOK) {
+ ret = journal_drop_changesets(zone->journal);
+ }
+ }
+
+ JOURNAL_UNLOCK_RW
+
+ return ret;
+}
+
+int zone_changes_load(conf_t *conf, zone_t *zone, list_t *dst, uint32_t from)
+{
+ if (conf == NULL || zone == NULL || dst == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = KNOT_ENOENT;
+
+ if (journal_exists(zone->journal_db, zone->name)) {
+ ret = open_journal(zone);
+ }
+
+ if (ret == KNOT_EOK) {
+ ret = journal_load_changesets(zone->journal, dst, from);
+ }
+
+ return ret;
+}
+
+int zone_chgset_ctx_load(conf_t *conf, zone_t *zone, chgset_ctx_list_t *dst, uint32_t from)
+{
+ if (conf == NULL || zone == NULL || dst == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = KNOT_ENOENT;
+
+ if (journal_exists(zone->journal_db, zone->name)) {
+ ret = open_journal(zone);
+ }
+
+ if (ret == KNOT_EOK) {
+ ret = journal_load_chgset_ctx(zone->journal, dst, from);
+ }
+
+ return ret;
+}
+
+int zone_in_journal_load(conf_t *conf, zone_t *zone, list_t *dst)
+{
+ if (conf == NULL || zone == NULL || dst == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = KNOT_ENOENT;
+
+ if (journal_exists(zone->journal_db, zone->name)) {
+ ret = open_journal(zone);
+ }
+
+ if (ret == KNOT_EOK) {
+ ret = journal_load_bootstrap(zone->journal, dst);
+ }
+
+ return ret;
+}
+
+int zone_in_journal_store(conf_t *conf, zone_t *zone, zone_contents_t *new_contents)
+{
+ if (conf == NULL || zone == NULL || new_contents == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ changeset_t *co_ch = changeset_from_contents(new_contents);
+ int ret = co_ch ? zone_change_store(conf, zone, co_ch) : KNOT_ENOMEM;
+ changeset_from_contents_free(co_ch);
+
+ if (ret == KNOT_EOK) {
+ log_zone_info(zone->name, "zone stored to journal, serial %u",
+ zone_contents_serial(new_contents));
+ }
+
+ return ret;
+}
+
+int zone_flush_journal(conf_t *conf, zone_t *zone)
+{
+ if (conf == NULL || zone == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ JOURNAL_LOCK_RW
+
+ // NO open_journal() here.
+
+ int ret = flush_journal(conf, zone, false);
+
+ JOURNAL_UNLOCK_RW
+
+ return ret;
+}
+
+int zone_journal_serial(conf_t *conf, zone_t *zone, bool *is_empty, uint32_t *serial_to)
+{
+ if (conf == NULL || zone == NULL || is_empty == NULL || serial_to == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = open_journal(zone);
+ if (ret == KNOT_EOK) {
+ kserial_t ks;
+ journal_metadata_info(zone->journal, is_empty, NULL, NULL, NULL, &ks, NULL, NULL);
+ *serial_to = (ks.valid ? ks.serial : 0);
+ }
+
+ return ret;
+}
+
+zone_contents_t *zone_switch_contents(zone_t *zone, zone_contents_t *new_contents)
+{
+ if (zone == NULL) {
+ return NULL;
+ }
+
+ zone_contents_t *old_contents;
+ zone_contents_t **current_contents = &zone->contents;
+ old_contents = rcu_xchg_pointer(current_contents, new_contents);
+
+ return old_contents;
+}
+
+bool zone_is_slave(conf_t *conf, const zone_t *zone)
+{
+ if (conf == NULL || zone == NULL) {
+ return false;
+ }
+
+ conf_val_t val = conf_zone_get(conf, C_MASTER, zone->name);
+ return conf_val_count(&val) > 0 ? true : false;
+}
+
+void zone_set_preferred_master(zone_t *zone, const struct sockaddr_storage *addr)
+{
+ if (zone == NULL || addr == NULL) {
+ return;
+ }
+
+ pthread_mutex_lock(&zone->preferred_lock);
+ free(zone->preferred_master);
+ zone->preferred_master = malloc(sizeof(struct sockaddr_storage));
+ *zone->preferred_master = *addr;
+ pthread_mutex_unlock(&zone->preferred_lock);
+}
+
+void zone_clear_preferred_master(zone_t *zone)
+{
+ if (zone == NULL) {
+ return;
+ }
+
+ pthread_mutex_lock(&zone->preferred_lock);
+ free(zone->preferred_master);
+ zone->preferred_master = NULL;
+ pthread_mutex_unlock(&zone->preferred_lock);
+}
+
+const knot_rdataset_t *zone_soa(const zone_t *zone)
+{
+ if (!zone || zone_contents_is_empty(zone->contents)) {
+ return NULL;
+ }
+
+ return node_rdataset(zone->contents->apex, KNOT_RRTYPE_SOA);
+}
+
+bool zone_expired(const zone_t *zone)
+{
+ if (!zone) {
+ return false;
+ }
+
+ const zone_timers_t *timers = &zone->timers;
+
+ return timers->last_refresh > 0 && timers->soa_expire > 0 &&
+ timers->last_refresh + timers->soa_expire <= time(NULL);
+}
+
+/*!
+ * \brief Get preferred zone master while checking its existence.
+ */
+int static preferred_master(conf_t *conf, zone_t *zone, conf_remote_t *master)
+{
+ pthread_mutex_lock(&zone->preferred_lock);
+
+ if (zone->preferred_master == NULL) {
+ pthread_mutex_unlock(&zone->preferred_lock);
+ return KNOT_ENOENT;
+ }
+
+ conf_val_t masters = conf_zone_get(conf, C_MASTER, zone->name);
+ while (masters.code == KNOT_EOK) {
+ conf_val_t addr = conf_id_get(conf, C_RMT, C_ADDR, &masters);
+ size_t addr_count = conf_val_count(&addr);
+
+ for (size_t i = 0; i < addr_count; i++) {
+ conf_remote_t remote = conf_remote(conf, &masters, i);
+ if (sockaddr_net_match((struct sockaddr *)&remote.addr,
+ (struct sockaddr *)zone->preferred_master,
+ -1)) {
+ *master = remote;
+ pthread_mutex_unlock(&zone->preferred_lock);
+ return KNOT_EOK;
+ }
+ }
+
+ conf_val_next(&masters);
+ }
+
+ pthread_mutex_unlock(&zone->preferred_lock);
+
+ return KNOT_ENOENT;
+}
+
+int zone_master_try(conf_t *conf, zone_t *zone, zone_master_cb callback,
+ void *callback_data, const char *err_str)
+{
+ if (conf == NULL || zone == NULL || callback == NULL || err_str == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ /* Try the preferred server. */
+
+ conf_remote_t preferred = { { AF_UNSPEC } };
+ if (preferred_master(conf, zone, &preferred) == KNOT_EOK) {
+ int ret = callback(conf, zone, &preferred, callback_data);
+ if (ret == KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ /* Try all the other servers. */
+
+ bool success = false;
+
+ conf_val_t masters = conf_zone_get(conf, C_MASTER, zone->name);
+ while (masters.code == KNOT_EOK) {
+ conf_val_t addr = conf_id_get(conf, C_RMT, C_ADDR, &masters);
+ size_t addr_count = conf_val_count(&addr);
+
+ for (size_t i = 0; i < addr_count; i++) {
+ conf_remote_t master = conf_remote(conf, &masters, i);
+ if (preferred.addr.ss_family != AF_UNSPEC &&
+ sockaddr_net_match((struct sockaddr *)&master.addr,
+ (struct sockaddr *)&preferred.addr,
+ -1)) {
+ preferred.addr.ss_family = AF_UNSPEC;
+ continue;
+ }
+
+ int ret = callback(conf, zone, &master, callback_data);
+ if (ret == KNOT_EOK) {
+ success = true;
+ break;
+ }
+
+ char addr_str[SOCKADDR_STRLEN] = { 0 };
+ sockaddr_tostr(addr_str, sizeof(addr_str),
+ (struct sockaddr *)&master.addr);
+ log_zone_debug(zone->name, "%s, remote %s, address %s, failed (%s)",
+ err_str, conf_str(&masters), addr_str,
+ knot_strerror(ret));
+ }
+
+ if (!success) {
+ log_zone_warning(zone->name, "%s, remote %s not usable",
+ err_str, conf_str(&masters));
+ }
+
+ conf_val_next(&masters);
+ }
+
+ return success ? KNOT_EOK : KNOT_ENOMASTER;
+}
+
+int zone_update_enqueue(zone_t *zone, knot_pkt_t *pkt, knotd_qdata_params_t *params)
+{
+ if (zone == NULL || pkt == NULL || params == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ /* Create serialized request. */
+ struct knot_request *req = malloc(sizeof(struct knot_request));
+ if (req == NULL) {
+ return KNOT_ENOMEM;
+ }
+ memset(req, 0, sizeof(struct knot_request));
+
+ /* Copy socket and request. */
+ req->fd = dup(params->socket);
+ memcpy(&req->remote, params->remote, sizeof(struct sockaddr_storage));
+
+ req->query = knot_pkt_new(NULL, pkt->max_size, NULL);
+ int ret = knot_pkt_copy(req->query, pkt);
+ if (ret != KNOT_EOK) {
+ knot_pkt_free(req->query);
+ free(req);
+ return ret;
+ }
+
+ pthread_mutex_lock(&zone->ddns_lock);
+
+ /* Enqueue created request. */
+ ptrlist_add(&zone->ddns_queue, req, NULL);
+ ++zone->ddns_queue_size;
+
+ pthread_mutex_unlock(&zone->ddns_lock);
+
+ /* Schedule UPDATE event. */
+ zone_events_schedule_now(zone, ZONE_EVENT_UPDATE);
+
+ return KNOT_EOK;
+}
+
+size_t zone_update_dequeue(zone_t *zone, list_t *updates)
+{
+ if (zone == NULL || updates == NULL) {
+ return 0;
+ }
+
+ pthread_mutex_lock(&zone->ddns_lock);
+ if (EMPTY_LIST(zone->ddns_queue)) {
+ /* Lost race during reload. */
+ pthread_mutex_unlock(&zone->ddns_lock);
+ return 0;
+ }
+
+ *updates = zone->ddns_queue;
+ size_t update_count = zone->ddns_queue_size;
+ init_list(&zone->ddns_queue);
+ zone->ddns_queue_size = 0;
+
+ pthread_mutex_unlock(&zone->ddns_lock);
+
+ return update_count;
+}
+
+int zone_dump_to_dir(conf_t *conf, zone_t *zone, const char *dir)
+{
+ if (zone == NULL || dir == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ size_t dir_len = strlen(dir);
+ if (dir_len == 0) {
+ return KNOT_EINVAL;
+ }
+
+ char *zonefile = conf_zonefile(conf, zone->name);
+ char *zonefile_basename = strrchr(zonefile, '/');
+ if (zonefile_basename == NULL) {
+ zonefile_basename = zonefile;
+ }
+
+ size_t target_length = strlen(zonefile_basename) + dir_len + 2;
+ char target[target_length];
+ (void)snprintf(target, target_length, "%s/%s", dir, zonefile_basename);
+ if (strcmp(target, zonefile) == 0) {
+ free(zonefile);
+ return KNOT_EDENIED;
+ }
+ free(zonefile);
+
+ return zonefile_write(target, zone->contents);
+}
+
+int zone_set_master_serial(zone_t *zone, uint32_t serial)
+{
+ int ret = kasp_db_open(*kaspdb());
+ if (ret == KNOT_EOK) {
+ ret = kasp_db_store_serial(*kaspdb(), zone->name, KASPDB_SERIAL_MASTER, serial);
+ }
+ return ret;
+}
+
+int zone_get_master_serial(zone_t *zone, uint32_t *serial)
+{
+ if (!kasp_db_exists(*kaspdb())) {
+ *serial = zone_contents_serial(zone->contents);
+ return KNOT_EOK;
+ }
+ int ret = kasp_db_open(*kaspdb());
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ ret = kasp_db_load_serial(*kaspdb(), zone->name, KASPDB_SERIAL_MASTER, serial);
+ if (ret == KNOT_ENOENT) {
+ *serial = zone_contents_serial(zone->contents);
+ return KNOT_EOK;
+ }
+ return ret;
+}
+
+int zone_set_lastsigned_serial(zone_t *zone, uint32_t serial)
+{
+ int ret = kasp_db_open(*kaspdb());
+ if (ret == KNOT_EOK) {
+ ret = kasp_db_store_serial(*kaspdb(), zone->name, KASPDB_SERIAL_LASTSIGNED, serial);
+ }
+ return ret;
+}
+
+bool zone_get_lastsigned_serial(zone_t *zone, uint32_t *serial)
+{
+ if (!kasp_db_exists(*kaspdb())) {
+ return false;
+ }
+ int ret = kasp_db_open(*kaspdb());
+ if (ret == KNOT_EOK) {
+ ret = kasp_db_load_serial(*kaspdb(), zone->name, KASPDB_SERIAL_LASTSIGNED, serial);
+ }
+ return (ret == KNOT_EOK);
+}
diff --git a/src/knot/zone/zone.h b/src/knot/zone/zone.h
new file mode 100644
index 0000000..360e222
--- /dev/null
+++ b/src/knot/zone/zone.h
@@ -0,0 +1,177 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "knot/conf/conf.h"
+#include "knot/conf/confio.h"
+#include "knot/journal/journal.h"
+#include "knot/events/events.h"
+#include "knot/zone/contents.h"
+#include "knot/zone/timers.h"
+#include "libknot/dname.h"
+#include "libknot/packet/pkt.h"
+
+struct zone_update;
+
+/*!
+ * \brief Zone flags.
+ */
+typedef enum zone_flag_t {
+ ZONE_FORCE_AXFR = 1 << 0, /* Force AXFR as next transfer. */
+ ZONE_FORCE_RESIGN = 1 << 1, /* Force zone re-sign. */
+ ZONE_FORCE_FLUSH = 1 << 2, /* Force zone flush. */
+} zone_flag_t;
+
+/*!
+ * \brief Structure for holding DNS zone.
+ */
+typedef struct zone
+{
+ knot_dname_t *name;
+ zone_contents_t *contents;
+ zone_flag_t flags;
+
+ /*! \brief Dynamic configuration zone change type. */
+ conf_io_type_t change_type;
+
+ /*! \brief Zonefile parameters. */
+ struct {
+ time_t mtime;
+ uint32_t serial;
+ bool exists;
+ bool resigned;
+ } zonefile;
+
+ /*! \brief Zone events. */
+ zone_timers_t timers; //!< Persistent zone timers.
+ zone_events_t events; //!< Zone events timers.
+
+ /*! \brief DDNS queue and lock. */
+ pthread_mutex_t ddns_lock;
+ size_t ddns_queue_size;
+ list_t ddns_queue;
+
+ /*! \brief Control update context. */
+ struct zone_update *control_update;
+
+ /*! \brief Journal structure. */
+ journal_t *journal;
+
+ /*! \brief Journal access lock. */
+ pthread_mutex_t journal_lock;
+
+ /*! \brief Ptr to journal DB (in struct server) */
+ journal_db_t **journal_db;
+
+ /*! \brief Preferred master lock. */
+ pthread_mutex_t preferred_lock;
+ /*! \brief Preferred master for remote operation. */
+ struct sockaddr_storage *preferred_master;
+
+ /*! \brief Query modules. */
+ list_t query_modules;
+ struct query_plan *query_plan;
+} zone_t;
+
+/*!
+ * \brief Creates new zone with emtpy zone content.
+ *
+ * \param name Zone name.
+ *
+ * \return The initialized zone structure or NULL if an error occurred.
+ */
+zone_t* zone_new(const knot_dname_t *name);
+
+/*!
+ * \brief Deallocates the zone structure.
+ *
+ * \note The function also deallocates all bound structures (contents, etc.).
+ *
+ * \param zone_ptr Zone to be freed.
+ */
+void zone_free(zone_t **zone_ptr);
+
+/*!
+ * \brief Clears possible control update transaction.
+ *
+ * \param zone Zone to be cleared.
+ */
+void zone_control_clear(zone_t *zone);
+
+int zone_change_store(conf_t *conf, zone_t *zone, changeset_t *change);
+int zone_changes_clear(conf_t *conf, zone_t *zone);
+int zone_changes_load(conf_t *conf, zone_t *zone, list_t *dst, uint32_t from);
+int zone_chgset_ctx_load(conf_t *conf, zone_t *zone, chgset_ctx_list_t *dst, uint32_t from);
+int zone_in_journal_load(conf_t *conf, zone_t *zone, list_t *dst);
+int zone_in_journal_store(conf_t *conf, zone_t *zone, zone_contents_t *new_contents);
+int zone_journal_serial(conf_t *conf, zone_t *zone, bool *is_empty, uint32_t *serial_to);
+
+/*! \brief Synchronize zone file with journal. */
+int zone_flush_journal(conf_t *conf, zone_t *zone);
+
+/*!
+ * \brief Atomically switch the content of the zone.
+ */
+zone_contents_t *zone_switch_contents(zone_t *zone, zone_contents_t *new_contents);
+
+/*! \brief Checks if the zone is slave. */
+bool zone_is_slave(conf_t *conf, const zone_t *zone);
+
+/*! \brief Sets the address as a preferred master address. */
+void zone_set_preferred_master(zone_t *zone, const struct sockaddr_storage *addr);
+
+/*! \brief Clears the current preferred master address. */
+void zone_clear_preferred_master(zone_t *zone);
+
+/*! \brief Get zone SOA RR. */
+const knot_rdataset_t *zone_soa(const zone_t *zone);
+
+/*! \brief Check if zone is expired according to timers. */
+bool zone_expired(const zone_t *zone);
+
+typedef int (*zone_master_cb)(conf_t *conf, zone_t *zone, const conf_remote_t *remote,
+ void *data);
+
+/*!
+ * \brief Perform an action with a first working master server.
+ *
+ * The function iterates over available masters. For each master, the callback
+ * function is called. If the callback function succeeds (\ref KNOT_EOK is
+ * returned), the iteration is terminated.
+ *
+ * \return Error code from the last callback.
+ */
+int zone_master_try(conf_t *conf, zone_t *zone, zone_master_cb callback,
+ void *callback_data, const char *err_str);
+
+
+/*! \brief Enqueue UPDATE request for processing. */
+int zone_update_enqueue(zone_t *zone, knot_pkt_t *pkt, knotd_qdata_params_t *params);
+
+/*! \brief Dequeue UPDATE request. Returns number of queued updates. */
+size_t zone_update_dequeue(zone_t *zone, list_t *updates);
+
+/*! \brief Write zone contents to zonefile, but into different directory. */
+int zone_dump_to_dir(conf_t *conf, zone_t *zone, const char *dir);
+
+int zone_set_master_serial(zone_t *zone, uint32_t serial);
+
+int zone_get_master_serial(zone_t *zone, uint32_t *serial);
+
+int zone_set_lastsigned_serial(zone_t *zone, uint32_t serial);
+
+bool zone_get_lastsigned_serial(zone_t *zone, uint32_t *serial);
diff --git a/src/knot/zone/zonedb-load.c b/src/knot/zone/zonedb-load.c
new file mode 100644
index 0000000..a6e9834
--- /dev/null
+++ b/src/knot/zone/zonedb-load.c
@@ -0,0 +1,346 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <urcu.h>
+
+#include "knot/common/log.h"
+#include "knot/conf/module.h"
+#include "knot/events/replan.h"
+#include "knot/zone/timers.h"
+#include "knot/zone/zone-load.h"
+#include "knot/zone/zone.h"
+#include "knot/zone/zonedb-load.h"
+#include "knot/zone/zonedb.h"
+#include "knot/zone/zonefile.h"
+#include "libknot/libknot.h"
+
+static bool zone_file_updated(conf_t *conf, const zone_t *old_zone,
+ const knot_dname_t *zone_name)
+{
+ assert(conf);
+ assert(zone_name);
+
+ char *zonefile = conf_zonefile(conf, zone_name);
+ time_t mtime;
+ int ret = zonefile_exists(zonefile, &mtime);
+ free(zonefile);
+
+ return (ret == KNOT_EOK && old_zone != NULL &&
+ !(old_zone->zonefile.exists && old_zone->zonefile.mtime == mtime));
+}
+
+static zone_t *create_zone_from(const knot_dname_t *name, server_t *server)
+{
+ zone_t *zone = zone_new(name);
+ if (!zone) {
+ return NULL;
+ }
+
+ zone->journal_db = &server->journal_db;
+
+ int result = zone_events_setup(zone, server->workers, &server->sched,
+ server->timers_db);
+ if (result != KNOT_EOK) {
+ zone_free(&zone);
+ return NULL;
+ }
+
+ return zone;
+}
+
+/*!
+ * \brief Set timer if unset (value is 0).
+ */
+static void time_set_default(time_t *time, time_t value)
+{
+ assert(time);
+
+ if (*time == 0) {
+ *time = value;
+ }
+}
+
+/*!
+ * \brief Set default timers for new zones or invalidate if not valid.
+ */
+static void timers_sanitize(conf_t *conf, zone_t *zone)
+{
+ assert(conf);
+ assert(zone);
+
+ time_t now = time(NULL);
+
+ // replace SOA expire if we have better knowledge
+ if (!zone_contents_is_empty(zone->contents)) {
+ const knot_rdataset_t *soa = zone_soa(zone);
+ zone->timers.soa_expire = knot_soa_expire(soa->rdata);
+ }
+
+ // assume now if we don't know when we flushed
+ time_set_default(&zone->timers.last_flush, now);
+
+ if (zone_is_slave(conf, zone)) {
+ // assume now if we don't know
+ time_set_default(&zone->timers.last_refresh, now);
+ time_set_default(&zone->timers.next_refresh, now);
+ } else {
+ // invalidate if we don't have a master
+ zone->timers.last_refresh = 0;
+ zone->timers.next_refresh = 0;
+ }
+}
+
+static zone_t *create_zone_reload(conf_t *conf, const knot_dname_t *name,
+ server_t *server, zone_t *old_zone)
+{
+ zone_t *zone = create_zone_from(name, server);
+ if (!zone) {
+ return NULL;
+ }
+
+ zone->contents = old_zone->contents;
+
+ zone->timers = old_zone->timers;
+ timers_sanitize(conf, zone);
+
+ if (zone_file_updated(conf, old_zone, name) && !zone_expired(zone)) {
+ replan_load_updated(zone, old_zone);
+ } else {
+ zone->zonefile = old_zone->zonefile;
+ replan_load_current(conf, zone, old_zone);
+ }
+
+ if (old_zone->control_update != NULL) {
+ log_zone_warning(old_zone->name, "control transaction aborted");
+ zone_control_clear(old_zone);
+ }
+
+ return zone;
+}
+
+static zone_t *create_zone_new(conf_t *conf, const knot_dname_t *name,
+ server_t *server)
+{
+ zone_t *zone = create_zone_from(name, server);
+ if (!zone) {
+ return NULL;
+ }
+
+ int ret = zone_timers_read(server->timers_db, name, &zone->timers);
+ if (ret != KNOT_EOK && ret != KNOT_ENOENT) {
+ log_zone_error(zone->name, "failed to load persistent timers (%s)",
+ knot_strerror(ret));
+ zone_free(&zone);
+ return NULL;
+ }
+
+ timers_sanitize(conf, zone);
+
+ if (zone_expired(zone)) {
+ // expired => force bootstrap, no load attempt
+ log_zone_info(zone->name, "zone will be bootstrapped");
+ assert(zone_is_slave(conf, zone));
+ replan_load_bootstrap(conf, zone);
+ } else {
+ log_zone_info(zone->name, "zone will be loaded");
+ replan_load_new(zone); // if load fails, fallback to bootstrap
+ }
+
+ return zone;
+}
+
+/*!
+ * \brief Load or reload the zone.
+ *
+ * \param conf Configuration.
+ * \param server Server.
+ * \param old_zone Already loaded zone (can be NULL).
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+static zone_t *create_zone(conf_t *conf, const knot_dname_t *name, server_t *server,
+ zone_t *old_zone)
+{
+ assert(conf);
+ assert(name);
+ assert(server);
+
+ if (old_zone) {
+ return create_zone_reload(conf, name, server, old_zone);
+ } else {
+ return create_zone_new(conf, name, server);
+ }
+}
+
+static void mark_changed_zones(knot_zonedb_t *zonedb, trie_t *changed)
+{
+ if (changed == NULL) {
+ return;
+ }
+
+ trie_it_t *it = trie_it_begin(changed);
+ for (; !trie_it_finished(it); trie_it_next(it)) {
+ const knot_dname_t *name =
+ (const knot_dname_t *)trie_it_key(it, NULL);
+
+ zone_t *zone = knot_zonedb_find(zonedb, name);
+ if (zone != NULL) {
+ conf_io_type_t type = (conf_io_type_t)(*trie_it_val(it));
+ assert(!(type & CONF_IO_TSET));
+ zone->change_type = type;
+ }
+ }
+ trie_it_free(it);
+}
+
+/*!
+ * \brief Create new zone database.
+ *
+ * Zones that should be retained are just added from the old database to the
+ * new. New zones are loaded.
+ *
+ * \param conf New server configuration.
+ * \param server Server instance.
+ *
+ * \return New zone database.
+ */
+static knot_zonedb_t *create_zonedb(conf_t *conf, server_t *server)
+{
+ assert(conf);
+ assert(server);
+
+ knot_zonedb_t *db_old = server->zone_db;
+ knot_zonedb_t *db_new = knot_zonedb_new();
+ if (!db_new) {
+ return NULL;
+ }
+
+ bool full = !(conf->io.flags & CONF_IO_FACTIVE) ||
+ (conf->io.flags & CONF_IO_FRLD_ZONES);
+
+ /* Mark changed zones. */
+ if (!full) {
+ mark_changed_zones(server->zone_db, conf->io.zones);
+ }
+
+ for (conf_iter_t iter = conf_iter(conf, C_ZONE); iter.code == KNOT_EOK;
+ conf_iter_next(conf, &iter)) {
+ conf_val_t id = conf_iter_id(conf, &iter);
+ const knot_dname_t *name = conf_dname(&id);
+
+ zone_t *old_zone = knot_zonedb_find(db_old, name);
+ if (old_zone != NULL && !full) {
+ /* Reuse unchanged zone. */
+ if (!(old_zone->change_type & CONF_IO_TRELOAD)) {
+ knot_zonedb_insert(db_new, old_zone);
+ continue;
+ }
+ }
+
+ zone_t *zone = create_zone(conf, name, server, old_zone);
+ if (zone == NULL) {
+ log_zone_error(name, "zone cannot be created");
+ continue;
+ }
+
+ conf_activate_modules(conf, zone->name, &zone->query_modules,
+ &zone->query_plan);
+
+ knot_zonedb_insert(db_new, zone);
+ }
+
+ return db_new;
+}
+
+/*!
+ * \brief Schedule deletion of old zones, and free the zone db structure.
+ *
+ * \note Zone content may be preserved in the new zone database, in this case
+ * new and old zone share the contents. Shared content is not freed.
+ *
+ * \param conf New server configuration.
+ * \param db_old Old zone database to remove.
+ * \param db_new New zone database for comparison if full reload.
+ */
+static void remove_old_zonedb(conf_t *conf, knot_zonedb_t *db_old,
+ knot_zonedb_t *db_new)
+{
+ if (db_old == NULL) {
+ return;
+ }
+
+ bool full = !(conf->io.flags & CONF_IO_FACTIVE) ||
+ (conf->io.flags & CONF_IO_FRLD_ZONES);
+
+ knot_zonedb_iter_t *it = knot_zonedb_iter_begin(db_old);
+
+ while (!knot_zonedb_iter_finished(it)) {
+ zone_t *zone = knot_zonedb_iter_val(it);
+
+ if (full) {
+ /* Check if reloaded (reused contents). */
+ if (knot_zonedb_find(db_new, zone->name)) {
+ zone->contents = NULL;
+ }
+ /* Completely new zone. */
+ } else {
+ /* Check if reloaded (reused contents). */
+ if (zone->change_type & CONF_IO_TRELOAD) {
+ zone->contents = NULL;
+ zone_free(&zone);
+ /* Check if removed (drop also contents). */
+ } else if (zone->change_type & CONF_IO_TUNSET) {
+ zone_free(&zone);
+ }
+ /* Completely reused zone. */
+ }
+
+ knot_zonedb_iter_next(it);
+ }
+
+ knot_zonedb_iter_free(it);
+
+ if (full) {
+ knot_zonedb_deep_free(&db_old);
+ } else {
+ knot_zonedb_free(&db_old);
+ }
+}
+
+void zonedb_reload(conf_t *conf, server_t *server)
+{
+ if (conf == NULL || server == NULL) {
+ return;
+ }
+
+ /* Insert all required zones to the new zone DB. */
+ knot_zonedb_t *db_new = create_zonedb(conf, server);
+ if (db_new == NULL) {
+ log_error("failed to create new zone database");
+ return;
+ }
+
+ /* Switch the databases. */
+ knot_zonedb_t **db_current = &server->zone_db;
+ knot_zonedb_t *db_old = rcu_xchg_pointer(db_current, db_new);
+
+ /* Wait for readers to finish reading old zone database. */
+ synchronize_rcu();
+
+ /* Remove old zone DB. */
+ remove_old_zonedb(conf, db_old, db_new);
+}
diff --git a/src/knot/zone/zonedb-load.h b/src/knot/zone/zonedb-load.h
new file mode 100644
index 0000000..fda12d8
--- /dev/null
+++ b/src/knot/zone/zonedb-load.h
@@ -0,0 +1,28 @@
+/* Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include "knot/conf/conf.h"
+#include "knot/server/server.h"
+
+/*!
+ * \brief Update zone database according to configuration.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] server Server instance.
+ */
+void zonedb_reload(conf_t *conf, server_t *server);
diff --git a/src/knot/zone/zonedb.c b/src/knot/zone/zonedb.c
new file mode 100644
index 0000000..d949a59
--- /dev/null
+++ b/src/knot/zone/zonedb.c
@@ -0,0 +1,167 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "knot/zone/zonedb.h"
+#include "libknot/packet/wire.h"
+#include "contrib/mempattern.h"
+#include "contrib/ucw/mempool.h"
+
+/*! \brief Discard zone in zone database. */
+static void discard_zone(zone_t *zone)
+{
+ // Don't flush if removed zone (no previous configuration available).
+ if (conf_rawid_exists(conf(), C_ZONE, zone->name, knot_dname_size(zone->name))) {
+ // Flush if bootstrapped or if the journal doesn't exist.
+ if (!zone->zonefile.exists || !journal_exists(zone->journal_db, zone->name)) {
+ zone_flush_journal(conf(), zone);
+ } else {
+ bool empty;
+ uint32_t journal_serial, zone_serial = zone_contents_serial(zone->contents);
+ int ret = zone_journal_serial(conf(), zone, &empty, &journal_serial);
+ if (ret != KNOT_EOK || empty || journal_serial != zone_serial) {
+ zone_flush_journal(conf(), zone);
+ }
+ }
+ }
+
+ zone_free(&zone);
+}
+
+knot_zonedb_t *knot_zonedb_new(void)
+{
+ knot_zonedb_t *db = calloc(1, sizeof(knot_zonedb_t));
+ if (db == NULL) {
+ return NULL;
+ }
+
+ mm_ctx_mempool(&db->mm, MM_DEFAULT_BLKSIZE);
+
+ db->trie = trie_create(&db->mm);
+ if (db->trie == NULL) {
+ mp_delete(db->mm.ctx);
+ free(db);
+ return NULL;
+ }
+
+ return db;
+}
+
+int knot_zonedb_insert(knot_zonedb_t *db, zone_t *zone)
+{
+ if (db == NULL || zone == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ assert(zone->name);
+ knot_dname_storage_t lf_storage;
+ uint8_t *lf = knot_dname_lf(zone->name, lf_storage);
+ assert(lf);
+
+ *trie_get_ins(db->trie, (char *)lf + 1, *lf) = zone;
+
+ return KNOT_EOK;
+}
+
+int knot_zonedb_del(knot_zonedb_t *db, const knot_dname_t *zone_name)
+{
+ if (db == NULL || zone_name == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ knot_dname_storage_t lf_storage;
+ uint8_t *lf = knot_dname_lf(zone_name, lf_storage);
+ assert(lf);
+
+ trie_val_t *rval = trie_get_try(db->trie, (char *)lf + 1, *lf);
+ if (rval == NULL) {
+ return KNOT_ENOENT;
+ }
+
+ return trie_del(db->trie, (char *)lf + 1, *lf, NULL);
+}
+
+zone_t *knot_zonedb_find(knot_zonedb_t *db, const knot_dname_t *zone_name)
+{
+ if (db == NULL) {
+ return NULL;
+ }
+
+ knot_dname_storage_t lf_storage;
+ uint8_t *lf = knot_dname_lf(zone_name, lf_storage);
+ assert(lf);
+
+ trie_val_t *val = trie_get_try(db->trie, (char *)lf + 1, *lf);
+ if (val == NULL) {
+ return NULL;
+ }
+
+ return *val;
+}
+
+zone_t *knot_zonedb_find_suffix(knot_zonedb_t *db, const knot_dname_t *zone_name)
+{
+ if (db == NULL || zone_name == NULL) {
+ return NULL;
+ }
+
+ while (true) {
+ knot_dname_storage_t lf_storage;
+ uint8_t *lf = knot_dname_lf(zone_name, lf_storage);
+ assert(lf);
+
+ trie_val_t *val = trie_get_try(db->trie, (char *)lf + 1, *lf);
+ if (val != NULL) {
+ return *val;
+ } else if (zone_name[0] == 0) {
+ return NULL;
+ }
+
+ zone_name = knot_wire_next_label(zone_name, NULL);
+ }
+}
+
+size_t knot_zonedb_size(const knot_zonedb_t *db)
+{
+ if (db == NULL) {
+ return 0;
+ }
+
+ return trie_weight(db->trie);
+}
+
+void knot_zonedb_free(knot_zonedb_t **db)
+{
+ if (db == NULL || *db == NULL) {
+ return;
+ }
+
+ mp_delete((*db)->mm.ctx);
+ free(*db);
+ *db = NULL;
+}
+
+void knot_zonedb_deep_free(knot_zonedb_t **db)
+{
+ if (db == NULL || *db == NULL) {
+ return;
+ }
+
+ knot_zonedb_foreach(*db, discard_zone);
+ knot_zonedb_free(db);
+}
diff --git a/src/knot/zone/zonedb.h b/src/knot/zone/zonedb.h
new file mode 100644
index 0000000..c5fab4d
--- /dev/null
+++ b/src/knot/zone/zonedb.h
@@ -0,0 +1,123 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief Zone database represents a list of managed zones.
+ */
+
+#pragma once
+
+#include "knot/zone/zone.h"
+#include "libknot/dname.h"
+#include "contrib/qp-trie/trie.h"
+
+typedef struct {
+ trie_t *trie;
+ knot_mm_t mm;
+} knot_zonedb_t;
+
+/*
+ * Mapping of iterators to internal data structure.
+ */
+typedef trie_it_t knot_zonedb_iter_t;
+#define knot_zonedb_iter_begin(db) trie_it_begin((db)->trie)
+#define knot_zonedb_iter_finished(it) trie_it_finished(it)
+#define knot_zonedb_iter_next(it) trie_it_next(it)
+#define knot_zonedb_iter_free(it) trie_it_free(it)
+#define knot_zonedb_iter_val(it) *trie_it_val(it)
+
+/*
+ * Simple foreach() access with callback and variable number of callback params.
+ */
+#define knot_zonedb_foreach(db, callback, ...) \
+{ \
+ knot_zonedb_iter_t *it = knot_zonedb_iter_begin((db)); \
+ while(!knot_zonedb_iter_finished(it)) { \
+ callback((zone_t *)knot_zonedb_iter_val(it), ##__VA_ARGS__); \
+ knot_zonedb_iter_next(it); \
+ } \
+ knot_zonedb_iter_free(it); \
+}
+
+/*!
+ * \brief Allocates and initializes the zone database structure.
+ *
+ * \return Pointer to the created zone database structure or NULL if an error
+ * occurred.
+ */
+knot_zonedb_t *knot_zonedb_new(void);
+
+/*!
+ * \brief Adds new zone to the database.
+ *
+ * \param db Zone database to store the zone.
+ * \param zone Parsed zone.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EZONEIN
+ */
+int knot_zonedb_insert(knot_zonedb_t *db, zone_t *zone);
+
+/*!
+ * \brief Removes the given zone from the database if it exists.
+ *
+ * \param db Zone database to remove from.
+ * \param zone_name Name of the zone to be removed.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_ENOZONE
+ */
+int knot_zonedb_del(knot_zonedb_t *db, const knot_dname_t *zone_name);
+
+/*!
+ * \brief Finds zone exactly matching the given zone name.
+ *
+ * \param db Zone database to search in.
+ * \param zone_name Domain name representing the zone name.
+ *
+ * \return Zone with \a zone_name being the owner of the zone apex or NULL if
+ * not found.
+ */
+zone_t *knot_zonedb_find(knot_zonedb_t *db, const knot_dname_t *zone_name);
+
+/*!
+ * \brief Finds zone the given domain name should belong to.
+ *
+ * \param db Zone database to search in.
+ * \param zone_name Domain name to find zone for.
+ *
+ * \retval Zone in which the domain name should be present or NULL if no such
+ * zone is found.
+ */
+zone_t *knot_zonedb_find_suffix(knot_zonedb_t *db, const knot_dname_t *zone_name);
+
+size_t knot_zonedb_size(const knot_zonedb_t *db);
+
+/*!
+ * \brief Destroys and deallocates the zone database structure (but not the
+ * zones within).
+ *
+ * \param db Zone database to be destroyed.
+ */
+void knot_zonedb_free(knot_zonedb_t **db);
+
+/*!
+ * \brief Destroys and deallocates the whole zone database including the zones.
+ *
+ * \param db Zone database to be destroyed.
+ */
+void knot_zonedb_deep_free(knot_zonedb_t **db);
diff --git a/src/knot/zone/zonefile.c b/src/knot/zone/zonefile.c
new file mode 100644
index 0000000..37fc90b
--- /dev/null
+++ b/src/knot/zone/zonefile.c
@@ -0,0 +1,343 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "libknot/libknot.h"
+#include "contrib/files.h"
+#include "knot/common/log.h"
+#include "knot/dnssec/zone-nsec.h"
+#include "knot/zone/semantic-check.h"
+#include "knot/zone/contents.h"
+#include "knot/zone/zonefile.h"
+#include "knot/zone/zone-dump.h"
+
+#define ERROR(zone, fmt, ...) log_zone_error(zone, "zone loader, " fmt, ##__VA_ARGS__)
+#define WARNING(zone, fmt, ...) log_zone_warning(zone, "zone loader, " fmt, ##__VA_ARGS__)
+#define NOTICE(zone, fmt, ...) log_zone_notice(zone, "zone loader, " fmt, ##__VA_ARGS__)
+
+static void process_error(zs_scanner_t *s)
+{
+ zcreator_t *zc = s->process.data;
+ const knot_dname_t *zname = zc->z->apex->owner;
+
+ ERROR(zname, "%s in zone, file '%s', line %"PRIu64" (%s)",
+ s->error.fatal ? "fatal error" : "error",
+ s->file.name, s->line_counter,
+ zs_strerror(s->error.code));
+}
+
+static bool handle_err(zcreator_t *zc, const knot_rrset_t *rr, int ret, bool master)
+{
+ const knot_dname_t *zname = zc->z->apex->owner;
+
+ char buff[KNOT_DNAME_TXT_MAXLEN + 1];
+ char *owner = knot_dname_to_str(buff, rr->owner, sizeof(buff));
+ if (owner == NULL) {
+ owner = "";
+ }
+
+ if (ret == KNOT_EOUTOFZONE) {
+ WARNING(zname, "ignoring out-of-zone data, owner %s", owner);
+ return true;
+ } else if (ret == KNOT_ETTL) {
+ char type[16] = { '\0' };
+ knot_rrtype_to_string(rr->type, type, sizeof(type));
+ NOTICE(zname, "TTL mismatch, owner %s, type %s, TTL set to %u",
+ owner, type, rr->ttl);
+ return true;
+ } else {
+ ERROR(zname, "failed to process record, owner %s", owner);
+ return false;
+ }
+}
+
+int zcreator_step(zcreator_t *zc, const knot_rrset_t *rr)
+{
+ if (zc == NULL || rr == NULL || rr->rrs.count != 1) {
+ return KNOT_EINVAL;
+ }
+
+ if (rr->type == KNOT_RRTYPE_SOA &&
+ node_rrtype_exists(zc->z->apex, KNOT_RRTYPE_SOA)) {
+ // Ignore extra SOA
+ return KNOT_EOK;
+ }
+
+ zone_node_t *node = NULL;
+ int ret = zone_contents_add_rr(zc->z, rr, &node);
+ if (ret != KNOT_EOK) {
+ if (!handle_err(zc, rr, ret, zc->master)) {
+ // Fatal error
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+/*! \brief Creates RR from parser input, passes it to handling function. */
+static void process_data(zs_scanner_t *scanner)
+{
+ zcreator_t *zc = scanner->process.data;
+ if (zc->ret != KNOT_EOK) {
+ scanner->state = ZS_STATE_STOP;
+ return;
+ }
+
+ knot_dname_t *owner = knot_dname_copy(scanner->r_owner, NULL);
+ if (owner == NULL) {
+ zc->ret = KNOT_ENOMEM;
+ return;
+ }
+
+ knot_rrset_t rr;
+ knot_rrset_init(&rr, owner, scanner->r_type, scanner->r_class, scanner->r_ttl);
+
+ int ret = knot_rrset_add_rdata(&rr, scanner->r_data, scanner->r_data_length, NULL);
+ if (ret != KNOT_EOK) {
+ knot_rrset_clear(&rr, NULL);
+ zc->ret = ret;
+ return;
+ }
+
+ /* Convert RDATA dnames to lowercase before adding to zone. */
+ ret = knot_rrset_rr_to_canonical(&rr);
+ if (ret != KNOT_EOK) {
+ knot_rrset_clear(&rr, NULL);
+ zc->ret = ret;
+ return;
+ }
+
+ zc->ret = zcreator_step(zc, &rr);
+ knot_rrset_clear(&rr, NULL);
+}
+
+int zonefile_open(zloader_t *loader, const char *source,
+ const knot_dname_t *origin, bool semantic_checks, time_t time)
+{
+ if (!loader) {
+ return KNOT_EINVAL;
+ }
+
+ memset(loader, 0, sizeof(zloader_t));
+
+ /* Check zone file. */
+ if (access(source, F_OK | R_OK) != 0) {
+ return KNOT_EACCES;
+ }
+
+ /* Create context. */
+ zcreator_t *zc = malloc(sizeof(zcreator_t));
+ if (zc == NULL) {
+ return KNOT_ENOMEM;
+ }
+ memset(zc, 0, sizeof(zcreator_t));
+
+ zc->z = zone_contents_new(origin);
+ if (zc->z == NULL) {
+ free(zc);
+ return KNOT_ENOMEM;
+ }
+
+ /* Prepare textual owner for zone scanner. */
+ char *origin_str = knot_dname_to_str_alloc(origin);
+ if (origin_str == NULL) {
+ zone_contents_deep_free(zc->z);
+ free(zc);
+ return KNOT_ENOMEM;
+ }
+
+ if (zs_init(&loader->scanner, origin_str, KNOT_CLASS_IN, 3600) != 0 ||
+ zs_set_input_file(&loader->scanner, source) != 0 ||
+ zs_set_processing(&loader->scanner, process_data, process_error, zc) != 0) {
+ zs_deinit(&loader->scanner);
+ free(origin_str);
+ zone_contents_deep_free(zc->z);
+ free(zc);
+ return KNOT_EFILE;
+ }
+ free(origin_str);
+
+ loader->source = strdup(source);
+ loader->creator = zc;
+ loader->semantic_checks = semantic_checks;
+ loader->time = time;
+
+ return KNOT_EOK;
+}
+
+zone_contents_t *zonefile_load(zloader_t *loader)
+{
+ if (!loader) {
+ return NULL;
+ }
+
+ zcreator_t *zc = loader->creator;
+ const knot_dname_t *zname = zc->z->apex->owner;
+
+ assert(zc);
+ int ret = zs_parse_all(&loader->scanner);
+ if (ret != 0 && loader->scanner.error.counter == 0) {
+ ERROR(zname, "failed to load zone, file '%s' (%s)",
+ loader->source, zs_strerror(loader->scanner.error.code));
+ goto fail;
+ }
+
+ if (zc->ret != KNOT_EOK) {
+ ERROR(zname, "failed to load zone, file '%s' (%s)",
+ loader->source, knot_strerror(zc->ret));
+ goto fail;
+ }
+
+ if (loader->scanner.error.counter > 0) {
+ ERROR(zname, "failed to load zone, file '%s', %"PRIu64" errors",
+ loader->source, loader->scanner.error.counter);
+ goto fail;
+ }
+
+ if (!node_rrtype_exists(loader->creator->z->apex, KNOT_RRTYPE_SOA)) {
+ loader->err_handler->fatal_error = true;
+ loader->err_handler->cb(loader->err_handler, zc->z, NULL,
+ SEM_ERR_SOA_NONE, NULL);
+ goto fail;
+ }
+
+ ret = zone_contents_adjust_full(zc->z);
+ if (ret != KNOT_EOK) {
+ ERROR(zname, "failed to finalize zone contents (%s)",
+ knot_strerror(ret));
+ goto fail;
+ }
+
+ ret = sem_checks_process(zc->z, loader->semantic_checks,
+ loader->err_handler, loader->time);
+
+ if (ret != KNOT_EOK) {
+ ERROR(zname, "failed to load zone, file '%s' (%s)",
+ loader->source, knot_strerror(ret));
+ goto fail;
+ }
+
+ return zc->z;
+
+fail:
+ zone_contents_deep_free(zc->z);
+ return NULL;
+}
+
+int zonefile_exists(const char *path, time_t *mtime)
+{
+ if (path == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ struct stat zonefile_st = { 0 };
+ if (stat(path, &zonefile_st) < 0) {
+ return knot_map_errno();
+ }
+
+ if (mtime != NULL) {
+ *mtime = zonefile_st.st_mtime;
+ }
+
+ return KNOT_EOK;
+}
+
+int zonefile_write(const char *path, zone_contents_t *zone)
+{
+ if (!zone || !path) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = make_path(path, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ FILE *file = NULL;
+ char *tmp_name = NULL;
+ ret = open_tmp_file(path, &tmp_name, &file, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = zone_dump_text(zone, file, true);
+ fclose(file);
+ if (ret != KNOT_EOK) {
+ unlink(tmp_name);
+ free(tmp_name);
+ return ret;
+ }
+
+ /* Swap temporary zonefile and new zonefile. */
+ ret = rename(tmp_name, path);
+ if (ret != 0) {
+ ret = knot_map_errno();
+ unlink(tmp_name);
+ free(tmp_name);
+ return ret;
+ }
+
+ free(tmp_name);
+
+ return KNOT_EOK;
+}
+
+void zonefile_close(zloader_t *loader)
+{
+ if (!loader) {
+ return;
+ }
+
+ zs_deinit(&loader->scanner);
+ free(loader->source);
+ free(loader->creator);
+}
+
+void err_handler_logger(sem_handler_t *handler, const zone_contents_t *zone,
+ const zone_node_t *node, sem_error_t error, const char *data)
+{
+ assert(handler != NULL);
+ assert(zone != NULL);
+
+ char buff[KNOT_DNAME_TXT_MAXLEN + 1] = "";
+ if (node != NULL) {
+ (void)knot_dname_to_str(buff, node->owner, sizeof(buff));
+ }
+
+ log_fmt_zone(handler->fatal_error ? LOG_ERR : LOG_WARNING,
+ LOG_SOURCE_ZONE, zone->apex->owner, NULL,
+ "check%s%s, %s%s%s",
+ (node != NULL ? ", node " : ""),
+ (node != NULL ? buff : ""),
+ sem_error_msg(error),
+ (data != NULL ? " " : ""),
+ (data != NULL ? data : ""));
+}
+
+#undef ERROR
+#undef WARNING
+#undef NOTICE
diff --git a/src/knot/zone/zonefile.h b/src/knot/zone/zonefile.h
new file mode 100644
index 0000000..90283ee
--- /dev/null
+++ b/src/knot/zone/zonefile.h
@@ -0,0 +1,104 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdio.h>
+
+#include "knot/zone/zone.h"
+#include "knot/zone/semantic-check.h"
+#include "libzscanner/scanner.h"
+/*!
+ * \brief Zone creator structure.
+ */
+typedef struct zcreator {
+ zone_contents_t *z; /*!< Created zone. */
+ bool master; /*!< True if server is a primary master for the zone. */
+ int ret; /*!< Return value. */
+} zcreator_t;
+
+/*!
+ * \brief Zone loader structure.
+ */
+typedef struct {
+ char *source; /*!< Zone source file. */
+ bool semantic_checks; /*!< Do semantic checks. */
+ sem_handler_t *err_handler; /*!< Semantic checks error handler. */
+ zcreator_t *creator; /*!< Loader context. */
+ zs_scanner_t scanner; /*!< Zone scanner. */
+ time_t time; /*!< time for zone check. */
+} zloader_t;
+
+void err_handler_logger(sem_handler_t *handler, const zone_contents_t *zone,
+ const zone_node_t *node, sem_error_t error, const char *data);
+
+/*!
+ * \brief Open zone file for loading.
+ *
+ * \param loader Output zone loader.
+ * \param source Source file name.
+ * \param origin Zone origin.
+ * \param semantic_checks Perform semantic checks.
+ * \param time Time for semantic check.
+ *
+ * \retval Initialized loader on success.
+ * \retval NULL on error.
+ */
+int zonefile_open(zloader_t *loader, const char *source,
+ const knot_dname_t *origin, bool semantic_checks, time_t time);
+
+/*!
+ * \brief Loads zone from a zone file.
+ *
+ * \param loader Zone loader instance.
+ *
+ * \retval Loaded zone contents on success.
+ * \retval NULL otherwise.
+ */
+zone_contents_t *zonefile_load(zloader_t *loader);
+
+/*!
+ * \brief Checks if zonefile exists.
+ *
+ * \param path Zonefile path.
+ * \param mtime Zonefile mtime if exists (can be NULL).
+ *
+ * \return KNOT_E*
+ */
+int zonefile_exists(const char *path, time_t *mtime);
+
+/*!
+ * \brief Write zone contents to zone file.
+ */
+int zonefile_write(const char *path, zone_contents_t *zone);
+
+/*!
+ * \brief Close zone file loader.
+ *
+ * \param loader Zone loader instance.
+ */
+void zonefile_close(zloader_t *loader);
+
+/*!
+ * \brief Adds one RR into zone.
+ *
+ * \param zl Zone loader.
+ * \param rr RR to add.
+ *
+ * \return KNOT_E*
+ */
+int zcreator_step(zcreator_t *zl, const knot_rrset_t *rr);
diff --git a/src/knotd.pc.in b/src/knotd.pc.in
new file mode 100644
index 0000000..6db74ca
--- /dev/null
+++ b/src/knotd.pc.in
@@ -0,0 +1,9 @@
+prefix=@prefix@
+exec_prefix=@prefix@
+libdir=@libdir@
+module_instdir=@module_instdir@
+
+Name: knotd
+Description: Knot DNS daemon
+URL: https://www.knot-dns.cz
+Version: @PACKAGE_VERSION@
diff --git a/src/libdnssec.pc.in b/src/libdnssec.pc.in
new file mode 100644
index 0000000..6c0aa5c
--- /dev/null
+++ b/src/libdnssec.pc.in
@@ -0,0 +1,13 @@
+prefix=@prefix@
+exec_prefix=@prefix@
+libdir=@libdir@
+includedir=@includedir@
+soname=@libdnssec_SONAME@
+
+Name: libdnssec
+Description: Knot DNS DNSSEC library
+URL: https://www.knot-dns.cz
+Version: @PACKAGE_VERSION@
+Requires.private: gnutls >= 3.3
+Libs: -L${libdir} -ldnssec
+Cflags: -I${includedir}
diff --git a/src/libdnssec/Makefile.inc b/src/libdnssec/Makefile.inc
new file mode 100644
index 0000000..112f95b
--- /dev/null
+++ b/src/libdnssec/Makefile.inc
@@ -0,0 +1,87 @@
+lib_LTLIBRARIES += libdnssec.la
+pkgconfig_DATA += libdnssec.pc
+
+noinst_LTLIBRARIES += libshared.la
+
+libshared_la_CPPFLAGS = $(AM_CPPFLAGS) $(gnutls_CFLAGS)
+
+libshared_la_SOURCES = \
+ libdnssec/shared/bignum.c \
+ libdnssec/shared/bignum.h \
+ libdnssec/shared/binary_wire.h \
+ libdnssec/shared/dname.c \
+ libdnssec/shared/dname.h \
+ libdnssec/shared/fs.c \
+ libdnssec/shared/fs.h \
+ libdnssec/shared/hex.c \
+ libdnssec/shared/hex.h \
+ libdnssec/shared/keyid_gnutls.c \
+ libdnssec/shared/keyid_gnutls.h \
+ libdnssec/shared/pem.c \
+ libdnssec/shared/pem.h \
+ libdnssec/shared/shared.h
+
+libdnssec_la_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAG_VISIBILITY) $(gnutls_CFLAGS)
+libdnssec_la_LDFLAGS = $(AM_LDFLAGS) $(libdnssec_VERSION_INFO) $(gnutls_LIBS)
+if EXCLUDE_LIBS_LIBDNSSEC
+libdnssec_la_LDFLAGS += $(LDFLAG_EXCLUDE_LIBS)
+endif
+libdnssec_la_LIBADD = libshared.la
+if ENABLE_PKCS11
+libdnssec_la_LIBADD += $(pthread_LIBS)
+endif
+
+include_libdnssecdir = $(includedir)/libdnssec
+include_libdnssec_HEADERS = \
+ libdnssec/binary.h \
+ libdnssec/crypto.h \
+ libdnssec/dnssec.h \
+ libdnssec/error.h \
+ libdnssec/key.h \
+ libdnssec/keyid.h \
+ libdnssec/keystore.h \
+ libdnssec/keytag.h \
+ libdnssec/list.h \
+ libdnssec/nsec.h \
+ libdnssec/random.h \
+ libdnssec/sign.h \
+ libdnssec/tsig.h \
+ libdnssec/version.h
+
+libdnssec_la_SOURCES = \
+ libdnssec/contrib/vpool.c \
+ libdnssec/contrib/vpool.h \
+ libdnssec/binary.c \
+ libdnssec/crypto.c \
+ libdnssec/error.c \
+ libdnssec/key/algorithm.c \
+ libdnssec/key/algorithm.h \
+ libdnssec/key/convert.c \
+ libdnssec/key/convert.h \
+ libdnssec/key/dnskey.c \
+ libdnssec/key/dnskey.h \
+ libdnssec/key/ds.c \
+ libdnssec/key/internal.h \
+ libdnssec/key/key.c \
+ libdnssec/key/keytag.c \
+ libdnssec/key/privkey.c \
+ libdnssec/key/privkey.h \
+ libdnssec/key/simple.c \
+ libdnssec/keyid.c \
+ libdnssec/keystore/internal.h \
+ libdnssec/keystore/keystore.c \
+ libdnssec/keystore/pkcs11.c \
+ libdnssec/keystore/pkcs8.c \
+ libdnssec/keystore/pkcs8_dir.c \
+ libdnssec/list/list.c \
+ libdnssec/list/ucw_clists.h \
+ libdnssec/nsec/bitmap.c \
+ libdnssec/nsec/hash.c \
+ libdnssec/nsec/nsec.c \
+ libdnssec/p11/p11.c \
+ libdnssec/p11/p11.h \
+ libdnssec/random.c \
+ libdnssec/sign/der.c \
+ libdnssec/sign/der.h \
+ libdnssec/sign/sign.c \
+ libdnssec/tsig.c
diff --git a/src/libdnssec/binary.c b/src/libdnssec/binary.c
new file mode 100644
index 0000000..a57b421
--- /dev/null
+++ b/src/libdnssec/binary.c
@@ -0,0 +1,169 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <string.h>
+
+#include "libdnssec/binary.h"
+#include "libdnssec/error.h"
+#include "libdnssec/shared/shared.h"
+
+// Workaround for symbol redefinition if linked statically.
+#define base64_encode base64encode
+#define base64_decode base64decode
+#define base64_encode_alloc base64encodealloc
+#define base64_decode_alloc base64decodealloc
+#include "contrib/base64.c"
+
+/* -- public API ----------------------------------------------------------- */
+
+_public_
+int dnssec_binary_alloc(dnssec_binary_t *data, size_t size)
+{
+ if (!data || size == 0) {
+ return DNSSEC_EINVAL;
+ }
+
+ uint8_t *new_data = calloc(1, size);
+ if (!new_data) {
+ return DNSSEC_ENOMEM;
+ }
+
+ data->data = new_data;
+ data->size = size;
+
+ return DNSSEC_EOK;
+}
+
+_public_
+void dnssec_binary_free(dnssec_binary_t *binary)
+{
+ if (!binary) {
+ return;
+ }
+
+ free(binary->data);
+ clear_struct(binary);
+}
+
+_public_
+int dnssec_binary_dup(const dnssec_binary_t *from, dnssec_binary_t *to)
+{
+ if (!from || !to) {
+ return DNSSEC_EINVAL;
+ }
+
+ uint8_t *copy = malloc(from->size);
+ if (copy == NULL) {
+ return DNSSEC_ENOMEM;
+ }
+
+ memmove(copy, from->data, from->size);
+
+ to->size = from->size;
+ to->data = copy;
+
+ return DNSSEC_EOK;
+}
+
+_public_
+int dnssec_binary_resize(dnssec_binary_t *data, size_t new_size)
+{
+ if (!data) {
+ return DNSSEC_EINVAL;
+ }
+
+ uint8_t *new_data = realloc(data->data, new_size);
+ if (new_size > 0 && new_data == NULL) {
+ return DNSSEC_ENOMEM;
+ }
+
+ data->data = new_data;
+ data->size = new_size;
+
+ return DNSSEC_EOK;
+}
+
+_public_
+int dnssec_binary_cmp(const dnssec_binary_t *one, const dnssec_binary_t *two)
+{
+ if (one == two) {
+ return 0;
+ }
+
+ uint8_t *data_one = one && one->size > 0 ? one->data : NULL;
+ uint8_t *data_two = two && two->size > 0 ? two->data : NULL;
+
+ if (data_one == data_two) {
+ return 0;
+ } else if (data_one == NULL) {
+ return -1;
+ } else if (data_two == NULL) {
+ return +1;
+ }
+
+ size_t min_size = one->size <= two->size ? one->size : two->size;
+ int cmp = memcmp(data_one, data_two, min_size);
+ if (cmp != 0) {
+ return cmp;
+ } else if (one->size == two->size) {
+ return 0;
+ } else if (one->size < two->size) {
+ return -1;
+ } else {
+ return +1;
+ }
+}
+
+_public_
+int dnssec_binary_from_base64(const dnssec_binary_t *base64,
+ dnssec_binary_t *binary)
+{
+ if (!base64 || !binary) {
+ return DNSSEC_EINVAL;
+ }
+
+ uint8_t *data;
+ int32_t size = base64_decode_alloc(base64->data, base64->size, &data);
+ if (size < 0) {
+ return DNSSEC_EINVAL;
+ }
+
+ binary->data = data;
+ binary->size = size;
+
+ return DNSSEC_EOK;
+}
+
+_public_
+int dnssec_binary_to_base64(const dnssec_binary_t *binary,
+ dnssec_binary_t *base64)
+{
+ if (!binary || !base64) {
+ return DNSSEC_EINVAL;
+ }
+
+ uint8_t *data;
+ int32_t size = base64_encode_alloc(binary->data, binary->size, &data);
+ if (size < 0) {
+ return DNSSEC_EINVAL;
+ }
+
+ base64->data = data;
+ base64->size = size;
+
+ return DNSSEC_EOK;
+}
diff --git a/src/libdnssec/binary.h b/src/libdnssec/binary.h
new file mode 100644
index 0000000..fb0cf9b
--- /dev/null
+++ b/src/libdnssec/binary.h
@@ -0,0 +1,133 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*!
+ * \file
+ *
+ * \addtogroup binary
+ *
+ * \brief Universal binary data container.
+ *
+ * The module provides universal binary data container extensively used by
+ * a lot of functions provided by the library.
+ *
+ * Example of use:
+ * ~~~~~ {.c}
+ *
+ * dnssec_binary_t data = { 0 };
+ *
+ * int result = dnssec_binary_alloc(&data, 32);
+ * if (result != DNSSEC_EOK) {
+ * return result;
+ * }
+ *
+ * memcpy(&data.data, buffer, data.size);
+ *
+ * // ...
+ *
+ * dnssec_binary_free(&data);
+ *
+ * ~~~~~
+ *
+ * @{
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdlib.h>
+
+/*!
+ * Universal structure to hold binary data.
+ */
+typedef struct dnssec_binary {
+ size_t size; /*!< Size of the binary data. */
+ uint8_t *data; /*!< Stored data. */
+} dnssec_binary_t;
+
+/*!
+ * Allocate new binary data structure.
+ *
+ * \param[out] data Binary to be allocated.
+ * \param[in] size Requested size of the binary.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int dnssec_binary_alloc(dnssec_binary_t *data, size_t size);
+
+/*!
+ * Free content of binary structure.
+ *
+ * \param binary Binary structure to be freed.
+ */
+void dnssec_binary_free(dnssec_binary_t *binary);
+
+/*!
+ * Create a copy of a binary structure.
+ *
+ * \param[in] from Source of the copy.
+ * \param[out] to Target of the copy.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int dnssec_binary_dup(const dnssec_binary_t *from, dnssec_binary_t *to);
+
+/*!
+ * Resize binary structure to a new size.
+ *
+ * Internally uses realloc, which means that this function can be also used
+ * as a malloc or free.
+ *
+ * \param data Binary to be resized.
+ * \param new_size New size.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int dnssec_binary_resize(dnssec_binary_t *data, size_t new_size);
+
+/*!
+ * Compare two binary structures (equivalent of memcmp).
+ *
+ * \note NULL sorts before data.
+ *
+ * \param one First binary.
+ * \param two Second binary.
+ *
+ * \return 0 if one equals two, <0 if one sorts before two, >0 otherwise.
+ */
+int dnssec_binary_cmp(const dnssec_binary_t *one, const dnssec_binary_t *two);
+
+/*!
+ * Allocate binary from Base64 encoded string.
+ *
+ * \param[in] base64 Base64 encoded data.
+ * \param[out] binary Decoded binary data.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int dnssec_binary_from_base64(const dnssec_binary_t *base64,
+ dnssec_binary_t *binary);
+
+/*!
+ * Create Base64 encoded string from binary data.
+ *
+ * \param[in] binary Binary data.
+ * \param[out] base64 Base64 encode data.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int dnssec_binary_to_base64(const dnssec_binary_t *binary,
+ dnssec_binary_t *base64);
+/*! @} */
diff --git a/src/libdnssec/contrib/vpool.c b/src/libdnssec/contrib/vpool.c
new file mode 100644
index 0000000..d2e1006
--- /dev/null
+++ b/src/libdnssec/contrib/vpool.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2006, 2008 Alexey Vatchenko <av@bsdua.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libdnssec/contrib/vpool.h"
+
+static void vpool_shift(struct vpool *pool);
+static int vpool_new_size(struct vpool *pool, size_t datsize,
+ size_t *size);
+static int vpool_resize(struct vpool *pool, size_t datsize);
+
+static void
+vpool_shift(struct vpool *pool)
+{
+ if (pool->v_buf != pool->v_basebuf) {
+ memmove(pool->v_basebuf, pool->v_buf, pool->v_off);
+ pool->v_buf = pool->v_basebuf;
+ }
+}
+
+static int
+vpool_new_size(struct vpool *pool, size_t datsize, size_t *size)
+{
+ size_t need;
+ size_t rem;
+
+ if (datsize <= pool->v_size - pool->v_off) {
+ *size = pool->v_size;
+ return (0);
+ }
+
+ /* Check limit of new requested size */
+ if (pool->v_limit - pool->v_off < datsize) {
+ return (EFBIG);
+ }
+ need = pool->v_off + datsize;
+
+ /* Check limit of new size aligned to block size */
+ rem = need % pool->v_blksize;
+ if (rem != 0) {
+ if (pool->v_limit - pool->v_off >=
+ datsize + (pool->v_blksize - rem)) {
+ need += pool->v_blksize - rem;
+ } else {
+ need = pool->v_limit;
+ }
+ }
+
+ *size = need;
+ return (0);
+}
+
+static int
+vpool_resize(struct vpool *pool, size_t datsize)
+{
+ void *ret;
+ size_t size;
+ int error;
+
+ error = vpool_new_size(pool, datsize, &size);
+ if (error != 0) {
+ return (error);
+ }
+
+ if (size > pool->v_size) {
+ ret = malloc(size);
+ if (ret == NULL) {
+ return (ENOMEM);
+ }
+
+ memcpy(ret, pool->v_buf, pool->v_off);
+ free(pool->v_basebuf);
+ pool->v_basebuf = pool->v_buf = ret;
+ pool->v_size = size;
+ } else if ((pool->v_size - pool->v_off) -
+ (pool->v_buf - pool->v_basebuf) < datsize) {
+ vpool_shift(pool);
+ }
+
+ return (0);
+}
+
+void
+vpool_init(struct vpool *pool, size_t blksize, size_t limit)
+{
+
+ pool->v_basebuf = pool->v_buf = NULL;
+ pool->v_off = pool->v_size = 0;
+
+ pool->v_blksize = (blksize == 0) ? 4096 : blksize; /* XXX */
+ pool->v_limit = (limit == 0) ? SIZE_MAX : limit;
+
+ pool->v_lasterr = 0;
+}
+
+void
+vpool_final(struct vpool *pool)
+{
+ free(pool->v_basebuf);
+}
+
+void
+vpool_reset(struct vpool *pool)
+{
+ free(pool->v_basebuf);
+ pool->v_basebuf = pool->v_buf = NULL;
+ pool->v_off = pool->v_size = 0;
+ pool->v_lasterr = 0;
+}
+
+void
+vpool_wipe(struct vpool *pool)
+{
+ pool->v_off = 0;
+ pool->v_lasterr = 0;
+}
+
+void *
+vpool_insert(struct vpool *pool, size_t where, void *data, size_t datsize)
+{
+ void *ret;
+ int error;
+
+ error = vpool_resize(pool, datsize);
+ if (error != 0) {
+ pool->v_lasterr = error;
+ return (NULL);
+ }
+
+ /*
+ * If ``where'' is greater than or equal to offset then
+ * we are appending data to the end of the buffer.
+ */
+ if (where > pool->v_off) {
+ where = pool->v_off;
+ }
+
+ ret = (uint8_t *)pool->v_buf + where;
+ if (pool->v_off - where > 0) {
+ memmove(ret + datsize, ret, pool->v_off - where);
+ }
+ memcpy(ret, data, datsize);
+ pool->v_off += datsize;
+ pool->v_lasterr = 0;
+
+ return (ret);
+}
+
+void *
+vpool_expand(struct vpool *pool, size_t where, size_t size)
+{
+ void *ret;
+ int error;
+
+ error = vpool_resize(pool, size);
+ if (error != 0) {
+ pool->v_lasterr = error;
+ return (NULL);
+ }
+
+ /*
+ * If ``where'' is greater than or equal to offset then
+ * we are appending data to the end of the buffer.
+ */
+ if (where > pool->v_off) {
+ where = pool->v_off;
+ }
+
+ ret = (uint8_t *)pool->v_buf + where;
+ if (pool->v_off - where > 0) {
+ memmove(ret + size, ret, pool->v_off - where);
+ }
+ pool->v_off += size;
+ pool->v_lasterr = 0;
+
+ return (ret);
+}
+
+int
+vpool_truncate(struct vpool *pool,
+ size_t where, size_t size, enum vpool_trunc how)
+{
+ /* Check if caller wants to remove more data than we have */
+ if (where >= pool->v_off ||
+ size > pool->v_off || pool->v_off - size < where) {
+ pool->v_lasterr = ERANGE;
+ return (pool->v_lasterr);
+ }
+
+ if (how == VPOOL_EXCLUDE) {
+ if (where == 0) {
+ /*
+ * Optimization.
+ * Don't move data, just adjust pointer.
+ */
+ pool->v_buf = (uint8_t *)pool->v_buf + size;
+ } else {
+ memmove((uint8_t *)pool->v_buf + where,
+ (uint8_t *)pool->v_buf + where + size,
+ pool->v_off - size - where);
+ }
+ pool->v_off -= size;
+ } else {
+ pool->v_buf = (uint8_t *)pool->v_buf + where;
+ pool->v_off = size;
+ }
+
+ pool->v_lasterr = 0;
+ return (0);
+}
+
+void
+vpool_export(struct vpool *pool, void **buf, size_t *size)
+{
+ vpool_shift(pool);
+ *buf = pool->v_buf;
+ *size = pool->v_off;
+ pool->v_basebuf = pool->v_buf = NULL;
+ pool->v_off = pool->v_size = 0;
+ pool->v_lasterr = 0;
+}
diff --git a/src/libdnssec/contrib/vpool.h b/src/libdnssec/contrib/vpool.h
new file mode 100644
index 0000000..82e3d66
--- /dev/null
+++ b/src/libdnssec/contrib/vpool.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2006, 2008 Alexey Vatchenko <av@bsdua.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * VPool: implementation of pool of data with a variable size.
+ */
+#ifndef _VPOOL_H_
+#define _VPOOL_H_
+
+#include <stddef.h>
+#include <limits.h>
+
+struct vpool {
+ void *v_basebuf; /* pointer returned by (re|m)alloc() */
+ void *v_buf; /* actual data starts here */
+ size_t v_off;
+ size_t v_size;
+
+ size_t v_blksize;
+ size_t v_limit;
+ int v_lasterr;
+};
+
+enum vpool_trunc {VPOOL_EXCLUDE, VPOOL_INCLUDE};
+#define VPOOL_TAIL UINT_MAX
+
+void vpool_init(struct vpool *pool, size_t blksize, size_t limit);
+void vpool_final(struct vpool *pool);
+
+void vpool_reset(struct vpool *pool);
+void vpool_wipe(struct vpool *pool);
+
+void * vpool_insert(struct vpool *pool,
+ size_t where, void *data, size_t datsize);
+void * vpool_expand(struct vpool *pool, size_t where, size_t size);
+
+int vpool_truncate(struct vpool *pool,
+ size_t where, size_t size, enum vpool_trunc how);
+
+#define vpool_is_empty(pool) ((pool)->v_off == 0)
+#define vpool_get_buf(pool) ((pool)->v_buf)
+#define vpool_get_length(pool) ((pool)->v_off)
+#define vpool_get_error(pool) ((pool)->v_lasterr)
+
+void vpool_export(struct vpool *pool, void **buf, size_t *size);
+
+#endif /* !_VPOOL_H_ */
diff --git a/src/libdnssec/crypto.c b/src/libdnssec/crypto.c
new file mode 100644
index 0000000..f54e20f
--- /dev/null
+++ b/src/libdnssec/crypto.c
@@ -0,0 +1,42 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <gnutls/gnutls.h>
+#include <gnutls/pkcs11.h>
+
+#include "libdnssec/crypto.h"
+#include "libdnssec/p11/p11.h"
+#include "libdnssec/shared/shared.h"
+
+_public_
+void dnssec_crypto_init(void)
+{
+ p11_init();
+ gnutls_global_init();
+}
+
+_public_
+void dnssec_crypto_cleanup(void)
+{
+ gnutls_global_deinit();
+ p11_cleanup();
+}
+
+_public_
+void dnssec_crypto_reinit(void)
+{
+ p11_reinit();
+}
diff --git a/src/libdnssec/crypto.h b/src/libdnssec/crypto.h
new file mode 100644
index 0000000..46541b4
--- /dev/null
+++ b/src/libdnssec/crypto.h
@@ -0,0 +1,74 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*!
+ * \file
+ *
+ * \addtogroup crypto
+ *
+ * \brief Cryptographic backend initialization.
+ *
+ * For most cryptographic operations, the library requires global
+ * initialization. Also, if the application creates a subprocess, the
+ * library has to be reinitialized in the child process after \c fork().
+ *
+ * ~~~~~ {.c}
+ * int main(void)
+ * {
+ * int exit_code = 0;
+ *
+ * dnssec_crypto_init();
+ *
+ * pid_t child_pid = fork();
+ * if (child_pid < 0) {
+ * perror("fork");
+ * exit_code = 1;
+ * } else if (child_pid == 0) {
+ * dnssec_crypto_reinit();
+ * exit_code = child();
+ * } else {
+ * exit_code = parent();
+ * }
+ *
+ * dnssec_crypto_cleanup();
+ * return exit_code;
+ * }
+ * ~~~~~
+ *
+ * @{
+ */
+
+#pragma once
+
+/*!
+ * Initialize cryptographic backend.
+ */
+void dnssec_crypto_init(void);
+
+/*!
+ * Reinitialize cryptographic backend.
+ *
+ * Must be called after fork() by the child.
+ */
+void dnssec_crypto_reinit(void);
+
+/*!
+ * Deinitialize cryptographic backend.
+ *
+ * Should be called when terminating the application.
+ */
+void dnssec_crypto_cleanup(void);
+
+/*! @} */
diff --git a/src/libdnssec/dnssec.h b/src/libdnssec/dnssec.h
new file mode 100644
index 0000000..8383901
--- /dev/null
+++ b/src/libdnssec/dnssec.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * \file
+ *
+ * Convenient header to include all library modules.
+ */
+
+#pragma once
+
+#include <libdnssec/binary.h>
+#include <libdnssec/crypto.h>
+#include <libdnssec/error.h>
+#include <libdnssec/key.h>
+#include <libdnssec/keyid.h>
+#include <libdnssec/keystore.h>
+#include <libdnssec/keytag.h>
+#include <libdnssec/list.h>
+#include <libdnssec/nsec.h>
+#include <libdnssec/random.h>
+#include <libdnssec/sign.h>
+#include <libdnssec/tsig.h>
diff --git a/src/libdnssec/error.c b/src/libdnssec/error.c
new file mode 100644
index 0000000..97f7f8f
--- /dev/null
+++ b/src/libdnssec/error.c
@@ -0,0 +1,84 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <string.h>
+
+#include "libdnssec/error.h"
+#include "libdnssec/shared/shared.h"
+
+typedef struct error_message_t {
+ int code;
+ const char *text;
+} error_message_t;
+
+static const error_message_t ERROR_MESSAGES[] = {
+ { DNSSEC_EOK, "no error" },
+
+ { DNSSEC_ENOMEM, "not enough memory" },
+ { DNSSEC_EINVAL, "invalid argument" },
+ { DNSSEC_ENOENT, "no such file or directory" },
+
+ { DNSSEC_ERROR, "unspecified error" },
+ { DNSSEC_NOT_IMPLEMENTED_ERROR, "not implemented" },
+ { DNSSEC_MALFORMED_DATA, "malformed data" },
+ { DNSSEC_NOT_FOUND, "not found" },
+
+ { DNSSEC_PKCS8_IMPORT_ERROR, "PKCS #8 import error" },
+ { DNSSEC_KEY_EXPORT_ERROR, "key export error" },
+ { DNSSEC_KEY_IMPORT_ERROR, "key import error" },
+ { DNSSEC_KEY_GENERATE_ERROR, "key generation error" },
+
+ { DNSSEC_INVALID_PUBLIC_KEY, "invalid public key" },
+ { DNSSEC_INVALID_PRIVATE_KEY, "invalid private key" },
+ { DNSSEC_INVALID_KEY_ALGORITHM, "invalid key algorithm" },
+ { DNSSEC_INVALID_KEY_SIZE, "invalid key size" },
+ { DNSSEC_INVALID_KEY_ID, "invalid key ID" },
+ { DNSSEC_INVALID_KEY_NAME, "invalid key name" },
+
+ { DNSSEC_NO_PUBLIC_KEY, "no public key" },
+ { DNSSEC_NO_PRIVATE_KEY, "no private key" },
+ { DNSSEC_KEY_ALREADY_PRESENT, "key already present" },
+
+ { DNSSEC_SIGN_INIT_ERROR, "signing initialization error" },
+ { DNSSEC_SIGN_ERROR, "signing error" },
+ { DNSSEC_INVALID_SIGNATURE, "invalid signature" },
+
+ { DNSSEC_INVALID_NSEC3_ALGORITHM, "invalid NSEC3 algorithm" },
+ { DNSSEC_NSEC3_HASHING_ERROR, "NSEC3 hashing error" },
+
+ { DNSSEC_INVALID_DS_ALGORITHM, "invalid DS algorithm" },
+ { DNSSEC_DS_HASHING_ERROR, "DS hashing error" },
+
+ { DNSSEC_KEYSTORE_INVALID_CONFIG, "invalid KASP keystore configuration" },
+
+ { DNSSEC_P11_FAILED_TO_LOAD_MODULE, "failed to load PKCS #11 module" },
+ { DNSSEC_P11_TOO_MANY_MODULES, "too many PKCS #11 modules loaded" },
+ { DNSSEC_P11_TOKEN_NOT_AVAILABLE, "PKCS #11 token not available" },
+
+ { 0 }
+};
+
+_public_
+const char *dnssec_strerror(int error)
+{
+ for (const error_message_t *m = ERROR_MESSAGES; m->text; m++) {
+ if (m->code == error) {
+ return m->text;
+ }
+ }
+
+ return NULL;
+}
diff --git a/src/libdnssec/error.h b/src/libdnssec/error.h
new file mode 100644
index 0000000..eaa6afd
--- /dev/null
+++ b/src/libdnssec/error.h
@@ -0,0 +1,112 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*!
+ * \file
+ *
+ * \addtogroup error
+ *
+ * \brief Error codes and error reporting.
+ *
+ * The module defines all error codes used in the library, and functions
+ * to convert the error codes to sensible error strings.
+ *
+ * ~~~~~ {.c}
+ * int result;
+ *
+ * result = dnssec_key_set_pubkey(NULL, NULL);
+ * assert(result == DNSSEC_EINVAL);
+ *
+ * fprintf(stderr, "Error: %s.\n", dnssec_strerror(result));
+ * // Error: Invalid argument.
+ * ~~~~~
+ *
+ * @{
+ */
+
+#pragma once
+
+#include <errno.h>
+
+/*!
+ * Library error codes.
+ */
+enum dnssec_error {
+ DNSSEC_EOK = 0,
+
+ DNSSEC_ENOMEM = -ENOMEM,
+ DNSSEC_EINVAL = -EINVAL,
+ DNSSEC_ENOENT = -ENOENT,
+
+ DNSSEC_ERROR_MIN = -1500,
+
+ DNSSEC_ERROR = DNSSEC_ERROR_MIN,
+ DNSSEC_NOT_IMPLEMENTED_ERROR,
+ DNSSEC_MALFORMED_DATA,
+ DNSSEC_NOT_FOUND,
+
+ DNSSEC_PKCS8_IMPORT_ERROR,
+ DNSSEC_KEY_EXPORT_ERROR,
+ DNSSEC_KEY_IMPORT_ERROR,
+ DNSSEC_KEY_GENERATE_ERROR,
+
+ DNSSEC_INVALID_PUBLIC_KEY,
+ DNSSEC_INVALID_PRIVATE_KEY,
+ DNSSEC_INVALID_KEY_ALGORITHM,
+ DNSSEC_INVALID_KEY_SIZE,
+ DNSSEC_INVALID_KEY_ID,
+ DNSSEC_INVALID_KEY_NAME,
+
+ DNSSEC_NO_PUBLIC_KEY,
+ DNSSEC_NO_PRIVATE_KEY,
+ DNSSEC_KEY_ALREADY_PRESENT,
+
+ DNSSEC_SIGN_INIT_ERROR,
+ DNSSEC_SIGN_ERROR,
+ DNSSEC_INVALID_SIGNATURE,
+
+ DNSSEC_INVALID_NSEC3_ALGORITHM,
+ DNSSEC_NSEC3_HASHING_ERROR,
+
+ DNSSEC_INVALID_DS_ALGORITHM,
+ DNSSEC_DS_HASHING_ERROR,
+
+ DNSSEC_KEYSTORE_INVALID_CONFIG,
+
+ DNSSEC_P11_FAILED_TO_LOAD_MODULE,
+ DNSSEC_P11_TOO_MANY_MODULES,
+ DNSSEC_P11_TOKEN_NOT_AVAILABLE,
+
+ DNSSEC_ERROR_MAX = -1001
+};
+
+/*!
+ * Translate error code to error message.
+ *
+ * \param error Error code.
+ *
+ * \return Statically allocated error message string or NULL if unknown.
+ */
+const char *dnssec_strerror(int error);
+
+/*!
+ * Convert errno value to DNSSEC error code.
+ */
+static inline int dnssec_errno_to_error(int ecode)
+{
+ return -ecode;
+}
+
+/*! @} */
diff --git a/src/libdnssec/key.h b/src/libdnssec/key.h
new file mode 100644
index 0000000..27de778
--- /dev/null
+++ b/src/libdnssec/key.h
@@ -0,0 +1,318 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*!
+ * \file
+ *
+ * \addtogroup key
+ *
+ * \brief DNSSEC public and private key manipulation.
+ *
+ * The dnssec_key_t is an abstraction for a DNSSEC key pair. If the key
+ * key is initialized with a public key data only, it can be used only for
+ * signature verification. In order to use the key for signing, private key
+ * has to be loaded. If only a private key is loaded into the structure,
+ * the public key is automatically constructed.
+ *
+ * The module interface provides various functions to retrieve information
+ * about the key. But the key is mostly used by other modules of the library.
+ *
+ * The following example shows construction of a key from DNSKEY RDATA:
+ *
+ * ~~~~~ {.c}
+ *
+ * dnssec_binary_t rdata = // ...;
+ *
+ * int result;
+ * dnssec_key_t *key = NULL;
+ *
+ * // create new DNSSEC key
+ * result = dnssec_key_new(&key);
+ * if (result != DNSSEC_EOK) {
+ * return result;
+ * }
+ *
+ * // load the DNSKEY RDATA
+ * result = dnssec_key_set_rdata(key, &rdata);
+ * if (result != DNSSEC_EOK) {
+ * dnssec_key_free(key);
+ * return result;
+ * }
+ *
+ * // print key tag
+ * printf("key %s\n", dnssec_key_get_keytag(key));
+ *
+ * // make sure what we can do with the key
+ * assert(dnssec_key_can_verify(key) == true);
+ * assert(dnssec_key_can_sign(key) == false);
+ *
+ * // ...
+ *
+ * // cleanup
+ * dnssec_key_free(key);
+ *
+ * ~~~~~
+ *
+ * @{
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <libdnssec/binary.h>
+
+/*!
+ * DNSKEY algorithm numbers.
+ *
+ * \see https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml
+ */
+typedef enum dnssec_key_algorithm {
+ DNSSEC_KEY_ALGORITHM_INVALID = 0,
+ DNSSEC_KEY_ALGORITHM_RSA_SHA1 = 5,
+ DNSSEC_KEY_ALGORITHM_RSA_SHA1_NSEC3 = 7,
+ DNSSEC_KEY_ALGORITHM_RSA_SHA256 = 8,
+ DNSSEC_KEY_ALGORITHM_RSA_SHA512 = 10,
+ DNSSEC_KEY_ALGORITHM_ECDSA_P256_SHA256 = 13,
+ DNSSEC_KEY_ALGORITHM_ECDSA_P384_SHA384 = 14,
+ DNSSEC_KEY_ALGORITHM_ED25519 = 15,
+ DNSSEC_KEY_ALGORITHM_ED448 = 16,
+} dnssec_key_algorithm_t;
+
+struct dnssec_key;
+
+/*!
+ * DNSSEC key.
+ */
+typedef struct dnssec_key dnssec_key_t;
+
+/*!
+ * Check whether a DNSKEY algorithm is supported.
+ *
+ * @note: less secure algorithms may go unsupported on purpose.
+ */
+bool dnssec_algorithm_key_support(dnssec_key_algorithm_t algo);
+
+/*!
+ * Allocate new DNSSEC key.
+ *
+ * The protocol field of the key is set to 3 (DNSSEC).
+ * The flags field of the key is set to 256 (zone key, no SEP).
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int dnssec_key_new(dnssec_key_t **key);
+
+/*!
+ * Clear the DNSSEC key.
+ *
+ * Has the same effect as calling \ref dnssec_key_free and \ref dnssec_key_new.
+ */
+void dnssec_key_clear(dnssec_key_t *key);
+
+/*!
+ * Free the key allocated by \ref dnssec_key_new.
+ */
+void dnssec_key_free(dnssec_key_t *key);
+
+/*!
+ * Create a copy of a DNSSEC key.
+ *
+ * Only a public part of the key is copied.
+ */
+dnssec_key_t *dnssec_key_dup(const dnssec_key_t *key);
+
+/*!
+ * Get the key tag of the DNSSEC key.
+ */
+uint16_t dnssec_key_get_keytag(const dnssec_key_t *key);
+
+/*!
+ * Get the domain name of the DNSSEC key.
+ */
+const uint8_t *dnssec_key_get_dname(const dnssec_key_t *key);
+
+/*!
+ * Set the domain name of the DNSSEC key.
+ */
+int dnssec_key_set_dname(dnssec_key_t *key, const uint8_t *dname);
+
+/*!
+ * Get the flags field of the DNSSEC key.
+ */
+uint16_t dnssec_key_get_flags(const dnssec_key_t *key);
+
+/*!
+ * Set the flags field of the DNSSEC key.
+ */
+int dnssec_key_set_flags(dnssec_key_t *key, uint16_t flags);
+
+/*!
+ * Get the protocol field of the DNSSEC key.
+ */
+uint8_t dnssec_key_get_protocol(const dnssec_key_t *key);
+
+/*!
+ * Get the protocol field of the DNSSEC key.
+ */
+int dnssec_key_set_protocol(dnssec_key_t *key, uint8_t protocol);
+
+/*!
+ * Get the algorithm field of the DNSSEC key.
+ */
+uint8_t dnssec_key_get_algorithm(const dnssec_key_t *key);
+
+/*!
+ * Set the algorithm field of the DNSSEC key.
+ *
+ * The function will fail if the algorithm is incompatible with the
+ * loaded key. This means, that the function can be used to set the initial
+ * algorithm and later, only the hashing algorithm can be changed.
+ */
+int dnssec_key_set_algorithm(dnssec_key_t *key, uint8_t algorithm);
+
+/*!
+ * Get the public key field of the DNSSEC key.
+ *
+ * The returned content must not be modified by the caller. A reference
+ * to internally allocated structure is returned.
+ */
+int dnssec_key_get_pubkey(const dnssec_key_t *key, dnssec_binary_t *pubkey);
+
+/*!
+ * Set the public key field of the DNSSEC key.
+ *
+ * A valid algorithm has to be set prior to calling this function.
+ *
+ * The function will fail if the key is already loaded in the structure.
+ */
+int dnssec_key_set_pubkey(dnssec_key_t *key, const dnssec_binary_t *pubkey);
+
+/*!
+ * Get the bit size of the cryptographic key used with the DNSSEC key.
+ */
+unsigned dnssec_key_get_size(const dnssec_key_t *key);
+
+/*!
+ * \brief Compute key ID from public key.
+ *
+ * \param key Key structure holding the public key.
+ * \param id Output: key ID in hex.
+ *
+ * \return DNSSEC_E*
+ */
+int dnssec_key_get_keyid(const dnssec_key_t *key, char **id);
+
+/*!
+ * Get the RDATA of the DNSSEC key.
+ *
+ * The returned content must not be modified by the caller. A reference
+ * to internally allocated structure is returned.
+ */
+int dnssec_key_get_rdata(const dnssec_key_t *key, dnssec_binary_t *rdata);
+
+/*!
+ * Set the RDATA of the DNSSEC key.
+ *
+ * Calling this function has the same effect as setting the individual
+ * fields of the key step-by-step. The same limitations apply.
+ */
+int dnssec_key_set_rdata(dnssec_key_t *key, const dnssec_binary_t *rdata);
+
+/*!
+ * Load PKCS #8 private key in the unencrypted PEM format.
+ *
+ * At least an algorithm must be set prior to calling this function.
+ *
+ * The function will create public key, unless it was already set (using
+ * \ref dnssec_key_set_pubkey or \ref dnssec_key_set_rdata). If the public key
+ * was set, the function will prevent loading of non-matching private key.
+ */
+int dnssec_key_load_pkcs8(dnssec_key_t *key, const dnssec_binary_t *pem);
+
+/*!
+ * Check if the key can be used for signing.
+ */
+bool dnssec_key_can_sign(const dnssec_key_t *key);
+
+/*!
+ * Check if the key can be used for verification.
+ */
+bool dnssec_key_can_verify(const dnssec_key_t *key);
+
+/*!
+ * Get private key size range for a DNSSEC algorithm.
+ *
+ * \param[in] algorithm DNSKEY algorithm.
+ * \param[out] min Minimal size of the private key (can be NULL).
+ * \param[out] max Maximal size of the private key (can be NULL).
+ *
+ * \return DNSSEC_EOK for valid parameters.
+ */
+int dnssec_algorithm_key_size_range(dnssec_key_algorithm_t algorithm,
+ unsigned *min, unsigned *max);
+
+/*!
+ * Check if the private key size matches DNSKEY constraints.
+ *
+ * \param algorithm DNSKEY algorithm.
+ * \param bits Private key size.
+ *
+ * \return DNSKEY algorithm matches the key size constraints.
+ */
+bool dnssec_algorithm_key_size_check(dnssec_key_algorithm_t algorithm,
+ unsigned bits);
+
+/*!
+ * Get default key size for given algorithm.
+ *
+ * The default size is balance between security and response lengths with
+ * respect to use in DNS.
+ */
+int dnssec_algorithm_key_size_default(dnssec_key_algorithm_t algorithm);
+
+/*!
+ * DS algorithm numbers.
+ *
+ * \see https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml
+ */
+typedef enum dnssec_key_digest {
+ DNSSEC_KEY_DIGEST_INVALID = 0,
+ DNSSEC_KEY_DIGEST_SHA1 = 1,
+ DNSSEC_KEY_DIGEST_SHA256 = 2,
+ DNSSEC_KEY_DIGEST_SHA384 = 4,
+} dnssec_key_digest_t;
+
+/*!
+ * Check whether a DS algorithm is supported.
+ *
+ * @note: less secure algorithms may go unsupported on purpose.
+ */
+bool dnssec_algorithm_digest_support(dnssec_key_digest_t algo);
+
+/*!
+ * Create DS (Delgation Signer) RDATA from DNSSEC key.
+ *
+ * \param[in] key DNSSEC key.
+ * \param[in] digest Digest algorithm to be used.
+ * \param[out] rdata Allocated DS RDATA.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int dnssec_key_create_ds(const dnssec_key_t *key, dnssec_key_digest_t digest,
+ dnssec_binary_t *rdata);
+
+/** @} */
diff --git a/src/libdnssec/key/algorithm.c b/src/libdnssec/key/algorithm.c
new file mode 100644
index 0000000..84f5386
--- /dev/null
+++ b/src/libdnssec/key/algorithm.c
@@ -0,0 +1,163 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <gnutls/gnutls.h>
+
+#include "libdnssec/error.h"
+#include "libdnssec/key.h"
+#include "libdnssec/key/algorithm.h"
+#include "libdnssec/shared/shared.h"
+
+/* -- internal ------------------------------------------------------------- */
+
+struct limits {
+ unsigned min;
+ unsigned max;
+ unsigned def;
+ bool (*validate)(unsigned bits);
+};
+
+static const struct limits *get_limits(dnssec_key_algorithm_t algorithm)
+{
+ static const struct limits RSA = {
+ .min = 1024,
+ .max = 4096,
+ .def = 2048,
+ };
+
+ static const struct limits EC256 = {
+ .min = 256,
+ .max = 256,
+ .def = 256,
+ };
+
+ static const struct limits EC384 = {
+ .min = 384,
+ .max = 384,
+ .def = 384,
+ };
+
+ static const struct limits ED25519 = {
+ .min = 256,
+ .max = 256,
+ .def = 256,
+ };
+
+ static const struct limits ED448 = {
+ .min = 456,
+ .max = 456,
+ .def = 456,
+ };
+
+ switch (algorithm) {
+ case DNSSEC_KEY_ALGORITHM_RSA_SHA1:
+ case DNSSEC_KEY_ALGORITHM_RSA_SHA1_NSEC3:
+ case DNSSEC_KEY_ALGORITHM_RSA_SHA256:
+ case DNSSEC_KEY_ALGORITHM_RSA_SHA512:
+ return &RSA;
+ case DNSSEC_KEY_ALGORITHM_ECDSA_P256_SHA256:
+ return &EC256;
+ case DNSSEC_KEY_ALGORITHM_ECDSA_P384_SHA384:
+ return &EC384;
+ case DNSSEC_KEY_ALGORITHM_ED25519:
+ return &ED25519;
+ case DNSSEC_KEY_ALGORITHM_ED448:
+ return &ED448;
+ default:
+ return NULL;
+ }
+}
+
+/* -- internal API --------------------------------------------------------- */
+
+gnutls_pk_algorithm_t algorithm_to_gnutls(dnssec_key_algorithm_t dnssec)
+{
+ switch (dnssec) {
+ case DNSSEC_KEY_ALGORITHM_RSA_SHA1:
+ case DNSSEC_KEY_ALGORITHM_RSA_SHA1_NSEC3:
+ case DNSSEC_KEY_ALGORITHM_RSA_SHA256:
+ case DNSSEC_KEY_ALGORITHM_RSA_SHA512:
+ return GNUTLS_PK_RSA;
+ case DNSSEC_KEY_ALGORITHM_ECDSA_P256_SHA256:
+ case DNSSEC_KEY_ALGORITHM_ECDSA_P384_SHA384:
+ return GNUTLS_PK_EC;
+ case DNSSEC_KEY_ALGORITHM_ED25519:
+#ifdef HAVE_ED25519
+ return GNUTLS_PK_EDDSA_ED25519;
+#endif
+ case DNSSEC_KEY_ALGORITHM_ED448:
+ default:
+ return GNUTLS_PK_UNKNOWN;
+ }
+}
+
+/* -- public API ----------------------------------------------------------- */
+
+_public_
+bool dnssec_algorithm_key_support(dnssec_key_algorithm_t algo)
+{
+ return algorithm_to_gnutls(algo) != GNUTLS_PK_UNKNOWN;
+}
+
+_public_
+int dnssec_algorithm_key_size_range(dnssec_key_algorithm_t algorithm,
+ unsigned *min_ptr, unsigned *max_ptr)
+{
+ if (!min_ptr && !max_ptr) {
+ return DNSSEC_EINVAL;
+ }
+
+ const struct limits *limits = get_limits(algorithm);
+ if (!limits) {
+ return DNSSEC_INVALID_KEY_ALGORITHM;
+ }
+
+ if (min_ptr) {
+ *min_ptr = limits->min;
+ }
+ if (max_ptr) {
+ *max_ptr = limits->max;
+ }
+
+ return DNSSEC_EOK;
+}
+
+_public_
+bool dnssec_algorithm_key_size_check(dnssec_key_algorithm_t algorithm,
+ unsigned bits)
+{
+ const struct limits *limits = get_limits(algorithm);
+ if (!limits) {
+ return false;
+ }
+
+ if (bits < limits->min || bits > limits->max) {
+ return false;
+ }
+
+ if (limits->validate && !limits->validate(bits)) {
+ return false;
+ }
+
+ return true;
+}
+
+_public_
+int dnssec_algorithm_key_size_default(dnssec_key_algorithm_t algorithm)
+{
+ const struct limits *limits = get_limits(algorithm);
+ return limits ? limits->def : 0;
+}
diff --git a/src/libdnssec/key/algorithm.h b/src/libdnssec/key/algorithm.h
new file mode 100644
index 0000000..586682c
--- /dev/null
+++ b/src/libdnssec/key/algorithm.h
@@ -0,0 +1,30 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <gnutls/gnutls.h>
+
+#include "libdnssec/key.h"
+
+/*!
+ * Convert DNSKEY algorithm identifier to GnuTLS identifier.
+ *
+ * \param dnssec DNSSEC DNSKEY algorithm identifier.
+ *
+ * \return GnuTLS private key algorithm identifier, GNUTLS_PK_UNKNOWN on error.
+ */
+gnutls_pk_algorithm_t algorithm_to_gnutls(dnssec_key_algorithm_t dnssec);
diff --git a/src/libdnssec/key/convert.c b/src/libdnssec/key/convert.c
new file mode 100644
index 0000000..b8ebb7d
--- /dev/null
+++ b/src/libdnssec/key/convert.c
@@ -0,0 +1,375 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <gnutls/abstract.h>
+#include <gnutls/gnutls.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "libdnssec/shared/bignum.h"
+#include "libdnssec/binary.h"
+#include "libdnssec/error.h"
+#include "libdnssec/key.h"
+#include "libdnssec/key/algorithm.h"
+#include "libdnssec/key/dnskey.h"
+#include "libdnssec/shared/shared.h"
+#include "libdnssec/shared/binary_wire.h"
+
+/* -- wrappers for GnuTLS types -------------------------------------------- */
+
+static size_t bignum_size_u_datum(const gnutls_datum_t *_bignum)
+{
+ const dnssec_binary_t bignum = binary_from_datum(_bignum);
+ return bignum_size_u(&bignum);
+}
+
+static void wire_write_bignum_datum(wire_ctx_t *ctx, size_t width,
+ const gnutls_datum_t *_bignum)
+{
+ const dnssec_binary_t bignum = binary_from_datum(_bignum);
+ bignum_write(ctx, width, &bignum);
+}
+
+static gnutls_datum_t wire_take_datum(wire_ctx_t *ctx, size_t count)
+{
+ gnutls_datum_t result = { .data = ctx->position, .size = count };
+ ctx->position += count;
+
+ return result;
+}
+
+/* -- DNSSEC to crypto ------------------------------------------------------*/
+
+/*!
+ * Convert RSA public key to DNSSEC format.
+ */
+static int rsa_pubkey_to_rdata(gnutls_pubkey_t key, dnssec_binary_t *rdata)
+{
+ assert(key);
+ assert(rdata);
+
+ _cleanup_datum_ gnutls_datum_t modulus = { 0 };
+ _cleanup_datum_ gnutls_datum_t exponent = { 0 };
+
+ int result = gnutls_pubkey_get_pk_rsa_raw(key, &modulus, &exponent);
+ if (result != GNUTLS_E_SUCCESS) {
+ return DNSSEC_KEY_EXPORT_ERROR;
+ }
+
+ size_t exponent_size = bignum_size_u_datum(&exponent);
+ if (exponent_size > UINT8_MAX) {
+ return DNSSEC_KEY_EXPORT_ERROR;
+ }
+
+ size_t modulus_size = bignum_size_u_datum(&modulus);
+
+ result = dnssec_binary_alloc(rdata, 1 + exponent_size + modulus_size);
+ if (result != DNSSEC_EOK) {
+ return result;
+ }
+
+ wire_ctx_t wire = binary_init(rdata);
+ wire_ctx_write_u8(&wire, exponent_size);
+ wire_write_bignum_datum(&wire, exponent_size, &exponent);
+ wire_write_bignum_datum(&wire, modulus_size, &modulus);
+ assert(wire_ctx_offset(&wire) == rdata->size);
+
+ return DNSSEC_EOK;
+}
+
+/*!
+ * Get point size for an ECDSA curve.
+ */
+static size_t ecdsa_curve_point_size(gnutls_ecc_curve_t curve)
+{
+ switch (curve) {
+ case GNUTLS_ECC_CURVE_SECP256R1: return 32;
+ case GNUTLS_ECC_CURVE_SECP384R1: return 48;
+ default: return 0;
+ }
+}
+
+#if defined(HAVE_ED25519) || defined(HAVE_ED448)
+static size_t eddsa_curve_point_size(gnutls_ecc_curve_t curve)
+{
+ switch (curve) {
+#ifdef HAVE_ED25519
+ case GNUTLS_ECC_CURVE_ED25519: return 32;
+#endif
+#ifdef HAVE_ED448
+ case GNUTLS_ECC_CURVE_ED448: return 57;
+#endif
+ default: return 0;
+ }
+}
+#endif
+
+/*!
+ * Convert ECDSA public key to DNSSEC format.
+ */
+static int ecdsa_pubkey_to_rdata(gnutls_pubkey_t key, dnssec_binary_t *rdata)
+{
+ assert(key);
+ assert(rdata);
+
+ _cleanup_datum_ gnutls_datum_t point_x = { 0 };
+ _cleanup_datum_ gnutls_datum_t point_y = { 0 };
+ gnutls_ecc_curve_t curve = { 0 };
+
+ int result = gnutls_pubkey_get_pk_ecc_raw(key, &curve, &point_x, &point_y);
+ if (result != GNUTLS_E_SUCCESS) {
+ return DNSSEC_KEY_EXPORT_ERROR;
+ }
+
+ size_t point_size = ecdsa_curve_point_size(curve);
+ if (point_size == 0) {
+ return DNSSEC_INVALID_PUBLIC_KEY;
+ }
+
+ result = dnssec_binary_alloc(rdata, 2 * point_size);
+ if (result != DNSSEC_EOK) {
+ return result;
+ }
+
+ wire_ctx_t wire = binary_init(rdata);
+ wire_write_bignum_datum(&wire, point_size, &point_x);
+ wire_write_bignum_datum(&wire, point_size, &point_y);
+ assert(wire_ctx_offset(&wire) == rdata->size);
+
+ return DNSSEC_EOK;
+}
+
+/*!
+ * Convert EDDSA public key to DNSSEC format.
+ */
+#if defined(HAVE_ED25519) || defined(HAVE_ED448)
+static int eddsa_pubkey_to_rdata(gnutls_pubkey_t key, dnssec_binary_t *rdata)
+{
+ assert(key);
+ assert(rdata);
+
+ _cleanup_datum_ gnutls_datum_t point_x = { 0 };
+ gnutls_ecc_curve_t curve = { 0 };
+
+ int result = gnutls_pubkey_get_pk_ecc_raw(key, &curve, &point_x, NULL);
+ if (result != GNUTLS_E_SUCCESS) {
+ return DNSSEC_KEY_EXPORT_ERROR;
+ }
+
+ size_t point_size = eddsa_curve_point_size(curve);
+ if (point_size == 0) {
+ return DNSSEC_INVALID_PUBLIC_KEY;
+ }
+
+ result = dnssec_binary_alloc(rdata, point_size);
+ if (result != DNSSEC_EOK) {
+ return result;
+ }
+
+ wire_ctx_t wire = binary_init(rdata);
+ wire_write_bignum_datum(&wire, point_size, &point_x);
+ assert(wire_ctx_offset(&wire) == rdata->size);
+
+ return DNSSEC_EOK;
+}
+#endif
+
+/* -- crypto to DNSSEC ------------------------------------------------------*/
+
+/*!
+ * Convert RSA key in DNSSEC format to crypto key.
+ */
+static int rsa_rdata_to_pubkey(const dnssec_binary_t *rdata, gnutls_pubkey_t key)
+{
+ assert(rdata);
+ assert(key);
+
+ if (rdata->size == 0) {
+ return DNSSEC_INVALID_PUBLIC_KEY;
+ }
+
+ wire_ctx_t ctx = binary_init(rdata);
+
+ // parse public exponent
+
+ uint8_t exponent_size = wire_ctx_read_u8(&ctx);
+ if (exponent_size == 0 || wire_ctx_available(&ctx) < exponent_size) {
+ return DNSSEC_INVALID_PUBLIC_KEY;
+ }
+
+ gnutls_datum_t exponent = wire_take_datum(&ctx, exponent_size);
+
+ // parse modulus
+
+ size_t modulus_size = wire_ctx_available(&ctx);
+ if (modulus_size == 0) {
+ return DNSSEC_INVALID_PUBLIC_KEY;
+ }
+
+ gnutls_datum_t modulus = wire_take_datum(&ctx, modulus_size);
+
+ assert(wire_ctx_offset(&ctx) == rdata->size);
+
+ int result = gnutls_pubkey_import_rsa_raw(key, &modulus, &exponent);
+ if (result != GNUTLS_E_SUCCESS) {
+ return DNSSEC_KEY_IMPORT_ERROR;
+ }
+
+ return DNSSEC_EOK;
+}
+
+/**
+ * Get ECDSA curve based on DNSKEY RDATA size.
+ */
+static gnutls_ecc_curve_t ecdsa_curve_from_rdata_size(size_t rdata_size)
+{
+ switch (rdata_size) {
+ case 64: return GNUTLS_ECC_CURVE_SECP256R1;
+ case 96: return GNUTLS_ECC_CURVE_SECP384R1;
+ default: return GNUTLS_ECC_CURVE_INVALID;
+ }
+}
+
+/**
+ * Get EDDSA curve based on DNSKEY RDATA size.
+ */
+#if defined(HAVE_ED25519) || defined(HAVE_ED448)
+static gnutls_ecc_curve_t eddsa_curve_from_rdata_size(size_t rdata_size)
+{
+ switch (rdata_size) {
+#ifdef HAVE_ED25519
+ case 32: return GNUTLS_ECC_CURVE_ED25519;
+#endif
+#ifdef HAVE_ED448
+ case 57: return GNUTLS_ECC_CURVE_ED448;
+#endif
+ default: return GNUTLS_ECC_CURVE_INVALID;
+ }
+}
+#endif
+
+/*!
+ * Convert ECDSA key in DNSSEC format to crypto key.
+ */
+static int ecdsa_rdata_to_pubkey(const dnssec_binary_t *rdata, gnutls_pubkey_t key)
+{
+ assert(rdata);
+ assert(key);
+
+ gnutls_ecc_curve_t curve = ecdsa_curve_from_rdata_size(rdata->size);
+ if (curve == GNUTLS_ECC_CURVE_INVALID) {
+ return DNSSEC_INVALID_PUBLIC_KEY;
+ }
+
+ // parse points
+
+ wire_ctx_t ctx = binary_init(rdata);
+
+ size_t point_size = wire_ctx_available(&ctx) / 2;
+ gnutls_datum_t point_x = wire_take_datum(&ctx, point_size);
+ gnutls_datum_t point_y = wire_take_datum(&ctx, point_size);
+ assert(wire_ctx_offset(&ctx) == rdata->size);
+
+ int result = gnutls_pubkey_import_ecc_raw(key, curve, &point_x, &point_y);
+ if (result != GNUTLS_E_SUCCESS) {
+ return DNSSEC_KEY_IMPORT_ERROR;
+ }
+
+ return DNSSEC_EOK;
+}
+
+/*!
+ * Convert EDDSA key in DNSSEC format to crypto key.
+ */
+#if defined(HAVE_ED25519) || defined(HAVE_ED448)
+static int eddsa_rdata_to_pubkey(const dnssec_binary_t *rdata, gnutls_pubkey_t key)
+{
+ assert(rdata);
+ assert(key);
+
+ gnutls_ecc_curve_t curve = eddsa_curve_from_rdata_size(rdata->size);
+ if (curve == GNUTLS_ECC_CURVE_INVALID) {
+ return DNSSEC_INVALID_PUBLIC_KEY;
+ }
+
+ wire_ctx_t ctx = binary_init(rdata);
+
+ size_t point_size = wire_ctx_available(&ctx);
+ gnutls_datum_t point_x = wire_take_datum(&ctx, point_size);
+ assert(wire_ctx_offset(&ctx) == rdata->size);
+
+ int result = gnutls_pubkey_import_ecc_raw(key, curve, &point_x, NULL);
+ if (result != GNUTLS_E_SUCCESS) {
+ return DNSSEC_KEY_IMPORT_ERROR;
+ }
+
+ return DNSSEC_EOK;
+}
+#endif
+
+/* -- internal API --------------------------------------------------------- */
+
+/*!
+ * Encode public key to the format used in DNSKEY RDATA.
+ */
+int convert_pubkey_to_dnskey(gnutls_pubkey_t key, dnssec_binary_t *rdata)
+{
+ assert(key);
+ assert(rdata);
+
+ int algorithm = gnutls_pubkey_get_pk_algorithm(key, NULL);
+ if (algorithm < 0) {
+ return DNSSEC_INVALID_PUBLIC_KEY;
+ }
+
+ switch ((gnutls_pk_algorithm_t)algorithm) {
+ case GNUTLS_PK_RSA: return rsa_pubkey_to_rdata(key, rdata);
+ case GNUTLS_PK_EC: return ecdsa_pubkey_to_rdata(key, rdata);
+#ifdef HAVE_ED25519
+ case GNUTLS_PK_EDDSA_ED25519: return eddsa_pubkey_to_rdata(key, rdata);
+#endif
+#ifdef HAVE_ED448
+ case GNUTLS_PK_EDDSA_ED448: return eddsa_pubkey_to_rdata(key, rdata);
+#endif
+ default: return DNSSEC_INVALID_KEY_ALGORITHM;
+ }
+}
+
+/*!
+ * Create public key from the format encoded in DNSKEY RDATA.
+ */
+int convert_dnskey_to_pubkey(uint8_t algorithm, const dnssec_binary_t *rdata,
+ gnutls_pubkey_t key)
+{
+ assert(rdata);
+ assert(key);
+
+ gnutls_pk_algorithm_t gnutls_alg = algorithm_to_gnutls(algorithm);
+
+ switch(gnutls_alg) {
+ case GNUTLS_PK_RSA: return rsa_rdata_to_pubkey(rdata, key);
+ case GNUTLS_PK_EC: return ecdsa_rdata_to_pubkey(rdata, key);
+#ifdef HAVE_ED25519
+ case GNUTLS_PK_EDDSA_ED25519: return eddsa_rdata_to_pubkey(rdata, key);
+#endif
+#ifdef HAVE_ED448
+ case GNUTLS_PK_EDDSA_ED448: return eddsa_rdata_to_pubkey(rdata, key);
+#endif
+ default: return DNSSEC_INVALID_KEY_ALGORITHM;
+ }
+}
diff --git a/src/libdnssec/key/convert.h b/src/libdnssec/key/convert.h
new file mode 100644
index 0000000..bd2196e
--- /dev/null
+++ b/src/libdnssec/key/convert.h
@@ -0,0 +1,44 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <gnutls/abstract.h>
+
+#include "libdnssec/binary.h"
+#include "libdnssec/key.h"
+
+/*!
+ * Encode public key into the format used in DNSKEY RDATA.
+ *
+ * \param[in] key Public key to be encoded.
+ * \param[out] rdata Encoded key (allocated).
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int convert_pubkey_to_dnskey(gnutls_pubkey_t key, dnssec_binary_t *rdata);
+
+/*!
+ * Create public key from the format encoded in DNSKEY RDATA.
+ *
+ * \param[in] algorithm DNSSEC algorithm identification.
+ * \param[in] rdata Public key in DNSKEY RDATA format.
+ * \param[out] key GnuTLS public key (initialized).
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int convert_dnskey_to_pubkey(uint8_t algorithm, const dnssec_binary_t *rdata,
+ gnutls_pubkey_t key);
diff --git a/src/libdnssec/key/dnskey.c b/src/libdnssec/key/dnskey.c
new file mode 100644
index 0000000..dc89bcd
--- /dev/null
+++ b/src/libdnssec/key/dnskey.c
@@ -0,0 +1,82 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "libdnssec/binary.h"
+#include "libdnssec/error.h"
+#include "libdnssec/key/dnskey.h"
+#include "libdnssec/key/convert.h"
+#include "libdnssec/shared/binary_wire.h"
+
+/* -- internal API --------------------------------------------------------- */
+
+/*!
+ * Update 'Public key' field of DNSKEY RDATA.
+ */
+int dnskey_rdata_set_pubkey(dnssec_binary_t *rdata, const dnssec_binary_t *pubkey)
+{
+ assert(rdata);
+ assert(pubkey);
+
+ size_t new_size = DNSKEY_RDATA_OFFSET_PUBKEY + pubkey->size;
+ int result = dnssec_binary_resize(rdata, new_size);
+ if (result != DNSSEC_EOK) {
+ return result;
+ }
+
+ wire_ctx_t wire = binary_init(rdata);
+ wire_ctx_set_offset(&wire, DNSKEY_RDATA_OFFSET_PUBKEY);
+ binary_write(&wire, pubkey);
+ assert(wire_ctx_offset(&wire) == rdata->size);
+
+ return DNSSEC_EOK;
+}
+
+/*!
+ * Create a GnuTLS public key from DNSKEY RDATA.
+ *
+ * \param rdata DNSKEY RDATA.
+ * \param key_ptr Resulting public key.
+ */
+int dnskey_rdata_to_crypto_key(const dnssec_binary_t *rdata, gnutls_pubkey_t *key_ptr)
+{
+ assert(rdata);
+ assert(key_ptr);
+
+ uint8_t algorithm = 0;
+ dnssec_binary_t rdata_pubkey = { 0 };
+
+ wire_ctx_t wire = binary_init(rdata);
+ wire_ctx_set_offset(&wire, DNSKEY_RDATA_OFFSET_ALGORITHM);
+ algorithm = wire_ctx_read_u8(&wire);
+ wire_ctx_set_offset(&wire, DNSKEY_RDATA_OFFSET_PUBKEY);
+ binary_available(&wire, &rdata_pubkey);
+
+ gnutls_pubkey_t key = NULL;
+ int result = gnutls_pubkey_init(&key);
+ if (result != GNUTLS_E_SUCCESS) {
+ return DNSSEC_ENOMEM;
+ }
+
+ result = convert_dnskey_to_pubkey(algorithm, &rdata_pubkey, key);
+ if (result != DNSSEC_EOK) {
+ gnutls_pubkey_deinit(key);
+ return result;
+ }
+
+ *key_ptr = key;
+
+ return DNSSEC_EOK;
+}
diff --git a/src/libdnssec/key/dnskey.h b/src/libdnssec/key/dnskey.h
new file mode 100644
index 0000000..de681c8
--- /dev/null
+++ b/src/libdnssec/key/dnskey.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <gnutls/abstract.h>
+
+#include "libdnssec/binary.h"
+#include "libdnssec/error.h"
+
+/*!
+ * DNSKEY RDATA fields offsets.
+ *
+ * \see RFC 4034 (section 2.1)
+ */
+enum dnskey_rdata_offsets {
+ DNSKEY_RDATA_OFFSET_FLAGS = 0,
+ DNSKEY_RDATA_OFFSET_PROTOCOL = 2,
+ DNSKEY_RDATA_OFFSET_ALGORITHM = 3,
+ DNSKEY_RDATA_OFFSET_PUBKEY = 4,
+};
+
+/*!
+ * Update 'Public key' field of DNSKEY RDATA.
+ */
+int dnskey_rdata_set_pubkey(dnssec_binary_t *rdata,
+ const dnssec_binary_t *pubkey);
+
+/*!
+ * Create a GnuTLS public key from DNSKEY RDATA.
+ */
+int dnskey_rdata_to_crypto_key(const dnssec_binary_t *rdata,
+ gnutls_pubkey_t *key_ptr);
diff --git a/src/libdnssec/key/ds.c b/src/libdnssec/key/ds.c
new file mode 100644
index 0000000..dcb4afe
--- /dev/null
+++ b/src/libdnssec/key/ds.c
@@ -0,0 +1,115 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "libdnssec/binary.h"
+#include "libdnssec/error.h"
+#include "libdnssec/key.h"
+#include "libdnssec/key/internal.h"
+#include "libdnssec/shared/dname.h"
+#include "libdnssec/shared/shared.h"
+#include "libdnssec/shared/binary_wire.h"
+
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+/*!
+ * Convert DNSSEC DS digest algorithm to GnuTLS digest algorithm.
+ */
+static gnutls_digest_algorithm_t lookup_algorithm(dnssec_key_digest_t algorithm)
+{
+ switch (algorithm) {
+ case DNSSEC_KEY_DIGEST_SHA1: return GNUTLS_DIG_SHA1;
+ case DNSSEC_KEY_DIGEST_SHA256: return GNUTLS_DIG_SHA256;
+ case DNSSEC_KEY_DIGEST_SHA384: return GNUTLS_DIG_SHA384;
+ default:
+ return GNUTLS_DIG_UNKNOWN;
+ };
+}
+
+_public_
+bool dnssec_algorithm_digest_support(dnssec_key_digest_t algo)
+{
+ return lookup_algorithm(algo) != GNUTLS_DIG_UNKNOWN;
+}
+
+static void wire_write_digest(wire_ctx_t *wire,
+ gnutls_hash_hd_t digest, int digest_size)
+{
+ assert(wire_ctx_available(wire) >= digest_size);
+ gnutls_hash_output(digest, wire->position);
+ wire->position += digest_size;
+}
+
+_public_
+int dnssec_key_create_ds(const dnssec_key_t *key,
+ dnssec_key_digest_t ds_algorithm,
+ dnssec_binary_t *rdata_ptr)
+{
+ if (!key || !rdata_ptr) {
+ return DNSSEC_EINVAL;
+ }
+
+ if (!key->dname) {
+ return DNSSEC_INVALID_KEY_NAME;
+ }
+
+ if (!key->public_key){
+ return DNSSEC_INVALID_PUBLIC_KEY;
+ }
+
+ gnutls_digest_algorithm_t algorithm = lookup_algorithm(ds_algorithm);
+ if (algorithm == GNUTLS_DIG_UNKNOWN) {
+ return DNSSEC_INVALID_DS_ALGORITHM;
+ }
+
+ // compute DS hash
+
+ _cleanup_hash_ gnutls_hash_hd_t digest = NULL;
+ int r = gnutls_hash_init(&digest, algorithm);
+ if (r < 0) {
+ return DNSSEC_DS_HASHING_ERROR;
+ }
+
+ if (gnutls_hash(digest, key->dname, dname_length(key->dname)) != 0 ||
+ gnutls_hash(digest, key->rdata.data, key->rdata.size) != 0
+ ) {
+ return DNSSEC_DS_HASHING_ERROR;
+ }
+
+ // build DS RDATA
+
+ int digest_size = gnutls_hash_get_len(algorithm);
+ if (digest_size == 0) {
+ return DNSSEC_DS_HASHING_ERROR;
+ }
+
+ dnssec_binary_t rdata = { 0 };
+ r = dnssec_binary_alloc(&rdata, 4 + digest_size);
+ if (r != DNSSEC_EOK) {
+ return r;
+ }
+
+ wire_ctx_t wire = binary_init(&rdata);
+ wire_ctx_write_u16(&wire, dnssec_key_get_keytag(key));
+ wire_ctx_write_u8(&wire, dnssec_key_get_algorithm(key));
+ wire_ctx_write_u8(&wire, ds_algorithm);
+ wire_write_digest(&wire, digest, digest_size);
+ assert(wire_ctx_offset(&wire) == wire.size);
+
+ *rdata_ptr = rdata;
+
+ return DNSSEC_EOK;
+}
diff --git a/src/libdnssec/key/internal.h b/src/libdnssec/key/internal.h
new file mode 100644
index 0000000..10c9c8e
--- /dev/null
+++ b/src/libdnssec/key/internal.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <gnutls/abstract.h>
+#include <stdint.h>
+
+#include "libdnssec/key.h"
+#include "libdnssec/shared/dname.h"
+
+/*!
+ * DNSSEC key.
+ */
+struct dnssec_key {
+ uint8_t *dname;
+ dnssec_binary_t rdata;
+
+ gnutls_pubkey_t public_key;
+ gnutls_privkey_t private_key;
+ unsigned bits;
+};
diff --git a/src/libdnssec/key/key.c b/src/libdnssec/key/key.c
new file mode 100644
index 0000000..6f24f87
--- /dev/null
+++ b/src/libdnssec/key/key.c
@@ -0,0 +1,440 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <gnutls/abstract.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libdnssec/binary.h"
+#include "libdnssec/error.h"
+#include "libdnssec/key.h"
+#include "libdnssec/key/algorithm.h"
+#include "libdnssec/key/convert.h"
+#include "libdnssec/key/dnskey.h"
+#include "libdnssec/key/internal.h"
+#include "libdnssec/shared/keyid_gnutls.h"
+#include "libdnssec/keystore.h"
+#include "libdnssec/keytag.h"
+#include "libdnssec/shared/pem.h"
+#include "libdnssec/shared/shared.h"
+#include "libdnssec/shared/binary_wire.h"
+#include "contrib/wire_ctx.h"
+
+/*!
+ * Minimal size of DNSKEY RDATA.
+ */
+#define DNSKEY_RDATA_MIN_SIZE DNSKEY_RDATA_OFFSET_PUBKEY
+
+/*!
+ * RDATA template for newly allocated keys.
+ */
+static const dnssec_binary_t DNSKEY_RDATA_TEMPLATE = {
+ .size = 4,
+ .data = (uint8_t []) { 0x01, 0x00, 0x03, 0x00 }
+};
+
+/* -- key allocation ------------------------------------------------------- */
+
+_public_
+int dnssec_key_new(dnssec_key_t **key_ptr)
+{
+ if (!key_ptr) {
+ return DNSSEC_EINVAL;
+ }
+
+ dnssec_key_t *key = calloc(1, sizeof(*key));
+ if (!key) {
+ return DNSSEC_ENOMEM;
+ }
+
+ int r = dnssec_binary_dup(&DNSKEY_RDATA_TEMPLATE, &key->rdata);
+ if (r != DNSSEC_EOK) {
+ free(key);
+ return DNSSEC_ENOMEM;
+ }
+
+ *key_ptr = key;
+
+ return DNSSEC_EOK;
+}
+
+/*!
+ * Clear allocated fields inside the key structure, except RDATA.
+ */
+static void key_free_internals(dnssec_key_t *key)
+{
+ assert(key);
+
+ free(key->dname);
+ key->dname = NULL;
+
+ gnutls_privkey_deinit(key->private_key);
+ key->private_key = NULL;
+
+ gnutls_pubkey_deinit(key->public_key);
+ key->public_key = NULL;
+}
+
+_public_
+void dnssec_key_clear(dnssec_key_t *key)
+{
+ if (!key) {
+ return;
+ }
+
+ // reuse RDATA
+ dnssec_binary_t rdata = key->rdata;
+
+ // clear the structure
+ key_free_internals(key);
+ clear_struct(key);
+
+ // restore template RDATA (downsize, no need to realloc)
+ assert(rdata.size >= DNSKEY_RDATA_MIN_SIZE);
+ rdata.size = DNSKEY_RDATA_MIN_SIZE;
+ memmove(rdata.data, DNSKEY_RDATA_TEMPLATE.data, rdata.size);
+
+ key->rdata = rdata;
+}
+
+_public_
+void dnssec_key_free(dnssec_key_t *key)
+{
+ if (!key) {
+ return;
+ }
+
+ key_free_internals(key);
+ dnssec_binary_free(&key->rdata);
+
+ free(key);
+}
+
+_public_
+dnssec_key_t *dnssec_key_dup(const dnssec_key_t *key)
+{
+ if (!key) {
+ return NULL;
+ }
+
+ dnssec_key_t *dup = NULL;
+
+ if (dnssec_key_new(&dup) != DNSSEC_EOK ||
+ dnssec_key_set_dname(dup, key->dname) != DNSSEC_EOK ||
+ dnssec_key_set_rdata(dup, &key->rdata) != DNSSEC_EOK
+ ) {
+ dnssec_key_free(dup);
+ return NULL;
+ }
+
+ return dup;
+}
+
+/* -- freely modifiable attributes ----------------------------------------- */
+
+_public_
+const uint8_t *dnssec_key_get_dname(const dnssec_key_t *key)
+{
+ if (!key) {
+ return NULL;
+ }
+
+ return key->dname;
+}
+
+_public_
+int dnssec_key_set_dname(dnssec_key_t *key, const uint8_t *dname)
+{
+ if (!key) {
+ return DNSSEC_EINVAL;
+ }
+
+ uint8_t *copy = NULL;
+ if (dname) {
+ copy = dname_copy(dname);
+ if (!copy) {
+ return DNSSEC_ENOMEM;
+ }
+
+ dname_normalize(copy);
+ }
+
+ free(key->dname);
+ key->dname = copy;
+
+ return DNSSEC_EOK;
+}
+
+_public_
+uint16_t dnssec_key_get_flags(const dnssec_key_t *key)
+{
+ if (!key) {
+ return 0;
+ }
+
+ wire_ctx_t wire = binary_init(&key->rdata);
+ wire_ctx_set_offset(&wire, DNSKEY_RDATA_OFFSET_FLAGS);
+ return wire_ctx_read_u16(&wire);
+}
+
+_public_
+int dnssec_key_set_flags(dnssec_key_t *key, uint16_t flags)
+{
+ if (!key) {
+ return DNSSEC_EINVAL;
+ }
+
+ wire_ctx_t wire = binary_init(&key->rdata);
+ wire_ctx_set_offset(&wire, DNSKEY_RDATA_OFFSET_FLAGS);
+ wire_ctx_write_u16(&wire, flags);
+
+ return DNSSEC_EOK;
+}
+
+_public_
+uint8_t dnssec_key_get_protocol(const dnssec_key_t *key)
+{
+ if (!key) {
+ return 0;
+ }
+
+ wire_ctx_t wire = binary_init(&key->rdata);
+ wire_ctx_set_offset(&wire, DNSKEY_RDATA_OFFSET_PROTOCOL);
+ return wire_ctx_read_u8(&wire);
+}
+
+_public_
+int dnssec_key_set_protocol(dnssec_key_t *key, uint8_t protocol)
+{
+ if (!key) {
+ return DNSSEC_EINVAL;
+ }
+
+ wire_ctx_t wire = binary_init(&key->rdata);
+ wire_ctx_set_offset(&wire, DNSKEY_RDATA_OFFSET_PROTOCOL);
+ wire_ctx_write_u8(&wire, protocol);
+
+ return DNSSEC_EOK;
+}
+
+/* -- restricted attributes ------------------------------------------------ */
+
+_public_
+uint16_t dnssec_key_get_keytag(const dnssec_key_t *key)
+{
+ uint16_t keytag = 0;
+ if (dnssec_key_can_verify(key)) {
+ dnssec_keytag(&key->rdata, &keytag);
+ }
+
+ return keytag;
+}
+
+/*!
+ * Check if current public key algorithm matches with the new algorithm.
+ */
+static bool can_change_algorithm(dnssec_key_t *key, uint8_t algorithm)
+{
+ assert(key);
+
+ if (!key->public_key) {
+ return true;
+ }
+
+ gnutls_pk_algorithm_t update = algorithm_to_gnutls(algorithm);
+ if (update == GNUTLS_PK_UNKNOWN) {
+ return false;
+ }
+
+ int current = gnutls_pubkey_get_pk_algorithm(key->public_key, NULL);
+ assert(current >= 0);
+
+ return current == update;
+}
+
+_public_
+uint8_t dnssec_key_get_algorithm(const dnssec_key_t *key)
+{
+ if (!key) {
+ return 0;
+ }
+
+ wire_ctx_t wire = binary_init(&key->rdata);
+ wire_ctx_set_offset(&wire, DNSKEY_RDATA_OFFSET_ALGORITHM);
+ return wire_ctx_read_u8(&wire);
+}
+
+_public_
+int dnssec_key_set_algorithm(dnssec_key_t *key, uint8_t algorithm)
+{
+ if (!key) {
+ return DNSSEC_EINVAL;
+ }
+
+ if (!can_change_algorithm(key, algorithm)) {
+ return DNSSEC_INVALID_KEY_ALGORITHM;
+ }
+
+ wire_ctx_t wire = binary_init(&key->rdata);
+ wire_ctx_set_offset(&wire, DNSKEY_RDATA_OFFSET_ALGORITHM);
+ wire_ctx_write_u8(&wire, algorithm);
+
+ return DNSSEC_EOK;
+}
+
+_public_
+int dnssec_key_get_pubkey(const dnssec_key_t *key, dnssec_binary_t *pubkey)
+{
+ if (!key || !pubkey) {
+ return DNSSEC_EINVAL;
+ }
+
+ wire_ctx_t wire = binary_init(&key->rdata);
+ wire_ctx_set_offset(&wire, DNSKEY_RDATA_OFFSET_PUBKEY);
+ binary_available(&wire, pubkey);
+
+ return DNSSEC_EOK;
+}
+
+_public_
+int dnssec_key_set_pubkey(dnssec_key_t *key, const dnssec_binary_t *pubkey)
+{
+ if (!key || !pubkey || !pubkey->data) {
+ return DNSSEC_EINVAL;
+ }
+
+ if (key->public_key) {
+ return DNSSEC_KEY_ALREADY_PRESENT;
+ }
+
+ if (dnssec_key_get_algorithm(key) == 0) {
+ return DNSSEC_INVALID_KEY_ALGORITHM;
+ }
+
+ int result = dnskey_rdata_set_pubkey(&key->rdata, pubkey);
+ if (result != DNSSEC_EOK) {
+ return result;
+ }
+
+ result = dnskey_rdata_to_crypto_key(&key->rdata, &key->public_key);
+ if (result != DNSSEC_EOK) {
+ key->rdata.size = DNSKEY_RDATA_OFFSET_PUBKEY; // downsize
+ return result;
+ }
+
+ return DNSSEC_EOK;
+}
+
+_public_
+unsigned dnssec_key_get_size(const dnssec_key_t *key)
+{
+ if (!key || !key->public_key) {
+ return 0;
+ }
+
+ unsigned bits = 0;
+ uint8_t algorithm = dnssec_key_get_algorithm(key);
+ switch (algorithm) {
+ case 13:
+ bits = 256;
+ break;
+ case 14:
+ bits = 384;
+ break;
+ case 15:
+ bits = 256;
+ break;
+ case 16:
+ bits = 456;
+ break;
+ default:
+ gnutls_pubkey_get_pk_algorithm(key->public_key, &bits);
+ }
+
+ return bits;
+}
+
+_public_
+int dnssec_key_get_keyid(const dnssec_key_t *key, char **id)
+{
+ if (!key || !id) {
+ return DNSSEC_EINVAL;
+ }
+
+ return keyid_pubkey_hex(key->public_key, id);
+}
+
+_public_
+int dnssec_key_get_rdata(const dnssec_key_t *key, dnssec_binary_t *rdata)
+{
+ if (!key || !rdata) {
+ return DNSSEC_EINVAL;
+ }
+
+ *rdata = key->rdata;
+
+ return DNSSEC_EOK;
+}
+
+_public_
+int dnssec_key_set_rdata(dnssec_key_t *key, const dnssec_binary_t *rdata)
+{
+ if (!key || !rdata || !rdata->data) {
+ return DNSSEC_EINVAL;
+ }
+
+ if (rdata->size < DNSKEY_RDATA_MIN_SIZE) {
+ return DNSSEC_MALFORMED_DATA;
+ }
+
+ if (key->public_key) {
+ return DNSSEC_KEY_ALREADY_PRESENT;
+ }
+
+ gnutls_pubkey_t new_pubkey = NULL;
+ int result = dnskey_rdata_to_crypto_key(rdata, &new_pubkey);
+ if (result != DNSSEC_EOK) {
+ return result;
+ }
+
+ result = dnssec_binary_resize(&key->rdata, rdata->size);
+ if (result != DNSSEC_EOK) {
+ gnutls_pubkey_deinit(new_pubkey);
+ return result;
+ }
+
+ // commit result
+ memmove(key->rdata.data, rdata->data, rdata->size);
+ key->public_key = new_pubkey;
+
+ return DNSSEC_EOK;
+}
+
+/* -- key presence checking ------------------------------------------------ */
+
+_public_
+bool dnssec_key_can_sign(const dnssec_key_t *key)
+{
+ return key && key->private_key;
+}
+
+_public_
+bool dnssec_key_can_verify(const dnssec_key_t *key)
+{
+ return key && key->public_key;
+}
diff --git a/src/libdnssec/key/keytag.c b/src/libdnssec/key/keytag.c
new file mode 100644
index 0000000..edff684
--- /dev/null
+++ b/src/libdnssec/key/keytag.c
@@ -0,0 +1,88 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "libdnssec/binary.h"
+#include "libdnssec/error.h"
+#include "libdnssec/key/dnskey.h"
+#include "libdnssec/shared/shared.h"
+
+/*!
+ * Compute keytag for RSA/MD5 key.
+ *
+ * \see RFC 2537 (section 2), RFC 4034 (appendix B.1)
+ */
+static uint16_t keytag_compat(const dnssec_binary_t *rdata)
+{
+ assert(rdata);
+ assert(rdata->data);
+
+ if (rdata->size < 9) { // in fact, the condition could be stricter
+ return 0;
+ }
+
+ uint8_t msb = rdata->data[rdata->size - 3];
+ uint8_t lsb = rdata->data[rdata->size - 2];
+
+ return (msb << 8) + lsb;
+}
+
+/*!
+ * Compute keytag for other than RSA/MD5 key.
+ *
+ * \see RFC 4034 (appendix B)
+ */
+static uint16_t keytag_current(const dnssec_binary_t *rdata)
+{
+ assert(rdata);
+ assert(rdata->data);
+
+ uint32_t ac = 0;
+ for (int i = 0; i < rdata->size; i++) {
+ ac += (i & 1) ? rdata->data[i] : rdata->data[i] << 8;
+ }
+
+ return (ac >> 16) + ac;
+}
+
+/* -- public API ----------------------------------------------------------- */
+
+/*!
+ * Compute keytag for a DNSSEC key.
+ */
+_public_
+int dnssec_keytag(const dnssec_binary_t *rdata, uint16_t *keytag)
+{
+ if (!rdata || !keytag) {
+ return DNSSEC_EINVAL;
+ }
+
+ if (!rdata->data || rdata->size < DNSKEY_RDATA_OFFSET_PUBKEY) {
+ return DNSSEC_MALFORMED_DATA;
+ }
+
+ uint8_t algorithm = rdata->data[DNSKEY_RDATA_OFFSET_ALGORITHM];
+ if (algorithm == 1) {
+ *keytag = keytag_compat(rdata);
+ } else {
+ *keytag = keytag_current(rdata);
+ }
+
+ return DNSSEC_EOK;
+}
diff --git a/src/libdnssec/key/privkey.c b/src/libdnssec/key/privkey.c
new file mode 100644
index 0000000..ec1dcbd
--- /dev/null
+++ b/src/libdnssec/key/privkey.c
@@ -0,0 +1,140 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <gnutls/abstract.h>
+#include <gnutls/gnutls.h>
+
+#include "libdnssec/binary.h"
+#include "libdnssec/error.h"
+#include "libdnssec/key/algorithm.h"
+#include "libdnssec/key/convert.h"
+#include "libdnssec/key/dnskey.h"
+#include "libdnssec/key/internal.h"
+#include "libdnssec/key/privkey.h"
+#include "libdnssec/shared/shared.h"
+#include "libdnssec/shared/binary_wire.h"
+
+/* -- internal functions --------------------------------------------------- */
+
+/*!
+ * Check if the algorithm number is valid for given DNSKEY.
+ */
+static bool valid_algorithm(dnssec_key_t *key, gnutls_privkey_t privkey)
+{
+ uint8_t current = dnssec_key_get_algorithm(key);
+ int gnu_algorithm = gnutls_privkey_get_pk_algorithm(privkey, NULL);
+
+ return (gnu_algorithm == algorithm_to_gnutls(current));
+}
+
+/*!
+ * Create GnuTLS public key from private key.
+ */
+static int public_from_private(gnutls_privkey_t privkey, gnutls_pubkey_t *pubkey)
+{
+ assert(privkey);
+ assert(pubkey);
+
+ gnutls_pubkey_t new_key = NULL;
+ int result = gnutls_pubkey_init(&new_key);
+ if (result != GNUTLS_E_SUCCESS) {
+ return DNSSEC_ENOMEM;
+ }
+
+ result = gnutls_pubkey_import_privkey(new_key, privkey, 0, 0);
+ if (result != GNUTLS_E_SUCCESS) {
+ gnutls_pubkey_deinit(new_key);
+ return DNSSEC_KEY_IMPORT_ERROR;
+ }
+
+ *pubkey = new_key;
+
+ return DNSSEC_EOK;
+}
+
+/*!
+ * Create public key (GnuTLS and DNSKEY RDATA) from a private key.
+ */
+static int create_public_key(gnutls_privkey_t privkey,
+ gnutls_pubkey_t *pubkey_ptr,
+ dnssec_binary_t *rdata)
+{
+ assert(privkey);
+ assert(pubkey_ptr);
+ assert(rdata);
+
+ // crypto public key
+
+ gnutls_pubkey_t pubkey = NULL;
+ int result = public_from_private(privkey, &pubkey);
+ if (result != DNSSEC_EOK) {
+ return result;
+ }
+
+ // dnssec public key
+
+ _cleanup_binary_ dnssec_binary_t rdata_pubkey = { 0 };
+ result = convert_pubkey_to_dnskey(pubkey, &rdata_pubkey);
+ if (result != DNSSEC_EOK) {
+ gnutls_pubkey_deinit(pubkey);
+ return result;
+ }
+
+ size_t rdata_size = DNSKEY_RDATA_OFFSET_PUBKEY + rdata_pubkey.size;
+ result = dnssec_binary_resize(rdata, rdata_size);
+ if (result != DNSSEC_EOK) {
+ gnutls_pubkey_deinit(pubkey);
+ return result;
+ }
+
+ // updated RDATA
+
+ wire_ctx_t wire = binary_init(rdata);
+ wire_ctx_set_offset(&wire, DNSKEY_RDATA_OFFSET_PUBKEY);
+ binary_write(&wire, &rdata_pubkey);
+ assert(wire_ctx_offset(&wire) == rdata->size);
+
+ *pubkey_ptr = pubkey;
+
+ return DNSSEC_EOK;
+}
+
+/* -- internal API --------------------------------------------------------- */
+
+/*!
+ * Load a private key into a DNSSEC key, create a public part if necessary.
+ */
+int key_set_private_key(dnssec_key_t *key, gnutls_privkey_t privkey)
+{
+ assert(key);
+ assert(privkey);
+ assert(key->private_key == NULL);
+
+ if (!valid_algorithm(key, privkey)) {
+ return DNSSEC_INVALID_KEY_ALGORITHM;
+ }
+
+ if (!key->public_key) {
+ int r = create_public_key(privkey, &key->public_key, &key->rdata);
+ if (r != DNSSEC_EOK) {
+ return r;
+ }
+ }
+
+ key->private_key = privkey;
+
+ return DNSSEC_EOK;
+}
diff --git a/src/libdnssec/key/privkey.h b/src/libdnssec/key/privkey.h
new file mode 100644
index 0000000..c0c5bb2
--- /dev/null
+++ b/src/libdnssec/key/privkey.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <gnutls/abstract.h>
+
+#include "libdnssec/key.h"
+
+/*!
+ * Load a private key into a DNSSEC key, create a public part if necessary.
+ *
+ * If the public key is not loaded, at least an algorithm must be set.
+ *
+ * Updates private key, public key, RDATA, and key identifiers.
+ *
+ * \param key DNSSEC key to be updated.
+ * \param privkey Private key to be set.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int key_set_private_key(dnssec_key_t *key, gnutls_privkey_t privkey);
diff --git a/src/libdnssec/key/simple.c b/src/libdnssec/key/simple.c
new file mode 100644
index 0000000..a2d8ea4
--- /dev/null
+++ b/src/libdnssec/key/simple.c
@@ -0,0 +1,55 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <gnutls/abstract.h>
+#include <gnutls/gnutls.h>
+
+#include "libdnssec/binary.h"
+#include "libdnssec/error.h"
+#include "libdnssec/key.h"
+#include "libdnssec/key/dnskey.h"
+#include "libdnssec/key/internal.h"
+#include "libdnssec/key/privkey.h"
+#include "libdnssec/shared/pem.h"
+#include "libdnssec/shared/shared.h"
+
+/* -- public API ----------------------------------------------------------- */
+
+_public_
+int dnssec_key_load_pkcs8(dnssec_key_t *key, const dnssec_binary_t *pem)
+{
+ if (!key || !pem || !pem->data) {
+ return DNSSEC_EINVAL;
+ }
+
+ if (dnssec_key_get_algorithm(key) == 0) {
+ return DNSSEC_INVALID_KEY_ALGORITHM;
+ }
+
+ gnutls_privkey_t privkey = NULL;
+ int r = pem_privkey(pem, &privkey);
+ if (r != DNSSEC_EOK) {
+ return r;
+ }
+
+ r = key_set_private_key(key, privkey);
+ if (r != DNSSEC_EOK) {
+ gnutls_privkey_deinit(privkey);
+ return r;
+ }
+
+ return DNSSEC_EOK;
+}
diff --git a/src/libdnssec/keyid.c b/src/libdnssec/keyid.c
new file mode 100644
index 0000000..c99a657
--- /dev/null
+++ b/src/libdnssec/keyid.c
@@ -0,0 +1,87 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <string.h>
+
+#include "libdnssec/error.h"
+#include "libdnssec/keyid.h"
+#include "libdnssec/shared/shared.h"
+
+#include "contrib/ctype.h"
+#include "contrib/tolower.h"
+
+/* -- public API ----------------------------------------------------------- */
+
+_public_
+bool dnssec_keyid_is_valid(const char *id)
+{
+ if (!id) {
+ return false;
+ }
+
+ if (strlen(id) != DNSSEC_KEYID_SIZE) {
+ return false;
+ }
+
+ for (int i = 0; i < DNSSEC_KEYID_SIZE; i++) {
+ if (!is_xdigit(id[i])) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+_public_
+void dnssec_keyid_normalize(char *id)
+{
+ if (!id) {
+ return;
+ }
+
+ for (size_t i = 0; i < DNSSEC_KEYID_SIZE; i++) {
+ assert(id[i] != '\0' && is_xdigit(id[i]));
+ id[i] = knot_tolower(id[i]);
+ }
+}
+
+_public_
+char *dnssec_keyid_copy(const char *id)
+{
+ if (!id) {
+ return NULL;
+ }
+
+ char *copy = strdup(id);
+ if (!copy) {
+ return NULL;
+ }
+
+ dnssec_keyid_normalize(copy);
+
+ return copy;
+}
+
+_public_
+bool dnssec_keyid_equal(const char *one, const char *two)
+{
+ if (!one || !two) {
+ return NULL;
+ }
+
+ return (strcasecmp(one, two) == 0);
+}
diff --git a/src/libdnssec/keyid.h b/src/libdnssec/keyid.h
new file mode 100644
index 0000000..24e201e
--- /dev/null
+++ b/src/libdnssec/keyid.h
@@ -0,0 +1,80 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*!
+ * \file
+ *
+ * \addtogroup keyid
+ *
+ * \brief DNSSEC key ID manipulation.
+ *
+ * The module contains auxiliary functions for manipulation with key IDs.
+ *
+ * Example:
+ *
+ * ~~~~~ {.c}
+ *
+ * char *key_id = "ef26672cafede0732dd18fba6488fa390b5589af";
+ * assert(dnssec_keyid_is_valid(key_id));
+ *
+ * char copy[DNSSEC_KEY_ID_SIZE + 1] = { 0 };
+ * memcpy(copy, key_id, sizeof(copy));
+ * for (int i = 0; i < DNSSEC_KEY_ID_SIZE; i++) {
+ * copy[i] = toupper((unsigned char)copy[i]);
+ * }
+ *
+ * assert(dnssec_keyid_equal(key_id, copy));
+ *
+ * ~~~~~
+ *
+ * @{
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+/*!
+ * Length of the key ID in presentation form (ASCII).
+ */
+#define DNSSEC_KEYID_SIZE 40
+
+/*!
+ * Length of the key ID in internal form (binary).
+ */
+#define DNSSEC_KEYID_BINARY_SIZE 20
+
+/*!
+ * Check if a provided string is a valid key ID string.
+ */
+bool dnssec_keyid_is_valid(const char *id);
+
+/*!
+ * Normalize the key ID string.
+ */
+void dnssec_keyid_normalize(char *id);
+
+/*!
+ * Create a normalized copy if the key ID.
+ */
+char *dnssec_keyid_copy(const char *id);
+
+/*!
+ * Check if two key IDs are equal.
+ */
+bool dnssec_keyid_equal(const char *one, const char *two);
+
+/*! @} */
diff --git a/src/libdnssec/keystore.h b/src/libdnssec/keystore.h
new file mode 100644
index 0000000..2382518
--- /dev/null
+++ b/src/libdnssec/keystore.h
@@ -0,0 +1,297 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*!
+ * \file
+ *
+ * \addtogroup keystore
+ *
+ * \brief Private key store access.
+ *
+ * The module provides abstraction for private key store. Basically, PKCS #8
+ * and PKCS #11 interfaces are supported.
+ *
+ * PKCS #8 uses unencrypted PEM, and allows implementation of custom stores.
+ *
+ * PKCS #11 provides access Hardware Security Modules.
+ *
+ * Example of using default PKCS #8 and to generate an RSA key:
+ *
+ * ~~~~~ {.c}
+ *
+ * int result;
+ * dnssec_keystore_t *store = NULL;
+ *
+ * // create key store access context
+ * dnssec_keystore_init_pkcs8_dir(&store);
+ *
+ * // open the key store
+ * result = dnssec_keystore_open(&store, "/path/to/keydb");
+ * if (result != DNSSEC_EOK) {
+ * return result;
+ * }
+ *
+ * // generate new private key in the key store
+ * int algorithm = DNSSEC_KEY_ALGORITHM_RSA_SHA256;
+ * unsigned bits = 2048;
+ * char *id = NULL;
+ * int dnssec_keystore_generate_key(store, algorithm, bits, &key_id);
+ * if (result != DNSSEC_EOK) {
+ * dnssec_keystore_close(store);
+ * return result;
+ * }
+ * printf("ID of the new key: %s\n", key_id);
+ *
+ * // create new signing key
+ * dnssec_key_t *key = NULL;
+ * result = dnssec_key_new(&key);
+ * if (result != DNSSEC_EOK) {
+ * free(key_id);
+ * dnssec_keystore_close(store);
+ * return result;
+ * }
+ *
+ * // import the key from the key store
+ * result = dnssec_key_import_keystore(key, store, key_id, algorithm);
+ * if (result != DNSSEC_EOK) {
+ * free(key_id);
+ * dnssec_key_free(key);
+ * dnssec_keystore_close(store);
+ * return result;
+ * }
+ *
+ * // use the key for signing ...
+ *
+ * // cleanup
+ * free(key_id);
+ * dnssec_key_free(key);
+ * dnssec_keystore_close(store);
+ * dnssec_keystore_deinit(store);
+ *
+ * ~~~~~
+ * @{
+ */
+
+#pragma once
+
+#include <libdnssec/binary.h>
+#include <libdnssec/key.h>
+#include <libdnssec/list.h>
+
+struct dnssec_keystore;
+
+/*!
+ * DNSSEC private keys store.
+ */
+typedef struct dnssec_keystore dnssec_keystore_t;
+
+/*!
+ * PKCS #8 key store callback functions for custom providers.
+ */
+typedef struct dnssec_keystore_pkcs8_functions {
+ /*!
+ * Callback to allocate key store handle.
+ *
+ * \param[out] handle_ptr Allocated key store handle.
+ */
+ int (*handle_new)(void **handle_ptr);
+
+ /*!
+ * Callback to deallocate key store handle.
+ *
+ * \param handle Key store handle.
+ */
+ int (*handle_free)(void *handle);
+
+ /*!
+ * Callback to initialize the key store.
+ *
+ * \param handle Key store handle.
+ * \param config Configuration string.
+ */
+ int (*init)(void *handle, const char *config);
+
+ /*!
+ * Callback to open the key store.
+ *
+ * \param[out] handle Key store handle.
+ * \param[in] config Configuration string.
+ */
+ int (*open)(void *handle, const char *config);
+
+ /*!
+ * Callback to close the key store.
+ *
+ * \param handle Key store handle.
+ */
+ int (*close)(void *handle);
+
+ /*!
+ * Callback to read a PEM key.
+ *
+ * \param[in] handle Key store handle.
+ * \param[in] id Key ID of the key to be retrieved (ASCII form).
+ * \param[out] pem Key material in uncencrypted PEM format.
+ */
+ int (*read)(void *handle, const char *id, dnssec_binary_t *pem);
+
+ /*!
+ * Callback to write a PEM key.
+ *
+ * \param handle Key store handle.
+ * \param id Key ID of the key to be saved (ASCII form).
+ * \param pem Key material in unencrypted PEM format.
+ */
+ int (*write)(void *handle, const char *id, const dnssec_binary_t *pem);
+
+ /*!
+ * Callback to get a list of all PEM key IDs.
+ *
+ * \param[in] handle Key store handle.
+ * \param[out] list Allocated list of key IDs.
+ */
+ int (*list)(void *handle, dnssec_list_t **list);
+
+ /*!
+ * Callback to remove a PEM key.
+ *
+ * \param handle Key store handle.
+ * \param id Key ID of the key to be removed (ASCII form).
+ */
+ int (*remove)(void *handle, const char *id);
+} dnssec_keystore_pkcs8_functions_t;
+
+/*!
+ * Create default PKCS #8 private key store context.
+ *
+ * The default store maintains the private keys in one directory on the file
+ * system. The private keys are stored in unencrypted PEM format, named
+ * key-id.pem. The configuration string is a path to the directory.
+ *
+ * \param[out] store Opened key store.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int dnssec_keystore_init_pkcs8_dir(dnssec_keystore_t **store);
+
+/*!
+ * Create custom PKCS #8 private key store context.
+ *
+ * \param[out] store Opened key store.
+ * \param[in] impl Implementation of the key store provider.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int dnssec_keystore_init_pkcs8_custom(dnssec_keystore_t **store,
+ const dnssec_keystore_pkcs8_functions_t *impl);
+
+/*!
+ * Crate new PKCS #11 private key store context.
+ *
+ * \param[out] store Opened key store.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int dnssec_keystore_init_pkcs11(dnssec_keystore_t **store);
+
+/*!
+ * Deinitialize private key store context.
+ *
+ * \param store Key store to be deinitialized.
+ */
+int dnssec_keystore_deinit(dnssec_keystore_t *store);
+
+/*!
+ * Initialize new private key store.
+ */
+int dnssec_keystore_init(dnssec_keystore_t *store, const char *config);
+
+/*!
+ * Open private key store.
+ */
+int dnssec_keystore_open(dnssec_keystore_t *store, const char *config);
+
+/*!
+ * Close private key store.
+ *
+ * \param store Key store to be closed.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int dnssec_keystore_close(dnssec_keystore_t *store);
+
+/*!
+ * Get a list of key IDs stored in the key store.
+ *
+ * \todo Not implemented.
+ *
+ * \param[in] store Key store.
+ * \param[out] list Resulting list of key IDs.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int dnssec_keystore_list_keys(dnssec_keystore_t *store, dnssec_list_t **list);
+
+/*!
+ * Generate a new key in the key store.
+ *
+ * \param[in] store Key store.
+ * \param[in] algorithm Algorithm.
+ * \param[in] bits Bit length of the key to be generated.
+ * \param[out] id_ptr ID of the generated key. Must be freed by the caller.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int dnssec_keystore_generate_key(dnssec_keystore_t *store,
+ dnssec_key_algorithm_t algorithm,
+ unsigned bits, char **id_ptr);
+
+/*!
+ * Import an existing key into the key store.
+ *
+ * \param[in] store Key store.
+ * \param[in] pem Private key material in PEM format.
+ * \param[out] id_ptr ID of the imported key. Must be freed by the caller.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int dnssec_keystore_import(dnssec_keystore_t *store, const dnssec_binary_t *pem,
+ char **id_ptr);
+
+/*!
+ * Remove a private key from the key store.
+ *
+ * \param store Key store.
+ * \param id ID of the private key to be deleted.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int dnssec_keystore_remove_key(dnssec_keystore_t *store, const char *id);
+
+/*!
+ * Import public and/or private key from the key store into a DNSSEC key.
+ *
+ * The key algorithm has to be set before calling this function.
+ *
+ * \param key DNSSEC key to be initialized.
+ * \param keystore Private key store.
+ * \param id ID of the key.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int dnssec_key_import_keystore(dnssec_key_t *key, dnssec_keystore_t *keystore,
+ const char *id);
+
+/*! @} */
diff --git a/src/libdnssec/keystore/internal.h b/src/libdnssec/keystore/internal.h
new file mode 100644
index 0000000..a87dd03
--- /dev/null
+++ b/src/libdnssec/keystore/internal.h
@@ -0,0 +1,52 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <gnutls/gnutls.h>
+#include <gnutls/abstract.h>
+
+#include "libdnssec/binary.h"
+#include "libdnssec/key.h"
+#include "libdnssec/keystore.h"
+#include "libdnssec/list.h"
+
+typedef struct keystore_functions {
+ // construction of internal context
+ int (*ctx_new)(void **ctx_ptr, void *data);
+ int (*ctx_free)(void *ctx);
+ // keystore init/open/close
+ int (*init)(void *ctx, const char *config);
+ int (*open)(void *ctx, const char *config);
+ int (*close)(void *ctx);
+ // keystore access
+ int (*list_keys)(void *ctx, dnssec_list_t **list);
+ int (*generate_key)(void *ctx, gnutls_pk_algorithm_t algorithm,
+ unsigned bits, char **id_ptr);
+ int (*import_key)(void *ctx, const dnssec_binary_t *pem, char **id_ptr);
+ int (*remove_key)(void *ctx, const char *id);
+ // private key access
+ int (*get_private)(void *ctx, const char *id, gnutls_privkey_t *key_ptr);
+} keystore_functions_t;
+
+struct dnssec_keystore {
+ const keystore_functions_t *functions;
+ void *ctx;
+};
+
+int keystore_create(dnssec_keystore_t **store_ptr,
+ const keystore_functions_t *functions,
+ void *ctx_custom_data);
diff --git a/src/libdnssec/keystore/keystore.c b/src/libdnssec/keystore/keystore.c
new file mode 100644
index 0000000..203441a
--- /dev/null
+++ b/src/libdnssec/keystore/keystore.c
@@ -0,0 +1,183 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "libdnssec/error.h"
+#include "libdnssec/key.h"
+#include "libdnssec/key/algorithm.h"
+#include "libdnssec/key/dnskey.h"
+#include "libdnssec/key/internal.h"
+#include "libdnssec/key/privkey.h"
+#include "libdnssec/keyid.h"
+#include "libdnssec/keystore.h"
+#include "libdnssec/keystore/internal.h"
+#include "libdnssec/shared/shared.h"
+
+/* -- internal API --------------------------------------------------------- */
+
+int keystore_create(dnssec_keystore_t **store_ptr,
+ const keystore_functions_t *functions,
+ void *ctx_custom_data)
+{
+ assert(store_ptr);
+ assert(functions);
+
+ dnssec_keystore_t *store = calloc(1, sizeof(*store));
+ if (!store) {
+ return DNSSEC_ENOMEM;
+ }
+
+ store->functions = functions;
+
+ int result = functions->ctx_new(&store->ctx, ctx_custom_data);
+ if (result != DNSSEC_EOK) {
+ free(store);
+ return DNSSEC_ENOMEM;
+ }
+
+ *store_ptr = store;
+ return DNSSEC_EOK;
+}
+
+/* -- public API ----------------------------------------------------------- */
+
+_public_
+int dnssec_keystore_deinit(dnssec_keystore_t *store)
+{
+ if (!store) {
+ return DNSSEC_EINVAL;
+ }
+
+ dnssec_keystore_close(store);
+ store->functions->ctx_free(store->ctx);
+
+ free(store);
+
+ return DNSSEC_EOK;
+}
+
+_public_
+int dnssec_keystore_init(dnssec_keystore_t *store, const char *config)
+{
+ if (!store) {
+ return DNSSEC_EINVAL;
+ }
+
+ return store->functions->init(store->ctx, config);
+}
+
+_public_
+int dnssec_keystore_open(dnssec_keystore_t *store, const char *config)
+{
+ if (!store) {
+ return DNSSEC_EINVAL;
+ }
+
+ return store->functions->open(store->ctx, config);
+}
+
+_public_
+int dnssec_keystore_close(dnssec_keystore_t *store)
+{
+ if (!store) {
+ return DNSSEC_EINVAL;
+ }
+
+ return store->functions->close(store->ctx);
+}
+
+_public_
+int dnssec_keystore_list_keys(dnssec_keystore_t *store, dnssec_list_t **list)
+{
+ if (!store || !list) {
+ return DNSSEC_EINVAL;
+ }
+
+ return store->functions->list_keys(store->ctx, list);
+}
+
+_public_
+int dnssec_keystore_generate_key(dnssec_keystore_t *store,
+ dnssec_key_algorithm_t _algorithm,
+ unsigned bits, char **id_ptr)
+{
+ if (!store || !_algorithm || !id_ptr) {
+ return DNSSEC_EINVAL;
+ }
+
+ // prepare parameters
+
+ gnutls_pk_algorithm_t algorithm = algorithm_to_gnutls(_algorithm);
+ if (algorithm == GNUTLS_PK_UNKNOWN) {
+ return DNSSEC_INVALID_KEY_ALGORITHM;
+ }
+
+ if (!dnssec_algorithm_key_size_check(_algorithm, bits)) {
+ return DNSSEC_INVALID_KEY_SIZE;
+ }
+
+ return store->functions->generate_key(store->ctx, algorithm, bits, id_ptr);
+}
+
+_public_
+int dnssec_keystore_import(dnssec_keystore_t *store, const dnssec_binary_t *pem,
+ char **id_ptr)
+{
+ if (!store || !pem || !id_ptr) {
+ return DNSSEC_EINVAL;
+ }
+
+ return store->functions->import_key(store->ctx, pem, id_ptr);
+}
+
+_public_
+int dnssec_keystore_remove_key(dnssec_keystore_t *store, const char *key_id)
+{
+ if (!store || !key_id) {
+ return DNSSEC_EINVAL;
+ }
+
+ return store->functions->remove_key(store->ctx, key_id);
+}
+
+_public_
+int dnssec_key_import_keystore(dnssec_key_t *key, dnssec_keystore_t *store,
+ const char *id)
+{
+ if (!key || !store || !id || dnssec_key_get_algorithm(key) == 0) {
+ return DNSSEC_EINVAL;
+ }
+
+ if (key->private_key) {
+ return DNSSEC_KEY_ALREADY_PRESENT;
+ }
+
+ gnutls_privkey_t privkey = NULL;
+ int r = store->functions->get_private(store->ctx, id, &privkey);
+ if (r != DNSSEC_EOK) {
+ return r;
+ }
+
+ r = key_set_private_key(key, privkey);
+ if (r != DNSSEC_EOK) {
+ gnutls_privkey_deinit(privkey);
+ return r;
+ }
+
+ return DNSSEC_EOK;
+}
diff --git a/src/libdnssec/keystore/pkcs11.c b/src/libdnssec/keystore/pkcs11.c
new file mode 100644
index 0000000..dbe1a37
--- /dev/null
+++ b/src/libdnssec/keystore/pkcs11.c
@@ -0,0 +1,440 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <gnutls/gnutls.h>
+#include <pthread.h>
+
+#include "libdnssec/error.h"
+#include "libdnssec/shared/hex.h"
+#include "libdnssec/keyid.h"
+#include "libdnssec/shared/keyid_gnutls.h"
+#include "libdnssec/keystore.h"
+#include "libdnssec/keystore/internal.h"
+#include "libdnssec/p11/p11.h"
+#include "libdnssec/shared/pem.h"
+#include "libdnssec/shared/shared.h"
+
+#ifdef ENABLE_PKCS11
+
+struct pkcs11_ctx {
+ char *url;
+};
+
+typedef struct pkcs11_ctx pkcs11_ctx_t;
+
+/*!
+ * Flags used when generating/import key into the token.
+ */
+static const int TOKEN_ADD_FLAGS = GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE
+ | GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE;
+
+static int key_url(const char *token_uri, const char *key_id, char **url_ptr)
+{
+ assert(token_uri);
+ assert(key_id);
+ assert(url_ptr);
+
+ if (!dnssec_keyid_is_valid(key_id)) {
+ return DNSSEC_INVALID_KEY_ID;
+ }
+
+ size_t token_len = strlen(token_uri);
+ size_t id_len = strlen(key_id);
+
+ // url: <token-url>;id=%aa%bb%cc..
+
+ size_t len = token_len + 4 + (id_len / 2 * 3);
+ char *url = malloc(len + 1);
+ if (!url) {
+ return DNSSEC_ENOMEM;
+ }
+
+ size_t prefix = snprintf(url, len, "%s;id=", token_uri);
+ if (prefix != token_len + 4) {
+ free(url);
+ return DNSSEC_ENOMEM;
+ }
+
+ assert(id_len % 2 == 0);
+ char *pos = url + prefix;
+ for (int i = 0; i < id_len; i += 2, pos += 3) {
+ pos[0] = '%';
+ pos[1] = key_id[i];
+ pos[2] = key_id[i+1];
+ }
+ assert(url + len == pos);
+ url[len] = '\0';
+
+ *url_ptr = url;
+ return DNSSEC_EOK;
+}
+
+/**
+ * Parse configuration string. Accepted format: "<pkcs11-url> <module-path>"
+ */
+static int parse_config(const char *config, char **uri_ptr, char **module_ptr)
+{
+ const char *space = strchr(config, ' ');
+ if (!space) {
+ return DNSSEC_KEYSTORE_INVALID_CONFIG;
+ }
+
+ char *url = strndup(config, space - config);
+ char *module = strdup(space + 1);
+
+ if (!url || !module) {
+ free(url);
+ free(module);
+ return DNSSEC_ENOMEM;
+ }
+
+ *uri_ptr = url;
+ *module_ptr = module;
+
+ return DNSSEC_EOK;
+}
+
+/*!
+ * Load PKCS #11 module and check if the token is available.
+ */
+static int safe_open(const char *config, char **url_ptr)
+{
+ char *url = NULL;
+ char *module = NULL;
+
+ int r = parse_config(config, &url, &module);
+ if (r != DNSSEC_EOK) {
+ return r;
+ }
+
+ r = p11_load_module(module);
+ free(module);
+ if (r != GNUTLS_E_SUCCESS) {
+ free(url);
+ return DNSSEC_P11_FAILED_TO_LOAD_MODULE;
+ }
+
+ unsigned int flags = 0;
+ r = gnutls_pkcs11_token_get_flags(url, &flags);
+ if (r != GNUTLS_E_SUCCESS) {
+ free(url);
+ return DNSSEC_P11_TOKEN_NOT_AVAILABLE;
+ }
+
+ *url_ptr = url;
+
+ return DNSSEC_EOK;
+}
+
+/* -- internal API --------------------------------------------------------- */
+
+static void disable_pkcs11_callbacks(void)
+{
+ gnutls_pkcs11_set_pin_function(NULL, NULL);
+ gnutls_pkcs11_set_token_function(NULL, NULL);
+}
+
+static int pkcs11_ctx_new(void **ctx_ptr, _unused_ void *data)
+{
+ static pthread_once_t once = PTHREAD_ONCE_INIT;
+ pthread_once(&once, disable_pkcs11_callbacks);
+
+ pkcs11_ctx_t *ctx = calloc(1, sizeof(*ctx));
+ if (!ctx) {
+ return DNSSEC_ENOMEM;
+ }
+
+ *ctx_ptr = ctx;
+
+ return DNSSEC_EOK;
+}
+
+static int pkcs11_ctx_free(void *ctx)
+{
+ if (ctx) {
+ free(ctx);
+ }
+
+ return DNSSEC_EOK;
+}
+
+static int pkcs11_init(void *ctx, const char *config)
+{
+ /*
+ * Current keystore initialization is idempotent. We don't really
+ * initialize the token because don't want to wipe the data. We just
+ * check that the token is available the same way pkcs11_open() does.
+ */
+
+ _cleanup_free_ char *url = NULL;
+
+ return safe_open(config, &url);
+}
+
+static int pkcs11_open(void *_ctx, const char *config)
+{
+ pkcs11_ctx_t *ctx = _ctx;
+
+ return safe_open(config, &ctx->url);
+}
+
+static int pkcs11_close(void *_ctx)
+{
+ pkcs11_ctx_t *ctx = _ctx;
+
+ free(ctx->url);
+ clear_struct(ctx);
+
+ return DNSSEC_EOK;
+}
+
+static char *get_object_id(gnutls_pkcs11_obj_t object)
+{
+ assert(object);
+
+ uint8_t buffer[DNSSEC_KEYID_BINARY_SIZE] = { 0 };
+ size_t size = sizeof(buffer);
+
+ int r = gnutls_pkcs11_obj_get_info(object, GNUTLS_PKCS11_OBJ_ID, buffer, &size);
+ if (r != GNUTLS_E_SUCCESS || size != sizeof(buffer)) {
+ return NULL;
+ }
+
+ const dnssec_binary_t bin = { .data = buffer, .size = sizeof(buffer) };
+ char *id = NULL;
+ if (bin_to_hex(&bin, &id) != DNSSEC_EOK) {
+ return NULL;
+ }
+
+ assert(strlen(id) == DNSSEC_KEYID_SIZE);
+
+ return id;
+}
+
+static int pkcs11_list_keys(void *_ctx, dnssec_list_t **list)
+{
+ pkcs11_ctx_t *ctx = _ctx;
+
+ dnssec_list_t *ids = dnssec_list_new();
+ if (!ids) {
+ return DNSSEC_ENOMEM;
+ }
+
+ gnutls_pkcs11_obj_t *objects = NULL;
+ unsigned count = 0;
+
+ int flags = GNUTLS_PKCS11_OBJ_FLAG_PRIVKEY |
+ GNUTLS_PKCS11_OBJ_FLAG_LOGIN;
+
+ int r = gnutls_pkcs11_obj_list_import_url4(&objects, &count, ctx->url, flags);
+ if (r != GNUTLS_E_SUCCESS) {
+ dnssec_list_free(ids);
+ return DNSSEC_P11_TOKEN_NOT_AVAILABLE;
+ }
+
+ for (unsigned i = 0; i < count; i++) {
+ gnutls_pkcs11_obj_t object = objects[i];
+ char *id = get_object_id(object);
+ dnssec_list_append(ids, id);
+ gnutls_pkcs11_obj_deinit(object);
+ }
+
+ gnutls_free(objects);
+
+ *list = ids;
+ return DNSSEC_EOK;
+}
+
+static int pkcs11_generate_key(void *_ctx, gnutls_pk_algorithm_t algorithm,
+ unsigned bits, char **id_ptr)
+{
+ pkcs11_ctx_t *ctx = _ctx;
+
+ uint8_t buf[20] = { 0 };
+ gnutls_rnd(GNUTLS_RND_RANDOM, buf, sizeof(buf));
+ dnssec_binary_t cka_id = { .data = buf, .size = sizeof(buf) };
+
+ int flags = TOKEN_ADD_FLAGS | GNUTLS_PKCS11_OBJ_FLAG_LOGIN;
+ gnutls_datum_t gt_cka_id = binary_to_datum(&cka_id);
+ int r = gnutls_pkcs11_privkey_generate3(ctx->url, algorithm, bits, NULL, &gt_cka_id, 0, NULL, 0, flags);
+ if (r != GNUTLS_E_SUCCESS) {
+ return DNSSEC_KEY_GENERATE_ERROR;
+ }
+
+ char *id = NULL;
+ r = bin_to_hex(&cka_id, &id);
+ if (r != DNSSEC_EOK) {
+ return DNSSEC_ENOMEM;
+ }
+
+ *id_ptr = id;
+
+ return DNSSEC_EOK;
+}
+
+static int import_pem(const dnssec_binary_t *pem,
+ gnutls_x509_privkey_t *key_ptr,
+ gnutls_pubkey_t *pubkey_ptr)
+{
+ gnutls_x509_privkey_t x509_key = NULL;
+ gnutls_privkey_t key = NULL;
+ gnutls_pubkey_t pubkey = NULL;
+
+ int r = pem_x509(pem, &x509_key);
+ if (r != DNSSEC_EOK) {
+ goto fail;
+ }
+
+ if (gnutls_privkey_init(&key) != GNUTLS_E_SUCCESS ||
+ gnutls_pubkey_init(&pubkey) != GNUTLS_E_SUCCESS
+ ) {
+ r = DNSSEC_ENOMEM;
+ goto fail;
+ }
+
+ if (gnutls_privkey_import_x509(key, x509_key, 0) != GNUTLS_E_SUCCESS ||
+ gnutls_pubkey_import_privkey(pubkey, key, 0, 0) != GNUTLS_E_SUCCESS
+ ) {
+ r = DNSSEC_KEY_IMPORT_ERROR;
+ goto fail;
+ }
+
+fail:
+ gnutls_privkey_deinit(key);
+
+ if (r == DNSSEC_EOK) {
+ *key_ptr = x509_key;
+ *pubkey_ptr = pubkey;
+ } else {
+ gnutls_x509_privkey_deinit(x509_key);
+ gnutls_pubkey_deinit(pubkey);
+ }
+
+ return r;
+}
+
+static int pkcs11_import_key(void *_ctx, const dnssec_binary_t *pem, char **id_ptr)
+{
+ pkcs11_ctx_t *ctx = _ctx;
+
+ _cleanup_x509_privkey_ gnutls_x509_privkey_t key = NULL;
+ _cleanup_pubkey_ gnutls_pubkey_t pubkey = NULL;
+
+ int r = import_pem(pem, &key, &pubkey);
+ if (r != DNSSEC_EOK) {
+ return r;
+ }
+
+ _cleanup_binary_ dnssec_binary_t id = { 0 };
+ r = keyid_x509(key, &id);
+ if (r != DNSSEC_EOK) {
+ return r;
+ }
+
+ int flags = TOKEN_ADD_FLAGS | GNUTLS_PKCS11_OBJ_FLAG_LOGIN;
+ gnutls_datum_t gid = binary_to_datum(&id);
+
+ r = gnutls_pkcs11_copy_x509_privkey2(ctx->url, key, NULL, &gid, 0, flags);
+ if (r != GNUTLS_E_SUCCESS) {
+ return DNSSEC_KEY_IMPORT_ERROR;
+ }
+
+ r = gnutls_pkcs11_copy_pubkey(ctx->url, pubkey, NULL, &gid, 0, flags);
+ if (r != GNUTLS_E_SUCCESS) {
+ // note, we result with dangling private key in the token
+ return DNSSEC_KEY_IMPORT_ERROR;
+ }
+
+ return bin_to_hex(&id, id_ptr);
+}
+
+static int pkcs11_remove_key(void *_ctx, const char *id)
+{
+ pkcs11_ctx_t *ctx = _ctx;
+
+ _cleanup_free_ char *url = NULL;
+ int r = key_url(ctx->url, id, &url);
+ if (r != DNSSEC_EOK) {
+ return r;
+ }
+
+ r = gnutls_pkcs11_delete_url(url, GNUTLS_PKCS11_OBJ_FLAG_LOGIN);
+ if (r < 0) {
+ return DNSSEC_ERROR;
+ } else if (r == 0) {
+ return DNSSEC_ENOENT;
+ }
+
+ return DNSSEC_EOK;
+}
+
+static int pkcs11_get_private(void *_ctx, const char *id, gnutls_privkey_t *key_ptr)
+{
+ pkcs11_ctx_t *ctx = _ctx;
+
+ _cleanup_free_ char *url = NULL;
+ int r = key_url(ctx->url, id, &url);
+ if (r != DNSSEC_EOK) {
+ return r;
+ }
+
+ gnutls_privkey_t key = NULL;
+ r = gnutls_privkey_init(&key);
+ if (r != GNUTLS_E_SUCCESS) {
+ return DNSSEC_ENOMEM;
+ }
+
+ r = gnutls_privkey_import_pkcs11_url(key, url);
+ if (r != GNUTLS_E_SUCCESS) {
+ gnutls_privkey_deinit(key);
+ return DNSSEC_NOT_FOUND;
+ }
+
+ *key_ptr = key;
+
+ return DNSSEC_EOK;
+}
+
+/* -- public API ----------------------------------------------------------- */
+
+_public_
+int dnssec_keystore_init_pkcs11(dnssec_keystore_t **store_ptr)
+{
+ static const keystore_functions_t IMPLEMENTATION = {
+ .ctx_new = pkcs11_ctx_new,
+ .ctx_free = pkcs11_ctx_free,
+ .init = pkcs11_init,
+ .open = pkcs11_open,
+ .close = pkcs11_close,
+ .list_keys = pkcs11_list_keys,
+ .generate_key = pkcs11_generate_key,
+ .import_key = pkcs11_import_key,
+ .remove_key = pkcs11_remove_key,
+ .get_private = pkcs11_get_private,
+ };
+
+ return keystore_create(store_ptr, &IMPLEMENTATION, NULL);
+}
+
+#else // !ENABLE_PKCS11
+
+_public_
+int dnssec_keystore_init_pkcs11(dnssec_keystore_t **store_ptr)
+{
+ return DNSSEC_NOT_IMPLEMENTED_ERROR;
+}
+
+#endif
diff --git a/src/libdnssec/keystore/pkcs8.c b/src/libdnssec/keystore/pkcs8.c
new file mode 100644
index 0000000..f05eda0
--- /dev/null
+++ b/src/libdnssec/keystore/pkcs8.c
@@ -0,0 +1,211 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+
+#include "libdnssec/error.h"
+#include "libdnssec/key/algorithm.h"
+#include "libdnssec/keyid.h"
+#include "libdnssec/keystore.h"
+#include "libdnssec/keystore/internal.h"
+#include "libdnssec/shared/pem.h"
+#include "libdnssec/shared/shared.h"
+
+/*!
+ * PKCS #8 key store context.
+ */
+typedef struct pkcs8_ctx {
+ /*! Storage implementation callbacks. */
+ const dnssec_keystore_pkcs8_functions_t *functions;
+ /*! Implementation specific context data. */
+ void *data;
+} pkcs8_ctx_t;
+
+/* -- internal API --------------------------------------------------------- */
+
+static int pkcs8_ctx_new(void **ctx_ptr, void *_functions)
+{
+ assert(ctx_ptr);
+ assert(_functions);
+
+ pkcs8_ctx_t *ctx = calloc(1, sizeof(*ctx));
+ if (!ctx) {
+ return DNSSEC_ENOMEM;
+ }
+
+ ctx->functions = _functions;
+
+ int r = ctx->functions->handle_new(&ctx->data);
+ if (r != DNSSEC_EOK) {
+ free(ctx);
+ return r;
+ }
+
+ *ctx_ptr = ctx;
+
+ return DNSSEC_EOK;
+}
+
+static int pkcs8_ctx_free(void *_ctx)
+{
+ pkcs8_ctx_t *ctx = _ctx;
+ int r = ctx->functions->handle_free(ctx->data);
+
+ free(ctx);
+
+ return r;
+}
+
+static int pkcs8_init(void *_ctx, const char *config)
+{
+ pkcs8_ctx_t *ctx = _ctx;
+ return ctx->functions->init(ctx->data, config);
+}
+
+static int pkcs8_open(void *_ctx, const char *config)
+{
+ pkcs8_ctx_t *ctx = _ctx;
+ return ctx->functions->open(ctx->data, config);
+}
+
+static int pkcs8_close(void *_ctx)
+{
+ pkcs8_ctx_t *ctx = _ctx;
+ return ctx->functions->close(ctx->data);
+}
+
+static int pkcs8_list_keys(void *_ctx, dnssec_list_t **list)
+{
+ pkcs8_ctx_t *ctx = _ctx;
+ return ctx->functions->list(ctx->data, list);
+}
+
+static int pkcs8_generate_key(void *_ctx, gnutls_pk_algorithm_t algorithm,
+ unsigned bits, char **id_ptr)
+{
+ assert(_ctx);
+ assert(id_ptr);
+
+ pkcs8_ctx_t *ctx = _ctx;
+
+ // generate key
+
+ char *new_id = NULL;
+ _cleanup_binary_ dnssec_binary_t data = { 0 };
+ int r = pem_generate(algorithm, bits, &data, &new_id);
+ if (r != DNSSEC_EOK) {
+ return r;
+ }
+
+ // save key
+
+ r = ctx->functions->write(ctx->data, new_id, &data);
+ if (r != DNSSEC_EOK) {
+ return r;
+ }
+
+ // finish
+
+ *id_ptr = new_id;
+
+ return DNSSEC_EOK;
+}
+
+static int pkcs8_import_key(void *_ctx, const dnssec_binary_t *pem, char **id_ptr)
+{
+ pkcs8_ctx_t *ctx = _ctx;
+
+ // retrieve key ID
+
+ char *id = NULL;
+ int r = pem_keyid(pem, &id);
+ if (r != DNSSEC_EOK) {
+ return r;
+ }
+
+ // save the key
+
+ r = ctx->functions->write(ctx->data, id, pem);
+ if (r != DNSSEC_EOK) {
+ free(id);
+ return r;
+ }
+
+ *id_ptr = id;
+
+ return DNSSEC_EOK;
+}
+
+static int pkcs8_remove_key(void *_ctx, const char *id)
+{
+ pkcs8_ctx_t *ctx = _ctx;
+ return ctx->functions->remove(ctx->data, id);
+}
+
+static int pkcs8_get_private(void *_ctx, const char *id, gnutls_privkey_t *key_ptr)
+{
+ assert(_ctx);
+ assert(id);
+ assert(key_ptr);
+
+ pkcs8_ctx_t *ctx = _ctx;
+
+ // load private key data
+
+ _cleanup_binary_ dnssec_binary_t pem = { 0 };
+ int r = ctx->functions->read(ctx->data, id, &pem);
+ if (r != DNSSEC_EOK) {
+ return r;
+ }
+
+ // construct the key
+
+ gnutls_privkey_t key = NULL;
+ r = pem_privkey(&pem, &key);
+ if (r != DNSSEC_EOK) {
+ return r;
+ }
+
+ *key_ptr = key;
+
+ return DNSSEC_EOK;
+}
+
+static const keystore_functions_t PKCS8_FUNCTIONS = {
+ .ctx_new = pkcs8_ctx_new,
+ .ctx_free = pkcs8_ctx_free,
+ .init = pkcs8_init,
+ .open = pkcs8_open,
+ .close = pkcs8_close,
+ .list_keys = pkcs8_list_keys,
+ .generate_key = pkcs8_generate_key,
+ .import_key = pkcs8_import_key,
+ .remove_key = pkcs8_remove_key,
+ .get_private = pkcs8_get_private,
+};
+
+/* -- public API ----------------------------------------------------------- */
+
+_public_
+int dnssec_keystore_init_pkcs8_custom(dnssec_keystore_t **store_ptr,
+ const dnssec_keystore_pkcs8_functions_t *store_functions)
+{
+ if (!store_ptr || !store_functions) {
+ return DNSSEC_EINVAL;
+ }
+
+ return keystore_create(store_ptr, &PKCS8_FUNCTIONS, (void *)store_functions);
+}
diff --git a/src/libdnssec/keystore/pkcs8_dir.c b/src/libdnssec/keystore/pkcs8_dir.c
new file mode 100644
index 0000000..bc67ad5
--- /dev/null
+++ b/src/libdnssec/keystore/pkcs8_dir.c
@@ -0,0 +1,379 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "libdnssec/binary.h"
+#include "libdnssec/error.h"
+#include "libdnssec/shared/fs.h"
+#include "libdnssec/key.h"
+#include "libdnssec/keystore.h"
+#include "libdnssec/keystore/internal.h"
+#include "libdnssec/shared/shared.h"
+
+#define DIR_INIT_MODE 0750
+
+/*!
+ * Context for PKCS #8 key directory.
+ */
+typedef struct pkcs8_dir_handle {
+ char *dir_name;
+} pkcs8_dir_handle_t;
+
+/* -- internal functions --------------------------------------------------- */
+
+/*!
+ * Get path to a private key in PKCS #8 PEM format.
+ */
+static char *key_path(const char *dir, const char *id)
+{
+ char *strp = NULL;
+
+ int ret = asprintf(&strp, "%s/%s.pem", dir, id);
+ if (ret < 0) {
+ return NULL;
+ }
+ return strp;
+}
+
+/*!
+ * Get size of the file and reset the position to the beginning of the file.
+ */
+static int file_size(int fd, size_t *size)
+{
+ off_t offset = lseek(fd, 0, SEEK_END);
+ if (offset == -1) {
+ return dnssec_errno_to_error(errno);
+ }
+
+ if (lseek(fd, 0, SEEK_SET) == -1) {
+ return dnssec_errno_to_error(errno);
+ }
+
+ assert(offset >= 0);
+ *size = offset;
+
+ return DNSSEC_EOK;
+}
+
+/*!
+ * Open a key file and get the descriptor.
+ */
+static int key_open(const char *dir_name, const char *id, int flags,
+ mode_t mode, int *fd_ptr)
+{
+ assert(dir_name);
+ assert(id);
+ assert(fd_ptr);
+
+ _cleanup_free_ char *filename = key_path(dir_name, id);
+ if (!filename) {
+ return DNSSEC_ENOMEM;
+ }
+
+ int fd = open(filename, flags, mode);
+ if (fd == -1) {
+ return dnssec_errno_to_error(errno);
+ }
+
+ *fd_ptr = fd;
+
+ return DNSSEC_EOK;
+}
+
+static int key_open_read(const char *dir_name, const char *id, int *fd_ptr)
+{
+ return key_open(dir_name, id, O_RDONLY, 0, fd_ptr);
+}
+
+static int key_open_write(const char *dir_name, const char *id, int *fd_ptr)
+{
+ return key_open(dir_name, id, O_WRONLY|O_CREAT|O_EXCL,
+ S_IRUSR|S_IWUSR|S_IRGRP, fd_ptr);
+}
+
+/*!
+ * Strip '.pem' suffix, basename has to be valid key ID.
+ */
+static char *filename_to_keyid(const char *filename)
+{
+ assert(filename);
+
+ size_t len = strlen(filename);
+
+ const char ext[] = ".pem";
+ const size_t ext_len = sizeof(ext) - 1;
+
+ if (len < ext_len || strcmp(filename + len - ext_len, ext) != 0) {
+ return NULL;
+ }
+
+ return strndup(filename, len - ext_len);
+}
+
+/* -- PKCS #8 dir access API ----------------------------------------------- */
+
+static int pkcs8_dir_handle_new(void **handle_ptr)
+{
+ if (!handle_ptr) {
+ return DNSSEC_EINVAL;
+ }
+
+ pkcs8_dir_handle_t *handle = calloc(1, sizeof(*handle));
+ if (!handle) {
+ return DNSSEC_ENOMEM;
+ }
+
+ *handle_ptr = handle;
+
+ return DNSSEC_EOK;
+}
+
+static int pkcs8_dir_handle_free(void *handle)
+{
+ free(handle);
+
+ return DNSSEC_EOK;
+}
+
+static int pkcs8_dir_init(void *handle, const char *path)
+{
+ if (!handle || !path) {
+ return DNSSEC_EINVAL;
+ }
+
+ return fs_mkdir(path, DIR_INIT_MODE, true);
+}
+
+static int pkcs8_dir_open(void *_handle, const char *config)
+{
+ if (!_handle || !config) {
+ return DNSSEC_EINVAL;
+ }
+
+ pkcs8_dir_handle_t *handle = _handle;
+
+ char *path = realpath(config, NULL);
+ if (!path) {
+ return DNSSEC_NOT_FOUND;
+ }
+
+ handle->dir_name = path;
+
+ return DNSSEC_EOK;
+}
+
+static int pkcs8_dir_close(void *_handle)
+{
+ if (!_handle) {
+ return DNSSEC_EINVAL;
+ }
+
+ pkcs8_dir_handle_t *handle = _handle;
+
+ free(handle->dir_name);
+ memset(handle, 0, sizeof(*handle));
+
+ return DNSSEC_EOK;
+}
+
+static int pkcs8_dir_read(void *_handle, const char *id, dnssec_binary_t *pem)
+{
+ if (!_handle || !id || !pem) {
+ return DNSSEC_EINVAL;
+ }
+
+ pkcs8_dir_handle_t *handle = _handle;
+
+ // open file and get it's size
+
+ _cleanup_close_ int file = 0;
+ int result = key_open_read(handle->dir_name, id, &file);
+ if (result != DNSSEC_EOK) {
+ return result;
+ }
+
+ size_t size = 0;
+ result = file_size(file, &size);
+ if (result != DNSSEC_EOK) {
+ return result;
+ }
+
+ if (size == 0) {
+ return DNSSEC_MALFORMED_DATA;
+ }
+
+ // read the stored data
+
+ dnssec_binary_t read_pem = { 0 };
+ result = dnssec_binary_alloc(&read_pem, size);
+ if (result != DNSSEC_EOK) {
+ return result;
+ }
+
+ ssize_t read_count = read(file, read_pem.data, read_pem.size);
+ if (read_count == -1) {
+ dnssec_binary_free(&read_pem);
+ return dnssec_errno_to_error(errno);
+ }
+
+ assert(read_count == read_pem.size);
+ *pem = read_pem;
+
+ return DNSSEC_EOK;
+}
+
+static bool key_is_duplicate(int open_error, pkcs8_dir_handle_t *handle,
+ const char *id, const dnssec_binary_t *pem)
+{
+ assert(handle);
+ assert(id);
+ assert(pem);
+
+ if (open_error != dnssec_errno_to_error(EEXIST)) {
+ return false;
+ }
+
+ _cleanup_binary_ dnssec_binary_t old = { 0 };
+ int r = pkcs8_dir_read(handle, id, &old);
+ if (r != DNSSEC_EOK) {
+ return false;
+ }
+
+ return dnssec_binary_cmp(&old, pem) == 0;
+}
+
+static int pkcs8_dir_write(void *_handle, const char *id, const dnssec_binary_t *pem)
+{
+ if (!_handle || !id || !pem) {
+ return DNSSEC_EINVAL;
+ }
+
+ if (pem->size == 0 || pem->data == NULL) {
+ return DNSSEC_MALFORMED_DATA;
+ }
+
+ pkcs8_dir_handle_t *handle = _handle;
+
+ // create the file
+
+ _cleanup_close_ int file = 0;
+ int result = key_open_write(handle->dir_name, id, &file);
+ if (result != DNSSEC_EOK) {
+ if (key_is_duplicate(result, handle, id, pem)) {
+ return DNSSEC_EOK;
+ }
+ return result;
+ }
+
+ // write the data
+
+ ssize_t wrote_count = write(file, pem->data, pem->size);
+ if (wrote_count == -1) {
+ return dnssec_errno_to_error(errno);
+ }
+
+ assert(wrote_count == pem->size);
+
+ return DNSSEC_EOK;
+}
+
+static int pkcs8_dir_list(void *_handle, dnssec_list_t **list_ptr)
+{
+ if (!_handle || !list_ptr) {
+ return DNSSEC_EINVAL;
+ }
+
+ pkcs8_dir_handle_t *handle = _handle;
+
+ _cleanup_closedir_ DIR *dir = opendir(handle->dir_name);
+ if (!dir) {
+ return DNSSEC_NOT_FOUND;
+ }
+
+ dnssec_list_t *list = dnssec_list_new();
+ if (!list) {
+ return DNSSEC_ENOMEM;
+ }
+
+ errno = 0;
+ struct dirent *result;
+ while ((result = readdir(dir)) != NULL) {
+ char *keyid = filename_to_keyid(result->d_name);
+ if (keyid) {
+ dnssec_list_append(list, keyid);
+ }
+ }
+
+ if (errno != 0) {
+ dnssec_list_free_full(list, NULL, NULL);
+ return dnssec_errno_to_error(errno);
+ }
+
+ *list_ptr = list;
+
+ return DNSSEC_EOK;
+}
+
+static int pkcs8_dir_remove(void *_handle, const char *id)
+{
+ if (!_handle || !id) {
+ return DNSSEC_EINVAL;
+ }
+
+ pkcs8_dir_handle_t *handle = _handle;
+
+ _cleanup_free_ char *filename = key_path(handle->dir_name, id);
+ if (!filename) {
+ return DNSSEC_ENOMEM;
+ }
+
+ if (unlink(filename) == -1) {
+ return dnssec_errno_to_error(errno);
+ }
+
+ return DNSSEC_EOK;
+}
+
+const dnssec_keystore_pkcs8_functions_t PKCS8_DIR_FUNCTIONS = {
+ .handle_new = pkcs8_dir_handle_new,
+ .handle_free = pkcs8_dir_handle_free,
+ .init = pkcs8_dir_init,
+ .open = pkcs8_dir_open,
+ .close = pkcs8_dir_close,
+ .read = pkcs8_dir_read,
+ .write = pkcs8_dir_write,
+ .list = pkcs8_dir_list,
+ .remove = pkcs8_dir_remove,
+};
+
+/* -- public API ----------------------------------------------------------- */
+
+_public_
+int dnssec_keystore_init_pkcs8_dir(dnssec_keystore_t **store_ptr)
+{
+ if (!store_ptr) {
+ return DNSSEC_EINVAL;
+ }
+
+ return dnssec_keystore_init_pkcs8_custom(store_ptr, &PKCS8_DIR_FUNCTIONS);
+}
diff --git a/src/libdnssec/keytag.h b/src/libdnssec/keytag.h
new file mode 100644
index 0000000..5a8424e
--- /dev/null
+++ b/src/libdnssec/keytag.h
@@ -0,0 +1,63 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*!
+ * \file
+ *
+ * \addtogroup keytag
+ *
+ * \brief Low-level key tag computation API.
+ *
+ * The module provides simple interface for DNSKEY key id computation.
+ *
+ * Example:
+ *
+ * ~~~~~ {.c}
+ *
+ * dnssec_binary_t dnskey_rdata = // ... ;
+ *
+ * int result;
+ * uint16_t keytag = 0;
+ *
+ * result = dnssec_keytag(&dnskey_rdata, &keytag);
+ * if (result != DNSSEC_EOK) {
+ * return result;
+ * }
+ *
+ * printf("keytag: %s\n", keytag);
+ *
+ * ~~~~~
+ *
+ * @{
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <libdnssec/binary.h>
+
+/*!
+ * Compute a key tag for a DNSSEC key.
+ *
+ * \param[in] rdata DNSKEY RDATA.
+ * \param[out] keytag Computed keytag.
+ *
+ * \return Error code, DNSSEC_EOK of successful.
+ */
+int dnssec_keytag(const dnssec_binary_t *rdata, uint16_t *keytag);
+
+/*!
+ * @}
+ */
diff --git a/src/libdnssec/list.h b/src/libdnssec/list.h
new file mode 100644
index 0000000..838c0b5
--- /dev/null
+++ b/src/libdnssec/list.h
@@ -0,0 +1,85 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*!
+ * \file
+ *
+ * \addtogroup list
+ *
+ * \brief DNSSEC generic lists.
+ *
+ * @{
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+struct dnssec_list;
+typedef struct dnssec_list dnssec_list_t;
+
+struct dnssec_item;
+typedef struct dnssec_item dnssec_item_t;
+
+void *dnssec_item_get(const dnssec_item_t *item);
+void dnssec_item_set(dnssec_item_t *item, void *data);
+
+dnssec_list_t *dnssec_list_new(void);
+void dnssec_list_free(dnssec_list_t *list);
+
+typedef void (*dnssec_item_free_cb)(void *data, void *ctx);
+
+/*!
+ * Free the list including contained items.
+ *
+ * If \c free_cb is NULL, standard libc \c free will used to free the items.
+ *
+ * \param list List to be freed.
+ * \param free_cb Free function called for each item in the list.
+ * \param free_ctx Context passed to item free.
+ */
+void dnssec_list_free_full(dnssec_list_t *list, dnssec_item_free_cb free_cb,
+ void *free_ctx);
+
+void dnssec_list_clear(dnssec_list_t *list);
+void dnssec_list_clear_full(dnssec_list_t *list, dnssec_item_free_cb free_cb,
+ void *free_ctx);
+
+dnssec_item_t *dnssec_list_head(dnssec_list_t *list);
+dnssec_item_t *dnssec_list_tail(dnssec_list_t *list);
+dnssec_item_t *dnssec_list_next(dnssec_list_t *list, dnssec_item_t *item);
+dnssec_item_t *dnssec_list_prev(dnssec_list_t *list, dnssec_item_t *item);
+dnssec_item_t *dnssec_list_nth(dnssec_list_t *list, size_t position);
+
+bool dnssec_list_is_empty(dnssec_list_t *list);
+size_t dnssec_list_size(dnssec_list_t *list);
+
+int dnssec_list_insert_after(dnssec_item_t *item, void *data);
+int dnssec_list_insert_before(dnssec_item_t *item, void *data);
+int dnssec_list_append(dnssec_list_t *list, void *data);
+int dnssec_list_prepend(dnssec_list_t *list, void *data);
+
+void dnssec_list_remove(dnssec_item_t *item);
+
+dnssec_item_t *dnssec_list_search(dnssec_list_t *list, void *data);
+bool dnssec_list_contains(dnssec_list_t *list, void *data);
+
+#define dnssec_list_foreach(var, list) \
+ for (dnssec_item_t *__tmp, *var = dnssec_list_head(list); \
+ __tmp = dnssec_list_next(list, var), var != NULL; \
+ var = __tmp)
+
+/*! @} */
diff --git a/src/libdnssec/list/list.c b/src/libdnssec/list/list.c
new file mode 100644
index 0000000..5d9aded
--- /dev/null
+++ b/src/libdnssec/list/list.c
@@ -0,0 +1,298 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdlib.h>
+
+#include "libdnssec/list.h"
+#include "libdnssec/list/ucw_clists.h"
+#include "libdnssec/error.h"
+#include "libdnssec/shared/shared.h"
+
+struct dnssec_list {
+ clist list;
+};
+
+struct dnssec_item {
+ cnode node;
+ void *data;
+};
+
+/*!
+ * Allocate new list item and set item data.
+ */
+static dnssec_item_t *item_new(void *data)
+{
+ dnssec_item_t *item = malloc(sizeof(*item));
+ if (item) {
+ clear_struct(item);
+ item->data = data;
+ }
+
+ return item;
+}
+
+/*!
+ * Wrapper around libc free with unused context.
+ */
+static void wrap_free(void *ptr, void *ctx _unused_)
+{
+ free(ptr);
+}
+
+/* -- public API ----------------------------------------------------------- */
+
+_public_
+void *dnssec_item_get(const dnssec_item_t *item)
+{
+ return item ? item->data : NULL;
+}
+
+_public_
+void dnssec_item_set(dnssec_item_t *item, void *data)
+{
+ if (item) {
+ item->data = data;
+ }
+}
+
+_public_
+dnssec_list_t *dnssec_list_new(void)
+{
+ dnssec_list_t *list = malloc(sizeof(*list));
+ if (list) {
+ clist_init(&list->list);
+ }
+
+ return list;
+}
+
+_public_
+void dnssec_list_clear(dnssec_list_t *list)
+{
+ if (!list) {
+ return;
+ }
+
+ dnssec_list_foreach(item, list) {
+ free(item);
+ }
+}
+
+_public_
+void dnssec_list_clear_full(dnssec_list_t *list, dnssec_item_free_cb free_cb,
+ void *free_ctx)
+{
+ if (!list) {
+ return;
+ }
+
+ if (!free_cb) {
+ free_cb = wrap_free;
+ }
+
+ dnssec_list_foreach(item, list) {
+ free_cb(item->data, free_ctx);
+ free(item);
+ }
+}
+
+_public_
+void dnssec_list_free(dnssec_list_t *list)
+{
+ if (!list) {
+ return;
+ }
+
+ dnssec_list_clear(list);
+ free(list);
+}
+
+_public_
+void dnssec_list_free_full(dnssec_list_t *list, dnssec_item_free_cb free_cb,
+ void *free_ctx)
+{
+ if (!list) {
+ return;
+ }
+
+ dnssec_list_clear_full(list, free_cb, free_ctx);
+ free(list);
+}
+
+_public_
+dnssec_item_t *dnssec_list_head(dnssec_list_t *list)
+{
+ if (!list) {
+ return NULL;
+ }
+
+ return clist_head(&list->list);
+}
+
+_public_
+dnssec_item_t *dnssec_list_tail(dnssec_list_t *list)
+{
+ if (!list) {
+ return NULL;
+ }
+
+ return clist_tail(&list->list);
+}
+
+_public_
+dnssec_item_t *dnssec_list_next(dnssec_list_t *list, dnssec_item_t *item)
+{
+ if (!list || !item) {
+ return NULL;
+ }
+
+ return clist_next(&list->list, &item->node);
+}
+
+_public_
+dnssec_item_t *dnssec_list_prev(dnssec_list_t *list, dnssec_item_t *item)
+{
+ if (!list || !item) {
+ return NULL;
+ }
+
+ return clist_prev(&list->list, &item->node);
+}
+
+_public_
+dnssec_item_t *dnssec_list_nth(dnssec_list_t *list, size_t position)
+{
+ size_t index = 0;
+ dnssec_item_t *item = dnssec_list_head(list);
+
+ while (item) {
+ if (index == position) {
+ return item;
+ } else {
+ item = dnssec_list_next(list, item);
+ index += 1;
+ }
+ }
+
+ return NULL;
+}
+
+_public_
+bool dnssec_list_is_empty(dnssec_list_t *list)
+{
+ return !list || clist_empty(&list->list);
+}
+
+_public_
+size_t dnssec_list_size(dnssec_list_t *list)
+{
+ return list ? clist_size(&list->list) : 0;
+}
+
+_public_
+int dnssec_list_insert_before(dnssec_item_t *item, void *data)
+{
+ if (!item) {
+ return DNSSEC_EINVAL;
+ }
+
+ dnssec_item_t *add = item_new(data);
+ if (!add) {
+ return DNSSEC_ENOMEM;
+ }
+
+ clist_insert_before(&add->node, &item->node);
+
+ return DNSSEC_EOK;
+}
+
+_public_
+int dnssec_list_insert_after(dnssec_item_t *item, void *data)
+{
+ if (!item) {
+ return DNSSEC_EINVAL;
+ }
+
+ dnssec_item_t *add = item_new(data);
+ if (!add) {
+ return DNSSEC_ENOMEM;
+ }
+
+ clist_insert_after(&add->node, &item->node);
+
+ return DNSSEC_EOK;
+}
+
+_public_
+int dnssec_list_append(dnssec_list_t *list, void *data)
+{
+ if (!list) {
+ return DNSSEC_EINVAL;
+ }
+
+ dnssec_item_t *add = item_new(data);
+ if (!add) {
+ return DNSSEC_ENOMEM;
+ }
+
+ clist_add_tail(&list->list , &add->node);
+
+ return DNSSEC_EOK;
+}
+
+_public_
+int dnssec_list_prepend(dnssec_list_t *list, void *data)
+{
+ if (!list) {
+ return DNSSEC_EINVAL;
+ }
+
+ dnssec_item_t *add = item_new(data);
+ if (!add) {
+ return DNSSEC_ENOMEM;
+ }
+
+ clist_add_head(&list->list , &add->node);
+
+ return DNSSEC_EOK;
+}
+
+_public_
+void dnssec_list_remove(dnssec_item_t *item)
+{
+ if (item) {
+ clist_remove(&item->node);
+ free(item);
+ }
+}
+
+_public_
+dnssec_item_t *dnssec_list_search(dnssec_list_t *list, void *data)
+{
+ dnssec_list_foreach(item, list) {
+ if (item->data == data) {
+ return item;
+ }
+ }
+
+ return NULL;
+}
+
+_public_
+bool dnssec_list_contains(dnssec_list_t *list, void *data)
+{
+ return dnssec_list_search(list, data) != NULL;
+}
diff --git a/src/libdnssec/list/ucw_clists.h b/src/libdnssec/list/ucw_clists.h
new file mode 100644
index 0000000..080d01e
--- /dev/null
+++ b/src/libdnssec/list/ucw_clists.h
@@ -0,0 +1,260 @@
+/*
+ * UCW Library -- Circular Linked Lists
+ *
+ * (c) 2003--2010 Martin Mares <mj@ucw.cz>
+ *
+ * This software may be freely distributed and used according to the terms
+ * of the GNU Lesser General Public License.
+ */
+
+#ifndef _UCW_CLISTS_H
+#define _UCW_CLISTS_H
+
+/**
+ * Common header for list nodes.
+ **/
+typedef struct cnode {
+ struct cnode *next, *prev;
+} cnode;
+
+/**
+ * Circular doubly linked list.
+ **/
+typedef struct clist {
+ struct cnode head;
+} clist;
+
+/**
+ * Initialize a new circular linked list. Must be called before any other function.
+ **/
+static inline void clist_init(clist *l)
+{
+ cnode *head = &l->head;
+ head->next = head->prev = head;
+}
+
+/**
+ * Return the first node on \p l or NULL if \p l is empty.
+ **/
+static inline void *clist_head(clist *l)
+{
+ return (l->head.next != &l->head) ? l->head.next : NULL;
+}
+
+/**
+ * Return the last node on \p l or NULL if \p l is empty.
+ **/
+static inline void *clist_tail(clist *l)
+{
+ return (l->head.prev != &l->head) ? l->head.prev : NULL;
+}
+
+/**
+ * Find the next node to \p n or NULL if \p n is the last one.
+ **/
+static inline void *clist_next(clist *l, cnode *n)
+{
+ return (n->next != &l->head) ? (void *) n->next : NULL;
+}
+
+/**
+ * Find the previous node to \p n or NULL if \p n is the first one.
+ **/
+static inline void *clist_prev(clist *l, cnode *n)
+{
+ return (n->prev != &l->head) ? (void *) n->prev : NULL;
+}
+
+/**
+ * Return a non-zero value iff \p l is empty.
+ **/
+static inline int clist_empty(clist *l)
+{
+ return (l->head.next == &l->head);
+}
+
+/**
+ * Loop over all nodes in the \ref list and perform the next C statement on them. The current node is stored in \p n which must be defined before as pointer to any type.
+ * The list should not be changed during this loop command.
+ **/
+#define CLIST_WALK(n,list) for(n=(void*)(list).head.next; (cnode*)(n) != &(list).head; n=(void*)((cnode*)(n))->next)
+
+/**
+ * Same as \ref CLIST_WALK(), but allows removal of the current node. This macro requires one more variable to store some temporary pointers.
+ **/
+#define CLIST_WALK_DELSAFE(n,list,tmp) for(n=(void*)(list).head.next; tmp=(void*)((cnode*)(n))->next, (cnode*)(n) != &(list).head; n=(void*)tmp)
+
+/**
+ * Same as \ref CLIST_WALK(), but it defines the variable for the current node in place. \p type should be a pointer type.
+ **/
+#define CLIST_FOR_EACH(type,n,list) for(type n=(void*)(list).head.next; (cnode*)(n) != &(list).head; n=(void*)((cnode*)(n))->next)
+
+/**
+ * Same as \ref CLIST_WALK_DELSAFE(), but it defines the variable for the current node in place. \p type should be a pointer type. The temporary variable must be still known before.
+ **/
+#define CLIST_FOR_EACH_DELSAFE(type,n,list,tmp) for(type n=(void*)(list).head.next; tmp=(void*)((cnode*)(n))->next, (cnode*)(n) != &(list).head; n=(void*)tmp)
+
+/**
+ * Reversed version of \ref CLIST_FOR_EACH().
+ **/
+#define CLIST_FOR_EACH_BACKWARDS(type,n,list) for(type n=(void*)(list).head.prev; (cnode*)(n) != &(list).head; n=(void*)((cnode*)(n))->prev)
+
+/**
+ * Insert a new node just after the node \p after. To insert at the head of the list, use \ref clist_add_head() instead.
+ **/
+static inline void clist_insert_after(cnode *what, cnode *after)
+{
+ cnode *before = after->next;
+ what->next = before;
+ what->prev = after;
+ before->prev = what;
+ after->next = what;
+}
+
+/**
+ * Insert a new node just before the node \p before. To insert at the tail of the list, use \ref clist_add_tail() instead.
+ **/
+static inline void clist_insert_before(cnode *what, cnode *before)
+{
+ cnode *after = before->prev;
+ what->next = before;
+ what->prev = after;
+ before->prev = what;
+ after->next = what;
+}
+
+/**
+ * Insert a new node in front of all other nodes.
+ **/
+static inline void clist_add_head(clist *l, cnode *n)
+{
+ clist_insert_after(n, &l->head);
+}
+
+/**
+ * Insert a new node after all other nodes.
+ **/
+static inline void clist_add_tail(clist *l, cnode *n)
+{
+ clist_insert_before(n, &l->head);
+}
+
+/**
+ * Remove node \p n.
+ **/
+static inline void clist_remove(cnode *n)
+{
+ cnode *before = n->prev;
+ cnode *after = n->next;
+ before->next = after;
+ after->prev = before;
+}
+
+/**
+ * Remove the first node in \p l, if it exists. Return the pointer to that node or NULL.
+ **/
+static inline void *clist_remove_head(clist *l)
+{
+ cnode *n = clist_head(l);
+ if (n)
+ clist_remove(n);
+ return n;
+}
+
+/**
+ * Remove the last node in \p l, if it exists. Return the pointer to that node or NULL.
+ **/
+static inline void *clist_remove_tail(clist *l)
+{
+ cnode *n = clist_tail(l);
+ if (n)
+ clist_remove(n);
+ return n;
+}
+
+/**
+ * Merge two lists by inserting the list \p what just after the node \p after in a different list.
+ * The first list is then cleared.
+ **/
+static inline void clist_insert_list_after(clist *what, cnode *after)
+{
+ if (!clist_empty(what))
+ {
+ cnode *w = &what->head;
+ w->prev->next = after->next;
+ after->next->prev = w->prev;
+ w->next->prev = after;
+ after->next = w->next;
+ clist_init(what);
+ }
+}
+
+/**
+ * Move all items from a source list to a destination list. The source list
+ * becomes empty, the original contents of the destination list are destroyed.
+ **/
+static inline void clist_move(clist *to, clist *from)
+{
+ clist_init(to);
+ clist_insert_list_after(from, &to->head);
+ clist_init(from);
+}
+
+/**
+ * Compute the number of nodes in \p l. Beware of linear time complexity.
+ **/
+static inline unsigned int clist_size(clist *l)
+{
+ unsigned int i = 0;
+ CLIST_FOR_EACH(cnode *, n, *l)
+ i++;
+ return i;
+}
+
+/**
+ * Remove a node \p n and mark it as unlinked by setting the previous and next pointers to NULL.
+ **/
+static inline void clist_unlink(cnode *n)
+{
+ clist_remove(n);
+ n->prev = n->next = NULL;
+}
+
+/**
+ * Remove the first node on \p l and mark it as unlinked.
+ * Return the pointer to that node or NULL.
+ **/
+static inline void *clist_unlink_head(clist *l)
+{
+ cnode *n = clist_head(l);
+ if (n)
+ clist_unlink(n);
+ return n;
+}
+
+/**
+ * Remove the last node on \p l and mark it as unlinked.
+ * Return the pointer to that node or NULL.
+ **/
+static inline void *clist_unlink_tail(clist *l)
+{
+ cnode *n = clist_tail(l);
+ if (n)
+ clist_unlink(n);
+ return n;
+}
+
+/**
+ * Check if a node is linked a list. Unlinked nodes are recognized by having their
+ * previous and next pointers equal to NULL. Returns 0 or 1.
+ *
+ * Nodes initialized to all zeroes are unlinked, inserting a node anywhere in a list
+ * makes it linked. Normal removal functions like \ref clist_remove() do not mark nodes
+ * as unlinked, you need to call \ref clist_unlink() instead.
+ **/
+static inline int clist_is_linked(cnode *n)
+{
+ return !!n->next;
+}
+
+#endif
diff --git a/src/libdnssec/nsec.h b/src/libdnssec/nsec.h
new file mode 100644
index 0000000..ce69752
--- /dev/null
+++ b/src/libdnssec/nsec.h
@@ -0,0 +1,214 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*!
+ * \file
+ *
+ * \addtogroup nsec
+ *
+ * \brief NSEC bitmap and NSEC3 hash computation API.
+ *
+ * The module provides interface for computation of NSEC3 hashes and for
+ * construction of bit maps used in NSEC and NSEC3 records.
+ *
+ * Example of NSEC3 hash computation:
+ *
+ * ~~~~~ {.c}
+ *
+ * int result;
+ *
+ * // NSEC3 parameters for hashing
+ * nssec_nsec3_params_t params = {
+ * .algorithm = DNSSEC_NSEC3_ALGORITHM_SHA1,
+ * .flags = 0,
+ * .iterations = 10,
+ * .salt = {
+ * .size = 4,
+ * .data = (uint8_t *){ 0xc0, 0x1d, 0xca, 0xfe }
+ * }
+ * };
+ *
+ * // domain name (in wire format)
+ * uint8_t *dname = "\0x08""knot-dns""\0x02""cz";
+ *
+ * // resulting hash
+ * dnssec_binary_t hash = { 0 };
+ *
+ * result = dnssec_nsec3_hash(&dname, &params, &hash);
+ * if (result != DNSSEC_EOK) {
+ * return result;
+ * }
+ *
+ * assert(hash.size == 20);
+ * // hash.data contains binary data, which encoded in Base32 would be:
+ * // 7PTVGE7QV67EM61ROS9238P5RAKR2DM7
+ *
+ * dnssec_binary_free(&hash);
+ *
+ * ~~~~~
+ *
+ * Example of NSEC/NSEC3 bitmap construction.
+ *
+ * ~~~~~ {.c}
+ *
+ * int result;
+ * dnssec_nsec_bitmap_t *ctx;
+ * dnssec_binary_t bitmap;
+ *
+ * // create encoding context
+ * ctx = dnssec_nsec_bitmap_new();
+ * if (ctx == NULL) {
+ * return KNOT_ENOMEM;
+ * }
+ *
+ * // add resource records into the bitmap
+ * dnssec_nsec_bitmap_add(ctx, 1); // A RR type
+ * dnssec_nsec_bitmap_add(ctx, 28); // AAAA RR type
+ *
+ * // allocate space for the encoded bitmap
+ * size_t size = dnssec_nsec_bitmap_size(ctx);
+ * result = dnssec_binary_alloc(&bitmap, size);
+ * if (result != DNSSEC_EOK) {
+ * dnssec_nsec_bitmap_free(ctx);
+ * return result;
+ * }
+ *
+ * // write the encoded bitmap and free the context
+ * dnssec_nsec_bitmap_write(ctx, &bitmap);
+ * dnssec_nsec_bitmap_free(ctx);
+ *
+ * // use the bitmap ...
+ *
+ * dnssec_binary_free(&bitmap);
+ * ~~~~~
+ *
+ * @{
+ */
+
+#pragma once
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <libdnssec/binary.h>
+
+/*!
+ * DNSSEC NSEC3 algorithm numbers.
+ */
+typedef enum dnssec_nsec_algorithm {
+ DNSSEC_NSEC3_ALGORITHM_UNKNOWN = 0,
+ DNSSEC_NSEC3_ALGORITHM_SHA1 = 1,
+} dnssec_nsec3_algorithm_t;
+
+/*!
+ * DNSSEC NSEC3 parameters.
+ */
+typedef struct dnssec_nsec3_params {
+ dnssec_nsec3_algorithm_t algorithm; /*!< NSEC3 algorithm. */
+ uint8_t flags; /*!< NSEC3 flags. */
+ uint16_t iterations; /*!< NSEC3 iterations count. */
+ dnssec_binary_t salt; /*!< NSEC3 salt. */
+} dnssec_nsec3_params_t;
+
+/*!
+ * Free NSEC3 parameters.
+ */
+void dnssec_nsec3_params_free(dnssec_nsec3_params_t *params);
+
+/*!
+ * Parse NSEC3 parameters from NSEC3PARAM RDATA.
+ *
+ * \param params Output parameters.
+ * \param rdata NSEC3PARAM RDATA.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int dnssec_nsec3_params_from_rdata(dnssec_nsec3_params_t *params,
+ const dnssec_binary_t *rdata);
+
+/*!
+ * Check whether a given NSEC bitmap contains a given RR type.
+ *
+ * \param bitmap Bitmap of an NSEC record.
+ * \param size Size of the bitmap.
+ * \param type RR type to check for.
+ *
+ * \return true if bitmap contains type, false otherwise.
+ */
+bool dnssec_nsec_bitmap_contains(const uint8_t *bitmap, uint16_t size, uint16_t type);
+
+/*!
+ * Compute NSEC3 hash for given data.
+ *
+ * \todo Input data must be converted to lowercase!
+ *
+ * \param[in] data Data to be hashed (usually domain name).
+ * \param[in] params NSEC3 parameters.
+ * \param[out] hash Computed hash (will be allocated or resized).
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int dnssec_nsec3_hash(const dnssec_binary_t *data,
+ const dnssec_nsec3_params_t *params,
+ dnssec_binary_t *hash);
+
+/*!
+ * Get length of raw NSEC3 hash for a given algorithm.
+ *
+ * \param algorithm NSEC3 algorithm number.
+ *
+ * \return Length of raw NSEC3 hash, zero on error.
+ */
+size_t dnssec_nsec3_hash_length(dnssec_nsec3_algorithm_t algorithm);
+
+struct dnssec_nsec_bitmap;
+
+/*!
+ * Context for encoding of RR types bitmap used in NSEC/NSEC3.
+ */
+typedef struct dnssec_nsec_bitmap dnssec_nsec_bitmap_t;
+
+/*!
+ * Allocate new bit map encoding context.
+ */
+dnssec_nsec_bitmap_t *dnssec_nsec_bitmap_new(void);
+
+/*!
+ * Clear existing bit map encoding context.
+ */
+void dnssec_nsec_bitmap_clear(dnssec_nsec_bitmap_t *bitmap);
+
+/*!
+ * Free bit map encoding context.
+ */
+void dnssec_nsec_bitmap_free(dnssec_nsec_bitmap_t *bitmap);
+
+/*!
+ * Add one RR type into the bitmap.
+ */
+void dnssec_nsec_bitmap_add(dnssec_nsec_bitmap_t *bitmap, uint16_t type);
+
+/*!
+ * Compute the size of the encoded bitmap.
+ */
+size_t dnssec_nsec_bitmap_size(const dnssec_nsec_bitmap_t *bitmap);
+
+/*!
+ * Write encoded bitmap into the given buffer.
+ */
+void dnssec_nsec_bitmap_write(const dnssec_nsec_bitmap_t *bitmap, uint8_t *output);
+
+/*! @} */
diff --git a/src/libdnssec/nsec/bitmap.c b/src/libdnssec/nsec/bitmap.c
new file mode 100644
index 0000000..001613a
--- /dev/null
+++ b/src/libdnssec/nsec/bitmap.c
@@ -0,0 +1,142 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <limits.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "libdnssec/nsec.h"
+#include "libdnssec/shared/shared.h"
+
+#define BITMAP_WINDOW_SIZE 256
+#define BITMAP_WINDOW_BYTES (BITMAP_WINDOW_SIZE/CHAR_BIT)
+#define BITMAP_WINDOW_COUNT 256
+
+/*!
+ * One window of an NSEC bitmap.
+ */
+typedef struct window {
+ uint8_t used;
+ uint8_t data[BITMAP_WINDOW_BYTES];
+} window_t;
+
+struct dnssec_nsec_bitmap {
+ int used;
+ window_t windows[BITMAP_WINDOW_COUNT];
+};
+
+/* -- public API ----------------------------------------------------------- */
+
+/*!
+ * Allocate new bit map encoding context.
+ */
+_public_
+dnssec_nsec_bitmap_t *dnssec_nsec_bitmap_new(void)
+{
+ dnssec_nsec_bitmap_t *bitmap = malloc(sizeof(*bitmap));
+ if (!bitmap) {
+ return NULL;
+ }
+
+ dnssec_nsec_bitmap_clear(bitmap);
+
+ return bitmap;
+}
+
+/*!
+ * Clear existing bit map encoding context.
+ */
+_public_
+void dnssec_nsec_bitmap_clear(dnssec_nsec_bitmap_t *bitmap)
+{
+ clear_struct(bitmap);
+}
+
+/*!
+ * Free bit map encoding context.
+ */
+_public_
+void dnssec_nsec_bitmap_free(dnssec_nsec_bitmap_t *bitmap)
+{
+ free(bitmap);
+}
+
+/*!
+ * Add one RR type into the bitmap.
+ */
+_public_
+void dnssec_nsec_bitmap_add(dnssec_nsec_bitmap_t *bitmap, uint16_t type)
+{
+ int win = type / BITMAP_WINDOW_SIZE;
+ int bit = type % BITMAP_WINDOW_SIZE;
+
+ if (bitmap->used <= win) {
+ bitmap->used = win + 1;
+ }
+
+ int win_byte = bit / CHAR_BIT;
+ int win_bit = bit % CHAR_BIT;
+
+ window_t *window = &bitmap->windows[win];
+ window->data[win_byte] |= 0x80 >> win_bit;
+ if (window->used <= win_byte) {
+ window->used = win_byte + 1;
+ }
+}
+
+/*!
+ * Compute the size of the encoded bitmap.
+ */
+_public_
+size_t dnssec_nsec_bitmap_size(const dnssec_nsec_bitmap_t *bitmap)
+{
+ size_t result = 0;
+
+ for (int i = 0; i < bitmap->used; i++) {
+ int used = bitmap->windows[i].used;
+ if (used == 0) {
+ continue;
+ }
+
+ result += 2 + used; // windows number, window size, data
+ }
+
+ return result;
+}
+
+/*!
+ * Write encoded bitmap into the given buffer.
+ */
+_public_
+void dnssec_nsec_bitmap_write(const dnssec_nsec_bitmap_t *bitmap, uint8_t *output)
+{
+ uint8_t *write_ptr = output;
+ for (int win = 0; win < bitmap->used; win++) {
+ int used = bitmap->windows[win].used;
+ if (used == 0) {
+ continue;
+ }
+
+ *write_ptr = (uint8_t)win;
+ write_ptr += 1;
+
+ *write_ptr = (uint8_t)used;
+ write_ptr += 1;
+
+ memmove(write_ptr, bitmap->windows[win].data, used);
+ write_ptr += used;
+ }
+}
diff --git a/src/libdnssec/nsec/hash.c b/src/libdnssec/nsec/hash.c
new file mode 100644
index 0000000..897320f
--- /dev/null
+++ b/src/libdnssec/nsec/hash.c
@@ -0,0 +1,125 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+#include <string.h>
+
+#include "libdnssec/error.h"
+#include "libdnssec/nsec.h"
+#include "libdnssec/shared/shared.h"
+
+/*!
+ * Compute NSEC3 hash for given data and algorithm.
+ *
+ * \see RFC 5155
+ *
+ * \todo Input data should be converted to lowercase.
+ */
+static int nsec3_hash(gnutls_digest_algorithm_t algorithm, int iterations,
+ const dnssec_binary_t *salt, const dnssec_binary_t *data,
+ dnssec_binary_t *hash)
+{
+ assert(salt);
+ assert(data);
+ assert(hash);
+
+ int hash_size = gnutls_hash_get_len(algorithm);
+ if (hash_size <= 0) {
+ return DNSSEC_NSEC3_HASHING_ERROR;
+ }
+
+ int result = dnssec_binary_resize(hash, hash_size);
+ if (result != DNSSEC_EOK) {
+ return result;
+ }
+
+ _cleanup_hash_ gnutls_hash_hd_t digest = NULL;
+ result = gnutls_hash_init(&digest, algorithm);
+ if (result < 0) {
+ return DNSSEC_NSEC3_HASHING_ERROR;
+ }
+
+ const uint8_t *in = data->data;
+ size_t in_size = data->size;
+
+ for (int i = 0; i <= iterations; i++) {
+ result = gnutls_hash(digest, in, in_size);
+ if (result < 0) {
+ return DNSSEC_NSEC3_HASHING_ERROR;
+ }
+
+ result = gnutls_hash(digest, salt->data, salt->size);
+ if (result < 0) {
+ return DNSSEC_NSEC3_HASHING_ERROR;
+ }
+
+ gnutls_hash_output(digest, hash->data);
+
+ in = hash->data;
+ in_size = hash->size;
+ }
+
+ return DNSSEC_EOK;
+}
+
+/*!
+ * Get GnuTLS digest algorithm from DNSSEC algorithm number.
+ */
+static gnutls_digest_algorithm_t algorithm_d2g(dnssec_nsec3_algorithm_t dnssec)
+{
+ switch (dnssec) {
+ case DNSSEC_NSEC3_ALGORITHM_SHA1: return GNUTLS_DIG_SHA1;
+ default: return GNUTLS_DIG_UNKNOWN;
+ }
+}
+
+/* -- public API ----------------------------------------------------------- */
+
+/*!
+ * Compute NSEC3 hash for given data.
+ */
+_public_
+int dnssec_nsec3_hash(const dnssec_binary_t *data,
+ const dnssec_nsec3_params_t *params,
+ dnssec_binary_t *hash)
+{
+ if (!data || !params || !hash) {
+ return DNSSEC_EINVAL;
+ }
+
+ gnutls_digest_algorithm_t algorithm = algorithm_d2g(params->algorithm);
+ if (algorithm == GNUTLS_DIG_UNKNOWN) {
+ return DNSSEC_INVALID_NSEC3_ALGORITHM;
+ }
+
+ return nsec3_hash(algorithm, params->iterations, &params->salt, data, hash);
+}
+
+/*!
+ * Get length of raw NSEC3 hash for a given algorithm.
+ */
+_public_
+size_t dnssec_nsec3_hash_length(dnssec_nsec3_algorithm_t algorithm)
+{
+ gnutls_digest_algorithm_t gnutls = algorithm_d2g(algorithm);
+ if (gnutls == GNUTLS_DIG_UNKNOWN) {
+ return 0;
+ }
+
+ return gnutls_hash_get_len(gnutls);
+}
diff --git a/src/libdnssec/nsec/nsec.c b/src/libdnssec/nsec/nsec.c
new file mode 100644
index 0000000..bb6084a
--- /dev/null
+++ b/src/libdnssec/nsec/nsec.c
@@ -0,0 +1,116 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "libdnssec/nsec.h"
+#include "libdnssec/shared/shared.h"
+#include "libdnssec/shared/binary_wire.h"
+
+#include "libdnssec/binary.h"
+#include "libdnssec/error.h"
+
+/*!
+ * Free NSEC3 parameters.
+ */
+_public_
+void dnssec_nsec3_params_free(dnssec_nsec3_params_t *params)
+{
+ if (!params) {
+ return;
+ }
+
+ dnssec_binary_free(&params->salt);
+ clear_struct(params);
+}
+
+/*!
+ * Parse NSEC3 parameters from NSEC3PARAM RDATA.
+ *
+ * \see RFC 5155 (section 4.2)
+ */
+_public_
+int dnssec_nsec3_params_from_rdata(dnssec_nsec3_params_t *params,
+ const dnssec_binary_t *rdata)
+{
+ if (!params || !rdata || !rdata->data) {
+ return DNSSEC_EINVAL;
+ }
+
+ dnssec_nsec3_params_t new_params = { 0 };
+
+ wire_ctx_t wire = binary_init(rdata);
+
+ if (wire_ctx_available(&wire) < 5) {
+ return DNSSEC_MALFORMED_DATA;
+ }
+
+ new_params.algorithm = wire_ctx_read_u8(&wire);
+ new_params.flags = wire_ctx_read_u8(&wire);
+ new_params.iterations = wire_ctx_read_u16(&wire);
+ new_params.salt.size = wire_ctx_read_u8(&wire);
+
+ if (wire_ctx_available(&wire) != new_params.salt.size) {
+ return DNSSEC_MALFORMED_DATA;
+ }
+
+ new_params.salt.data = malloc(new_params.salt.size);
+ if (new_params.salt.data == NULL) {
+ return DNSSEC_ENOMEM;
+ }
+
+ binary_read(&wire, &new_params.salt);
+ assert(wire_ctx_offset(&wire) == rdata->size);
+
+ *params = new_params;
+
+ return DNSSEC_EOK;
+}
+
+_public_
+bool dnssec_nsec_bitmap_contains(const uint8_t *bitmap, uint16_t size, uint16_t type)
+{
+ if (!bitmap || size == 0) {
+ return false;
+ }
+
+ const uint8_t type_hi = (type >> 8); // Which window block contains type.
+ const uint8_t type_lo = (type & 0xff);
+ const uint8_t bitmap_idx = (type_lo >> 3); // Which byte in the window block contains type.
+ const uint8_t bit_mask = 1 << (7 - (type_lo & 0x07)); // Which bit in the byte represents type.
+
+ size_t bitmap_pos = 0;
+ while (bitmap_pos + 3 <= size) {
+ uint8_t block_idx = bitmap[bitmap_pos++]; // Skip window block No.
+ uint8_t block_size = bitmap[bitmap_pos++]; // Skip window block size.
+
+ // Size checks.
+ if (block_size == 0 || bitmap_pos + block_size > size) {
+ return false;
+ }
+
+ // Check whether we found the correct window block.
+ if (block_idx == type_hi) {
+ if (bitmap_idx < block_size) {
+ // Check if the bit for type is set.
+ return bitmap[bitmap_pos + bitmap_idx] & bit_mask;
+ }
+ return false;
+ } else {
+ bitmap_pos += block_size;
+ }
+ }
+
+ return false;
+}
diff --git a/src/libdnssec/p11/p11.c b/src/libdnssec/p11/p11.c
new file mode 100644
index 0000000..07f34f2
--- /dev/null
+++ b/src/libdnssec/p11/p11.c
@@ -0,0 +1,113 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <gnutls/pkcs11.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libdnssec/p11/p11.h"
+#include "libdnssec/error.h"
+
+#ifdef ENABLE_PKCS11
+
+#define PKCS11_MODULES_MAX 16
+
+static char *pkcs11_modules[PKCS11_MODULES_MAX] = { 0 };
+static int pkcs11_modules_count = 0;
+
+static int map_result(int gnutls_result)
+{
+ return gnutls_result == GNUTLS_E_SUCCESS ? DNSSEC_EOK : DNSSEC_ERROR;
+}
+
+int p11_init(void)
+{
+ int r = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL);
+ return map_result(r);
+}
+
+int p11_reinit(void)
+{
+ int r = gnutls_pkcs11_reinit();
+ return map_result(r);
+}
+
+int p11_load_module(const char *module)
+{
+ for (int i = 0; i < pkcs11_modules_count; i++) {
+ if (strcmp(pkcs11_modules[i], module) == 0) {
+ return DNSSEC_EOK;
+ }
+ }
+
+ assert(pkcs11_modules_count <= PKCS11_MODULES_MAX);
+ if (pkcs11_modules_count == PKCS11_MODULES_MAX) {
+ return DNSSEC_P11_TOO_MANY_MODULES;
+ }
+
+ char *copy = strdup(module);
+ if (!copy) {
+ return DNSSEC_ENOMEM;
+ }
+
+ int r = gnutls_pkcs11_add_provider(module, NULL);
+ if (r != GNUTLS_E_SUCCESS) {
+ free(copy);
+ return DNSSEC_P11_FAILED_TO_LOAD_MODULE;
+ }
+
+ pkcs11_modules[pkcs11_modules_count] = copy;
+ pkcs11_modules_count += 1;
+
+ return DNSSEC_EOK;
+}
+
+void p11_cleanup(void)
+{
+ for (int i = 0; i < pkcs11_modules_count; i++) {
+ free(pkcs11_modules[i]);
+ pkcs11_modules[i] = NULL;
+ }
+
+ pkcs11_modules_count = 0;
+
+ gnutls_pkcs11_deinit();
+}
+
+#else
+
+int p11_init(void)
+{
+ return DNSSEC_EOK;
+}
+
+int p11_reinit(void)
+{
+ return DNSSEC_EOK;
+}
+
+int p11_load_module(const char *module)
+{
+ return DNSSEC_NOT_IMPLEMENTED_ERROR;
+}
+
+void p11_cleanup(void)
+{
+ // this function intentionally left blank
+}
+
+#endif
diff --git a/src/libdnssec/p11/p11.h b/src/libdnssec/p11/p11.h
new file mode 100644
index 0000000..a0f9969
--- /dev/null
+++ b/src/libdnssec/p11/p11.h
@@ -0,0 +1,41 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+/*!
+ * Initialize PKCS11 global context.
+ */
+int p11_init(void);
+
+/*!
+ * Reinitialize PKCS11 global context after fork().
+ */
+int p11_reinit(void);
+
+/*!
+ * Load PKCS11 module unless the module was already loaded.
+ *
+ * Duplicates are detected based on the module path.
+ */
+int p11_load_module(const char *name);
+
+/*!
+ * Clenaup PKCS11 global context.
+ *
+ * Should be called when the library is deinitialized to prevent memory leaks.
+ */
+void p11_cleanup(void);
diff --git a/src/libdnssec/random.c b/src/libdnssec/random.c
new file mode 100644
index 0000000..30b0c2d
--- /dev/null
+++ b/src/libdnssec/random.c
@@ -0,0 +1,53 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "libdnssec/error.h"
+#include "libdnssec/random.h"
+#include "libdnssec/shared/shared.h"
+
+/* -- public API ----------------------------------------------------------- */
+
+_public_
+int dnssec_random_buffer(uint8_t *data, size_t size)
+{
+ if (!data) {
+ return DNSSEC_EINVAL;
+ }
+
+ int result = gnutls_rnd(GNUTLS_RND_RANDOM, data, size);
+ if (result != 0) {
+ assert_unreachable();
+ return DNSSEC_ERROR;
+ }
+
+ return DNSSEC_EOK;
+}
+
+_public_
+int dnssec_random_binary(dnssec_binary_t *binary)
+{
+ if (!binary) {
+ return DNSSEC_EINVAL;
+ }
+
+ return dnssec_random_buffer(binary->data, binary->size);
+}
diff --git a/src/libdnssec/random.h b/src/libdnssec/random.h
new file mode 100644
index 0000000..0886e51
--- /dev/null
+++ b/src/libdnssec/random.h
@@ -0,0 +1,85 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*!
+ * \file
+ *
+ * \addtogroup random
+ *
+ * \brief Pseudo-random number generating API.
+ *
+ * The module provides generating of pseudo-random numbers and buffers.
+ *
+ * Example:
+ *
+ * ~~~
+ *
+ * uint16_t transaction_id = dnssec_random_uint16_t();
+ *
+ * ~~~
+ *
+ * @{
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <libdnssec/binary.h>
+
+/*!
+ * Fill a buffer with pseudo-random data.
+ *
+ * \param data Pointer to the output buffer.
+ * \param size Size of the output buffer.
+ *
+ * \return Error code, DNSEC_EOK if successful.
+ */
+int dnssec_random_buffer(uint8_t *data, size_t size);
+
+/*!
+ * Fill a binary structure with random data.
+ *
+ * \param data Preallocated binary structure to be filled.
+ *
+ * \return Error code, DNSEC_EOK if successful.
+ */
+int dnssec_random_binary(dnssec_binary_t *data);
+
+/*!
+ * Declare function dnssec_random_<type>().
+ */
+#define dnssec_register_random_type(type) \
+ static inline type dnssec_random_##type(void) { \
+ type value; \
+ dnssec_random_buffer((uint8_t *)&value, sizeof(value)); \
+ return value; \
+ }
+
+/*!
+ * Generate pseudo-random 16-bit number.
+ */
+static inline uint16_t dnssec_random_uint16_t(void);
+
+/*!
+ * Generate pseudo-random 32-bit number.
+ */
+static inline uint32_t dnssec_random_uint32_t(void);
+
+/*! \cond */
+dnssec_register_random_type(uint16_t);
+dnssec_register_random_type(uint32_t);
+/*! \endcond */
+
+/*! @} */
diff --git a/src/libdnssec/shared/bignum.c b/src/libdnssec/shared/bignum.c
new file mode 100644
index 0000000..921a1e6
--- /dev/null
+++ b/src/libdnssec/shared/bignum.c
@@ -0,0 +1,64 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <string.h>
+
+#include "libdnssec/shared/bignum.h"
+
+static void skip_leading_zeroes(dnssec_binary_t *value)
+{
+ while (value->size > 0 && value->data[0] == 0) {
+ value->data += 1;
+ value->size -= 1;
+ }
+}
+
+size_t bignum_size_u(const dnssec_binary_t *_value)
+{
+ dnssec_binary_t value = *_value;
+ skip_leading_zeroes(&value);
+
+ if (value.size == 0) {
+ return value.size + 1;
+ } else {
+ return value.size;
+ }
+}
+
+size_t bignum_size_s(const dnssec_binary_t *_value)
+{
+ dnssec_binary_t value = *_value;
+ skip_leading_zeroes(&value);
+
+ if (value.size == 0 || value.data[0] & 0x80) {
+ return value.size + 1;
+ } else {
+ return value.size;
+ }
+}
+
+void bignum_write(wire_ctx_t *ctx, size_t width, const dnssec_binary_t *_value)
+{
+ dnssec_binary_t value = *_value;
+ skip_leading_zeroes(&value);
+
+ size_t padding_len = width - value.size;
+ if (padding_len > 0) {
+ wire_ctx_clear(ctx, padding_len);
+ }
+ wire_ctx_write(ctx, value.data, value.size);
+}
diff --git a/src/libdnssec/shared/bignum.h b/src/libdnssec/shared/bignum.h
new file mode 100644
index 0000000..4186a63
--- /dev/null
+++ b/src/libdnssec/shared/bignum.h
@@ -0,0 +1,41 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <stdlib.h>
+
+#include "libdnssec/binary.h"
+#include "contrib/wire_ctx.h"
+
+/*!
+ * Size needed to write unsigned number in unsigned encoding.
+ */
+size_t bignum_size_u(const dnssec_binary_t *value);
+
+/*!
+ * Size needed to write unsigned number in signed encoding.
+ *
+ * Signed encoding expects the MSB to be zero.
+ */
+size_t bignum_size_s(const dnssec_binary_t *value);
+
+/*!
+ * Write unsigned number on a fixed width in a big-endian byte order.
+ *
+ * The destination size has to be set properly to accommodate used encoding.
+ */
+void bignum_write(wire_ctx_t *ctx, size_t width, const dnssec_binary_t *value);
diff --git a/src/libdnssec/shared/binary_wire.h b/src/libdnssec/shared/binary_wire.h
new file mode 100644
index 0000000..78ccff0
--- /dev/null
+++ b/src/libdnssec/shared/binary_wire.h
@@ -0,0 +1,53 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <stdlib.h>
+
+#include "contrib/wire_ctx.h"
+#include "libdnssec/binary.h"
+
+static inline wire_ctx_t binary_init(const dnssec_binary_t *binary)
+{
+ assert(binary);
+
+ return wire_ctx_init(binary->data, binary->size);
+}
+
+static inline void binary_read(wire_ctx_t *ctx, dnssec_binary_t *data)
+{
+ assert(data);
+
+ wire_ctx_read(ctx, data->data, data->size);
+}
+
+static inline void binary_available(wire_ctx_t *ctx, dnssec_binary_t *data)
+{
+ assert(ctx);
+ assert(data);
+
+ data->data = ctx->position;
+ data->size = wire_ctx_available(ctx);
+}
+
+static inline void binary_write(wire_ctx_t *ctx, const dnssec_binary_t *data)
+{
+ assert(ctx);
+ assert(data);
+
+ wire_ctx_write(ctx, data->data, data->size);
+}
diff --git a/src/libdnssec/shared/dname.c b/src/libdnssec/shared/dname.c
new file mode 100644
index 0000000..51605f6
--- /dev/null
+++ b/src/libdnssec/shared/dname.c
@@ -0,0 +1,165 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "libdnssec/shared/dname.h"
+#include "libdnssec/shared/shared.h"
+#include "contrib/tolower.h"
+
+/*!
+ * Get length of a domain name in wire format.
+ */
+size_t dname_length(const uint8_t *dname)
+{
+ if (!dname) {
+ return 0;
+ }
+
+ const uint8_t *scan = dname;
+ uint8_t label_len;
+ do {
+ label_len = *scan;
+ scan += 1 + label_len;
+ } while (label_len > 0);
+ assert(scan > dname);
+
+ size_t length = scan - dname;
+ if (length > DNAME_MAX_LENGTH) {
+ return 0;
+ }
+
+ return length;
+}
+
+/*!
+ * Copy domain name in wire format.
+ */
+uint8_t *dname_copy(const uint8_t *dname)
+{
+ if (!dname) {
+ return NULL;
+ }
+
+ size_t length = dname_length(dname);
+ if (length == 0) {
+ return NULL;
+ }
+
+ uint8_t *copy = malloc(length);
+ if (!copy) {
+ return NULL;
+ }
+
+ memmove(copy, dname, length);
+ return copy;
+}
+
+/*!
+ * Normalize dname label in-place.
+ *
+ * \return Number of processed bytes, 0 if we encounter the last label.
+ */
+static uint8_t normalize_label(uint8_t *label)
+{
+ assert(label);
+
+ uint8_t len = *label;
+ if (len == 0 || len > DNAME_MAX_LABEL_LENGTH) {
+ return 0;
+ }
+
+ for (uint8_t *scan = label + 1, *end = scan + len; scan < end; scan++) {
+ *scan = knot_tolower(*scan);
+ }
+
+ return len + 1;
+}
+
+/*!
+ * Normalize domain name in wire format.
+ */
+void dname_normalize(uint8_t *dname)
+{
+ if (!dname) {
+ return;
+ }
+
+ uint8_t read, *scan = dname;
+ do {
+ read = normalize_label(scan);
+ scan += read;
+ } while (read > 0);
+}
+
+/*!
+ * Compare dname labels case insensitively.
+ */
+static int label_casecmp(const uint8_t *a, const uint8_t *b, uint8_t len)
+{
+ assert(a);
+ assert(b);
+
+ for (const uint8_t *a_end = a + len; a < a_end; a++, b++) {
+ if (knot_tolower(*a) != knot_tolower(*b)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/*!
+ * Check if two dnames are equal.
+ */
+bool dname_equal(const uint8_t *one, const uint8_t *two)
+{
+ if (!one || !two) {
+ return false;
+ }
+
+ const uint8_t *scan_one = one;
+ const uint8_t *scan_two = two;
+
+ for (;;) {
+ if (*scan_one != *scan_two) {
+ return false;
+ }
+
+ uint8_t len = *scan_one;
+ if (len == 0) {
+ return true;
+ } else if (len > DNAME_MAX_LABEL_LENGTH) {
+ return false;
+ }
+
+ scan_one += 1;
+ scan_two += 1;
+
+ if (!label_casecmp(scan_one, scan_two, len)) {
+ return false;
+ }
+
+ scan_one += len;
+ scan_two += len;
+ }
+
+ return true;
+}
diff --git a/src/libdnssec/shared/dname.h b/src/libdnssec/shared/dname.h
new file mode 100644
index 0000000..82adeb7
--- /dev/null
+++ b/src/libdnssec/shared/dname.h
@@ -0,0 +1,57 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+/*!
+ * Maximal length of domain name including labels and length bytes.
+ * \see RFC 1035
+ */
+#define DNAME_MAX_LENGTH 255
+
+/*!
+ * Maximal length of the domain name label, excluding the label size.
+ * \see RFC 1035
+ */
+#define DNAME_MAX_LABEL_LENGTH 63
+
+/*!
+ * Get length of a domain name in wire format.
+ */
+size_t dname_length(const uint8_t *dname);
+
+/*!
+ * Copy domain name in wire format.
+ */
+uint8_t *dname_copy(const uint8_t *dname);
+
+/*!
+ * Normalize domain name in wire format.
+ *
+ * Currently converts all letters to lowercase.
+ */
+void dname_normalize(uint8_t *dname);
+
+/*!
+ * Check if two dnames are equal.
+ *
+ * Case insensitive.
+ */
+bool dname_equal(const uint8_t *one, const uint8_t *two);
diff --git a/src/libdnssec/shared/fs.c b/src/libdnssec/shared/fs.c
new file mode 100644
index 0000000..10c25d9
--- /dev/null
+++ b/src/libdnssec/shared/fs.c
@@ -0,0 +1,47 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "libdnssec/error.h"
+
+int fs_mkdir(const char *path, mode_t mode, bool ignore_existing)
+{
+ if (mkdir(path, mode) == 0) {
+ return DNSSEC_EOK;
+ }
+
+ if (!ignore_existing || errno != EEXIST) {
+ return dnssec_errno_to_error(errno);
+ }
+
+ assert(errno == EEXIST);
+
+ struct stat st = { 0 };
+ if (stat(path, &st) != 0) {
+ return dnssec_errno_to_error(errno);
+ }
+
+ if (!S_ISDIR(st.st_mode)) {
+ return dnssec_errno_to_error(ENOTDIR);
+ }
+
+ return DNSSEC_EOK;
+}
diff --git a/src/libdnssec/shared/fs.h b/src/libdnssec/shared/fs.h
new file mode 100644
index 0000000..542c87b
--- /dev/null
+++ b/src/libdnssec/shared/fs.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <stdbool.h>
+#include <sys/types.h>
+
+/*!
+ * Equivalent to mkdir(2), can succeed if the directory already exists.
+ */
+int fs_mkdir(const char *path, mode_t mode, bool ignore_existing);
diff --git a/src/libdnssec/shared/hex.c b/src/libdnssec/shared/hex.c
new file mode 100644
index 0000000..03c1491
--- /dev/null
+++ b/src/libdnssec/shared/hex.c
@@ -0,0 +1,167 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include "libdnssec/binary.h"
+#include "libdnssec/error.h"
+
+#include "contrib/ctype.h"
+
+/* -- binary to hex -------------------------------------------------------- */
+
+static const char BIN_TO_HEX[] = { '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+int bin_to_hex_static(const dnssec_binary_t *bin, dnssec_binary_t *hex)
+{
+ if (!bin || !hex) {
+ return DNSSEC_EINVAL;
+ }
+
+ if (bin->size * 2 != hex->size) {
+ return DNSSEC_EINVAL;
+ }
+
+ for (size_t i = 0; i < bin->size; i++) {
+ hex->data[2*i] = BIN_TO_HEX[bin->data[i] >> 4];
+ hex->data[2*i+1] = BIN_TO_HEX[bin->data[i] & 0x0f];
+ }
+
+ return DNSSEC_EOK;
+}
+
+int bin_to_hex(const dnssec_binary_t *bin, char **hex_ptr)
+{
+ if (!bin || !hex_ptr) {
+ return DNSSEC_EINVAL;
+ }
+
+ size_t hex_size = bin->size * 2;
+ char *hex = malloc(hex_size + 1);
+ if (!hex) {
+ return DNSSEC_ENOMEM;
+ }
+
+ dnssec_binary_t hex_bin = { .data = (uint8_t *)hex, .size = hex_size };
+ bin_to_hex_static(bin, &hex_bin);
+ hex[hex_size] = '\0';
+
+ *hex_ptr = hex;
+
+ return DNSSEC_EOK;
+}
+
+/* -- hex to binary -------------------------------------------------------- */
+
+/*!
+ * Convert HEX character to numeric value (assumes valid and lowercase input).
+ */
+static uint8_t hex_to_number(const char hex)
+{
+ if (hex >= '0' && hex <= '9') {
+ return hex - '0';
+ } else if (hex >= 'a' && hex <= 'f') {
+ return hex - 'a' + 10;
+ } else {
+ assert(hex >= 'A' && hex <= 'F');
+ return hex - 'A' + 10;
+ }
+}
+
+/*!
+ * Check if the input string has valid size and contains valid characters.
+ */
+static bool hex_valid_input(const dnssec_binary_t *hex)
+{
+ assert(hex);
+
+ if (hex->size % 2 != 0) {
+ return false;
+ }
+
+ for (int i = 0; i < hex->size; i++) {
+ if (!is_xdigit(hex->data[i])) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/*!
+ * Perform hex to bin conversion without checking the validity.
+ */
+static void hex_to_bin_convert(const dnssec_binary_t *hex, dnssec_binary_t *bin)
+{
+ assert(hex);
+ assert(bin);
+
+ for (size_t i = 0; i < bin->size; i++) {
+ uint8_t high = hex_to_number(hex->data[2 * i]);
+ uint8_t low = hex_to_number(hex->data[2 * i + 1]);
+ bin->data[i] = high << 4 | low;
+ }
+}
+
+int hex_to_bin_static(const dnssec_binary_t *hex, dnssec_binary_t *bin)
+{
+ if (!hex || !bin) {
+ return DNSSEC_EINVAL;
+ }
+
+ if (hex->size / 2 != bin->size) {
+ return DNSSEC_EINVAL;
+ }
+
+ if (!hex_valid_input(hex)) {
+ return DNSSEC_MALFORMED_DATA;
+ }
+
+ hex_to_bin_convert(hex, bin);
+
+ return DNSSEC_EOK;
+}
+
+int hex_to_bin(const char *hex_str, dnssec_binary_t *bin)
+{
+ if (!hex_str || !bin) {
+ return DNSSEC_EINVAL;
+ }
+
+ dnssec_binary_t hex = { .data = (uint8_t *)hex_str, .size = strlen(hex_str) };
+ if (!hex_valid_input(&hex)) {
+ return DNSSEC_MALFORMED_DATA;
+ }
+
+ size_t bin_size = hex.size / 2;
+ if (bin_size == 0) {
+ bin->size = 0;
+ bin->data = NULL;
+ return DNSSEC_EOK;
+ }
+
+ int result = dnssec_binary_alloc(bin, bin_size);
+ if (result != DNSSEC_EOK) {
+ return result;
+ }
+
+ hex_to_bin_static(&hex, bin);
+
+ return DNSSEC_EOK;
+}
diff --git a/src/libdnssec/shared/hex.h b/src/libdnssec/shared/hex.h
new file mode 100644
index 0000000..5a47cf4
--- /dev/null
+++ b/src/libdnssec/shared/hex.h
@@ -0,0 +1,39 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include "libdnssec/binary.h"
+
+/*!
+ * Convert binary data to preallocated hexadecimal string.
+ */
+int bin_to_hex_static(const dnssec_binary_t *bin, dnssec_binary_t *hex);
+
+/**
+ * Convert binary data to hexadecimal string.
+ */
+int bin_to_hex(const dnssec_binary_t *bin, char **hex_ptr);
+
+/*!
+ * Convert hex encoded string to preallocated binary data.
+ */
+int hex_to_bin_static(const dnssec_binary_t *hex, dnssec_binary_t *bin);
+
+/*!
+ * Convert hex encoded string to binary data.
+ */
+int hex_to_bin(const char *hex, dnssec_binary_t *bin);
diff --git a/src/libdnssec/shared/keyid_gnutls.c b/src/libdnssec/shared/keyid_gnutls.c
new file mode 100644
index 0000000..4fde08e
--- /dev/null
+++ b/src/libdnssec/shared/keyid_gnutls.c
@@ -0,0 +1,94 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <gnutls/abstract.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+#include <string.h>
+
+#include "libdnssec/binary.h"
+#include "libdnssec/error.h"
+#include "libdnssec/keyid.h"
+#include "libdnssec/shared/keyid_gnutls.h"
+#include "libdnssec/shared/shared.h"
+#include "libdnssec/shared/hex.h"
+
+/*!
+ * Get binary key ID from a key (public or private).
+ */
+static int keyid_bin(gnutls_x509_privkey_t key, gnutls_pubkey_t pubkey, dnssec_binary_t *id)
+{
+ assert(key || pubkey);
+ assert(id);
+
+ // Flags can be used to enable SHA-2 since GnuTLS 3.4.7.
+
+ int flags = 0;
+ uint8_t *buffer = alloca(DNSSEC_KEYID_BINARY_SIZE);
+ size_t size = DNSSEC_KEYID_SIZE;
+
+ int r = key ? gnutls_x509_privkey_get_key_id(key, flags, buffer, &size)
+ : gnutls_pubkey_get_key_id(pubkey, flags, buffer, &size);
+
+ if (r != GNUTLS_E_SUCCESS || size != DNSSEC_KEYID_BINARY_SIZE) {
+ return DNSSEC_INVALID_KEY_ID;
+ }
+
+ assert(size == DNSSEC_KEYID_BINARY_SIZE);
+ r = dnssec_binary_resize(id, size);
+ if (r != DNSSEC_EOK) {
+ return r;
+ }
+
+ memcpy(id->data, buffer, size);
+
+ return DNSSEC_EOK;
+}
+
+/*!
+ * Get hexadecimal key ID from a key (public or private).
+ */
+static int keyid_hex(gnutls_x509_privkey_t key, gnutls_pubkey_t pubkey, char **id)
+{
+ _cleanup_binary_ dnssec_binary_t bin = { 0 };
+ int r = keyid_bin(key, pubkey, &bin);
+ if (r != DNSSEC_EOK) {
+ return r;
+ }
+
+ return bin_to_hex(&bin, id);
+}
+
+int keyid_x509(gnutls_x509_privkey_t key, dnssec_binary_t *id)
+{
+ return keyid_bin(key, NULL, id);
+}
+
+int keyid_x509_hex(gnutls_x509_privkey_t key, char **id)
+{
+ return keyid_hex(key, NULL, id);
+}
+
+int keyid_pubkey(gnutls_pubkey_t pubkey, dnssec_binary_t *id)
+{
+ return keyid_bin(NULL, pubkey, id);
+}
+
+int keyid_pubkey_hex(gnutls_pubkey_t pubkey, char **id)
+{
+ return keyid_hex(NULL, pubkey, id);
+}
diff --git a/src/libdnssec/shared/keyid_gnutls.h b/src/libdnssec/shared/keyid_gnutls.h
new file mode 100644
index 0000000..27ee4cd
--- /dev/null
+++ b/src/libdnssec/shared/keyid_gnutls.h
@@ -0,0 +1,30 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <gnutls/abstract.h>
+#include <gnutls/gnutls.h>
+
+#include "libdnssec/binary.h"
+
+int keyid_x509(gnutls_x509_privkey_t key, dnssec_binary_t *id);
+
+int keyid_x509_hex(gnutls_x509_privkey_t key, char **id);
+
+int keyid_pubkey(gnutls_pubkey_t pubkey, dnssec_binary_t *id);
+
+int keyid_pubkey_hex(gnutls_pubkey_t pubkey, char **id);
diff --git a/src/libdnssec/shared/pem.c b/src/libdnssec/shared/pem.c
new file mode 100644
index 0000000..0e5ba00
--- /dev/null
+++ b/src/libdnssec/shared/pem.c
@@ -0,0 +1,198 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <gnutls/abstract.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+#include "libdnssec/binary.h"
+#include "libdnssec/error.h"
+#include "libdnssec/key.h"
+#include "libdnssec/keyid.h"
+#include "libdnssec/shared/keyid_gnutls.h"
+#include "libdnssec/shared/pem.h"
+#include "libdnssec/shared/shared.h"
+
+/* -- internal API --------------------------------------------------------- */
+
+/*!
+ * Create GnuTLS X.509 private key from unencrypted PEM data.
+ */
+int pem_x509(const dnssec_binary_t *pem, gnutls_x509_privkey_t *key)
+{
+ assert(pem);
+ assert(key);
+
+ gnutls_datum_t data = binary_to_datum(pem);
+
+ gnutls_x509_privkey_t _key = NULL;
+ int r = gnutls_x509_privkey_init(&_key);
+ if (r != GNUTLS_E_SUCCESS) {
+ return DNSSEC_ENOMEM;
+ }
+
+ int format = GNUTLS_X509_FMT_PEM;
+ char *password = NULL;
+ int flags = GNUTLS_PKCS_PLAIN;
+ r = gnutls_x509_privkey_import_pkcs8(_key, &data, format, password, flags);
+ if (r != GNUTLS_E_SUCCESS) {
+ gnutls_x509_privkey_deinit(_key);
+ return DNSSEC_PKCS8_IMPORT_ERROR;
+ }
+
+ *key = _key;
+
+ return DNSSEC_EOK;
+}
+
+/*!
+ * Create GnuTLS private key from unencrypted PEM data.
+ */
+int pem_privkey(const dnssec_binary_t *pem, gnutls_privkey_t *key)
+{
+ assert(pem);
+ assert(key);
+
+ gnutls_x509_privkey_t key_x509 = NULL;
+ int r = pem_x509(pem, &key_x509);
+ if (r != DNSSEC_EOK) {
+ return r;
+ }
+
+ gnutls_privkey_t key_abs = NULL;
+ r = gnutls_privkey_init(&key_abs);
+ if (r != GNUTLS_E_SUCCESS) {
+ gnutls_x509_privkey_deinit(key_x509);
+ return DNSSEC_ENOMEM;
+ }
+
+ int flags = GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE;
+ r = gnutls_privkey_import_x509(key_abs, key_x509, flags);
+ if (r != GNUTLS_E_SUCCESS) {
+ gnutls_x509_privkey_deinit(key_x509);
+ gnutls_privkey_deinit(key_abs);
+ return DNSSEC_ENOMEM;
+ }
+
+ *key = key_abs;
+
+ return DNSSEC_EOK;
+}
+
+/*!
+ * Generate new key and export it in the PEM format.
+ */
+int pem_generate(gnutls_pk_algorithm_t algorithm, unsigned bits,
+ dnssec_binary_t *pem, char **id)
+{
+ assert(pem);
+ assert(id);
+
+ // generate key
+
+ _cleanup_x509_privkey_ gnutls_x509_privkey_t key = NULL;
+ int r = gnutls_x509_privkey_init(&key);
+ if (r != GNUTLS_E_SUCCESS) {
+ return DNSSEC_ENOMEM;
+ }
+
+ r = gnutls_x509_privkey_generate(key, algorithm, bits, 0);
+ if (r != GNUTLS_E_SUCCESS) {
+ return DNSSEC_KEY_GENERATE_ERROR;
+ }
+
+ // convert to PEM and export the ID
+
+ dnssec_binary_t _pem = { 0 };
+ r = pem_from_x509(key, &_pem);
+ if (r != DNSSEC_EOK) {
+ return r;
+ }
+
+ // export key ID
+
+ char *_id = NULL;
+ r = keyid_x509_hex(key, &_id);
+ if (r != DNSSEC_EOK) {
+ dnssec_binary_free(&_pem);
+ return r;
+ }
+
+ *id = _id;
+ *pem = _pem;
+
+ return DNSSEC_EOK;
+}
+
+static int try_export_pem(gnutls_x509_privkey_t key, dnssec_binary_t *pem)
+{
+ assert(key);
+
+ gnutls_x509_crt_fmt_t format = GNUTLS_X509_FMT_PEM;
+ char *password = NULL;
+ int flags = GNUTLS_PKCS_PLAIN;
+
+ return gnutls_x509_privkey_export_pkcs8(key, format, password, flags,
+ pem->data, &pem->size);
+}
+
+/*!
+ * Export GnuTLS X.509 private key to PEM binary.
+ */
+int pem_from_x509(gnutls_x509_privkey_t key, dnssec_binary_t *pem)
+{
+ assert(key);
+ assert(pem);
+
+ dnssec_binary_t _pem = { 0 };
+ int r = try_export_pem(key, &_pem);
+ if (r != GNUTLS_E_SHORT_MEMORY_BUFFER || _pem.size == 0) {
+ return DNSSEC_KEY_EXPORT_ERROR;
+ }
+
+ r = dnssec_binary_alloc(&_pem, _pem.size);
+ if (r != DNSSEC_EOK) {
+ return r;
+ }
+
+ r = try_export_pem(key, &_pem);
+ if (r != GNUTLS_E_SUCCESS) {
+ dnssec_binary_free(&_pem);
+ return DNSSEC_KEY_EXPORT_ERROR;
+ }
+
+ *pem = _pem;
+
+ return DNSSEC_EOK;
+}
+
+/*!
+ * Get key ID of a private key in PEM format.
+ */
+int pem_keyid(const dnssec_binary_t *pem, char **id)
+{
+ assert(pem && pem->size > 0 && pem->data);
+ assert(id);
+
+ _cleanup_x509_privkey_ gnutls_x509_privkey_t key = NULL;
+ int r = pem_x509(pem, &key);
+ if (r != DNSSEC_EOK) {
+ return r;
+ }
+
+ return keyid_x509_hex(key, id);
+}
diff --git a/src/libdnssec/shared/pem.h b/src/libdnssec/shared/pem.h
new file mode 100644
index 0000000..c96065b
--- /dev/null
+++ b/src/libdnssec/shared/pem.h
@@ -0,0 +1,74 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <gnutls/gnutls.h>
+
+#include "libdnssec/binary.h"
+
+/*!
+ * Create GnuTLS X.509 private key from unencrypted PEM data.
+ *
+ * \param[in] pem PEM binary data.
+ * \param[out] key Resulting private key.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int pem_x509(const dnssec_binary_t *pem, gnutls_x509_privkey_t *key);
+
+/*!
+ * Create GnuTLS private key from unencrypted PEM data.
+ *
+ * \param[in] pem PEM binary data.
+ * \param[out] key Resulting private key.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int pem_privkey(const dnssec_binary_t *pem, gnutls_privkey_t *key);
+
+/*!
+ * Generate a private key and export it in the PEM format.
+ *
+ * \param[in] algorithm Algorithm to be used.
+ * \param[in] bits Size of the key to be generated.
+ * \param[out] pem Generated key in unencrypted PEM format.
+ * \param[out] id Key ID of the generated key.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int pem_generate(gnutls_pk_algorithm_t algorithm, unsigned bits,
+ dnssec_binary_t *pem, char **id);
+
+/*!
+ * Export GnuTLS X.509 private key to PEM binary.
+ *
+ * \param[in] key Key to be exported.
+ * \param[out] pem Generated key in unencrypted PEM format.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int pem_from_x509(gnutls_x509_privkey_t key, dnssec_binary_t *pem);
+
+/*!
+ * Get key ID of a private key in PEM format.
+ *
+ * \param[in] pem Key in unencrypted PEM format.
+ * \param[out] id ID of the key.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int pem_keyid(const dnssec_binary_t *pem, char **id);
diff --git a/src/libdnssec/shared/shared.h b/src/libdnssec/shared/shared.h
new file mode 100644
index 0000000..1f55033
--- /dev/null
+++ b/src/libdnssec/shared/shared.h
@@ -0,0 +1,129 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <assert.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <gnutls/abstract.h>
+#include <gnutls/crypto.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+#include "libdnssec/binary.h"
+
+#define _public_ __attribute__((visibility("default")))
+#define _hidden_ __attribute__((visibility("hidden")))
+
+#define _unused_ __attribute__((unused))
+
+/**
+ * Macro to clear a structure of known size.
+ *
+ * \param pointer Pointer to the structure.
+ */
+#define clear_struct(pointer) memset((pointer), '\0', sizeof(*(pointer)))
+
+#define streq(one, two) (strcmp((one), (two)) == 0)
+
+/* -- cleanup macros ------------------------------------------------------- */
+
+#define _cleanup_(var) __attribute__((cleanup(var)))
+
+static inline void free_ptr(void *ptr)
+{
+ free(*(void **)ptr);
+}
+
+static inline void close_ptr(int *ptr)
+{
+ if (*ptr != -1) {
+ close(*ptr);
+ }
+}
+
+static inline void fclose_ptr(FILE **ptr)
+{
+ if (*ptr) {
+ fclose(*ptr);
+ }
+}
+
+static inline void closedir_ptr(DIR **ptr)
+{
+ if (*ptr) {
+ closedir(*ptr);
+ }
+}
+
+static inline void free_gnutls_datum_ptr(gnutls_datum_t *ptr)
+{
+ gnutls_free(ptr->data);
+}
+
+static inline void free_x509_privkey_ptr(gnutls_x509_privkey_t *ptr)
+{
+ if (*ptr) {
+ gnutls_x509_privkey_deinit(*ptr);
+ }
+}
+
+static inline void free_pubkey_ptr(gnutls_pubkey_t *ptr)
+{
+ if (*ptr) {
+ gnutls_pubkey_deinit(*ptr);
+ }
+}
+
+static inline void free_gnutls_hash_ptr(gnutls_hash_hd_t *ptr)
+{
+ if (*ptr) {
+ gnutls_hash_deinit(*ptr, NULL);
+ }
+}
+
+#define _cleanup_free_ _cleanup_(free_ptr)
+#define _cleanup_close_ _cleanup_(close_ptr)
+#define _cleanup_fclose_ _cleanup_(fclose_ptr)
+#define _cleanup_closedir_ _cleanup_(closedir_ptr)
+#define _cleanup_binary_ _cleanup_(dnssec_binary_free)
+#define _cleanup_datum_ _cleanup_(free_gnutls_datum_ptr)
+#define _cleanup_x509_privkey_ _cleanup_(free_x509_privkey_ptr)
+#define _cleanup_pubkey_ _cleanup_(free_pubkey_ptr)
+#define _cleanup_hash_ _cleanup_(free_gnutls_hash_ptr)
+
+/* -- assertions ----------------------------------------------------------- */
+
+#define assert_unreachable() assert(0)
+
+/* -- crypto helpers ------------------------------------------------------- */
+
+static inline gnutls_datum_t binary_to_datum(const dnssec_binary_t *from)
+{
+ gnutls_datum_t to = { .size = from->size, .data = from->data };
+ return to;
+}
+
+static inline dnssec_binary_t binary_from_datum(const gnutls_datum_t *from)
+{
+ dnssec_binary_t to = { .size = from->size, .data = from->data };
+ return to;
+}
diff --git a/src/libdnssec/sign.h b/src/libdnssec/sign.h
new file mode 100644
index 0000000..4313533
--- /dev/null
+++ b/src/libdnssec/sign.h
@@ -0,0 +1,137 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*!
+ * \file
+ *
+ * \addtogroup sign
+ *
+ * \brief DNSSEC signing API
+ *
+ * The module provides the low level DNSSEC signing and verification.
+ *
+ * Example of signature validation:
+ *
+ * ~~~~~ {.c}
+ *
+ * dnssec_key_t *dnskey = // ... ;
+ * dnssec_binary_t *rrsig_header = // ... ;
+ * dnssec_binary_t *covered_rdata = // ... ;
+ * dnssec_binary_t *signature = // ... ;
+ *
+ * int result;
+ * dnssec_sign_ctx_t *ctx = NULL;
+ *
+ * result = dnssec_sign_new(&ctx, dnskey);
+ * if (result != DNSSEC_EOK) {
+ * return result;
+ * }
+ *
+ * dnssec_sign_add(ctx, rrsig_header);
+ * dnssec_sign_add(ctx, covered_rdata);
+ *
+ * result = dnssec_sign_verify(ctx, signature);
+ * if (result == DNSSEC_EOK) {
+ * // valid signature
+ * } else if (result == DNSSEC_INVALID_SIGNATURE) {
+ * // invalid signature
+ * } else {
+ * // error
+ * }
+ *
+ * dnssec_sign_free(ctx);
+ *
+ * ~~~~~
+ *
+ *
+ * @{
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <libdnssec/binary.h>
+#include <libdnssec/key.h>
+
+struct dnssec_sign_ctx;
+
+/*!
+ * DNSSEC signing context.
+ */
+typedef struct dnssec_sign_ctx dnssec_sign_ctx_t;
+
+/*!
+ * Create new DNSSEC signing context.
+ *
+ * \note \ref dnssec_sign_init is called as a part of this function.
+ *
+ * \param ctx_ptr Pointer to context to be allocated.
+ * \param key DNSSEC key to be used.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int dnssec_sign_new(dnssec_sign_ctx_t **ctx_ptr, const dnssec_key_t *key);
+
+/*!
+ * Free DNSSEC signing context.
+ *
+ * \param ctx Signing context to be freed.
+ */
+void dnssec_sign_free(dnssec_sign_ctx_t *ctx);
+
+/*!
+ * Reinitialize DNSSEC signing context to start a new operation.
+ *
+ * \param ctx Signing context.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int dnssec_sign_init(dnssec_sign_ctx_t *ctx);
+
+/*!
+ * Add data to be covered by DNSSEC signature.
+ *
+ * \param ctx Signing context.
+ * \param data Data to be signed.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int dnssec_sign_add(dnssec_sign_ctx_t *ctx, const dnssec_binary_t *data);
+
+/*!
+ * Write down the DNSSEC signature.
+ *
+ * \param ctx Signing context.
+ * \param signature Signature to be allocated and written.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int dnssec_sign_write(dnssec_sign_ctx_t *ctx, dnssec_binary_t *signature);
+
+/*!
+ * Verify DNSSEC signature.
+ *
+ * \param ctx Signing context.
+ * \param signature Signature to be verified.
+ *
+ * \return Error code.
+ * \retval DNSSEC_EOK Validation successful, valid signature.
+ * \retval DNSSEC_INVALID_SIGNATURE Validation successful, invalid signature.
+ */
+int dnssec_sign_verify(dnssec_sign_ctx_t *ctx, const dnssec_binary_t *signature);
+
+/** @} */
diff --git a/src/libdnssec/sign/der.c b/src/libdnssec/sign/der.c
new file mode 100644
index 0000000..4d79876
--- /dev/null
+++ b/src/libdnssec/sign/der.c
@@ -0,0 +1,229 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdbool.h>
+
+#include "libdnssec/shared/bignum.h"
+#include "libdnssec/binary.h"
+#include "libdnssec/error.h"
+#include "libdnssec/sign/der.h"
+#include "libdnssec/shared/binary_wire.h"
+
+/*
+ * In fact, this is a very tiny subset of ASN.1 encoding format implementation,
+ * which is necessary for the purpose of DNSSEC.
+ *
+ * References: RFC 3279 (X.509 PKI), X.690, RFC 6605 (ECDSA), RFC8080 (EDDSA)
+ *
+ * Dss-Sig-Value ::= SEQUENCE { r INTEGER, s INTEGER }
+ */
+
+#define ASN1_TYPE_SEQUENCE 0x30
+#define ASN1_TYPE_INTEGER 0x02
+
+#define ASN1_MAX_SIZE 127
+
+/*!
+ * Check if the next object has a given type.
+ */
+static bool asn1_expect_type(wire_ctx_t *wire, uint8_t type)
+{
+ assert(wire);
+ return (wire_ctx_available(wire) >= 1 && wire_ctx_read_u8(wire) == type);
+}
+
+/*!
+ * Decode the size of the object (only short format is supported).
+ */
+static int asn1_decode_size(wire_ctx_t *wire, size_t *size)
+{
+ assert(wire);
+ assert(size);
+
+ if (wire_ctx_available(wire) < 1) {
+ return DNSSEC_MALFORMED_DATA;
+ }
+
+ uint8_t byte = wire_ctx_read_u8(wire);
+ if (byte & 0x80) {
+ // long form, we do not need it for DNSSEC
+ return DNSSEC_NOT_IMPLEMENTED_ERROR;
+ }
+
+ *size = byte;
+
+ return DNSSEC_EOK;
+}
+
+/*!
+ * Decode an unsigned integer object.
+ */
+static int asn1_decode_integer(wire_ctx_t *wire, dnssec_binary_t *_value)
+{
+ assert(wire);
+ assert(_value);
+
+ if (!asn1_expect_type(wire, ASN1_TYPE_INTEGER)) {
+ return DNSSEC_MALFORMED_DATA;
+ }
+
+ size_t size;
+ int result = asn1_decode_size(wire, &size);
+ if (result != DNSSEC_EOK) {
+ return result;
+ }
+
+ if (size == 0 || size > wire_ctx_available(wire)) {
+ return DNSSEC_MALFORMED_DATA;
+ }
+
+ dnssec_binary_t value = { .data = wire->position, .size = size };
+ wire->position += size;
+
+ // skip leading zeroes (unless equal to zero)
+ while (value.size > 1 && value.data[0] == 0) {
+ value.data += 1;
+ value.size -= 1;
+ }
+
+ *_value = value;
+
+ return DNSSEC_EOK;
+}
+
+/*!
+ * Encode object header (type and length).
+ */
+static void asn1_write_header(wire_ctx_t *wire, uint8_t type, size_t length)
+{
+ assert(wire);
+ assert(length < ASN1_MAX_SIZE);
+
+ wire_ctx_write_u8(wire, type);
+ wire_ctx_write_u8(wire, length);
+}
+
+/*!
+ * Encode unsigned integer object.
+ */
+static void asn1_write_integer(wire_ctx_t *wire, size_t integer_size,
+ const dnssec_binary_t *integer)
+{
+ assert(wire);
+ assert(integer);
+ assert(integer->data);
+
+ asn1_write_header(wire, ASN1_TYPE_INTEGER, integer_size);
+ bignum_write(wire, integer_size, integer);
+}
+
+/*!
+ * Decode signature parameters from X.509 ECDSA signature.
+ */
+int dss_sig_value_decode(const dnssec_binary_t *der,
+ dnssec_binary_t *r, dnssec_binary_t *s)
+{
+ if (!der || !der->data || !r || !s) {
+ return DNSSEC_EINVAL;
+ }
+
+ wire_ctx_t wire = binary_init(der);
+
+ size_t size;
+ int result;
+
+ // decode the sequence
+
+ if (!asn1_expect_type(&wire, ASN1_TYPE_SEQUENCE)) {
+ return DNSSEC_MALFORMED_DATA;
+ }
+
+ result = asn1_decode_size(&wire, &size);
+ if (result != DNSSEC_EOK) {
+ return result;
+ }
+
+ if (size != wire_ctx_available(&wire)) {
+ return DNSSEC_MALFORMED_DATA;
+ }
+
+ // decode the 'r' and 's' values
+
+ dnssec_binary_t der_r;
+ result = asn1_decode_integer(&wire, &der_r);
+ if (result != DNSSEC_EOK) {
+ return result;
+ }
+
+ dnssec_binary_t der_s;
+ result = asn1_decode_integer(&wire, &der_s);
+ if (result != DNSSEC_EOK) {
+ return result;
+ }
+
+ if (wire_ctx_available(&wire) != 0) {
+ return DNSSEC_MALFORMED_DATA;
+ }
+
+ *r = der_r;
+ *s = der_s;
+
+ return DNSSEC_EOK;
+}
+
+/*!
+ * Encode signature parameters from X.509 ECDSA signature.
+ */
+int dss_sig_value_encode(const dnssec_binary_t *r, const dnssec_binary_t *s,
+ dnssec_binary_t *der)
+{
+ if (!r || !r->data || !s || !s->data || !der) {
+ return DNSSEC_EINVAL;
+ }
+
+ size_t r_size = bignum_size_s(r);
+ size_t s_size = bignum_size_s(s);
+
+ // check supported inputs range
+
+ if (r_size > ASN1_MAX_SIZE || s_size > ASN1_MAX_SIZE) {
+ return DNSSEC_NOT_IMPLEMENTED_ERROR;
+ }
+
+ size_t seq_size = 2 + r_size + 2 + s_size;
+ if (seq_size > ASN1_MAX_SIZE) {
+ return DNSSEC_NOT_IMPLEMENTED_ERROR;
+ }
+
+ // encode result
+
+ size_t total_size = 2 + seq_size;
+
+ dnssec_binary_t _der = { 0 };
+ if (dnssec_binary_alloc(&_der, total_size)) {
+ return DNSSEC_ENOMEM;
+ }
+
+ wire_ctx_t wire = binary_init(&_der);
+ asn1_write_header(&wire, ASN1_TYPE_SEQUENCE, seq_size);
+ asn1_write_integer(&wire, r_size, r);
+ asn1_write_integer(&wire, s_size, s);
+ assert(wire_ctx_available(&wire) == 0);
+
+ *der = _der;
+
+ return DNSSEC_EOK;
+}
diff --git a/src/libdnssec/sign/der.h b/src/libdnssec/sign/der.h
new file mode 100644
index 0000000..db8e910
--- /dev/null
+++ b/src/libdnssec/sign/der.h
@@ -0,0 +1,56 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include "libdnssec/binary.h"
+
+/*
+ * The ECDSA signatures in DNSSEC are encoded differently than in X.509
+ * (PKCS #1). The cryptographic libraries usually produce the signatures in
+ * X.509 format, which uses Dss-Sig-Value to encapsulate 'r' and 's' values
+ * of the signature.
+ *
+ * This module provides decoding and encoding of this format.
+ *
+ * The 'r' and 's' values are treated as unsigned values: The leading zeroes
+ * are stripped on decoding; an extra leading zero is added on encoding in case
+ * the value starts with a set bit.
+ */
+
+/*!
+ * Decode signature parameters from X.509 ECDSA signature.
+ *
+ * \param[in] der X.509 encoded signature.
+ * \param[out] s Value 's' of the signature, will point to the data in DER.
+ * \param[out] r Value 'r' of the signature, will point to the data in DER.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int dss_sig_value_decode(const dnssec_binary_t *der,
+ dnssec_binary_t *r, dnssec_binary_t *s);
+
+/*!
+ * Encode signature parameters from X.509 ECDSA signature.
+ *
+ * \param[in] s Value 's' of the signature.
+ * \param[in] r Value 'r' of the signature.
+ * \param[out] der X.509 signature, the content will be allocated.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int dss_sig_value_encode(const dnssec_binary_t *r, const dnssec_binary_t *s,
+ dnssec_binary_t *der);
diff --git a/src/libdnssec/sign/sign.c b/src/libdnssec/sign/sign.c
new file mode 100644
index 0000000..16b4e64
--- /dev/null
+++ b/src/libdnssec/sign/sign.c
@@ -0,0 +1,408 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+#include "contrib/macros.h"
+#include "libdnssec/shared/bignum.h"
+#include "libdnssec/error.h"
+#include "libdnssec/key.h"
+#include "libdnssec/key/internal.h"
+#include "libdnssec/shared/shared.h"
+#include "libdnssec/sign.h"
+#include "libdnssec/sign/der.h"
+#include "libdnssec/shared/binary_wire.h"
+#include "libdnssec/contrib/vpool.h"
+
+/*!
+ * Signature format conversion callback.
+ *
+ * \param ctx DNSSEC signing context.
+ * \param from Data in source format.
+ * \param to Allocated data in target format.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+typedef int (*signature_convert_cb)(dnssec_sign_ctx_t *ctx,
+ const dnssec_binary_t *from,
+ dnssec_binary_t *to);
+
+/*!
+ * Algorithm specific callbacks.
+ */
+typedef struct algorithm_functions {
+ //! Convert X.509 signature to DNSSEC format.
+ signature_convert_cb x509_to_dnssec;
+ //! Convert DNSSEC signature to X.509 format.
+ signature_convert_cb dnssec_to_x509;
+} algorithm_functions_t;
+
+typedef struct dnssec_buffer {
+ uint8_t *allocd; //!< Pointer to allocated data.
+ uint8_t *data; //!< API: pointer to data to copy from.
+ size_t max_length;
+ size_t length; //!< API: current length.
+} dnssec_buffer_t;
+
+/*!
+ * DNSSEC signing context.
+ */
+struct dnssec_sign_ctx {
+ const dnssec_key_t *key; //!< Signing key.
+ const algorithm_functions_t *functions; //!< Implementation specific.
+
+ gnutls_sign_algorithm_t sign_algorithm; //!< Used algorithm for signing.
+ struct vpool buffer; //!< Buffer for the data to be signed.
+};
+
+/* -- signature format conversions ----------------------------------------- */
+
+/*!
+ * Conversion of RSA signature between X.509 and DNSSEC format is a NOOP.
+ *
+ * \note Described in RFC 3110.
+ */
+static int rsa_copy_signature(dnssec_sign_ctx_t *ctx,
+ const dnssec_binary_t *from,
+ dnssec_binary_t *to)
+{
+ assert(ctx);
+ assert(from);
+ assert(to);
+
+ return dnssec_binary_dup(from, to);
+}
+
+static const algorithm_functions_t rsa_functions = {
+ .x509_to_dnssec = rsa_copy_signature,
+ .dnssec_to_x509 = rsa_copy_signature,
+};
+
+static size_t ecdsa_sign_integer_size(dnssec_sign_ctx_t *ctx)
+{
+ assert(ctx);
+
+ switch (ctx->sign_algorithm) {
+ case GNUTLS_SIGN_ECDSA_SHA256: return 32;
+ case GNUTLS_SIGN_ECDSA_SHA384: return 48;
+ default: return 0;
+ };
+}
+
+/*!
+ * Convert ECDSA signature to DNSSEC format.
+ *
+ * \note Described in RFC 6605.
+ */
+static int ecdsa_x509_to_dnssec(dnssec_sign_ctx_t *ctx,
+ const dnssec_binary_t *x509,
+ dnssec_binary_t *dnssec)
+{
+ assert(ctx);
+ assert(x509);
+ assert(dnssec);
+
+ dnssec_binary_t value_r = { 0 };
+ dnssec_binary_t value_s = { 0 };
+
+ int result = dss_sig_value_decode(x509, &value_r, &value_s);
+ if (result != DNSSEC_EOK) {
+ return result;
+ }
+
+ size_t int_size = ecdsa_sign_integer_size(ctx);
+ size_t r_size = bignum_size_u(&value_r);
+ size_t s_size = bignum_size_u(&value_s);
+
+ if (r_size > int_size || s_size > int_size) {
+ return DNSSEC_MALFORMED_DATA;
+ }
+
+ result = dnssec_binary_alloc(dnssec, 2 * int_size);
+ if (result != DNSSEC_EOK) {
+ return result;
+ }
+
+ wire_ctx_t wire = binary_init(dnssec);
+ bignum_write(&wire, int_size, &value_r);
+ bignum_write(&wire, int_size, &value_s);
+ assert(wire_ctx_offset(&wire) == dnssec->size);
+
+ return DNSSEC_EOK;
+}
+
+static int ecdsa_dnssec_to_x509(dnssec_sign_ctx_t *ctx,
+ const dnssec_binary_t *dnssec,
+ dnssec_binary_t *x509)
+{
+ assert(ctx);
+ assert(x509);
+ assert(dnssec);
+
+ size_t int_size = ecdsa_sign_integer_size(ctx);
+
+ if (dnssec->size != 2 * int_size) {
+ return DNSSEC_INVALID_SIGNATURE;
+ }
+
+ const dnssec_binary_t value_r = { .size = int_size, .data = dnssec->data };
+ const dnssec_binary_t value_s = { .size = int_size, .data = dnssec->data + int_size };
+
+ return dss_sig_value_encode(&value_r, &value_s, x509);
+}
+
+static const algorithm_functions_t ecdsa_functions = {
+ .x509_to_dnssec = ecdsa_x509_to_dnssec,
+ .dnssec_to_x509 = ecdsa_dnssec_to_x509,
+};
+
+#define eddsa_copy_signature rsa_copy_signature
+static const algorithm_functions_t eddsa_functions = {
+ .x509_to_dnssec = eddsa_copy_signature,
+ .dnssec_to_x509 = eddsa_copy_signature,
+};
+
+/* -- crypto helper functions --------------------------------------------- */
+
+static const algorithm_functions_t *get_functions(const dnssec_key_t *key)
+{
+ uint8_t algorithm = dnssec_key_get_algorithm(key);
+
+ switch ((dnssec_key_algorithm_t)algorithm) {
+ case DNSSEC_KEY_ALGORITHM_RSA_SHA1:
+ case DNSSEC_KEY_ALGORITHM_RSA_SHA1_NSEC3:
+ case DNSSEC_KEY_ALGORITHM_RSA_SHA256:
+ case DNSSEC_KEY_ALGORITHM_RSA_SHA512:
+ return &rsa_functions;
+ case DNSSEC_KEY_ALGORITHM_ECDSA_P256_SHA256:
+ case DNSSEC_KEY_ALGORITHM_ECDSA_P384_SHA384:
+ return &ecdsa_functions;
+ case DNSSEC_KEY_ALGORITHM_ED25519:
+ case DNSSEC_KEY_ALGORITHM_ED448:
+ return &eddsa_functions;
+ default:
+ return NULL;
+ }
+}
+
+#ifndef HAVE_SIGN_DATA2
+/**
+ * Get digest algorithm used with a given key.
+ */
+static gnutls_digest_algorithm_t get_digest_algorithm(const dnssec_key_t *key)
+{
+ uint8_t algorithm = dnssec_key_get_algorithm(key);
+
+ switch ((dnssec_key_algorithm_t)algorithm) {
+ case DNSSEC_KEY_ALGORITHM_RSA_SHA1:
+ case DNSSEC_KEY_ALGORITHM_RSA_SHA1_NSEC3:
+ return GNUTLS_DIG_SHA1;
+ case DNSSEC_KEY_ALGORITHM_RSA_SHA256:
+ case DNSSEC_KEY_ALGORITHM_ECDSA_P256_SHA256:
+ return GNUTLS_DIG_SHA256;
+ case DNSSEC_KEY_ALGORITHM_RSA_SHA512:
+ return GNUTLS_DIG_SHA512;
+ case DNSSEC_KEY_ALGORITHM_ECDSA_P384_SHA384:
+ return GNUTLS_DIG_SHA384;
+ case DNSSEC_KEY_ALGORITHM_ED25519:
+ return GNUTLS_DIG_SHA512;
+ case DNSSEC_KEY_ALGORITHM_ED448:
+ default:
+ return GNUTLS_DIG_UNKNOWN;
+ }
+}
+#endif
+
+static gnutls_sign_algorithm_t get_sign_algorithm(const dnssec_key_t *key)
+{
+ uint8_t algorithm = dnssec_key_get_algorithm(key);
+
+ switch ((dnssec_key_algorithm_t)algorithm) {
+ case DNSSEC_KEY_ALGORITHM_RSA_SHA1:
+ case DNSSEC_KEY_ALGORITHM_RSA_SHA1_NSEC3:
+ return GNUTLS_SIGN_RSA_SHA1;
+ case DNSSEC_KEY_ALGORITHM_RSA_SHA256:
+ return GNUTLS_SIGN_RSA_SHA256;
+ case DNSSEC_KEY_ALGORITHM_ECDSA_P256_SHA256:
+ return GNUTLS_SIGN_ECDSA_SHA256;
+ case DNSSEC_KEY_ALGORITHM_RSA_SHA512:
+ return GNUTLS_SIGN_RSA_SHA512;
+ case DNSSEC_KEY_ALGORITHM_ECDSA_P384_SHA384:
+ return GNUTLS_SIGN_ECDSA_SHA384;
+ case DNSSEC_KEY_ALGORITHM_ED25519:
+#ifdef HAVE_ED25519
+ return GNUTLS_SIGN_EDDSA_ED25519;
+#endif
+ case DNSSEC_KEY_ALGORITHM_ED448:
+#ifdef HAVE_ED448
+ return GNUTLS_SIGN_EDDSA_ED448;
+#endif
+ default:
+ return GNUTLS_SIGN_UNKNOWN;
+ }
+}
+
+/* -- public API ---------------------------------------------------------- */
+
+_public_
+int dnssec_sign_new(dnssec_sign_ctx_t **ctx_ptr, const dnssec_key_t *key)
+{
+ if (!ctx_ptr) {
+ return DNSSEC_EINVAL;
+ }
+
+ dnssec_sign_ctx_t *ctx = calloc(1, sizeof(*ctx));
+
+ ctx->key = key;
+
+ ctx->functions = get_functions(key);
+ if (ctx->functions == NULL) {
+ free(ctx);
+ return DNSSEC_INVALID_KEY_ALGORITHM;
+ }
+
+ ctx->sign_algorithm = get_sign_algorithm(key);
+ int result = dnssec_sign_init(ctx);
+ if (result != DNSSEC_EOK) {
+ free(ctx);
+ return result;
+ }
+
+ *ctx_ptr = ctx;
+
+ return DNSSEC_EOK;
+}
+
+_public_
+void dnssec_sign_free(dnssec_sign_ctx_t *ctx)
+{
+ if (!ctx) {
+ return;
+ }
+
+ vpool_reset(&ctx->buffer);
+
+ free(ctx);
+}
+
+_public_
+int dnssec_sign_init(dnssec_sign_ctx_t *ctx)
+{
+ if (!ctx) {
+ return DNSSEC_EINVAL;
+ }
+
+ if (vpool_get_buf(&ctx->buffer) != NULL) {
+ vpool_wipe(&ctx->buffer);
+ } else {
+ vpool_init(&ctx->buffer, 1024, 0);
+ }
+
+ return DNSSEC_EOK;
+}
+
+_public_
+int dnssec_sign_add(dnssec_sign_ctx_t *ctx, const dnssec_binary_t *data)
+{
+ if (!ctx || !data || !data->data) {
+ return DNSSEC_EINVAL;
+ }
+
+ void *result = vpool_insert(&ctx->buffer, vpool_get_length(&ctx->buffer), data->data, data->size);
+ if (result == NULL) {
+ return DNSSEC_SIGN_ERROR;
+ }
+
+ return DNSSEC_EOK;
+}
+
+_public_
+int dnssec_sign_write(dnssec_sign_ctx_t *ctx, dnssec_binary_t *signature)
+{
+ if (!ctx || !signature) {
+ return DNSSEC_EINVAL;
+ }
+
+ if (!dnssec_key_can_sign(ctx->key)) {
+ return DNSSEC_NO_PRIVATE_KEY;
+ }
+
+ gnutls_datum_t data = {
+ .data = vpool_get_buf(&ctx->buffer),
+ .size = vpool_get_length(&ctx->buffer)
+ };
+
+ assert(ctx->key->private_key);
+ _cleanup_datum_ gnutls_datum_t raw = { 0 };
+#ifdef HAVE_SIGN_DATA2
+ int result = gnutls_privkey_sign_data2(ctx->key->private_key,
+ ctx->sign_algorithm,
+ 0, &data, &raw);
+#else
+ gnutls_digest_algorithm_t digest_algorithm = get_digest_algorithm(ctx->key);
+ int result = gnutls_privkey_sign_data(ctx->key->private_key,
+ digest_algorithm,
+ 0, &data, &raw);
+#endif
+ if (result < 0) {
+ return DNSSEC_SIGN_ERROR;
+ }
+
+ dnssec_binary_t bin_raw = binary_from_datum(&raw);
+
+ return ctx->functions->x509_to_dnssec(ctx, &bin_raw, signature);
+}
+
+_public_
+int dnssec_sign_verify(dnssec_sign_ctx_t *ctx, const dnssec_binary_t *signature)
+{
+ if (!ctx || !signature) {
+ return DNSSEC_EINVAL;
+ }
+
+ if (!dnssec_key_can_verify(ctx->key)) {
+ return DNSSEC_NO_PUBLIC_KEY;
+ }
+
+ gnutls_datum_t data = {
+ .data = vpool_get_buf(&ctx->buffer),
+ .size = vpool_get_length(&ctx->buffer)
+ };
+
+ _cleanup_binary_ dnssec_binary_t bin_raw = { 0 };
+ int result = ctx->functions->dnssec_to_x509(ctx, signature, &bin_raw);
+ if (result != DNSSEC_EOK) {
+ return result;
+ }
+
+ gnutls_datum_t raw = binary_to_datum(&bin_raw);
+
+ assert(ctx->key->public_key);
+ result = gnutls_pubkey_verify_data2(ctx->key->public_key,
+ ctx->sign_algorithm,
+ 0, &data, &raw);
+ if (result == GNUTLS_E_PK_SIG_VERIFY_FAILED) {
+ return DNSSEC_INVALID_SIGNATURE;
+ } else if (result < 0) {
+ return DNSSEC_ERROR;
+ }
+
+ return DNSSEC_EOK;
+}
diff --git a/src/libdnssec/tsig.c b/src/libdnssec/tsig.c
new file mode 100644
index 0000000..3edc8a3
--- /dev/null
+++ b/src/libdnssec/tsig.c
@@ -0,0 +1,242 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libdnssec/shared/dname.h"
+#include "libdnssec/error.h"
+#include "libdnssec/shared/shared.h"
+#include "libdnssec/tsig.h"
+
+struct dnssec_tsig_ctx {
+ gnutls_mac_algorithm_t algorithm;
+ gnutls_hmac_hd_t hash;
+};
+
+/*!
+ * TSIG algorithm indentifiers.
+ */
+typedef struct {
+ dnssec_tsig_algorithm_t id;
+ gnutls_mac_algorithm_t gnutls_id;
+ const char *name;
+ const char *dname;
+} algorithm_id_t;
+
+/*!
+ * DNAME to algorithm conversion table.
+ */
+static const algorithm_id_t ALGORITHM_ID_TABLE[] = {
+ // RFC 4635
+ { DNSSEC_TSIG_HMAC_SHA1, GNUTLS_MAC_SHA1, "hmac-sha1", "\x9hmac-sha1" },
+ { DNSSEC_TSIG_HMAC_SHA224, GNUTLS_MAC_SHA224, "hmac-sha224", "\xbhmac-sha224" },
+ { DNSSEC_TSIG_HMAC_SHA256, GNUTLS_MAC_SHA256, "hmac-sha256", "\xbhmac-sha256" },
+ { DNSSEC_TSIG_HMAC_SHA384, GNUTLS_MAC_SHA384, "hmac-sha384", "\xbhmac-sha384" },
+ { DNSSEC_TSIG_HMAC_SHA512, GNUTLS_MAC_SHA512, "hmac-sha512", "\xbhmac-sha512" },
+ // RFC 2845
+ { DNSSEC_TSIG_HMAC_MD5, GNUTLS_MAC_MD5, "hmac-md5", "\x8hmac-md5\x7sig-alg\x3reg\x3int" },
+ { 0 }
+};
+
+/*!
+ * Algorithm match callback prototype.
+ */
+typedef bool (*algorithm_match_cb)(const algorithm_id_t *m, const void *data);
+
+/*!
+ * Lookup an algorithm in the algorithm table.
+ */
+static const algorithm_id_t *lookup_algorithm(algorithm_match_cb match,
+ const void *data)
+{
+ assert(match);
+
+ for (const algorithm_id_t *a = ALGORITHM_ID_TABLE; a->id; a++) {
+ if (match(a, data)) {
+ return a;
+ }
+ }
+
+ return NULL;
+}
+
+static bool match_dname(const algorithm_id_t *algorithm, const void *data)
+{
+ const uint8_t *search = data;
+ return dname_equal(search, (uint8_t *)algorithm->dname);
+}
+
+static bool match_name(const algorithm_id_t *algorithm, const void *data)
+{
+ const char *search = data;
+ return strcasecmp(search, algorithm->name) == 0;
+}
+
+static bool match_id(const algorithm_id_t *algorithm, const void *data)
+{
+ dnssec_tsig_algorithm_t search = (dnssec_tsig_algorithm_t)data;
+ return algorithm->id == search;
+}
+
+/*!
+ * Convert TSIG algorithm identifier to GnuTLS identifier.
+ */
+static gnutls_mac_algorithm_t algorithm_to_gnutls(dnssec_tsig_algorithm_t tsig)
+{
+ const algorithm_id_t *found = lookup_algorithm(match_id, (void *)tsig);
+ return (found ? found->gnutls_id : GNUTLS_MAC_UNKNOWN);
+}
+
+/* -- public API ----------------------------------------------------------- */
+
+_public_
+dnssec_tsig_algorithm_t dnssec_tsig_algorithm_from_dname(const uint8_t *dname)
+{
+ if (!dname) {
+ return DNSSEC_TSIG_UNKNOWN;
+ }
+
+ const algorithm_id_t *found = lookup_algorithm(match_dname, dname);
+ return (found ? found->id : DNSSEC_TSIG_UNKNOWN);
+}
+
+_public_
+const uint8_t *dnssec_tsig_algorithm_to_dname(dnssec_tsig_algorithm_t algorithm)
+{
+ const algorithm_id_t *found = lookup_algorithm(match_id, (void *)algorithm);
+ return (found ? (uint8_t *)found->dname : NULL);
+}
+
+_public_
+dnssec_tsig_algorithm_t dnssec_tsig_algorithm_from_name(const char *name)
+{
+ if (!name) {
+ return DNSSEC_TSIG_UNKNOWN;
+ }
+
+ const algorithm_id_t *found = lookup_algorithm(match_name, name);
+ return (found ? found->id : DNSSEC_TSIG_UNKNOWN);
+}
+
+_public_
+const char *dnssec_tsig_algorithm_to_name(dnssec_tsig_algorithm_t algorithm)
+{
+ const algorithm_id_t *found = lookup_algorithm(match_id, (void *)algorithm);
+ return (found ? found->name : NULL);
+}
+
+_public_
+int dnssec_tsig_optimal_key_size(dnssec_tsig_algorithm_t tsig)
+{
+ gnutls_mac_algorithm_t mac = algorithm_to_gnutls(tsig);
+ if (mac == GNUTLS_MAC_UNKNOWN) {
+ return 0;
+ }
+
+ return gnutls_mac_get_key_size(mac) * CHAR_BIT;
+}
+
+_public_
+int dnssec_tsig_new(dnssec_tsig_ctx_t **ctx_ptr,
+ dnssec_tsig_algorithm_t algorithm,
+ const dnssec_binary_t *key)
+{
+ if (!ctx_ptr || !key) {
+ return DNSSEC_EINVAL;
+ }
+
+ dnssec_tsig_ctx_t *ctx = calloc(1, sizeof(*ctx));
+ if (!ctx) {
+ return DNSSEC_ENOMEM;
+ }
+
+ ctx->algorithm = algorithm_to_gnutls(algorithm);
+ if (ctx->algorithm == GNUTLS_MAC_UNKNOWN) {
+ free(ctx);
+ return DNSSEC_INVALID_KEY_ALGORITHM;
+ }
+
+ int result = gnutls_hmac_init(&ctx->hash, ctx->algorithm, key->data, key->size);
+ if (result != 0) {
+ free(ctx);
+ return DNSSEC_SIGN_INIT_ERROR;
+ }
+
+ *ctx_ptr = ctx;
+
+ return DNSSEC_EOK;
+}
+
+_public_
+void dnssec_tsig_free(dnssec_tsig_ctx_t *ctx)
+{
+ if (!ctx) {
+ return;
+ }
+
+ gnutls_hmac_deinit(ctx->hash, NULL);
+ free(ctx);
+}
+
+_public_
+int dnssec_tsig_add(dnssec_tsig_ctx_t *ctx, const dnssec_binary_t *data)
+{
+ if (!ctx || !data) {
+ return DNSSEC_EINVAL;
+ }
+
+ int result = gnutls_hmac(ctx->hash, data->data, data->size);
+ if (result != 0) {
+ return DNSSEC_SIGN_ERROR;
+ }
+
+ return DNSSEC_EOK;
+}
+
+_public_
+size_t dnssec_tsig_size(dnssec_tsig_ctx_t *ctx)
+{
+ if (!ctx) {
+ return 0;
+ }
+
+ return gnutls_hmac_get_len(ctx->algorithm);
+}
+
+_public_
+size_t dnssec_tsig_algorithm_size(dnssec_tsig_algorithm_t algorithm)
+{
+ int gnutls_algorithm = algorithm_to_gnutls(algorithm);
+ return gnutls_hmac_get_len(gnutls_algorithm);
+}
+
+_public_
+int dnssec_tsig_write(dnssec_tsig_ctx_t *ctx, uint8_t *mac)
+{
+ if (!ctx || !mac) {
+ return DNSSEC_EINVAL;
+ }
+
+ gnutls_hmac_output(ctx->hash, mac);
+
+ return DNSSEC_EOK;
+}
diff --git a/src/libdnssec/tsig.h b/src/libdnssec/tsig.h
new file mode 100644
index 0000000..e861982
--- /dev/null
+++ b/src/libdnssec/tsig.h
@@ -0,0 +1,207 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*!
+ * \file
+ *
+ * \addtogroup tsig
+ *
+ * \brief Low-level TSIG signing API.
+ *
+ * Example:
+ *
+ * ~~~~~ {.c}
+ *
+ * int result;
+ *
+ * dnssec_binary_t *covered = // ... ;
+ * dnssec_binary_t *signature = // ... ;
+ *
+ * // convert algorithm from textual representation
+ * dnssec_tsig_algorithm_t algorithm;
+ * algorithm = dnssec_tsig_algorithm_from_name("hmac-sha256");
+ * assert(algorithm == DNSSEC_TSIG_HMAC_SHA256);
+ *
+ * // get shared key
+ * dnssec_binary_t key = {
+ * .size = 4,
+ * .data = (uint8_t *) { 0x11, 0x22, 0x33, 0x44 }
+ * };
+ *
+ * // create computation context
+ * dnssec_tsig_ctx_t *ctx;
+ * result = dnssec_tsig_new(&ctx, algorithm, &key);
+ * if (result != DNSSEC_EOK) {
+ * return result;
+ * }
+ *
+ * // add data to be covered by the signature
+ * dnssec_tsig_add(ctx, covered);
+ *
+ * // compute the expected signature (MAC)
+ * size_t size = dnssec_tsig_size(ctx);
+ * dnssec_binary_t expected_signature = { 0 };
+ * result = dnssec_binary_alloc(&expected_signature, size);
+ * if (result != DNSSEC_EOK) {
+ * dnssec_tsig_free(ctx);
+ * return result;
+ * }
+ * dnssec_tsig_write(ctx, &expected_signature);
+ *
+ * // compare the signatures
+ * if (dnssec_binary_cmp(signature, &expected_signature) == 0) {
+ * // valid signature
+ * } else {
+ * // invalid signature
+ * }
+ *
+ * // cleanup
+ * dnssec_binary_free(&expected_signature);
+ * dnssec_tsig_free(ctx);
+ *
+ * ~~~~~
+ *
+ * @{
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#include <libdnssec/binary.h>
+
+/*!
+ * TSIG algorithms.
+ *
+ * \note The numeric values are library specific.
+ */
+typedef enum dnssec_tsig_algorithm {
+ DNSSEC_TSIG_UNKNOWN = 0,
+ DNSSEC_TSIG_HMAC_MD5,
+ DNSSEC_TSIG_HMAC_SHA1,
+ DNSSEC_TSIG_HMAC_SHA224,
+ DNSSEC_TSIG_HMAC_SHA256,
+ DNSSEC_TSIG_HMAC_SHA384,
+ DNSSEC_TSIG_HMAC_SHA512
+} dnssec_tsig_algorithm_t;
+
+/*!
+ * Get TSIG algorithm number from domain name.
+ *
+ * \see https://www.iana.org/assignments/tsig-algorithm-names/tsig-algorithm-names.xhtml
+ *
+ * \param dname Domain name of the algorithm (e.g., 0x0b hmac-sha256).
+ *
+ * \return TSIG algorithm.
+ */
+dnssec_tsig_algorithm_t dnssec_tsig_algorithm_from_dname(const uint8_t *dname);
+
+/*!
+ * Get a domain name of the TSIG algorithm.
+ *
+ * \param algorithm TSIG algorithm.
+ *
+ * \return Domain name of the TSIG algorithm.
+ */
+const uint8_t *dnssec_tsig_algorithm_to_dname(dnssec_tsig_algorithm_t algorithm);
+
+/*!
+ * Get TSIG algorithm from a MAC name.
+ *
+ * \param name MAC name (e.g., hmac-sha256).
+ *
+ * \return TSIG algorithm.
+ */
+dnssec_tsig_algorithm_t dnssec_tsig_algorithm_from_name(const char *name);
+
+/*!
+ * Get MAC name from a TSIG algorithm.
+ *
+ * \param algorithm TSIG algorithm.
+ *
+ * \return MAC name of the TSIG algorithm.
+ */
+const char *dnssec_tsig_algorithm_to_name(dnssec_tsig_algorithm_t algorithm);
+
+/*!
+ * Get optimal size of a TSIG algorithm.
+ */
+int dnssec_tsig_optimal_key_size(dnssec_tsig_algorithm_t algorithm);
+
+struct dnssec_tsig_ctx;
+
+/*!
+ * TSIG signing context.
+ */
+typedef struct dnssec_tsig_ctx dnssec_tsig_ctx_t;
+
+/*!
+ * Create new TSIG signing context.
+ *
+ * \param[out] ctx Resulting TSIG context.
+ * \param[in] algorithm TSIG algorithm.
+ * \param[in] key Shared key to be used for signing.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int dnssec_tsig_new(dnssec_tsig_ctx_t **ctx, dnssec_tsig_algorithm_t algorithm,
+ const dnssec_binary_t *key);
+
+/*!
+ * Free the TSIG signing context.
+ *
+ * \param ctx TSIG signing context to be freed.
+ */
+void dnssec_tsig_free(dnssec_tsig_ctx_t *ctx);
+
+/*!
+ * Add data to be signed by TSIG.
+ *
+ * \param ctx TSIG signing context.
+ * \param data Data to be signed.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int dnssec_tsig_add(dnssec_tsig_ctx_t *ctx, const dnssec_binary_t *data);
+
+/*!
+ * Get size of the TSIG signature for given signing context.
+ *
+ * \param ctx TSIG signing context.
+ *
+ * \return The size of the TSIG signature.
+ */
+size_t dnssec_tsig_size(dnssec_tsig_ctx_t *ctx);
+
+/*!
+ * Get size of the TSIG signature for given algorithm.
+ *
+ * \param algorithm TSIG algorithm.
+ *
+ * \return The size of the TSIG signature.
+ */
+size_t dnssec_tsig_algorithm_size(dnssec_tsig_algorithm_t algorithm);
+
+/*!
+ * Write TSIG signature.
+ *
+ * \param[in] ctx TSIG signing context.
+ * \param[out] mac Resulting TSIG signature.
+ *
+ * \return Error code, DNSSEC_EOK if successful.
+ */
+int dnssec_tsig_write(dnssec_tsig_ctx_t *ctx, uint8_t *mac);
+
+/*! @} */
diff --git a/src/libdnssec/version.h b/src/libdnssec/version.h
new file mode 100644
index 0000000..e2c362f
--- /dev/null
+++ b/src/libdnssec/version.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#define DNSSEC_VERSION_MAJOR 2
+#define DNSSEC_VERSION_MINOR 7
+#define DNSSEC_VERSION_PATCH 0x06
+
+#define DNSSEC_VERSION_HEX ((DNSSEC_VERSION_MAJOR << 16) | \
+ (DNSSEC_VERSION_MINOR << 8) | \
+ (DNSSEC_VERSION_PATCH))
diff --git a/src/libdnssec/version.h.in b/src/libdnssec/version.h.in
new file mode 100644
index 0000000..de8752f
--- /dev/null
+++ b/src/libdnssec/version.h.in
@@ -0,0 +1,25 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#define DNSSEC_VERSION_MAJOR @KNOT_VERSION_MAJOR@
+#define DNSSEC_VERSION_MINOR @KNOT_VERSION_MINOR@
+#define DNSSEC_VERSION_PATCH 0x0@KNOT_VERSION_PATCH@
+
+#define DNSSEC_VERSION_HEX ((DNSSEC_VERSION_MAJOR << 16) | \
+ (DNSSEC_VERSION_MINOR << 8) | \
+ (DNSSEC_VERSION_PATCH))
diff --git a/src/libknot.pc.in b/src/libknot.pc.in
new file mode 100644
index 0000000..b723b24
--- /dev/null
+++ b/src/libknot.pc.in
@@ -0,0 +1,14 @@
+prefix=@prefix@
+exec_prefix=@prefix@
+libdir=@libdir@
+includedir=@includedir@
+soname=@libknot_SONAME@
+
+Name: libknot
+Description: Knot DNS library
+URL: https://www.knot-dns.cz
+Version: @PACKAGE_VERSION@
+Requires.private: libdnssec = @PACKAGE_VERSION@
+Libs: -L${libdir} -lknot
+Libs.private: -lm @external_lmdb_LIBS@
+Cflags: -I${includedir}
diff --git a/src/libknot/Makefile.inc b/src/libknot/Makefile.inc
new file mode 100644
index 0000000..16dc077
--- /dev/null
+++ b/src/libknot/Makefile.inc
@@ -0,0 +1,78 @@
+lib_LTLIBRARIES += libknot.la
+pkgconfig_DATA += libknot.pc
+
+libknot_la_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAG_VISIBILITY) $(lmdb_CFLAGS)
+libknot_la_LDFLAGS = $(AM_LDFLAGS) $(libknot_VERSION_INFO) $(lmdb_LIBS) \
+ $(LDFLAG_EXCLUDE_LIBS)
+libknot_la_LIBADD = libcontrib.la libdnssec.la $(math_LIBS)
+
+include_libknotdir = $(includedir)
+nobase_include_libknot_HEADERS = \
+ libknot/attribute.h \
+ libknot/codes.h \
+ libknot/consts.h \
+ libknot/control/control.h \
+ libknot/cookies.h \
+ libknot/descriptor.h \
+ libknot/dname.h \
+ libknot/endian.h \
+ libknot/errcode.h \
+ libknot/error.h \
+ libknot/libknot.h \
+ libknot/lookup.h \
+ libknot/mm_ctx.h \
+ libknot/db/db.h \
+ libknot/db/db_lmdb.h \
+ libknot/db/db_trie.h \
+ libknot/packet/compr.h \
+ libknot/packet/pkt.h \
+ libknot/packet/rrset-wire.h \
+ libknot/packet/wire.h \
+ libknot/rdata.h \
+ libknot/rdataset.h \
+ libknot/rrset-dump.h \
+ libknot/rrset.h \
+ libknot/rrtype/dnskey.h \
+ libknot/rrtype/ds.h \
+ libknot/rrtype/naptr.h \
+ libknot/rrtype/nsec.h \
+ libknot/rrtype/nsec3.h \
+ libknot/rrtype/nsec3param.h \
+ libknot/rrtype/opt.h \
+ libknot/rrtype/rdname.h \
+ libknot/rrtype/rrsig.h \
+ libknot/rrtype/soa.h \
+ libknot/rrtype/tsig.h \
+ libknot/tsig-op.h \
+ libknot/tsig.h \
+ libknot/wire.h \
+ libknot/yparser/yparser.h \
+ libknot/yparser/ypformat.h \
+ libknot/yparser/ypschema.h \
+ libknot/yparser/yptrafo.h \
+ libknot/version.h
+
+libknot_la_SOURCES = \
+ libknot/codes.c \
+ libknot/control/control.c \
+ libknot/cookies.c \
+ libknot/descriptor.c \
+ libknot/dname.c \
+ libknot/error.c \
+ libknot/db/db_lmdb.c \
+ libknot/db/db_trie.c \
+ libknot/packet/pkt.c \
+ libknot/packet/rrset-wire.c \
+ libknot/rdataset.c \
+ libknot/rrset-dump.c \
+ libknot/rrset.c \
+ libknot/rrtype/naptr.c \
+ libknot/rrtype/opt.c \
+ libknot/rrtype/tsig.c \
+ libknot/tsig-op.c \
+ libknot/tsig.c \
+ libknot/yparser/yparser.c \
+ libknot/yparser/ypbody.c \
+ libknot/yparser/ypformat.c \
+ libknot/yparser/ypschema.c \
+ libknot/yparser/yptrafo.c
diff --git a/src/libknot/attribute.h b/src/libknot/attribute.h
new file mode 100644
index 0000000..629bcc6
--- /dev/null
+++ b/src/libknot/attribute.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 2014 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief Function attributes.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+
+#pragma once
+
+/*! \brief Library visibility macros. */
+#define _public_ __attribute__((visibility("default")))
+#define _hidden_ __attribute__((visibility("hidden")))
+
+/*! \brief GNU C function attributes. */
+#if __GNUC__ >= 3
+#define _pure_ __attribute__ ((pure))
+#define _const_ __attribute__ ((const))
+#define _noreturn_ __attribute__ ((noreturn))
+#define _malloc_ __attribute__ ((malloc))
+#define _mustcheck_ __attribute__ ((warn_unused_result))
+#else
+#define _pure_
+#define _const_
+#define _noreturn_
+#define _malloc_
+#define _mustcheck_
+#endif
+
+/*! @} */
diff --git a/src/libknot/codes.c b/src/libknot/codes.c
new file mode 100644
index 0000000..55f20fb
--- /dev/null
+++ b/src/libknot/codes.c
@@ -0,0 +1,80 @@
+/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "libknot/attribute.h"
+#include "libknot/codes.h"
+#include "libknot/consts.h"
+
+_public_
+const knot_lookup_t knot_opcode_names[] = {
+ { KNOT_OPCODE_QUERY, "QUERY" },
+ { KNOT_OPCODE_IQUERY, "IQUERY" },
+ { KNOT_OPCODE_STATUS, "STATUS" },
+ { KNOT_OPCODE_NOTIFY, "NOTIFY" },
+ { KNOT_OPCODE_UPDATE, "UPDATE" },
+ { 0, NULL }
+};
+
+_public_
+const knot_lookup_t knot_rcode_names[] = {
+ { KNOT_RCODE_NOERROR, "NOERROR" },
+ { KNOT_RCODE_FORMERR, "FORMERR" },
+ { KNOT_RCODE_SERVFAIL, "SERVFAIL" },
+ { KNOT_RCODE_NXDOMAIN, "NXDOMAIN" },
+ { KNOT_RCODE_NOTIMPL, "NOTIMPL" },
+ { KNOT_RCODE_REFUSED, "REFUSED" },
+ { KNOT_RCODE_YXDOMAIN, "YXDOMAIN" },
+ { KNOT_RCODE_YXRRSET, "YXRRSET" },
+ { KNOT_RCODE_NXRRSET, "NXRRSET" },
+ { KNOT_RCODE_NOTAUTH, "NOTAUTH" },
+ { KNOT_RCODE_NOTZONE, "NOTZONE" },
+ { KNOT_RCODE_BADVERS, "BADVERS" },
+ { KNOT_RCODE_BADKEY, "BADKEY" },
+ { KNOT_RCODE_BADTIME, "BADTIME" },
+ { KNOT_RCODE_BADMODE, "BADMODE" },
+ { KNOT_RCODE_BADNAME, "BADNAME" },
+ { KNOT_RCODE_BADALG, "BADALG" },
+ { KNOT_RCODE_BADTRUNC, "BADTRUNC" },
+ { KNOT_RCODE_BADCOOKIE, "BADCOOKIE" },
+ { 0, NULL }
+};
+
+_public_
+const knot_lookup_t knot_tsig_rcode_names[] = {
+ { KNOT_RCODE_BADSIG, "BADSIG" },
+ { 0, NULL }
+};
+
+_public_
+const knot_lookup_t knot_dnssec_alg_names[] = {
+ { KNOT_DNSSEC_ALG_RSAMD5, "RSAMD5" },
+ { KNOT_DNSSEC_ALG_DH, "DH" },
+ { KNOT_DNSSEC_ALG_DSA, "DSA" },
+ { KNOT_DNSSEC_ALG_RSASHA1, "RSASHA1" },
+ { KNOT_DNSSEC_ALG_DSA_NSEC3_SHA1, "DSA_NSEC3_SHA1" },
+ { KNOT_DNSSEC_ALG_RSASHA1_NSEC3_SHA1, "RSASHA1_NSEC3_SHA1" },
+ { KNOT_DNSSEC_ALG_RSASHA256, "RSASHA256" },
+ { KNOT_DNSSEC_ALG_RSASHA512, "RSASHA512" },
+ { KNOT_DNSSEC_ALG_ECC_GOST, "ECC_GOST" },
+ { KNOT_DNSSEC_ALG_ECDSAP256SHA256, "ECDSAP256SHA256" },
+ { KNOT_DNSSEC_ALG_ECDSAP384SHA384, "ECDSAP384SHA384" },
+ { KNOT_DNSSEC_ALG_ED25519, "ED25519" },
+ { KNOT_DNSSEC_ALG_ED448, "ED448" },
+ { KNOT_DNSSEC_ALG_INDIRECT, "INDIRECT" },
+ { KNOT_DNSSEC_ALG_PRIVATEDNS, "PRIVATEDNS" },
+ { KNOT_DNSSEC_ALG_PRIVATEOID, "PRIVATEOID" },
+ { 0, NULL }
+};
diff --git a/src/libknot/codes.h b/src/libknot/codes.h
new file mode 100644
index 0000000..c5cf323
--- /dev/null
+++ b/src/libknot/codes.h
@@ -0,0 +1,49 @@
+/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief Some DNS-related code names.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+
+#pragma once
+
+#include "libknot/lookup.h"
+
+/*!
+ * \brief DNS operation code names.
+ */
+extern const knot_lookup_t knot_opcode_names[];
+
+/*!
+ * \brief DNS reply code names.
+ */
+extern const knot_lookup_t knot_rcode_names[];
+
+/*!
+ * \brief TSIG exceptions to reply code names.
+ */
+extern const knot_lookup_t knot_tsig_rcode_names[];
+
+/*!
+ * \brief DNSSEC algorithm names.
+ */
+extern const knot_lookup_t knot_dnssec_alg_names[];
+
+/*! @} */
diff --git a/src/libknot/consts.h b/src/libknot/consts.h
new file mode 100644
index 0000000..e516b9f
--- /dev/null
+++ b/src/libknot/consts.h
@@ -0,0 +1,157 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief Some DNS-related constants.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+
+#pragma once
+
+/*!
+ * \brief Basic limits for domain names (RFC 1035).
+ */
+#define KNOT_DNAME_MAXLEN 255 /*!< 1-byte maximum. */
+#define KNOT_DNAME_MAXLABELS 127 /*!< 1-char labels. */
+#define KNOT_DNAME_MAXLABELLEN 63 /*!< 2^6 - 1 */
+
+/*!
+ * \brief The longest textual dname representation.
+ *
+ * 3 x maximum_label + 1 x rest_label + 1 x zero_label
+ * Each dname label byte takes 4 characters (\\DDD).
+ * Each label takes 1 more byte for '.' character.
+ *
+ * KNOT_DNAME_TXT_MAXLEN = 3x(1 + 63x4) + 1x(1 + 61x4) + 1x(1 + 0)
+ */
+#define KNOT_DNAME_TXT_MAXLEN 1005
+
+/*!
+ * \brief Address family numbers.
+ *
+ * http://www.iana.org/assignments/address-family-numbers/address-family-numbers.xml
+ */
+typedef enum {
+ KNOT_ADDR_FAMILY_IPV4 = 1, /*!< IP version 4. */
+ KNOT_ADDR_FAMILY_IPV6 = 2 /*!< IP version 6. */
+} knot_addr_family_t;
+
+/*!
+ * \brief DNS operation codes (OPCODEs).
+ *
+ * http://www.iana.org/assignments/dns-parameters/dns-parameters.xml
+ */
+typedef enum {
+ KNOT_OPCODE_QUERY = 0, /*!< Standard query. */
+ KNOT_OPCODE_IQUERY = 1, /*!< Inverse query. */
+ KNOT_OPCODE_STATUS = 2, /*!< Server status request. */
+ KNOT_OPCODE_NOTIFY = 4, /*!< Notify message. */
+ KNOT_OPCODE_UPDATE = 5 /*!< Dynamic update. */
+} knot_opcode_t;
+
+/*!
+ * \brief DNS reply codes (RCODEs).
+ *
+ * http://www.iana.org/assignments/dns-parameters/dns-parameters.xml
+ */
+typedef enum {
+ KNOT_RCODE_NOERROR = 0, /*!< No error. */
+ KNOT_RCODE_FORMERR = 1, /*!< Format error. */
+ KNOT_RCODE_SERVFAIL = 2, /*!< Server failure. */
+ KNOT_RCODE_NXDOMAIN = 3, /*!< Non-existent domain. */
+ KNOT_RCODE_NOTIMPL = 4, /*!< Not implemented. */
+ KNOT_RCODE_REFUSED = 5, /*!< Refused. */
+ KNOT_RCODE_YXDOMAIN = 6, /*!< Name should not exist. */
+ KNOT_RCODE_YXRRSET = 7, /*!< RR set should not exist. */
+ KNOT_RCODE_NXRRSET = 8, /*!< RR set does not exist. */
+ KNOT_RCODE_NOTAUTH = 9, /*!< Server not authoritative. / Query not authorized. */
+ KNOT_RCODE_NOTZONE = 10, /*!< Name is not inside zone. */
+ KNOT_RCODE_BADVERS = 16, /*!< Bad OPT Version. */
+ KNOT_RCODE_BADSIG = 16, /*!< (TSIG) Signature failure. */
+ KNOT_RCODE_BADKEY = 17, /*!< (TSIG) Key is not supported. */
+ KNOT_RCODE_BADTIME = 18, /*!< (TSIG) Signature out of time window. */
+ KNOT_RCODE_BADMODE = 19, /*!< (TKEY) Bad mode. */
+ KNOT_RCODE_BADNAME = 20, /*!< (TKEY) Duplicate key name. */
+ KNOT_RCODE_BADALG = 21, /*!< (TKEY) Algorithm not supported. */
+ KNOT_RCODE_BADTRUNC = 22, /*!< (TSIG) Bad truncation. */
+ KNOT_RCODE_BADCOOKIE = 23 /*!< Bad/missing server cookie. */
+} knot_rcode_t;
+
+/*!
+ * \brief DNS packet section identifiers.
+ */
+typedef enum {
+ KNOT_ANSWER = 0,
+ KNOT_AUTHORITY = 1,
+ KNOT_ADDITIONAL = 2
+} knot_section_t;
+
+/*!
+ * \brief DS digest lengths.
+ */
+enum knot_ds_algorithm_len
+{
+ KNOT_DS_DIGEST_LEN_SHA1 = 20, /*!< RFC 3658 */
+ KNOT_DS_DIGEST_LEN_SHA256 = 32, /*!< RFC 4509 */
+ KNOT_DS_DIGEST_LEN_GOST = 32, /*!< RFC 5933 */
+ KNOT_DS_DIGEST_LEN_SHA384 = 48 /*!< RFC 6605 */
+};
+
+/*!
+ * \brief Constants for DNSSEC algorithm types.
+ *
+ * Source: http://www.iana.org/assignments/ds-rr-types/ds-rr-types.xml
+ */
+typedef enum {
+ KNOT_DS_ALG_SHA1 = 1,
+ KNOT_DS_ALG_SHA256 = 2,
+ KNOT_DS_ALG_GOST = 3,
+ KNOT_DS_ALG_SHA384 = 4
+} knot_ds_algorithm_t;
+
+/*!
+ * \brief DNSSEC algorithm numbers.
+ *
+ * http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xml
+ */
+typedef enum {
+ KNOT_DNSSEC_ALG_RSAMD5 = 1,
+ KNOT_DNSSEC_ALG_DH = 2,
+ KNOT_DNSSEC_ALG_DSA = 3,
+
+ KNOT_DNSSEC_ALG_RSASHA1 = 5,
+ KNOT_DNSSEC_ALG_DSA_NSEC3_SHA1 = 6,
+ KNOT_DNSSEC_ALG_RSASHA1_NSEC3_SHA1 = 7,
+ KNOT_DNSSEC_ALG_RSASHA256 = 8,
+
+ KNOT_DNSSEC_ALG_RSASHA512 = 10,
+
+ KNOT_DNSSEC_ALG_ECC_GOST = 12,
+ KNOT_DNSSEC_ALG_ECDSAP256SHA256 = 13,
+ KNOT_DNSSEC_ALG_ECDSAP384SHA384 = 14,
+
+ KNOT_DNSSEC_ALG_ED25519 = 15,
+ KNOT_DNSSEC_ALG_ED448 = 16,
+
+ KNOT_DNSSEC_ALG_INDIRECT = 252,
+ KNOT_DNSSEC_ALG_PRIVATEDNS = 253,
+ KNOT_DNSSEC_ALG_PRIVATEOID = 254
+} knot_dnssec_algorithm_t;
+
+/*! @} */
diff --git a/src/libknot/control/control.c b/src/libknot/control/control.c
new file mode 100644
index 0000000..af68cfe
--- /dev/null
+++ b/src/libknot/control/control.c
@@ -0,0 +1,561 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <poll.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libknot/control/control.h"
+#include "libknot/attribute.h"
+#include "libknot/error.h"
+#include "contrib/mempattern.h"
+#include "contrib/net.h"
+#include "contrib/sockaddr.h"
+#include "contrib/ucw/mempool.h"
+#include "contrib/wire_ctx.h"
+
+/*! Size of the input and output buffers. */
+#ifndef CTL_BUFF_SIZE
+#define CTL_BUFF_SIZE (256 * 1024)
+#endif
+
+/*! Default socket operations timeout in milliseconds. */
+#define DEFAULT_TIMEOUT (5 * 1000)
+
+/*! The first data item code. */
+#define DATA_CODE_OFFSET 16
+
+/*! Control context structure. */
+struct knot_ctl {
+ /*! Memory pool context. */
+ knot_mm_t mm;
+ /*! Network operations timeout. */
+ int timeout;
+ /*! Server listening socket. */
+ int listen_sock;
+ /*! Remote server/client socket. */
+ int sock;
+
+ /*! The latter read data. */
+ knot_ctl_data_t data;
+
+ /*! Write wire context. */
+ wire_ctx_t wire_out;
+ /*! Read wire context. */
+ wire_ctx_t wire_in;
+
+ /*! Write buffer. */
+ uint8_t buff_out[CTL_BUFF_SIZE];
+ /*! Read buffer. */
+ uint8_t buff_in[CTL_BUFF_SIZE];
+};
+
+static int type_to_code(knot_ctl_type_t type)
+{
+ switch (type) {
+ case KNOT_CTL_TYPE_END: return 0;
+ case KNOT_CTL_TYPE_DATA: return 1;
+ case KNOT_CTL_TYPE_EXTRA: return 2;
+ case KNOT_CTL_TYPE_BLOCK: return 3;
+ default: return -1;
+ }
+}
+
+static int code_to_type(uint8_t code)
+{
+ switch (code) {
+ case 0: return KNOT_CTL_TYPE_END;
+ case 1: return KNOT_CTL_TYPE_DATA;
+ case 2: return KNOT_CTL_TYPE_EXTRA;
+ case 3: return KNOT_CTL_TYPE_BLOCK;
+ default: return -1;
+ }
+}
+
+static bool is_data_type(knot_ctl_type_t type)
+{
+ switch (type) {
+ case KNOT_CTL_TYPE_DATA:
+ case KNOT_CTL_TYPE_EXTRA:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int idx_to_code(knot_ctl_idx_t idx)
+{
+ if (idx >= KNOT_CTL_IDX__COUNT) {
+ return -1;
+ }
+
+ return DATA_CODE_OFFSET + idx;
+}
+
+static int code_to_idx(uint8_t code)
+{
+ if (code < DATA_CODE_OFFSET ||
+ code >= DATA_CODE_OFFSET + KNOT_CTL_IDX__COUNT) {
+ return -1;
+ }
+
+ return code - DATA_CODE_OFFSET;
+}
+
+static void reset_buffers(knot_ctl_t *ctx)
+{
+ ctx->wire_out = wire_ctx_init(ctx->buff_out, CTL_BUFF_SIZE);
+ ctx->wire_in = wire_ctx_init(ctx->buff_in, 0);
+}
+
+static void clean_data(knot_ctl_t *ctx)
+{
+ mp_flush(ctx->mm.ctx);
+ memset(ctx->data, 0, sizeof(ctx->data));
+}
+
+static void close_sock(int *sock)
+{
+ if (*sock < 0) {
+ return;
+ }
+
+ close(*sock);
+ *sock = -1;
+}
+
+_public_
+knot_ctl_t* knot_ctl_alloc(void)
+{
+ knot_ctl_t *ctx = malloc(sizeof(*ctx));
+ if (ctx == NULL) {
+ return NULL;
+ }
+ memset(ctx, 0, sizeof(*ctx));
+
+ mm_ctx_mempool(&ctx->mm, MM_DEFAULT_BLKSIZE);
+ ctx->timeout = DEFAULT_TIMEOUT;
+ ctx->listen_sock = -1;
+ ctx->sock = -1;
+
+ reset_buffers(ctx);
+
+ return ctx;
+}
+
+_public_
+void knot_ctl_free(knot_ctl_t *ctx)
+{
+ if (ctx == NULL) {
+ return;
+ }
+
+ close_sock(&ctx->listen_sock);
+ close_sock(&ctx->sock);
+
+ clean_data(ctx);
+
+ mp_delete(ctx->mm.ctx);
+
+ memset(ctx, 0, sizeof(*ctx));
+ free(ctx);
+}
+
+_public_
+void knot_ctl_set_timeout(knot_ctl_t *ctx, int timeout_ms)
+{
+ if (ctx == NULL) {
+ return;
+ }
+
+ ctx->timeout = (timeout_ms > 0) ? timeout_ms : -1;
+}
+
+_public_
+int knot_ctl_bind(knot_ctl_t *ctx, const char *path)
+{
+ if (ctx == NULL || path == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ // Prepare socket address.
+ struct sockaddr_storage addr;
+ int ret = sockaddr_set(&addr, AF_UNIX, path, 0);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Bind the socket.
+ ctx->listen_sock = net_bound_socket(SOCK_STREAM, (struct sockaddr *)&addr, 0);
+ if (ctx->listen_sock < 0) {
+ return ctx->listen_sock;
+ }
+
+ // Start listening.
+ if (listen(ctx->listen_sock, 1) != 0) {
+ close_sock(&ctx->listen_sock);
+ return knot_map_errno();
+ }
+
+ return KNOT_EOK;
+}
+
+_public_
+void knot_ctl_unbind(knot_ctl_t *ctx)
+{
+ if (ctx == NULL || ctx->listen_sock < 0) {
+ return;
+ }
+
+ // Remove the control socket file.
+ struct sockaddr_storage addr;
+ socklen_t addr_len = sizeof(addr);
+ if (getsockname(ctx->listen_sock, (struct sockaddr *)&addr, &addr_len) == 0) {
+ char addr_str[SOCKADDR_STRLEN] = { 0 };
+ if (sockaddr_tostr(addr_str, sizeof(addr_str), (struct sockaddr *)&addr) > 0) {
+ (void)unlink(addr_str);
+ }
+ }
+
+ // Close the listening socket.
+ close_sock(&ctx->listen_sock);
+}
+
+_public_
+int knot_ctl_accept(knot_ctl_t *ctx)
+{
+ if (ctx == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ knot_ctl_close(ctx);
+
+ // Control interface.
+ struct pollfd pfd = { .fd = ctx->listen_sock, .events = POLLIN };
+ int ret = poll(&pfd, 1, -1);
+ if (ret <= 0) {
+ return knot_map_errno();
+ }
+
+ int client = net_accept(ctx->listen_sock, NULL);
+ if (client < 0) {
+ return client;
+ }
+
+ ctx->sock = client;
+
+ reset_buffers(ctx);
+
+ return KNOT_EOK;
+}
+
+_public_
+int knot_ctl_connect(knot_ctl_t *ctx, const char *path)
+{
+ if (ctx == NULL || path == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ // Prepare socket address.
+ struct sockaddr_storage addr;
+ int ret = sockaddr_set(&addr, AF_UNIX, path, 0);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Connect to socket.
+ ctx->sock = net_connected_socket(SOCK_STREAM, (struct sockaddr *)&addr, NULL);
+ if (ctx->sock < 0) {
+ return ctx->sock;
+ }
+
+ reset_buffers(ctx);
+
+ return KNOT_EOK;
+}
+
+_public_
+void knot_ctl_close(knot_ctl_t *ctx)
+{
+ if (ctx == NULL) {
+ return;
+ }
+
+ close_sock(&ctx->sock);
+}
+
+static int ensure_output(knot_ctl_t *ctx, uint16_t len)
+{
+ wire_ctx_t *w = &ctx->wire_out;
+
+ // Check for enough available room in the output buffer.
+ size_t available = wire_ctx_available(w);
+ if (available >= len) {
+ return KNOT_EOK;
+ }
+
+ // Flush the buffer.
+ int ret = net_stream_send(ctx->sock, w->wire, wire_ctx_offset(w),
+ ctx->timeout);
+ if (ret < 0) {
+ return ret;
+ }
+
+ *w = wire_ctx_init(w->wire, CTL_BUFF_SIZE);
+
+ return KNOT_EOK;
+}
+
+static int send_item(knot_ctl_t *ctx, uint8_t code, const char *data, bool flush)
+{
+ wire_ctx_t *w = &ctx->wire_out;
+
+ // Write the control block code.
+ int ret = ensure_output(ctx, sizeof(uint8_t));
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ wire_ctx_write_u8(w, code);
+ if (w->error != KNOT_EOK) {
+ return w->error;
+ }
+
+ // Control block data is optional.
+ if (data != NULL) {
+ // Get the data length.
+ size_t data_len = strlen(data);
+ if (data_len > UINT16_MAX) {
+ return KNOT_ERANGE;
+ }
+
+ // Write the data length.
+ ret = ensure_output(ctx, sizeof(uint16_t));
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ wire_ctx_write_u16(w, data_len);
+ if (w->error != KNOT_EOK) {
+ return w->error;
+ }
+
+ // Write the data.
+ ret = ensure_output(ctx, data_len);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ wire_ctx_write(w, (uint8_t *)data, data_len);
+ if (w->error != KNOT_EOK) {
+ return w->error;
+ }
+ }
+
+ // Send finalized buffer.
+ if (flush && wire_ctx_offset(w) > 0) {
+ ret = net_stream_send(ctx->sock, w->wire, wire_ctx_offset(w),
+ ctx->timeout);
+ if (ret < 0) {
+ return ret;
+ }
+
+ *w = wire_ctx_init(w->wire, CTL_BUFF_SIZE);
+ }
+
+ return KNOT_EOK;
+}
+
+_public_
+int knot_ctl_send(knot_ctl_t *ctx, knot_ctl_type_t type, knot_ctl_data_t *data)
+{
+ if (ctx == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ // Get the type code.
+ int code = type_to_code(type);
+ if (code == -1) {
+ return KNOT_EINVAL;
+ }
+
+ // Send unit type.
+ int ret = send_item(ctx, code, NULL, !is_data_type(type));
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Send unit data.
+ if (is_data_type(type) && data != NULL) {
+ // Send all non-empty data items.
+ for (knot_ctl_idx_t i = 0; i < KNOT_CTL_IDX__COUNT; i++) {
+ const char *value = (*data)[i];
+ if (value == NULL) {
+ continue;
+ }
+
+ ret = send_item(ctx, idx_to_code(i), value, false);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+static int ensure_input(knot_ctl_t *ctx, uint16_t len)
+{
+ wire_ctx_t *w = &ctx->wire_in;
+
+ // Check for enough available room in the input buffer.
+ size_t available = wire_ctx_available(w);
+ if (available >= len) {
+ return KNOT_EOK;
+ }
+
+ // Move unprocessed data to the beginning of the buffer.
+ memmove(w->wire, w->wire + wire_ctx_offset(w), available);
+
+ // Receive enough data.
+ while (available < len) {
+ int ret = net_stream_recv(ctx->sock, w->wire + available,
+ CTL_BUFF_SIZE - available,
+ ctx->timeout);
+ if (ret < 0) {
+ return ret;
+ }
+ assert(ret > 0);
+ available += ret;
+ }
+
+ ctx->wire_in = wire_ctx_init(w->wire, available);
+
+ return KNOT_EOK;
+}
+
+static int receive_item_code(knot_ctl_t *ctx, uint8_t *code)
+{
+ wire_ctx_t *w = &ctx->wire_in;
+
+ // Read the type.
+ int ret = ensure_input(ctx, sizeof(uint8_t));
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ *code = wire_ctx_read_u8(w);
+ if (w->error != KNOT_EOK) {
+ return w->error;
+ }
+
+ return KNOT_EOK;
+}
+
+static int receive_item_value(knot_ctl_t *ctx, char **value)
+{
+ wire_ctx_t *w = &ctx->wire_in;
+
+ // Read value length.
+ int ret = ensure_input(ctx, sizeof(uint16_t));
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ uint16_t data_len = wire_ctx_read_u16(w);
+ if (w->error != KNOT_EOK) {
+ return w->error;
+ }
+
+ // Read the value.
+ ret = ensure_input(ctx, data_len);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ *value = mm_alloc(&ctx->mm, data_len + 1);
+ if (*value == NULL) {
+ return KNOT_ENOMEM;
+ }
+ wire_ctx_read(w, *value, data_len);
+ if (w->error != KNOT_EOK) {
+ return w->error;
+ }
+ (*value)[data_len] = '\0';
+
+ return KNOT_EOK;
+}
+
+_public_
+int knot_ctl_receive(knot_ctl_t *ctx, knot_ctl_type_t *type, knot_ctl_data_t *data)
+{
+ if (ctx == NULL || type == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ wire_ctx_t *w = &ctx->wire_in;
+
+ // Reset output variables.
+ *type = KNOT_CTL_TYPE_END;
+ clean_data(ctx);
+
+ // Read data units until end of message.
+ bool have_type = false;
+ while (true) {
+ uint8_t code;
+ int ret = receive_item_code(ctx, &code);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Process unit type.
+ int current_type = code_to_type(code);
+ if (current_type != -1) {
+ if (have_type) {
+ // Revert parsed type.
+ wire_ctx_skip(w, -sizeof(uint8_t));
+ assert(w->error == KNOT_EOK);
+ break;
+ }
+
+ // Set the unit type.
+ *type = current_type;
+
+ if (is_data_type(current_type)) {
+ have_type = true;
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ // Check for data item code.
+ int idx = code_to_idx(code);
+ if (idx == -1) {
+ return KNOT_EINVAL;
+ }
+
+ // Store the item data value.
+ ret = receive_item_value(ctx, (char **)&ctx->data[idx]);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ // Set the output data.
+ if (data != NULL) {
+ memcpy(*data, ctx->data, sizeof(*data));
+ }
+
+ return KNOT_EOK;
+}
diff --git a/src/libknot/control/control.h b/src/libknot/control/control.h
new file mode 100644
index 0000000..e4f73a1
--- /dev/null
+++ b/src/libknot/control/control.h
@@ -0,0 +1,158 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief A server control interface.
+ *
+ * \addtogroup ctl
+ * @{
+ */
+
+#pragma once
+
+/*! Control data item indexes. */
+typedef enum {
+ KNOT_CTL_IDX_CMD = 0, /*!< Control command name. */
+ KNOT_CTL_IDX_FLAGS, /*!< Control command flags. */
+ KNOT_CTL_IDX_ERROR, /*!< Error message. */
+ KNOT_CTL_IDX_SECTION, /*!< Configuration section name. */
+ KNOT_CTL_IDX_ITEM, /*!< Configuration item name. */
+ KNOT_CTL_IDX_ID, /*!< Congiguration item identifier. */
+ KNOT_CTL_IDX_ZONE, /*!< Zone name. */
+ KNOT_CTL_IDX_OWNER, /*!< Zone record owner */
+ KNOT_CTL_IDX_TTL, /*!< Zone record TTL. */
+ KNOT_CTL_IDX_TYPE, /*!< Zone record type name. */
+ KNOT_CTL_IDX_DATA, /*!< Configuration item/zone record data. */
+ KNOT_CTL_IDX_FILTER, /*!< An option or a filter for output data processing. */
+ KNOT_CTL_IDX__COUNT, /*!< The number of data items. */
+} knot_ctl_idx_t;
+
+/*! Control unit types. */
+typedef enum {
+ KNOT_CTL_TYPE_END, /*!< End of message, cache flushed. */
+ KNOT_CTL_TYPE_DATA, /*!< Data unit, cached. */
+ KNOT_CTL_TYPE_EXTRA, /*!< Extra value data unit, cached. */
+ KNOT_CTL_TYPE_BLOCK, /*!< End of data block, cache flushed. */
+} knot_ctl_type_t;
+
+/*! Control input/output string data. */
+typedef const char* knot_ctl_data_t[KNOT_CTL_IDX__COUNT];
+
+/*! A control context. */
+struct knot_ctl;
+typedef struct knot_ctl knot_ctl_t;
+
+/*!
+ * Allocates a control context.
+ *
+ * \return Control context.
+ */
+knot_ctl_t* knot_ctl_alloc(void);
+
+/*!
+ * Deallocates a control context.
+ *
+ * \param[in] ctx Control context.
+ */
+void knot_ctl_free(knot_ctl_t *ctx);
+
+/*!
+ * Sets the timeout for socket operations.
+ *
+ * Default value is 5 seconds.
+ *
+ * \param[in] ctx Control context.
+ * \param[in] timeout_ms Timeout in milliseconds (0 for infinity).
+ */
+void knot_ctl_set_timeout(knot_ctl_t *ctx, int timeout_ms);
+
+/*!
+ * Binds a specified UNIX socket path.
+ *
+ * \note Server operation.
+ *
+ * \param[in] ctx Control context.
+ * \param[in] path Control UNIX socket path.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_ctl_bind(knot_ctl_t *ctx, const char *path);
+
+/*!
+ * Unbinds a control socket.
+ *
+ * \note Server operation.
+ *
+ * \param[in] ctx Control context.
+ */
+void knot_ctl_unbind(knot_ctl_t *ctx);
+
+/*!
+ * Connects to a specified UNIX socket path.
+ *
+ * \note Client operation.
+ *
+ * \param[in] ctx Control context.
+ * \param[in] path Control UNIX socket path.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_ctl_connect(knot_ctl_t *ctx, const char *path);
+
+/*!
+ * Waits for an incoming connection.
+ *
+ * \note Server operation.
+ *
+ * \param[in] ctx Control context.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_ctl_accept(knot_ctl_t *ctx);
+
+/*!
+ * Closes the remote connections.
+ *
+ * \note Applies to both server and client.
+ *
+ * \param[in] ctx Control context.
+ */
+void knot_ctl_close(knot_ctl_t *ctx);
+
+/*!
+ * Sends one control unit.
+ *
+ * \param[in] ctx Control context.
+ * \param[in] type Unit type to send.
+ * \param[in] data Data unit to send (optional, ignored if non-data type).
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_ctl_send(knot_ctl_t *ctx, knot_ctl_type_t type, knot_ctl_data_t *data);
+
+/*!
+ * Receives one control unit.
+ *
+ * \param[in] ctx Control context.
+ * \param[out] type Received unit type.
+ * \param[out] data Received data unit (optional).
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_ctl_receive(knot_ctl_t *ctx, knot_ctl_type_t *type, knot_ctl_data_t *data);
+
+/*! @} */
diff --git a/src/libknot/cookies.c b/src/libknot/cookies.c
new file mode 100644
index 0000000..dd024d5
--- /dev/null
+++ b/src/libknot/cookies.c
@@ -0,0 +1,130 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include "libknot/attribute.h"
+#include "libknot/cookies.h"
+#include "libknot/errcode.h"
+#include "contrib/string.h"
+#include "contrib/sockaddr.h"
+#include "contrib/openbsd/siphash.h"
+
+_public_
+int knot_edns_cookie_client_generate(knot_edns_cookie_t *out,
+ const knot_edns_cookie_params_t *params)
+{
+ if (out == NULL || params == NULL || params->client_addr == NULL ||
+ params->server_addr == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ SIPHASH_CTX ctx;
+ assert(sizeof(params->secret) == sizeof(SIPHASH_KEY));
+ SipHash24_Init(&ctx, (const SIPHASH_KEY *)params->secret);
+
+ size_t addr_len = 0;
+ void *addr = sockaddr_raw(params->client_addr, &addr_len);
+ SipHash24_Update(&ctx, addr, addr_len);
+
+ addr_len = 0;
+ addr = sockaddr_raw(params->server_addr, &addr_len);
+ SipHash24_Update(&ctx, addr, addr_len);
+
+ uint64_t hash = SipHash24_End(&ctx);
+ memcpy(out->data, &hash, sizeof(hash));
+ out->len = sizeof(hash);
+
+ return KNOT_EOK;
+}
+
+_public_
+int knot_edns_cookie_client_check(const knot_edns_cookie_t *cc,
+ const knot_edns_cookie_params_t *params)
+{
+ if (cc == NULL || cc->len != KNOT_EDNS_COOKIE_CLNT_SIZE) {
+ return KNOT_EINVAL;
+ }
+
+ knot_edns_cookie_t ref;
+ int ret = knot_edns_cookie_client_generate(&ref, params);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ assert(ref.len == KNOT_EDNS_COOKIE_CLNT_SIZE);
+
+ ret = const_time_memcmp(cc->data, ref.data, KNOT_EDNS_COOKIE_CLNT_SIZE);
+ if (ret != 0) {
+ return KNOT_EINVAL;
+ }
+
+ return KNOT_EOK;
+}
+
+_public_
+int knot_edns_cookie_server_generate(knot_edns_cookie_t *out,
+ const knot_edns_cookie_t *cc,
+ const knot_edns_cookie_params_t *params)
+{
+ if (out == NULL || cc == NULL || cc->len != KNOT_EDNS_COOKIE_CLNT_SIZE ||
+ params == NULL || params->client_addr == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ SIPHASH_CTX ctx;
+ assert(sizeof(params->secret) == sizeof(SIPHASH_KEY));
+ SipHash24_Init(&ctx, (const SIPHASH_KEY *)params->secret);
+
+ size_t addr_len = 0;
+ void *addr = sockaddr_raw(params->client_addr, &addr_len);
+ SipHash24_Update(&ctx, addr, addr_len);
+
+ SipHash24_Update(&ctx, cc->data, cc->len);
+
+ uint64_t hash = SipHash24_End(&ctx);
+ memcpy(out->data, &hash, sizeof(hash));
+ out->len = sizeof(hash);
+
+ return KNOT_EOK;
+}
+
+_public_
+int knot_edns_cookie_server_check(const knot_edns_cookie_t *sc,
+ const knot_edns_cookie_t *cc,
+ const knot_edns_cookie_params_t *params)
+{
+ if (sc == NULL || cc == NULL || params == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ knot_edns_cookie_t ref;
+ int ret = knot_edns_cookie_server_generate(&ref, cc, params);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ if (sc->len != ref.len) {
+ return KNOT_EINVAL;
+ }
+
+ ret = const_time_memcmp(sc->data, ref.data, sc->len);
+ if (ret != 0) {
+ return KNOT_EINVAL;
+ }
+
+ return KNOT_EOK;
+}
diff --git a/src/libknot/cookies.h b/src/libknot/cookies.h
new file mode 100644
index 0000000..5bdfb68
--- /dev/null
+++ b/src/libknot/cookies.h
@@ -0,0 +1,97 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+* \file
+*
+* \brief DNS cookies processing.
+*
+* \addtogroup libknot
+* @{
+*/
+
+#pragma once
+
+#include <stdint.h>
+#include <sys/socket.h>
+
+#include "libknot/rrtype/opt.h"
+
+#define KNOT_EDNS_COOKIE_SECRET_SIZE 16
+
+/*!
+ * \brief DNS Cookie parameters needed to compute the cookie value.
+ *
+ * \note Server address is not used for the server cookie check.
+ */
+typedef struct {
+ const struct sockaddr *client_addr; /*!< Client socket address. */
+ const struct sockaddr *server_addr; /*!< Server socket address. */
+ uint8_t secret[KNOT_EDNS_COOKIE_SECRET_SIZE]; /*!< Cookie secret data. */
+} knot_edns_cookie_params_t;
+
+/*!
+ * \brief Generate a client cookie using given parameters.
+ *
+ * \param out Generated client cookie.
+ * \param params Client cookie parameters.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EINVAL
+ */
+int knot_edns_cookie_client_generate(knot_edns_cookie_t *out,
+ const knot_edns_cookie_params_t *params);
+
+/*!
+ * \brief Check whether client cookie was generated using given parameters.
+ *
+ * \param cc Client cookie that should be checked.
+ * \param params Client cookie parameters.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EINVAL
+ */
+int knot_edns_cookie_client_check(const knot_edns_cookie_t *cc,
+ const knot_edns_cookie_params_t *params);
+
+/*!
+ * \brief Generate a server cookie using given parameters.
+ *
+ * \param out Generated server cookie.
+ * \param cc Client cookie parameter.
+ * \param params Server cookie parameters.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EINVAL
+ */
+int knot_edns_cookie_server_generate(knot_edns_cookie_t *out,
+ const knot_edns_cookie_t *cc,
+ const knot_edns_cookie_params_t *params);
+
+/*!
+ * \brief Check whether server cookie was generated using given parameters.
+ *
+ * \param sc Server cookie that should be checked.
+ * \param cc Client cookie parameter.
+ * \param params Server cookie parameters.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EINVAL
+ */
+int knot_edns_cookie_server_check(const knot_edns_cookie_t *sc,
+ const knot_edns_cookie_t *cc,
+ const knot_edns_cookie_params_t *params);
+
+/*! @} */
diff --git a/src/libknot/db/db.h b/src/libknot/db/db.h
new file mode 100644
index 0000000..f3edc15
--- /dev/null
+++ b/src/libknot/db/db.h
@@ -0,0 +1,91 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*!
+ * \file
+ *
+ * \brief Structures for binary data handling.
+ *
+ * \addtogroup db
+ * @{
+ */
+
+#pragma once
+
+#include "libknot/mm_ctx.h"
+
+enum {
+ /* Database flags */
+
+ KNOT_DB_RDONLY = 1 << 0, /*!< Read only. */
+ KNOT_DB_SORTED = 1 << 1, /*!< Sorted output. */
+
+ /* Operations */
+
+ KNOT_DB_NOOP = 1 << 2, /*!< No operation. */
+ KNOT_DB_FIRST = 1 << 3, /*!< First entry. */
+ KNOT_DB_LAST = 1 << 4, /*!< Last entry. */
+ KNOT_DB_NEXT = 1 << 5, /*!< Next entry. */
+ KNOT_DB_PREV = 1 << 6, /*!< Previous entry. */
+ KNOT_DB_LEQ = 1 << 7, /*!< Lesser or equal. */
+ KNOT_DB_GEQ = 1 << 8 /*!< Greater or equal. */
+};
+
+typedef void knot_db_t;
+typedef void knot_db_iter_t;
+
+typedef struct knot_db_val {
+ void *data;
+ size_t len;
+} knot_db_val_t;
+
+typedef struct knot_db_txn {
+ knot_db_t *db;
+ void *txn;
+} knot_db_txn_t;
+
+typedef struct knot_db_api {
+ const char *name;
+
+ /* Context operations */
+
+ int (*init)(knot_db_t **db, knot_mm_t *mm, void *opts);
+ void (*deinit)(knot_db_t *db);
+
+ /* Transactions */
+
+ int (*txn_begin)(knot_db_t *db, knot_db_txn_t *txn, unsigned flags);
+ int (*txn_commit)(knot_db_txn_t *txn);
+ void (*txn_abort)(knot_db_txn_t *txn);
+
+ /* Data access */
+
+ int (*count)(knot_db_txn_t *txn);
+ int (*clear)(knot_db_txn_t *txn);
+ int (*find)(knot_db_txn_t *txn, knot_db_val_t *key, knot_db_val_t *val, unsigned flags);
+ int (*insert)(knot_db_txn_t *txn, knot_db_val_t *key, knot_db_val_t *val, unsigned flags);
+ int (*del)(knot_db_txn_t *txn, knot_db_val_t *key);
+
+ /* Iteration */
+
+ knot_db_iter_t *(*iter_begin)(knot_db_txn_t *txn, unsigned flags);
+ knot_db_iter_t *(*iter_seek)(knot_db_iter_t *iter, knot_db_val_t *key, unsigned flags);
+ knot_db_iter_t *(*iter_next)(knot_db_iter_t *iter);
+ int (*iter_key)(knot_db_iter_t *iter, knot_db_val_t *key);
+ int (*iter_val)(knot_db_iter_t *iter, knot_db_val_t *val);
+ void (*iter_finish)(knot_db_iter_t *iter);
+} knot_db_api_t;
+
+/*! @} */
diff --git a/src/libknot/db/db_lmdb.c b/src/libknot/db/db_lmdb.c
new file mode 100644
index 0000000..f0e7be5
--- /dev/null
+++ b/src/libknot/db/db_lmdb.c
@@ -0,0 +1,568 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "libknot/attribute.h"
+#include "libknot/errcode.h"
+#include "libknot/db/db_lmdb.h"
+#include "contrib/mempattern.h"
+
+#include <lmdb.h>
+
+/* Defines */
+#define LMDB_DIR_MODE 0770
+#define LMDB_FILE_MODE 0660
+
+_public_ const unsigned KNOT_DB_LMDB_NOTLS = MDB_NOTLS;
+_public_ const unsigned KNOT_DB_LMDB_RDONLY = MDB_RDONLY;
+_public_ const unsigned KNOT_DB_LMDB_INTEGERKEY = MDB_INTEGERKEY;
+_public_ const unsigned KNOT_DB_LMDB_NOSYNC = MDB_NOSYNC;
+_public_ const unsigned KNOT_DB_LMDB_WRITEMAP = MDB_WRITEMAP;
+_public_ const unsigned KNOT_DB_LMDB_MAPASYNC = MDB_MAPASYNC;
+_public_ const unsigned KNOT_DB_LMDB_DUPSORT = MDB_DUPSORT;
+
+struct lmdb_env
+{
+ bool shared;
+ MDB_dbi dbi;
+ MDB_env *env;
+ knot_mm_t *pool;
+};
+
+/*!
+ * \brief Convert error code returned by LMDB to Knot DNS error code.
+ *
+ * LMDB defines own error codes but uses additional ones from libc:
+ * - LMDB errors do not conflict with Knot DNS ones.
+ * - Significant LMDB errors are mapped to Knot DNS ones.
+ * - Standard errors are converted to negative value to match Knot DNS mapping.
+ */
+static int lmdb_error_to_knot(int error)
+{
+ if (error == MDB_SUCCESS) {
+ return KNOT_EOK;
+ }
+
+ if (error == MDB_NOTFOUND) {
+ return KNOT_ENOENT;
+ }
+
+ if (error == MDB_TXN_FULL) {
+ return KNOT_ELIMIT;
+ }
+
+ if (error == MDB_MAP_FULL || error == ENOSPC) {
+ return KNOT_ESPACE;
+ }
+
+ return -abs(error);
+}
+
+static int create_env_dir(const char *path)
+{
+ int r = mkdir(path, LMDB_DIR_MODE);
+ if (r == -1 && errno != EEXIST) {
+ return lmdb_error_to_knot(errno);
+ }
+
+ return KNOT_EOK;
+}
+
+/*! \brief Set the environment map size.
+ * \note This also sets the maximum database size, see mdb_env_set_mapsize
+ */
+static int set_mapsize(MDB_env *env, size_t map_size)
+{
+ long page_size = sysconf(_SC_PAGESIZE);
+ if (page_size <= 0) {
+ return KNOT_ERROR;
+ }
+
+ /* Round to page size. */
+ map_size = (map_size / page_size) * page_size;
+ int ret = mdb_env_set_mapsize(env, map_size);
+ if (ret != MDB_SUCCESS) {
+ return lmdb_error_to_knot(ret);
+ }
+
+ return KNOT_EOK;
+}
+
+/*! \brief Close the database. */
+static void dbase_close(struct lmdb_env *env)
+{
+ mdb_dbi_close(env->env, env->dbi);
+ if (!env->shared) {
+ mdb_env_close(env->env);
+ }
+}
+
+/*! \brief Open database environment. */
+static int dbase_open_env(struct lmdb_env *env, struct knot_db_lmdb_opts *opts)
+{
+ MDB_env *mdb_env = NULL;
+ int ret = mdb_env_create(&mdb_env);
+ if (ret != MDB_SUCCESS) {
+ return lmdb_error_to_knot(ret);
+ }
+
+ ret = create_env_dir(opts->path);
+ if (ret != KNOT_EOK) {
+ mdb_env_close(mdb_env);
+ return ret;
+ }
+
+ ret = set_mapsize(mdb_env, opts->mapsize);
+ if (ret != KNOT_EOK) {
+ mdb_env_close(mdb_env);
+ return ret;
+ }
+
+ ret = mdb_env_set_maxdbs(mdb_env, opts->maxdbs);
+ if (ret != MDB_SUCCESS) {
+ mdb_env_close(mdb_env);
+ return lmdb_error_to_knot(ret);
+ }
+
+ ret = mdb_env_set_maxreaders(mdb_env, opts->maxreaders);
+ if (ret != MDB_SUCCESS) {
+ mdb_env_close(mdb_env);
+ return lmdb_error_to_knot(ret);
+ }
+
+#ifdef __OpenBSD__
+ /*
+ * Enforce that MDB_WRITEMAP is set.
+ *
+ * MDB assumes a unified buffer cache.
+ *
+ * See http://www.openldap.org/pub/hyc/mdm-paper.pdf section 3.1,
+ * references 17, 18, and 19.
+ *
+ * From Howard Chu: "This requirement can be relaxed in the
+ * current version of the library. If you create the environment
+ * with the MDB_WRITEMAP option then all reads and writes are
+ * performed using mmap, so the file buffer cache is irrelevant.
+ * Of course then you lose the protection that the read-only
+ * map offers."
+ */
+ opts->flags.env |= MDB_WRITEMAP;
+#endif
+
+ ret = mdb_env_open(mdb_env, opts->path, opts->flags.env, LMDB_FILE_MODE);
+ if (ret != MDB_SUCCESS) {
+ mdb_env_close(mdb_env);
+ return lmdb_error_to_knot(ret);
+ }
+
+ /* Keep the environment pointer. */
+ env->env = mdb_env;
+
+ return KNOT_EOK;
+}
+
+static int dbase_open(struct lmdb_env *env, struct knot_db_lmdb_opts *opts)
+{
+ unsigned flags = 0;
+ if (opts->flags.env & KNOT_DB_LMDB_RDONLY) {
+ flags = MDB_RDONLY;
+ }
+
+ /* Open the database. */
+ MDB_txn *txn = NULL;
+ int ret = mdb_txn_begin(env->env, NULL, flags, &txn);
+ if (ret != MDB_SUCCESS) {
+ mdb_env_close(env->env);
+ return lmdb_error_to_knot(ret);
+ }
+
+ ret = mdb_dbi_open(txn, opts->dbname, opts->flags.db | MDB_CREATE, &env->dbi);
+ if (ret != MDB_SUCCESS) {
+ mdb_txn_abort(txn);
+ mdb_env_close(env->env);
+ return lmdb_error_to_knot(ret);
+ }
+
+ ret = mdb_txn_commit(txn);
+ if (ret != MDB_SUCCESS) {
+ mdb_env_close(env->env);
+ return lmdb_error_to_knot(ret);
+ }
+
+ return KNOT_EOK;
+}
+
+static int init(knot_db_t **db_ptr, knot_mm_t *mm, void *arg)
+{
+ if (db_ptr == NULL || arg == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ struct lmdb_env *env = mm_alloc(mm, sizeof(struct lmdb_env));
+ if (env == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ memset(env, 0, sizeof(struct lmdb_env));
+ env->pool = mm;
+
+ /* Open new environment. */
+ struct lmdb_env *old_env = *db_ptr;
+ if (old_env == NULL) {
+ int ret = dbase_open_env(env, (struct knot_db_lmdb_opts *)arg);
+ if (ret != KNOT_EOK) {
+ mm_free(mm, env);
+ return ret;
+ }
+ } else {
+ /* Shared environment, this instance just owns the DBI. */
+ env->env = old_env->env;
+ env->shared = true;
+ }
+
+ /* Open the database. */
+ int ret = dbase_open(env, (struct knot_db_lmdb_opts *)arg);
+ if (ret != KNOT_EOK) {
+ mm_free(mm, env);
+ return ret;
+ }
+
+ /* Store the new environment. */
+ *db_ptr = env;
+
+ return KNOT_EOK;
+}
+
+static void deinit(knot_db_t *db)
+{
+ if (db) {
+ struct lmdb_env *env = db;
+
+ dbase_close(env);
+ mm_free(env->pool, env);
+ }
+}
+
+_public_
+int knot_db_lmdb_txn_begin(knot_db_t *db, knot_db_txn_t *txn, knot_db_txn_t *parent,
+ unsigned flags)
+{
+ txn->db = db;
+ txn->txn = NULL;
+
+ unsigned txn_flags = 0;
+ if (flags & KNOT_DB_RDONLY) {
+ txn_flags |= MDB_RDONLY;
+ }
+
+ MDB_txn *parent_txn = (parent != NULL) ? (MDB_txn *)parent->txn : NULL;
+
+ struct lmdb_env *env = db;
+ int ret = mdb_txn_begin(env->env, parent_txn, txn_flags, (MDB_txn **)&txn->txn);
+ if (ret != MDB_SUCCESS) {
+ return lmdb_error_to_knot(ret);
+ }
+
+ return KNOT_EOK;
+}
+
+static int txn_begin(knot_db_t *db, knot_db_txn_t *txn, unsigned flags)
+{
+ return knot_db_lmdb_txn_begin(db, txn, NULL, flags);
+}
+
+static int txn_commit(knot_db_txn_t *txn)
+{
+ int ret = mdb_txn_commit((MDB_txn *)txn->txn);
+ if (ret != MDB_SUCCESS) {
+ return lmdb_error_to_knot(ret);
+ }
+
+ return KNOT_EOK;
+}
+
+static void txn_abort(knot_db_txn_t *txn)
+{
+ mdb_txn_abort((MDB_txn *)txn->txn);
+}
+
+static int count(knot_db_txn_t *txn)
+{
+ struct lmdb_env *env = txn->db;
+
+ MDB_stat stat;
+ int ret = mdb_stat(txn->txn, env->dbi, &stat);
+ if (ret != MDB_SUCCESS) {
+ return lmdb_error_to_knot(ret);
+ }
+
+ return stat.ms_entries;
+}
+
+static int clear(knot_db_txn_t *txn)
+{
+ struct lmdb_env *env = txn->db;
+
+ int ret = mdb_drop(txn->txn, env->dbi, 0);
+ if (ret != MDB_SUCCESS) {
+ return lmdb_error_to_knot(ret);
+ }
+
+ return KNOT_EOK;
+}
+
+static knot_db_iter_t *iter_set(knot_db_iter_t *iter, knot_db_val_t *key, unsigned flags)
+{
+ MDB_cursor *cursor = iter;
+
+ MDB_cursor_op op = MDB_SET;
+ switch(flags) {
+ case KNOT_DB_NOOP: return cursor;
+ case KNOT_DB_FIRST: op = MDB_FIRST; break;
+ case KNOT_DB_LAST: op = MDB_LAST; break;
+ case KNOT_DB_NEXT: op = MDB_NEXT; break;
+ case KNOT_DB_PREV: op = MDB_PREV; break;
+ case KNOT_DB_LEQ:
+ case KNOT_DB_GEQ: op = MDB_SET_RANGE; break;
+ default: break;
+ }
+
+ MDB_val db_key = { 0, NULL };
+ if (key) {
+ db_key.mv_data = key->data;
+ db_key.mv_size = key->len;
+ }
+ MDB_val unused_key = { 0, NULL }, unused_val = { 0, NULL };
+
+ int ret = mdb_cursor_get(cursor, key ? &db_key : &unused_key, &unused_val, op);
+
+ /* LEQ is not supported in LMDB, workaround using GEQ. */
+ if (flags == KNOT_DB_LEQ && key) {
+ /* Searched key is after the last key. */
+ if (ret != MDB_SUCCESS) {
+ return iter_set(iter, NULL, KNOT_DB_LAST);
+ }
+ /* If the searched key != matched, get previous. */
+ if ((key->len != db_key.mv_size) ||
+ (memcmp(key->data, db_key.mv_data, key->len) != 0)) {
+ return iter_set(iter, NULL, KNOT_DB_PREV);
+ }
+ }
+
+ if (ret != MDB_SUCCESS) {
+ mdb_cursor_close(cursor);
+ return NULL;
+ }
+
+ return cursor;
+}
+
+static knot_db_iter_t *iter_begin(knot_db_txn_t *txn, unsigned flags)
+{
+ struct lmdb_env *env = txn->db;
+ MDB_cursor *cursor = NULL;
+
+ int ret = mdb_cursor_open(txn->txn, env->dbi, &cursor);
+ if (ret != MDB_SUCCESS) {
+ return NULL;
+ }
+
+ /* Clear sorted flag, as it's always sorted. */
+ flags &= ~KNOT_DB_SORTED;
+
+ return iter_set(cursor, NULL, (flags == 0) ? KNOT_DB_FIRST : flags);
+}
+
+static knot_db_iter_t *iter_next(knot_db_iter_t *iter)
+{
+ return iter_set(iter, NULL, KNOT_DB_NEXT);
+}
+
+_public_
+int knot_db_lmdb_iter_del(knot_db_iter_t *iter)
+{
+ MDB_cursor *cursor = iter;
+
+ int ret = mdb_cursor_del(cursor, 0);
+ if (ret != MDB_SUCCESS) {
+ return lmdb_error_to_knot(ret);
+ }
+
+ return KNOT_EOK;
+}
+
+static int iter_key(knot_db_iter_t *iter, knot_db_val_t *key)
+{
+ MDB_cursor *cursor = iter;
+
+ MDB_val mdb_key, mdb_val;
+ int ret = mdb_cursor_get(cursor, &mdb_key, &mdb_val, MDB_GET_CURRENT);
+ if (ret != MDB_SUCCESS) {
+ return lmdb_error_to_knot(ret);
+ }
+
+ key->data = mdb_key.mv_data;
+ key->len = mdb_key.mv_size;
+ return KNOT_EOK;
+}
+
+static int iter_val(knot_db_iter_t *iter, knot_db_val_t *val)
+{
+ MDB_cursor *cursor = iter;
+
+ MDB_val mdb_key, mdb_val;
+ int ret = mdb_cursor_get(cursor, &mdb_key, &mdb_val, MDB_GET_CURRENT);
+ if (ret != MDB_SUCCESS) {
+ return lmdb_error_to_knot(ret);
+ }
+
+ val->data = mdb_val.mv_data;
+ val->len = mdb_val.mv_size;
+ return KNOT_EOK;
+}
+
+static void iter_finish(knot_db_iter_t *iter)
+{
+ if (iter == NULL) {
+ return;
+ }
+
+ MDB_cursor *cursor = iter;
+ mdb_cursor_close(cursor);
+}
+
+static int find(knot_db_txn_t *txn, knot_db_val_t *key, knot_db_val_t *val, unsigned flags)
+{
+ knot_db_iter_t *iter = iter_begin(txn, KNOT_DB_NOOP);
+ if (iter == NULL) {
+ return KNOT_ERROR;
+ }
+
+ int ret = KNOT_EOK;
+ if (iter_set(iter, key, flags) == NULL) {
+ return KNOT_ENOENT;
+ } else {
+ ret = iter_val(iter, val);
+ }
+
+ iter_finish(iter);
+ return ret;
+}
+
+static int insert(knot_db_txn_t *txn, knot_db_val_t *key, knot_db_val_t *val, unsigned flags)
+{
+ struct lmdb_env *env = txn->db;
+
+ MDB_val db_key = { key->len, key->data };
+ MDB_val data = { val->len, val->data };
+
+ /* Reserve if only size is declared. */
+ unsigned mdb_flags = 0;
+ if (val->len > 0 && val->data == NULL) {
+ mdb_flags |= MDB_RESERVE;
+ }
+
+ int ret = mdb_put(txn->txn, env->dbi, &db_key, &data, mdb_flags);
+ if (ret != MDB_SUCCESS) {
+ return lmdb_error_to_knot(ret);
+ }
+
+ /* Update the result. */
+ val->data = data.mv_data;
+ val->len = data.mv_size;
+
+ return KNOT_EOK;
+}
+
+static int del(knot_db_txn_t *txn, knot_db_val_t *key)
+{
+ struct lmdb_env *env = txn->db;
+ MDB_val db_key = { key->len, key->data };
+ MDB_val data = { 0, NULL };
+
+ int ret = mdb_del(txn->txn, env->dbi, &db_key, &data);
+ if (ret != MDB_SUCCESS) {
+ return lmdb_error_to_knot(ret);
+ }
+
+ return KNOT_EOK;
+}
+
+_public_
+int knot_db_lmdb_del_exact(knot_db_txn_t *txn, knot_db_val_t *key, knot_db_val_t *val)
+{
+ struct lmdb_env *env = txn->db;
+ MDB_val db_key = { key->len, key->data };
+ MDB_val data = { val->len, val->data };
+
+ int ret = mdb_del(txn->txn, env->dbi, &db_key, &data);
+ if (ret != MDB_SUCCESS) {
+ return lmdb_error_to_knot(ret);
+ }
+
+ return KNOT_EOK;
+}
+
+_public_
+size_t knot_db_lmdb_get_mapsize(knot_db_t *db)
+{
+ struct lmdb_env *env = db;
+ MDB_envinfo info;
+ if (mdb_env_info(env->env, &info) != MDB_SUCCESS) {
+ return 0;
+ }
+
+ return info.me_mapsize;
+}
+
+// you should SUM all the usages of DBs sharing one mapsize
+_public_
+size_t knot_db_lmdb_get_usage(knot_db_t *db)
+{
+ struct lmdb_env *env = db;
+ knot_db_txn_t txn;
+ knot_db_lmdb_txn_begin(db, &txn, NULL, KNOT_DB_RDONLY);
+ MDB_stat st;
+ if (mdb_stat(txn.txn, env->dbi, &st) != MDB_SUCCESS) {
+ txn_abort(&txn);
+ return 0;
+ }
+ txn_abort(&txn);
+
+ size_t pgs_used = st.ms_branch_pages + st.ms_leaf_pages + st.ms_overflow_pages;
+
+ return (pgs_used * st.ms_psize);
+}
+
+_public_
+const knot_db_api_t *knot_db_lmdb_api(void)
+{
+ static const knot_db_api_t api = {
+ "lmdb",
+ init, deinit,
+ txn_begin, txn_commit, txn_abort,
+ count, clear, find, insert, del,
+ iter_begin, iter_set, iter_next, iter_key, iter_val, iter_finish
+ };
+
+ return &api;
+}
diff --git a/src/libknot/db/db_lmdb.h b/src/libknot/db/db_lmdb.h
new file mode 100644
index 0000000..d0213cf
--- /dev/null
+++ b/src/libknot/db/db_lmdb.h
@@ -0,0 +1,71 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*!
+ * \file
+ *
+ * \addtogroup db
+ * @{
+ */
+
+#pragma once
+
+#include "libknot/db/db.h"
+
+/* Defines. */
+#define KNOT_DB_LMDB_MAPSIZE (100 * 1024 * 1024)
+
+/* LMDB specific flags. */
+extern const unsigned KNOT_DB_LMDB_NOTLS;
+extern const unsigned KNOT_DB_LMDB_RDONLY;
+extern const unsigned KNOT_DB_LMDB_INTEGERKEY;
+extern const unsigned KNOT_DB_LMDB_NOSYNC;
+extern const unsigned KNOT_DB_LMDB_WRITEMAP;
+extern const unsigned KNOT_DB_LMDB_MAPASYNC;
+extern const unsigned KNOT_DB_LMDB_DUPSORT;
+
+/* Native options. */
+struct knot_db_lmdb_opts {
+ const char *path; /*!< Database environment path. */
+ const char *dbname; /*!< Database name (or NULL). */
+ size_t mapsize; /*!< Environment map size. */
+ unsigned maxdbs; /*!< Maximum number of databases in the env. */
+ unsigned maxreaders; /*!< Maximum number of concurrent readers */
+ struct {
+ unsigned env; /*!< Environment flags. */
+ unsigned db; /*!< Database flags. */
+ } flags;
+};
+
+/* Default options. */
+#define KNOT_DB_LMDB_OPTS_INITIALIZER { \
+ NULL, NULL, \
+ KNOT_DB_LMDB_MAPSIZE, \
+ 0, \
+ 126, /* = contrib/lmdb/mdb.c DEFAULT_READERS */ \
+ { 0, 0 } \
+}
+
+const knot_db_api_t *knot_db_lmdb_api(void);
+
+/* LMDB specific operations. */
+int knot_db_lmdb_del_exact(knot_db_txn_t *txn, knot_db_val_t *key, knot_db_val_t *val);
+int knot_db_lmdb_txn_begin(knot_db_t *db, knot_db_txn_t *txn, knot_db_txn_t *parent,
+ unsigned flags);
+int knot_db_lmdb_iter_del(knot_db_iter_t *iter);
+size_t knot_db_lmdb_get_mapsize(knot_db_t *db);
+size_t knot_db_lmdb_get_usage(knot_db_t *db);
+
+/*! @} */
diff --git a/src/libknot/db/db_trie.c b/src/libknot/db/db_trie.c
new file mode 100644
index 0000000..d0fbb0c
--- /dev/null
+++ b/src/libknot/db/db_trie.c
@@ -0,0 +1,178 @@
+/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+
+#include "libknot/attribute.h"
+#include "libknot/errcode.h"
+#include "libknot/db/db_trie.h"
+#include "contrib/qp-trie/trie.h"
+#include "contrib/macros.h"
+#include "contrib/mempattern.h"
+
+static int init(knot_db_t **db, knot_mm_t *mm, void *arg)
+{
+ if (db == NULL || arg == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ struct knot_db_trie_opts *opts = arg;
+ UNUSED(opts);
+ trie_t *trie = trie_create(mm);
+ if (!trie) {
+ return KNOT_ENOMEM;
+ }
+
+ *db = trie;
+
+ return KNOT_EOK;
+}
+
+static void deinit(knot_db_t *db)
+{
+ trie_free((trie_t *)db);
+}
+
+static int txn_begin(knot_db_t *db, knot_db_txn_t *txn, unsigned flags)
+{
+ txn->txn = (void *)(size_t)flags;
+ txn->db = db;
+ return KNOT_EOK; /* N/A */
+}
+
+static int txn_commit(knot_db_txn_t *txn)
+{
+ return KNOT_EOK;
+}
+
+static void txn_abort(knot_db_txn_t *txn)
+{
+}
+
+static int count(knot_db_txn_t *txn)
+{
+ return trie_weight((trie_t *)txn->db);
+}
+
+static int clear(knot_db_txn_t *txn)
+{
+ trie_clear((trie_t *)txn->db);
+
+ return KNOT_EOK;
+}
+
+static int find(knot_db_txn_t *txn, knot_db_val_t *key, knot_db_val_t *val, unsigned flags)
+{
+ trie_val_t *ret = trie_get_try((trie_t *)txn->db, key->data, key->len);
+ if (ret == NULL) {
+ return KNOT_ENOENT;
+ }
+
+ val->data = *ret;
+ val->len = sizeof(trie_val_t); /* Trie doesn't support storing length. */
+ return KNOT_EOK;
+}
+
+static int insert(knot_db_txn_t *txn, knot_db_val_t *key, knot_db_val_t *val, unsigned flags)
+{
+ /* No flags supported. */
+ if (flags != 0) {
+ return KNOT_ENOTSUP;
+ }
+
+ trie_val_t *ret = trie_get_ins((trie_t *)txn->db, key->data, key->len);
+ if (ret == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ *ret = val->data;
+ return KNOT_EOK;
+}
+
+static int del(knot_db_txn_t *txn, knot_db_val_t *key)
+{
+ return trie_del((trie_t *)txn->db, key->data, key->len, NULL);
+}
+
+static knot_db_iter_t *iter_begin(knot_db_txn_t *txn, unsigned flags)
+{
+ flags &= ~KNOT_DB_SORTED;
+
+ /* No operations other than begin are supported right now. */
+ if (flags != 0) {
+ return NULL;
+ }
+
+ return trie_it_begin((trie_t *)txn->db);
+}
+
+static knot_db_iter_t *iter_seek(knot_db_iter_t *iter, knot_db_val_t *key, unsigned flags)
+{
+ assert(0);
+ return NULL; /* ENOTSUP */
+}
+
+static knot_db_iter_t *iter_next(knot_db_iter_t *iter)
+{
+ trie_it_next((trie_it_t *)iter);
+ if (trie_it_finished((trie_it_t *)iter)) {
+ trie_it_free((trie_it_t *)iter);
+ return NULL;
+ }
+
+ return iter;
+}
+
+static int iter_key(knot_db_iter_t *iter, knot_db_val_t *val)
+{
+ val->data = (void *)trie_it_key((trie_it_t *)iter, &val->len);
+ if (val->data == NULL) {
+ return KNOT_ENOENT;
+ }
+
+ return KNOT_EOK;
+}
+
+static int iter_val(knot_db_iter_t *iter, knot_db_val_t *val)
+{
+ trie_val_t *ret = trie_it_val((trie_it_t *)iter);
+ if (ret == NULL) {
+ return KNOT_ENOENT;
+ }
+
+ val->data = *ret;
+ val->len = sizeof(trie_val_t);
+ return KNOT_EOK;
+}
+
+static void iter_finish(knot_db_iter_t *iter)
+{
+ trie_it_free((trie_it_t *)iter);
+}
+
+_public_
+const knot_db_api_t *knot_db_trie_api(void)
+{
+ static const knot_db_api_t api = {
+ "trie",
+ init, deinit,
+ txn_begin, txn_commit, txn_abort,
+ count, clear, find, insert, del,
+ iter_begin, iter_seek, iter_next, iter_key, iter_val, iter_finish
+ };
+
+ return &api;
+}
diff --git a/src/libknot/db/db_trie.h b/src/libknot/db/db_trie.h
new file mode 100644
index 0000000..d2afdf8
--- /dev/null
+++ b/src/libknot/db/db_trie.h
@@ -0,0 +1,39 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*!
+ * \file
+ *
+ * \addtogroup db
+ * @{
+ */
+
+#pragma once
+
+#include "libknot/db/db.h"
+
+/* Native options. */
+struct knot_db_trie_opts {
+ unsigned unused;
+};
+
+/* Default options. */
+#define KNOT_DB_TRIE_OPTS_INITIALIZER { \
+ 0 \
+}
+
+const knot_db_api_t *knot_db_trie_api(void);
+
+/*! @} */
diff --git a/src/libknot/descriptor.c b/src/libknot/descriptor.c
new file mode 100644
index 0000000..fa3bbd6
--- /dev/null
+++ b/src/libknot/descriptor.c
@@ -0,0 +1,411 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include "libknot/attribute.h"
+#include "libknot/descriptor.h"
+
+/*!
+ * \brief Table with DNS classes.
+ */
+static const char* dns_classes[] = {
+ [KNOT_CLASS_IN] = "IN",
+ [KNOT_CLASS_CH] = "CH",
+ [KNOT_CLASS_NONE] = "NONE",
+ [KNOT_CLASS_ANY] = "ANY"
+};
+
+/*!
+ * \brief RR type descriptors.
+ */
+static const knot_rdata_descriptor_t rdata_descriptors[] = {
+ [0] = { { KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, NULL },
+ [KNOT_RRTYPE_A] = { { 4, KNOT_RDATA_WF_END }, "A" },
+ [KNOT_RRTYPE_NS] = { { KNOT_RDATA_WF_COMPRESSIBLE_DNAME,
+ KNOT_RDATA_WF_END }, "NS" },
+ [KNOT_RRTYPE_CNAME] = { { KNOT_RDATA_WF_COMPRESSIBLE_DNAME,
+ KNOT_RDATA_WF_END }, "CNAME" },
+ [KNOT_RRTYPE_SOA] = { { KNOT_RDATA_WF_COMPRESSIBLE_DNAME,
+ KNOT_RDATA_WF_COMPRESSIBLE_DNAME,
+ 20, KNOT_RDATA_WF_END }, "SOA" },
+ [KNOT_RRTYPE_NULL] = { { KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, "NULL" },
+ [KNOT_RRTYPE_PTR] = { { KNOT_RDATA_WF_COMPRESSIBLE_DNAME,
+ KNOT_RDATA_WF_END }, "PTR" },
+ [KNOT_RRTYPE_HINFO] = { { KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, "HINFO" },
+ [KNOT_RRTYPE_MINFO] = { { KNOT_RDATA_WF_COMPRESSIBLE_DNAME,
+ KNOT_RDATA_WF_COMPRESSIBLE_DNAME,
+ KNOT_RDATA_WF_END }, "MINFO" },
+ [KNOT_RRTYPE_MX] = { { 2, KNOT_RDATA_WF_COMPRESSIBLE_DNAME,
+ KNOT_RDATA_WF_END }, "MX" },
+ [KNOT_RRTYPE_TXT] = { { KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, "TXT" },
+ [KNOT_RRTYPE_RP] = { { KNOT_RDATA_WF_DECOMPRESSIBLE_DNAME,
+ KNOT_RDATA_WF_DECOMPRESSIBLE_DNAME,
+ KNOT_RDATA_WF_END }, "RP" },
+ [KNOT_RRTYPE_AFSDB] = { { 2, KNOT_RDATA_WF_DECOMPRESSIBLE_DNAME,
+ KNOT_RDATA_WF_END }, "AFSDB" },
+ [KNOT_RRTYPE_RT] = { { 2, KNOT_RDATA_WF_DECOMPRESSIBLE_DNAME,
+ KNOT_RDATA_WF_END }, "RT" },
+ [KNOT_RRTYPE_SIG] = { { 18, KNOT_RDATA_WF_DECOMPRESSIBLE_DNAME,
+ KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, "SIG" },
+ [KNOT_RRTYPE_KEY] = { { KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, "KEY" },
+ [KNOT_RRTYPE_AAAA] = { { 16, KNOT_RDATA_WF_END }, "AAAA" },
+ [KNOT_RRTYPE_LOC] = { { 16, KNOT_RDATA_WF_END }, "LOC" },
+ [KNOT_RRTYPE_SRV] = { { 6, KNOT_RDATA_WF_DECOMPRESSIBLE_DNAME,
+ KNOT_RDATA_WF_END }, "SRV" },
+ [KNOT_RRTYPE_NAPTR] = { { KNOT_RDATA_WF_NAPTR_HEADER,
+ KNOT_RDATA_WF_DECOMPRESSIBLE_DNAME,
+ KNOT_RDATA_WF_END }, "NAPTR" },
+ [KNOT_RRTYPE_KX] = { { 2, KNOT_RDATA_WF_FIXED_DNAME,
+ KNOT_RDATA_WF_END }, "KX" },
+ [KNOT_RRTYPE_CERT] = { { KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, "CERT" },
+ [KNOT_RRTYPE_DNAME] = { { KNOT_RDATA_WF_FIXED_DNAME,
+ KNOT_RDATA_WF_END }, "DNAME" },
+ [KNOT_RRTYPE_OPT] = { { KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, "OPT" },
+ [KNOT_RRTYPE_APL] = { { KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, "APL" },
+ [KNOT_RRTYPE_DS] = { { KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, "DS" },
+ [KNOT_RRTYPE_SSHFP] = { { KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, "SSHFP" },
+ [KNOT_RRTYPE_IPSECKEY] = { { KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, "IPSECKEY" },
+ [KNOT_RRTYPE_RRSIG] = { { 18, KNOT_RDATA_WF_FIXED_DNAME,
+ KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, "RRSIG" },
+ [KNOT_RRTYPE_NSEC] = { { KNOT_RDATA_WF_FIXED_DNAME,
+ KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, "NSEC" },
+ [KNOT_RRTYPE_DNSKEY] = { { KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, "DNSKEY" },
+ [KNOT_RRTYPE_DHCID] = { { KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, "DHCID" },
+ [KNOT_RRTYPE_NSEC3] = { { KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, "NSEC3" },
+ [KNOT_RRTYPE_NSEC3PARAM] = { { KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, "NSEC3PARAM" },
+ [KNOT_RRTYPE_TLSA] = { { KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, "TLSA" },
+ [KNOT_RRTYPE_CDS] = { { KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, "CDS" },
+ [KNOT_RRTYPE_CDNSKEY] = { { KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, "CDNSKEY" },
+ [KNOT_RRTYPE_SPF] = { { KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, "SPF" },
+ [KNOT_RRTYPE_NID] = { { 10, KNOT_RDATA_WF_END }, "NID" },
+ [KNOT_RRTYPE_L32] = { { 6, KNOT_RDATA_WF_END }, "L32" },
+ [KNOT_RRTYPE_L64] = { { 10, KNOT_RDATA_WF_END }, "L64" },
+ [KNOT_RRTYPE_LP] = { { 2, KNOT_RDATA_WF_FIXED_DNAME,
+ KNOT_RDATA_WF_END }, "LP" },
+ [KNOT_RRTYPE_EUI48] = { { 6, KNOT_RDATA_WF_END }, "EUI48" },
+ [KNOT_RRTYPE_EUI64] = { { 8, KNOT_RDATA_WF_END }, "EUI64" },
+ [KNOT_RRTYPE_TKEY] = { { KNOT_RDATA_WF_FIXED_DNAME,
+ KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, "TKEY" },
+ [KNOT_RRTYPE_TSIG] = { { KNOT_RDATA_WF_FIXED_DNAME,
+ KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, "TSIG" },
+ [KNOT_RRTYPE_IXFR] = { { KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, "IXFR" },
+ [KNOT_RRTYPE_AXFR] = { { KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, "AXFR" },
+ [KNOT_RRTYPE_ANY] = { { KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, "ANY" },
+ [KNOT_RRTYPE_URI] = { { KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, "URI" },
+ [KNOT_RRTYPE_CAA] = { { KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, "CAA" },
+};
+
+#define MAX_RRTYPE sizeof(rdata_descriptors) / sizeof(knot_rdata_descriptor_t) - 1
+
+/*!
+ * \brief Some (OBSOLETE) RR type descriptors.
+ */
+static const knot_rdata_descriptor_t obsolete_rdata_descriptors[] = {
+ [0] = { { KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, NULL },
+ [KNOT_RRTYPE_MD] = { { KNOT_RDATA_WF_DECOMPRESSIBLE_DNAME,
+ KNOT_RDATA_WF_END }, "MD" },
+ [KNOT_RRTYPE_MF] = { { KNOT_RDATA_WF_DECOMPRESSIBLE_DNAME,
+ KNOT_RDATA_WF_END }, "MF" },
+ [KNOT_RRTYPE_MB] = { { KNOT_RDATA_WF_DECOMPRESSIBLE_DNAME,
+ KNOT_RDATA_WF_END }, "MB" },
+ [KNOT_RRTYPE_MG] = { { KNOT_RDATA_WF_DECOMPRESSIBLE_DNAME,
+ KNOT_RDATA_WF_END }, "MG" },
+ [KNOT_RRTYPE_MR] = { { KNOT_RDATA_WF_DECOMPRESSIBLE_DNAME,
+ KNOT_RDATA_WF_END }, "MR" },
+ [KNOT_RRTYPE_PX] = { { 2, KNOT_RDATA_WF_DECOMPRESSIBLE_DNAME,
+ KNOT_RDATA_WF_DECOMPRESSIBLE_DNAME,
+ KNOT_RDATA_WF_END }, "PX" },
+ [KNOT_RRTYPE_NXT] = { { KNOT_RDATA_WF_DECOMPRESSIBLE_DNAME,
+ KNOT_RDATA_WF_REMAINDER,
+ KNOT_RDATA_WF_END }, "NXT" },
+};
+
+_public_
+const knot_rdata_descriptor_t *knot_get_rdata_descriptor(const uint16_t type)
+{
+ if (type <= MAX_RRTYPE && rdata_descriptors[type].type_name != NULL) {
+ return &rdata_descriptors[type];
+ } else {
+ return &rdata_descriptors[0];
+ }
+}
+
+_public_
+const knot_rdata_descriptor_t *knot_get_obsolete_rdata_descriptor(const uint16_t type)
+{
+ if (type <= KNOT_RRTYPE_NXT &&
+ obsolete_rdata_descriptors[type].type_name != NULL) {
+ return &obsolete_rdata_descriptors[type];
+ } else {
+ return &obsolete_rdata_descriptors[0];
+ }
+}
+
+_public_
+int knot_rrtype_to_string(const uint16_t rrtype,
+ char *out,
+ const size_t out_len)
+{
+ if (out == NULL) {
+ return -1;
+ }
+
+ int ret;
+
+ const knot_rdata_descriptor_t *descr = knot_get_rdata_descriptor(rrtype);
+
+ if (descr->type_name != NULL) {
+ ret = snprintf(out, out_len, "%s", descr->type_name);
+ } else {
+ ret = snprintf(out, out_len, "TYPE%u", rrtype);
+ }
+
+ if (ret <= 0 || (size_t)ret >= out_len) {
+ return -1;
+ } else {
+ return ret;
+ }
+}
+
+_public_
+int knot_rrtype_from_string(const char *name, uint16_t *num)
+{
+ if (name == NULL || num == NULL) {
+ return -1;
+ }
+
+ int i;
+ char *end;
+ unsigned long n;
+
+ // Try to find name in descriptors table.
+ for (i = 0; i <= MAX_RRTYPE; i++) {
+ if (rdata_descriptors[i].type_name != NULL &&
+ strcasecmp(rdata_descriptors[i].type_name, name) == 0) {
+ *num = i;
+ return 0;
+ }
+ }
+
+ // Type name must begin with TYPE.
+ if (strncasecmp(name, "TYPE", 4) != 0) {
+ return -1;
+ } else {
+ name += 4;
+ }
+
+ // The rest must be a number.
+ n = strtoul(name, &end, 10);
+ if (end == name || *end != '\0' || n > UINT16_MAX) {
+ return -1;
+ }
+
+ *num = n;
+ return 0;
+}
+
+_public_
+int knot_rrclass_to_string(const uint16_t rrclass,
+ char *out,
+ const size_t out_len)
+{
+ if (out == NULL) {
+ return -1;
+ }
+
+ int ret;
+
+ if (rrclass <= KNOT_CLASS_ANY && dns_classes[rrclass] != NULL) {
+ ret = snprintf(out, out_len, "%s", dns_classes[rrclass]);
+ } else {
+ ret = snprintf(out, out_len, "CLASS%u", rrclass);
+ }
+
+ if (ret <= 0 || (size_t)ret >= out_len) {
+ return -1;
+ } else {
+ return ret;
+ }
+}
+
+_public_
+int knot_rrclass_from_string(const char *name, uint16_t *num)
+{
+ if (name == NULL || num == NULL) {
+ return -1;
+ }
+
+ int i;
+ char *end;
+ unsigned long n;
+
+ // Try to find the name in classes table.
+ for (i = 0; i <= KNOT_CLASS_ANY; i++) {
+ if (dns_classes[i] != NULL &&
+ strcasecmp(dns_classes[i], name) == 0) {
+ *num = i;
+ return 0;
+ }
+ }
+
+ // Class name must begin with CLASS.
+ if (strncasecmp(name, "CLASS", 5) != 0) {
+ return -1;
+ } else {
+ name += 5;
+ }
+
+ // The rest must be a number.
+ n = strtoul(name, &end, 10);
+ if (end == name || *end != '\0' || n > UINT16_MAX) {
+ return -1;
+ }
+
+ *num = n;
+ return 0;
+}
+
+_public_
+int knot_rrtype_is_metatype(const uint16_t type)
+{
+ return type == KNOT_RRTYPE_SIG ||
+ type == KNOT_RRTYPE_OPT ||
+ type == KNOT_RRTYPE_TKEY ||
+ type == KNOT_RRTYPE_TSIG ||
+ type == KNOT_RRTYPE_IXFR ||
+ type == KNOT_RRTYPE_AXFR ||
+ type == KNOT_RRTYPE_ANY;
+}
+
+_public_
+int knot_rrtype_is_dnssec(const uint16_t type)
+{
+ return type == KNOT_RRTYPE_DNSKEY ||
+ type == KNOT_RRTYPE_RRSIG ||
+ type == KNOT_RRTYPE_NSEC ||
+ type == KNOT_RRTYPE_NSEC3 ||
+ type == KNOT_RRTYPE_NSEC3PARAM ||
+ type == KNOT_RRTYPE_CDNSKEY ||
+ type == KNOT_RRTYPE_CDS;
+}
+
+_public_
+int knot_rrtype_additional_needed(const uint16_t type)
+{
+ return type == KNOT_RRTYPE_NS ||
+ type == KNOT_RRTYPE_MX ||
+ type == KNOT_RRTYPE_SRV;
+}
+
+_public_
+bool knot_rrtype_should_be_lowercased(const uint16_t type)
+{
+ return type == KNOT_RRTYPE_NS ||
+ type == KNOT_RRTYPE_MD ||
+ type == KNOT_RRTYPE_MF ||
+ type == KNOT_RRTYPE_CNAME ||
+ type == KNOT_RRTYPE_SOA ||
+ type == KNOT_RRTYPE_MB ||
+ type == KNOT_RRTYPE_MG ||
+ type == KNOT_RRTYPE_MR ||
+ type == KNOT_RRTYPE_PTR ||
+ type == KNOT_RRTYPE_MINFO ||
+ type == KNOT_RRTYPE_MX ||
+ type == KNOT_RRTYPE_RP ||
+ type == KNOT_RRTYPE_AFSDB ||
+ type == KNOT_RRTYPE_RT ||
+ type == KNOT_RRTYPE_SIG ||
+ type == KNOT_RRTYPE_PX ||
+ type == KNOT_RRTYPE_NXT ||
+ type == KNOT_RRTYPE_NAPTR ||
+ type == KNOT_RRTYPE_KX ||
+ type == KNOT_RRTYPE_SRV ||
+ type == KNOT_RRTYPE_DNAME ||
+ type == KNOT_RRTYPE_RRSIG;
+}
+
+_public_
+int knot_opt_code_to_string(const uint16_t code, char *out, const size_t out_len)
+{
+ if (out == NULL) {
+ return -1;
+ }
+
+ const char *name = NULL;
+
+ switch (code) {
+ case 1: name = "LLQ"; break;
+ case 2: name = "UL"; break;
+ case 3: name = "NSID"; break;
+ case 5: name = "DAU"; break;
+ case 6: name = "DHU"; break;
+ case 7: name = "N3U"; break;
+ case 8: name = "EDNS-CLIENT-SUBNET"; break;
+ case 9: name = "EDNS-EXPIRE"; break;
+ case 10: name = "COOKIE"; break;
+ case 11: name = "EDNS-TCP-KEEPALIVE"; break;
+ case 12: name = "PADDING"; break;
+ case 13: name = "CHAIN"; break;
+ case 14: name = "EDNS-KEY-TAG"; break;
+ }
+
+ int ret;
+
+ if (name != NULL) {
+ ret = snprintf(out, out_len, "%s", name);
+ } else {
+ ret = snprintf(out, out_len, "CODE%u", code);
+ }
+
+ if (ret <= 0 || (size_t)ret >= out_len) {
+ return -1;
+ } else {
+ return ret;
+ }
+}
diff --git a/src/libknot/descriptor.h b/src/libknot/descriptor.h
new file mode 100644
index 0000000..b91a7a9
--- /dev/null
+++ b/src/libknot/descriptor.h
@@ -0,0 +1,298 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \addtogroup rr
+ * @{
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#define KNOT_MAX_RDATA_BLOCKS 8
+#define KNOT_MAX_RDATA_DNAMES 2 // Update this when defining new RR types!
+
+/*!
+ * \brief Resource record class codes.
+ *
+ * http://www.iana.org/assignments/dns-parameters/dns-parameters.xml
+ */
+enum knot_rr_class {
+ KNOT_CLASS_IN = 1,
+ KNOT_CLASS_CH = 3,
+ KNOT_CLASS_NONE = 254,
+ KNOT_CLASS_ANY = 255
+};
+
+/*!
+ * \brief Resource record type constants.
+ *
+ * References:
+ * http://www.iana.org/assignments/dns-parameters/dns-parameters.xml
+ * RFC 3597#4
+ *
+ * METATYPE: Contains DNS data that can't be in a zone file.
+ * QTYPE: Specifies DNS query type; can't be in a zone file.
+ */
+enum knot_rr_type {
+ KNOT_RRTYPE_A = 1, /*!< An IPv4 host address. */
+ KNOT_RRTYPE_NS = 2, /*!< An authoritative name server. */
+
+ KNOT_RRTYPE_CNAME = 5, /*!< The canonical name for an alias. */
+ KNOT_RRTYPE_SOA = 6, /*!< The start of a zone of authority. */
+
+ KNOT_RRTYPE_NULL = 10, /*!< METATYPE. Used in RFC 8145. */
+
+ KNOT_RRTYPE_PTR = 12, /*!< A domain name pointer. */
+ KNOT_RRTYPE_HINFO = 13, /*!< A host information. */
+ KNOT_RRTYPE_MINFO = 14, /*!< A mailbox information. */
+ KNOT_RRTYPE_MX = 15, /*!< Mail exchange. */
+ KNOT_RRTYPE_TXT = 16, /*!< Text strings. */
+ KNOT_RRTYPE_RP = 17, /*!< For responsible person. */
+ KNOT_RRTYPE_AFSDB = 18, /*!< For AFS Data Base location. */
+
+ KNOT_RRTYPE_RT = 21, /*!< For route through. */
+
+ KNOT_RRTYPE_SIG = 24, /*!< METATYPE. Transaction signature. */
+ KNOT_RRTYPE_KEY = 25, /*!< For security key. */
+
+ KNOT_RRTYPE_AAAA = 28, /*!< IPv6 address. */
+ KNOT_RRTYPE_LOC = 29, /*!< Location information. */
+
+ KNOT_RRTYPE_SRV = 33, /*!< Server selection. */
+
+ KNOT_RRTYPE_NAPTR = 35, /*!< Naming authority pointer . */
+ KNOT_RRTYPE_KX = 36, /*!< Key exchanger. */
+ KNOT_RRTYPE_CERT = 37, /*!< Certificate record. */
+
+ KNOT_RRTYPE_DNAME = 39, /*!< Delegation name. */
+
+ KNOT_RRTYPE_OPT = 41, /*!< METATYPE. Option for EDNS. */
+ KNOT_RRTYPE_APL = 42, /*!< Address prefix list. */
+ KNOT_RRTYPE_DS = 43, /*!< Delegation signer. */
+ KNOT_RRTYPE_SSHFP = 44, /*!< SSH public key fingerprint. */
+ KNOT_RRTYPE_IPSECKEY = 45, /*!< IPSEC key. */
+ KNOT_RRTYPE_RRSIG = 46, /*!< DNSSEC signature. */
+ KNOT_RRTYPE_NSEC = 47, /*!< Next-secure record. */
+ KNOT_RRTYPE_DNSKEY = 48, /*!< DNS key. */
+ KNOT_RRTYPE_DHCID = 49, /*!< DHCP identifier. */
+ KNOT_RRTYPE_NSEC3 = 50, /*!< NSEC version 3. */
+ KNOT_RRTYPE_NSEC3PARAM = 51, /*!< NSEC3 parameters. */
+ KNOT_RRTYPE_TLSA = 52, /*!< DANE record. */
+
+ KNOT_RRTYPE_CDS = 59, /*!< Child delegation signer. */
+ KNOT_RRTYPE_CDNSKEY = 60, /*!< Child DNS key. */
+
+ KNOT_RRTYPE_SPF = 99, /*!< Sender policy framework. */
+
+ KNOT_RRTYPE_NID = 104, /*!< Node identifier. */
+ KNOT_RRTYPE_L32 = 105, /*!< 32-bit network locator. */
+ KNOT_RRTYPE_L64 = 106, /*!< 64-bit network locator. */
+ KNOT_RRTYPE_LP = 107, /*!< Subnetwork name. */
+ KNOT_RRTYPE_EUI48 = 108, /*!< 48-bit extended unique identifier. */
+ KNOT_RRTYPE_EUI64 = 109, /*!< 64-bit extended unique identifier. */
+
+ KNOT_RRTYPE_TKEY = 249, /*!< METATYPE. Transaction key. */
+ KNOT_RRTYPE_TSIG = 250, /*!< METATYPE. Transaction signature. */
+ KNOT_RRTYPE_IXFR = 251, /*!< QTYPE. Incremental zone transfer. */
+ KNOT_RRTYPE_AXFR = 252, /*!< QTYPE. Authoritative zone transfer. */
+
+ KNOT_RRTYPE_ANY = 255, /*!< QTYPE. Any record. */
+ KNOT_RRTYPE_URI = 256, /*!< Uniform resource identifier. */
+ KNOT_RRTYPE_CAA = 257, /*!< Certification authority restriction. */
+};
+
+/*!
+ * \brief Some (OBSOLETE) resource record type constants.
+ *
+ * References:
+ * http://www.iana.org/assignments/dns-parameters/dns-parameters.xml
+ * RFC 3597#4
+ *
+ * \note These records can contain compressed domain name in rdata so
+ * it is important to know the position of them during transfers.
+ */
+enum knot_obsolete_rr_type {
+ KNOT_RRTYPE_MD = 3,
+ KNOT_RRTYPE_MF = 4,
+ KNOT_RRTYPE_MB = 7,
+ KNOT_RRTYPE_MG = 8,
+ KNOT_RRTYPE_MR = 9,
+ KNOT_RRTYPE_PX = 26,
+ KNOT_RRTYPE_NXT = 30
+};
+
+/*!
+ * \brief Constants characterising the wire format of RDATA items.
+ */
+enum knot_rdata_wireformat {
+ /*!< Dname must not be compressed. */
+ KNOT_RDATA_WF_FIXED_DNAME = -10,
+ /*!< Dname can be both compressed and decompressed. */
+ KNOT_RDATA_WF_COMPRESSIBLE_DNAME,
+ /*!< Dname can be decompressed. */
+ KNOT_RDATA_WF_DECOMPRESSIBLE_DNAME,
+ /*!< Initial part of NAPTR record before dname. */
+ KNOT_RDATA_WF_NAPTR_HEADER,
+ /*!< Final part of a record. */
+ KNOT_RDATA_WF_REMAINDER,
+ /*!< The last descriptor in array. */
+ KNOT_RDATA_WF_END = 0
+};
+
+/*!
+ * \brief Structure describing rdata.
+ */
+typedef struct {
+ /*!< Item types describing rdata. */
+ const int block_types[KNOT_MAX_RDATA_BLOCKS];
+ /*!< RR type name. */
+ const char *type_name;
+} knot_rdata_descriptor_t;
+
+/*!
+ * \brief Gets rdata descriptor for given RR name.
+ *
+ * \param type Mnemonic of RR type whose descriptor should be returned.
+ *
+ * \retval RR descriptor for given name, NULL descriptor if
+ * unknown type.
+ */
+const knot_rdata_descriptor_t *knot_get_rdata_descriptor(const uint16_t type);
+
+/*!
+ * \brief Gets rdata descriptor for given RR name (obsolete version).
+ *
+ * \param type Mnemonic of RR type whose descriptor should be returned.
+ *
+ * \retval RR descriptor for given name, NULL descriptor if
+ * unknown type.
+ */
+const knot_rdata_descriptor_t *knot_get_obsolete_rdata_descriptor(const uint16_t type);
+
+/*!
+ * \brief Converts numeric type representation to mnemonic string.
+ *
+ * \param rrtype Type RR type code to be converted.
+ * \param out Output buffer.
+ * \param out_len Length of the output buffer.
+ *
+ * \retval Length of output string.
+ * \retval -1 if error.
+ */
+int knot_rrtype_to_string(const uint16_t rrtype,
+ char *out,
+ const size_t out_len);
+
+/*!
+ * \brief Converts mnemonic string representation of a type to numeric one.
+ *
+ * \param name Mnemonic string to be converted.
+ * \param num Output variable.
+ *
+ * \retval 0 if OK.
+ * \retval -1 if error.
+ */
+int knot_rrtype_from_string(const char *name, uint16_t *num);
+
+/*!
+ * \brief Converts numeric class representation to the string one.
+ *
+ * \param rrclass Class code to be converted.
+ * \param out Output buffer.
+ * \param out_len Length of the output buffer.
+ *
+ * \retval Length of output string.
+ * \retval -1 if error.
+ */
+int knot_rrclass_to_string(const uint16_t rrclass,
+ char *out,
+ const size_t out_len);
+
+/*!
+ * \brief Converts string representation of a class to numeric one.
+ *
+ * \param name Mnemonic string to be converted.
+ * \param num Output variable.
+ *
+ * \retval 0 if OK.
+ * \retval -1 if error.
+ */
+int knot_rrclass_from_string(const char *name, uint16_t *num);
+
+/*!
+ * \brief Checks if given item is one of metatypes or qtypes.
+ *
+ * \param type Item value.
+ *
+ * \retval > 0 if YES.
+ * \retval 0 if NO.
+ */
+int knot_rrtype_is_metatype(const uint16_t type);
+
+/*!
+ * \brief Checks if given item is one of the DNSSEC types.
+ *
+ * \param type Item value.
+ *
+ * \retval > 0 if YES.
+ * \retval 0 if NO.
+ */
+int knot_rrtype_is_dnssec(const uint16_t type);
+
+/*!
+ * \brief Checks whether the given type requires additional processing.
+ *
+ * Only MX, NS and SRV types require additional processing.
+ *
+ * \param type Type to check.
+ *
+ * \retval <> 0 if additional processing is needed for \a qtype.
+ * \retval 0 otherwise.
+ */
+int knot_rrtype_additional_needed(const uint16_t type);
+
+/*!
+ * \brief Checks whether the RDATA domain names should be lowercased in
+ * canonical format of RRSet of the given type.
+ *
+ * Types that should be lowercased are accorrding to RFC 4034, Section 6.2,
+ * except for NSEC (updated by RFC 6840, Section 5.1) and A6 (not supported).
+ *
+ * \param type RRSet type to check.
+ *
+ * \retval true If RDATA dnames for type should be lowercased in canonical format.
+ * \retval false Otherwise.
+ */
+bool knot_rrtype_should_be_lowercased(const uint16_t type);
+
+/*!
+ * \brief Translates option code to string.
+ *
+ * \param code Code of the option to translate.
+ * \param out Buffer for the output string.
+ * \param out_len The available size of the buffer.
+ *
+ * \retval Length of output string.
+ * \retval -1 if error.
+ */
+int knot_opt_code_to_string(const uint16_t code, char *out, const size_t out_len);
+
+/*! @} */
diff --git a/src/libknot/dname.c b/src/libknot/dname.c
new file mode 100644
index 0000000..1a2790e
--- /dev/null
+++ b/src/libknot/dname.c
@@ -0,0 +1,755 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libknot/attribute.h"
+#include "libknot/consts.h"
+#include "libknot/dname.h"
+#include "libknot/errcode.h"
+#include "libknot/packet/wire.h"
+#include "contrib/ctype.h"
+#include "contrib/mempattern.h"
+#include "contrib/tolower.h"
+
+static int label_is_equal(const uint8_t *lb1, const uint8_t *lb2)
+{
+ return (*lb1 == *lb2) && memcmp(lb1 + 1, lb2 + 1, *lb1) == 0;
+}
+
+/*!
+ * \brief Align name end-to-end and return number of common suffix labels.
+ *
+ * \param d1 Domain name1.
+ * \param d1_labels Number of labels in d1.
+ * \param d2 Domain name2.
+ * \param d2_labels Number of labels in d2.
+ */
+static int dname_align(const uint8_t **d1, uint8_t d1_labels,
+ const uint8_t **d2, uint8_t d2_labels)
+{
+ assert(d1 && d2);
+
+ for (unsigned j = d1_labels; j < d2_labels; ++j) {
+ *d2 = knot_wire_next_label(*d2, NULL);
+ }
+
+ for (unsigned j = d2_labels; j < d1_labels; ++j) {
+ *d1 = knot_wire_next_label(*d1, NULL);
+ }
+
+ return (d1_labels < d2_labels) ? d1_labels : d2_labels;
+}
+
+_public_
+int knot_dname_wire_check(const uint8_t *name, const uint8_t *endp,
+ const uint8_t *pkt)
+{
+ if (name == NULL || name == endp) {
+ return KNOT_EINVAL;
+ }
+
+ int wire_len = 0;
+ int name_len = 1; /* Keep \x00 terminal label in advance. */
+ bool is_compressed = false;
+
+ while (*name != '\0') {
+ /* Check bounds (must have at least 2 octets remaining). */
+ if (name + 2 > endp) {
+ return KNOT_EMALF;
+ }
+
+ if (knot_wire_is_pointer(name)) {
+ /* Check that the pointer points backwards
+ * otherwise it could result in infinite loop
+ */
+ if (pkt == NULL) {
+ return KNOT_EINVAL;
+ }
+ uint16_t ptr = knot_wire_get_pointer(name);
+ if (ptr >= (name - pkt)) {
+ return KNOT_EMALF;
+ }
+
+ name = pkt + ptr; /* Hop to compressed label */
+ if (!is_compressed) { /* Measure compressed size only */
+ wire_len += sizeof(uint16_t);
+ is_compressed = true;
+ }
+ } else {
+ /* Check label length. */
+ if (*name > KNOT_DNAME_MAXLABELLEN) {
+ return KNOT_EMALF;
+ }
+ /* Check if there's enough space. */
+ int lblen = *name + 1;
+ if (name_len + lblen > KNOT_DNAME_MAXLEN) {
+ return KNOT_EMALF;
+ }
+ /* Update wire size only for noncompressed part. */
+ name_len += lblen;
+ if (!is_compressed) {
+ wire_len += lblen;
+ }
+ /* Hop to next label. */
+ name += lblen;
+ }
+
+ /* Check bounds (must have at least 1 octet). */
+ if (name + 1 > endp) {
+ return KNOT_EMALF;
+ }
+ }
+
+ if (!is_compressed) { /* Terminal label. */
+ wire_len += 1;
+ }
+
+ return wire_len;
+}
+
+_public_
+size_t knot_dname_store(knot_dname_storage_t dst, const knot_dname_t *name)
+{
+ if (dst == NULL || name == NULL) {
+ return 0;
+ }
+
+ size_t len = knot_dname_size(name);
+ assert(len <= KNOT_DNAME_MAXLEN);
+ memcpy(dst, name, len);
+
+ return len;
+}
+
+_public_
+knot_dname_t *knot_dname_copy(const knot_dname_t *name, knot_mm_t *mm)
+{
+ if (name == NULL) {
+ return NULL;
+ }
+
+ size_t len = knot_dname_size(name);
+ knot_dname_t *dst = mm_alloc(mm, len);
+ if (dst == NULL) {
+ return NULL;
+ }
+ memcpy(dst, name, len);
+
+ return dst;
+}
+
+_public_
+int knot_dname_to_wire(uint8_t *dst, const knot_dname_t *src, size_t maxlen)
+{
+ if (dst == NULL || src == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ size_t len = knot_dname_size(src);
+ if (len > maxlen) {
+ return KNOT_ESPACE;
+ }
+ memcpy(dst, src, len);
+
+ return len;
+}
+
+_public_
+int knot_dname_unpack(uint8_t *dst, const knot_dname_t *src,
+ size_t maxlen, const uint8_t *pkt)
+{
+ if (dst == NULL || src == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ /* Seek first real label occurrence. */
+ src = knot_wire_seek_label(src, pkt);
+
+ /* Unpack rest of the labels. */
+ int len = 0;
+ while (*src != '\0') {
+ uint8_t lblen = *src + 1;
+ if (len + lblen > maxlen) {
+ return KNOT_ESPACE;
+ }
+ memcpy(dst + len, src, lblen);
+ len += lblen;
+ src = knot_wire_next_label(src, pkt);
+ }
+
+ /* Terminal label */
+ if (len + 1 > maxlen) {
+ return KNOT_EINVAL;
+ }
+
+ *(dst + len) = '\0';
+ return len + 1;
+}
+
+_public_
+char *knot_dname_to_str(char *dst, const knot_dname_t *name, size_t maxlen)
+{
+ if (name == NULL) {
+ return NULL;
+ }
+
+ size_t dname_size = knot_dname_size(name);
+
+ /* Check the size for len(dname) + 1 char termination. */
+ size_t alloc_size = (dst == NULL) ? dname_size + 1 : maxlen;
+ if (alloc_size < dname_size + 1) {
+ return NULL;
+ }
+
+ char *res = (dst == NULL) ? malloc(alloc_size) : dst;
+ if (res == NULL) {
+ return NULL;
+ }
+
+ uint8_t label_len = 0;
+ size_t str_len = 0;
+
+ for (unsigned i = 0; i < dname_size; i++) {
+ uint8_t c = name[i];
+
+ /* Read next label size. */
+ if (label_len == 0) {
+ label_len = c;
+
+ /* Write label separation. */
+ if (str_len > 0 || dname_size == 1) {
+ if (alloc_size <= str_len + 1) {
+ goto dname_to_str_failed;
+ }
+ res[str_len++] = '.';
+ }
+
+ continue;
+ }
+
+ if (is_alnum(c) || c == '-' || c == '_' || c == '*' ||
+ c == '/') {
+ if (alloc_size <= str_len + 1) {
+ goto dname_to_str_failed;
+ }
+ res[str_len++] = c;
+ } else if (is_punct(c) && c != '#') {
+ /* Exclusion of '#' character is to avoid possible
+ * collision with rdata hex notation '\#'. So it is
+ * encoded in \ddd notation.
+ */
+
+ if (dst != NULL) {
+ if (maxlen <= str_len + 2) {
+ goto dname_to_str_failed;
+ }
+ } else {
+ /* Extend output buffer for \x format. */
+ alloc_size += 1;
+ char *extended = realloc(res, alloc_size);
+ if (extended == NULL) {
+ goto dname_to_str_failed;
+ }
+ res = extended;
+ }
+
+ /* Write encoded character. */
+ res[str_len++] = '\\';
+ res[str_len++] = c;
+ } else {
+ if (dst != NULL) {
+ if (maxlen <= str_len + 4) {
+ goto dname_to_str_failed;
+ }
+ } else {
+ /* Extend output buffer for \DDD format. */
+ alloc_size += 3;
+ char *extended = realloc(res, alloc_size);
+ if (extended == NULL) {
+ goto dname_to_str_failed;
+ }
+ res = extended;
+ }
+
+ /* Write encoded character. */
+ int ret = snprintf(res + str_len, alloc_size - str_len,
+ "\\%03u", c);
+ if (ret <= 0 || ret >= alloc_size - str_len) {
+ goto dname_to_str_failed;
+ }
+
+ str_len += ret;
+ }
+
+ label_len--;
+ }
+
+ /* String_termination. */
+ assert(str_len < alloc_size);
+ res[str_len] = 0;
+
+ return res;
+
+dname_to_str_failed:
+
+ if (dst == NULL) {
+ free(res);
+ }
+
+ return NULL;
+}
+
+_public_
+knot_dname_t *knot_dname_from_str(uint8_t *dst, const char *name, size_t maxlen)
+{
+ if (name == NULL) {
+ return NULL;
+ }
+
+ size_t name_len = strlen(name);
+ if (name_len == 0) {
+ return NULL;
+ }
+
+ /* Wire size estimation. */
+ size_t alloc_size = maxlen;
+ if (dst == NULL) {
+ /* Check for the root label. */
+ if (name[0] == '.') {
+ /* Just the root dname can begin with a dot. */
+ if (name_len > 1) {
+ return NULL;
+ }
+ name_len = 0; /* Skip the following parsing. */
+ alloc_size = 1;
+ } else if (name[name_len - 1] != '.') { /* Check for non-FQDN. */
+ alloc_size = 1 + name_len + 1;
+ } else {
+ alloc_size = 1 + name_len ; /* + 1 ~ first label length. */
+ }
+ }
+
+ /* The minimal (root) dname takes 1 byte. */
+ if (alloc_size == 0) {
+ return NULL;
+ }
+
+ /* Check the maximal wire size. */
+ if (alloc_size > KNOT_DNAME_MAXLEN) {
+ alloc_size = KNOT_DNAME_MAXLEN;
+ }
+
+ /* Prepare output buffer. */
+ uint8_t *wire = (dst == NULL) ? malloc(alloc_size) : dst;
+ if (wire == NULL) {
+ return NULL;
+ }
+
+ uint8_t *label = wire;
+ uint8_t *wire_pos = wire + 1;
+ uint8_t *wire_end = wire + alloc_size;
+
+ /* Initialize the first label (root label). */
+ *label = 0;
+
+ const uint8_t *ch = (const uint8_t *)name;
+ const uint8_t *end = ch + name_len;
+
+ while (ch < end) {
+ /* Check the output buffer for enough space. */
+ if (wire_pos >= wire_end) {
+ goto dname_from_str_failed;
+ }
+
+ switch (*ch) {
+ case '.':
+ /* Check for invalid zero-length label. */
+ if (*label == 0 && name_len > 1) {
+ goto dname_from_str_failed;
+ }
+ label = wire_pos++;
+ *label = 0;
+ break;
+ case '\\':
+ ch++;
+
+ /* At least one more character is required OR
+ * check for maximal label length.
+ */
+ if (ch == end || ++(*label) > KNOT_DNAME_MAXLABELLEN) {
+ goto dname_from_str_failed;
+ }
+
+ /* Check for \DDD notation. */
+ if (is_digit(*ch)) {
+ /* Check for next two digits. */
+ if (ch + 2 >= end ||
+ !is_digit(*(ch + 1)) ||
+ !is_digit(*(ch + 2))) {
+ goto dname_from_str_failed;
+ }
+
+ uint32_t num = (*(ch + 0) - '0') * 100 +
+ (*(ch + 1) - '0') * 10 +
+ (*(ch + 2) - '0') * 1;
+ if (num > UINT8_MAX) {
+ goto dname_from_str_failed;
+ }
+ *(wire_pos++) = num;
+ ch +=2;
+ } else {
+ *(wire_pos++) = *ch;
+ }
+ break;
+ default:
+ /* Check for maximal label length. */
+ if (++(*label) > KNOT_DNAME_MAXLABELLEN) {
+ goto dname_from_str_failed;
+ }
+ *(wire_pos++) = *ch;
+ }
+ ch++;
+ }
+
+ /* Check for non-FQDN name. */
+ if (*label > 0) {
+ if (wire_pos >= wire_end) {
+ goto dname_from_str_failed;
+ }
+ *(wire_pos++) = 0;
+ }
+
+ /* Reduce output buffer if the size is overestimated. */
+ if (wire_pos < wire_end && dst == NULL) {
+ uint8_t *reduced = realloc(wire, wire_pos - wire);
+ if (reduced == NULL) {
+ goto dname_from_str_failed;
+ }
+ wire = reduced;
+ }
+
+ return wire;
+
+dname_from_str_failed:
+
+ if (dst == NULL) {
+ free(wire);
+ }
+
+ return NULL;
+}
+
+_public_
+void knot_dname_to_lower(knot_dname_t *name)
+{
+ if (name == NULL) {
+ return;
+ }
+
+ while (*name != '\0') {
+ uint8_t len = *name;
+ for (uint8_t i = 1; i <= len; ++i) {
+ name[i] = knot_tolower(name[i]);
+ }
+ name += 1 + len;
+ }
+}
+
+_public_
+size_t knot_dname_size(const knot_dname_t *name)
+{
+ if (name == NULL) {
+ return 0;
+ }
+
+ /* Count name size without terminal label. */
+ size_t len = 0;
+ while (*name != '\0' && !knot_wire_is_pointer(name)) {
+ uint8_t lblen = *name + 1;
+ len += lblen;
+ name += lblen;
+ }
+
+ if (knot_wire_is_pointer(name)) {
+ /* Add 2-octet compression pointer. */
+ return len + 2;
+ } else {
+ /* Add 1-octet terminal label. */
+ return len + 1;
+ }
+}
+
+_public_
+size_t knot_dname_realsize(const knot_dname_t *name, const uint8_t *pkt)
+{
+ if (name == NULL) {
+ return 0;
+ }
+
+ /* Seek first real label occurrence. */
+ name = knot_wire_seek_label(name, pkt);
+
+ size_t len = 0;
+ while (*name != '\0') {
+ len += *name + 1;
+ name = knot_wire_next_label(name, pkt);
+ }
+
+ /* Add 1-octet terminal label. */
+ return len + 1;
+}
+
+_public_
+size_t knot_dname_matched_labels(const knot_dname_t *d1, const knot_dname_t *d2)
+{
+ /* Count labels. */
+ size_t l1 = knot_dname_labels(d1, NULL);
+ size_t l2 = knot_dname_labels(d2, NULL);
+ if (l1 == 0 || l2 == 0) {
+ return 0;
+ }
+
+ /* Align end-to-end to common suffix. */
+ int common = dname_align(&d1, l1, &d2, l2);
+
+ /* Count longest chain leading to root label. */
+ size_t matched = 0;
+ while (common > 0) {
+ if (label_is_equal(d1, d2)) {
+ ++matched;
+ } else {
+ matched = 0; /* Broken chain. */
+ }
+
+ /* Next label. */
+ d1 = knot_wire_next_label(d1, NULL);
+ d2 = knot_wire_next_label(d2, NULL);
+ --common;
+ }
+
+ return matched;
+}
+
+_public_
+knot_dname_t *knot_dname_replace_suffix(const knot_dname_t *name, unsigned labels,
+ const knot_dname_t *suffix, knot_mm_t *mm)
+{
+ if (name == NULL) {
+ return NULL;
+ }
+
+ /* Calculate prefix and suffix lengths. */
+ size_t dname_lbs = knot_dname_labels(name, NULL);
+ if (dname_lbs < labels) {
+ return NULL;
+ }
+ size_t prefix_lbs = dname_lbs - labels;
+
+ size_t prefix_len = knot_dname_prefixlen(name, prefix_lbs, NULL);
+ size_t suffix_len = knot_dname_size(suffix);
+ if (prefix_len == 0 || suffix_len == 0) {
+ return NULL;
+ }
+
+ /* Create target name. */
+ size_t new_len = prefix_len + suffix_len;
+ knot_dname_t *out = mm_alloc(mm, new_len);
+ if (out == NULL) {
+ return NULL;
+ }
+
+ /* Copy prefix. */
+ uint8_t *dst = out;
+ while (prefix_lbs > 0) {
+ memcpy(dst, name, *name + 1);
+ dst += *name + 1;
+ name = knot_wire_next_label(name, NULL);
+ --prefix_lbs;
+ }
+
+ /* Copy suffix. */
+ while (*suffix != '\0') {
+ memcpy(dst, suffix, *suffix + 1);
+ dst += *suffix + 1;
+ suffix = knot_wire_next_label(suffix, NULL);
+ }
+
+ *dst = '\0';
+ return out;
+}
+
+_public_
+void knot_dname_free(knot_dname_t *name, knot_mm_t *mm)
+{
+ if (name == NULL) {
+ return;
+ }
+
+ mm_free(mm, name);
+}
+
+_public_
+int knot_dname_cmp(const knot_dname_t *d1, const knot_dname_t *d2)
+{
+ if (d1 == NULL) {
+ return -1;
+ } else if (d2 == NULL) {
+ return 1;
+ }
+
+ /* Convert to lookup format. */
+ knot_dname_storage_t lf1_storage;
+ knot_dname_storage_t lf2_storage;
+
+ uint8_t *lf1 = knot_dname_lf(d1, lf1_storage);
+ uint8_t *lf2 = knot_dname_lf(d2, lf2_storage);
+ assert(lf1 && lf2);
+
+ /* Compare common part. */
+ uint8_t common = lf1[0];
+ if (common > lf2[0]) {
+ common = lf2[0];
+ }
+ int ret = memcmp(lf1 + 1, lf2 + 1, common);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* If they match, compare lengths. */
+ if (lf1[0] < lf2[0]) {
+ return -1;
+ } else if (lf1[0] > lf2[0]) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+_public_
+bool knot_dname_is_equal(const knot_dname_t *d1, const knot_dname_t *d2)
+{
+ if (d1 == NULL || d2 == NULL) {
+ return false;
+ }
+
+ while (*d1 != '\0' || *d2 != '\0') {
+ if (label_is_equal(d1, d2)) {
+ d1 = knot_wire_next_label(d1, NULL);
+ d2 = knot_wire_next_label(d2, NULL);
+ } else {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+_public_
+size_t knot_dname_prefixlen(const uint8_t *name, unsigned nlabels, const uint8_t *pkt)
+{
+ if (name == NULL) {
+ return 0;
+ }
+
+ /* Zero labels means no prefix. */
+ if (nlabels == 0) {
+ return 0;
+ }
+
+ /* Seek first real label occurrence. */
+ name = knot_wire_seek_label(name, pkt);
+
+ size_t len = 0;
+ while (*name != '\0') {
+ len += *name + 1;
+ name = knot_wire_next_label(name, pkt);
+ if (--nlabels == 0) { /* Count N first labels only. */
+ break;
+ }
+ }
+
+ return len;
+}
+
+_public_
+size_t knot_dname_labels(const uint8_t *name, const uint8_t *pkt)
+{
+ if (name == NULL) {
+ return 0;
+ }
+
+ size_t count = 0;
+ while (*name != '\0') {
+ ++count;
+ name = knot_wire_next_label(name, pkt);
+ if (name == NULL) {
+ return 0;
+ }
+ }
+
+ return count;
+}
+
+_public_
+uint8_t *knot_dname_lf(const knot_dname_t *src, knot_dname_storage_t storage)
+{
+ if (src == NULL || storage == NULL) {
+ return NULL;
+ }
+
+ /* Writing from the end. */
+ storage[KNOT_DNAME_MAXLEN - 1] = '\0';
+ size_t idx = KNOT_DNAME_MAXLEN - 1;
+
+ while (*src != 0) {
+ size_t len = *src + 1;
+
+ assert(idx >= len);
+ idx -= len;
+ memcpy(&storage[idx], src, len);
+ storage[idx] = '\0';
+
+ src += len;
+ }
+
+ assert(KNOT_DNAME_MAXLEN >= 1 + idx);
+ storage[idx] = KNOT_DNAME_MAXLEN - 1 - idx;
+
+ return &storage[idx];
+}
+
+_public_
+int knot_dname_in_bailiwick(const knot_dname_t *name, const knot_dname_t *bailiwick)
+{
+ if (name == NULL || bailiwick == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int label_diff = knot_dname_labels(name, NULL) - knot_dname_labels(bailiwick, NULL);
+ if (label_diff < 0) {
+ return KNOT_EOUTOFZONE;
+ }
+
+ for (int i = 0; i < label_diff; ++i) {
+ name = knot_wire_next_label(name, NULL);
+ }
+
+ return knot_dname_is_equal(name, bailiwick) ? label_diff : KNOT_EOUTOFZONE;
+}
diff --git a/src/libknot/dname.h b/src/libknot/dname.h
new file mode 100644
index 0000000..c701610
--- /dev/null
+++ b/src/libknot/dname.h
@@ -0,0 +1,328 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief Domain name structure and API for manipulating it.
+ *
+ * \addtogroup dname
+ * @{
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "libknot/attribute.h"
+#include "libknot/consts.h"
+#include "libknot/mm_ctx.h"
+
+/*! \brief Type representing a domain name in wire format. */
+typedef uint8_t knot_dname_t;
+
+/*! \brief Local domain name storage. */
+typedef uint8_t knot_dname_storage_t[KNOT_DNAME_MAXLEN];
+
+/*!
+ * \brief Check dname on the wire for constraints.
+ *
+ * If the name passes such checks, it is safe to be used in rest of the functions.
+ *
+ * \param name Name on the wire.
+ * \param endp Name boundary.
+ * \param pkt Wire.
+ *
+ * \retval (compressed) size of the domain name.
+ * \retval KNOT_EINVAL
+ * \retval KNOT_EMALF
+ */
+_pure_ _mustcheck_
+int knot_dname_wire_check(const uint8_t *name, const uint8_t *endp,
+ const uint8_t *pkt);
+
+/*!
+ * \brief Duplicates the given domain name to a local storage.
+ *
+ * \param dst Destination storage.
+ * \param name Domain name to be copied.
+ *
+ * \retval size of the domain name.
+ * \retval 0 if invalid argument.
+ */
+_mustcheck_
+size_t knot_dname_store(knot_dname_storage_t dst, const knot_dname_t *name);
+
+/*!
+ * \brief Duplicates the given domain name.
+ *
+ * \param name Domain name to be copied.
+ * \param mm Memory context.
+ *
+ * \return New domain name which is an exact copy of \a name.
+ */
+_mustcheck_
+knot_dname_t *knot_dname_copy(const knot_dname_t *name, knot_mm_t *mm);
+
+/*!
+ * \brief Copy name to wire as is, no compression pointer expansion will be done.
+ *
+ * \param dst Destination wire.
+ * \param src Source name.
+ * \param maxlen Maximum wire length.
+ *
+ * \return the number of bytes written or negative error code
+ */
+int knot_dname_to_wire(uint8_t *dst, const knot_dname_t *src, size_t maxlen);
+
+/*!
+ * \brief Write unpacked name (i.e. compression pointers expanded)
+ *
+ * \note The function is very similar to the knot_dname_to_wire(), except
+ * it expands compression pointers. E.g. you want to use knot_dname_unpack()
+ * if you copy a dname from incoming packet to some persistent storage.
+ * And you want to use knot_dname_to_wire() if you know the name is not
+ * compressed or you want to copy it 1:1.
+ *
+ * \param dst Destination wire.
+ * \param src Source name.
+ * \param maxlen Maximum destination wire size.
+ * \param pkt Name packet wire (for compression pointers).
+ *
+ * \return number of bytes written
+ */
+int knot_dname_unpack(uint8_t *dst, const knot_dname_t *src,
+ size_t maxlen, const uint8_t *pkt);
+
+/*!
+ * \brief Converts the given domain name to its string representation.
+ *
+ * \note Output buffer is allocated automatically if dst is NULL.
+ *
+ * \param dst Output buffer.
+ * \param name Domain name to be converted.
+ * \param maxlen Output buffer length.
+ *
+ * \return 0-terminated string if successful, NULL if error.
+ */
+char *knot_dname_to_str(char *dst, const knot_dname_t *name, size_t maxlen);
+
+/*!
+ * \brief This function is a shortcut for \ref knot_dname_to_str with
+ * no output buffer parameters.
+ */
+_mustcheck_
+static inline char *knot_dname_to_str_alloc(const knot_dname_t *name)
+{
+ return knot_dname_to_str(NULL, name, 0);
+}
+
+/*!
+ * \brief Creates a dname structure from domain name given in presentation
+ * format.
+ *
+ * \note The resulting FQDN is stored in the wire format.
+ * \note Output buffer is allocated automatically if dst is NULL.
+ *
+ * \param dst Output buffer.
+ * \param name Domain name in presentation format (labels separated by dots,
+ * '\0' terminated).
+ * \param maxlen Output buffer length.
+ *
+ * \return New dname if successful, NULL if error.
+ */
+knot_dname_t *knot_dname_from_str(uint8_t *dst, const char *name, size_t maxlen);
+
+/*!
+ * \brief This function is a shortcut for \ref knot_dname_from_str with
+ * no output buffer parameters.
+ */
+_mustcheck_
+static inline knot_dname_t *knot_dname_from_str_alloc(const char *name)
+{
+ return knot_dname_from_str(NULL, name, 0);
+}
+
+/*!
+ * \brief Convert name to lowercase.
+ *
+ * \param name Domain name to be converted.
+ */
+void knot_dname_to_lower(knot_dname_t *name);
+
+/*!
+ * \brief Returns size of the given domain name.
+ *
+ * \note If the domain name is compressed, the length of not compressed part
+ * is returned.
+ *
+ * \param name Domain name to get the size of.
+ *
+ * \retval size of the domain name.
+ * \retval 0 if invalid argument.
+ */
+_pure_
+size_t knot_dname_size(const knot_dname_t *name);
+
+/*!
+ * \brief Returns full size of the given domain name (expanded compression ptrs).
+ *
+ * \param name Domain name to get the size of.
+ * \param pkt Related packet (or NULL if unpacked)
+ *
+ * \retval size of the domain name.
+ * \retval 0 if invalid argument.
+ */
+_pure_
+size_t knot_dname_realsize(const knot_dname_t *name, const uint8_t *pkt);
+
+/*!
+ * \brief Checks if the domain name is a wildcard.
+ *
+ * \param name Domain name to check.
+ *
+ * \retval true if \a dname is a wildcard domain name.
+ * \retval false otherwise.
+ */
+static inline
+bool knot_dname_is_wildcard(const knot_dname_t *name)
+{
+ return name != NULL && name[0] == 1 && name[1] == '*';
+}
+
+/*!
+ * \brief Returns the number of labels common for the two domain names (counted
+ * from the rightmost label.
+ *
+ * \param d1 First domain name.
+ * \param d2 Second domain name.
+ *
+ * \return Number of labels common for the two domain names.
+ */
+_pure_
+size_t knot_dname_matched_labels(const knot_dname_t *d1, const knot_dname_t *d2);
+
+/*!
+ * \brief Replaces the suffix of given size in one domain name with other domain
+ * name.
+ *
+ * \param name Domain name where to replace the suffix.
+ * \param labels Size of the suffix to be replaced.
+ * \param suffix New suffix to be used as a replacement.
+ * \param mm Memory context.
+ *
+ * \return New domain name created by replacing suffix of \a dname of size
+ * \a size with \a suffix.
+ */
+_mustcheck_
+knot_dname_t *knot_dname_replace_suffix(const knot_dname_t *name, unsigned labels,
+ const knot_dname_t *suffix, knot_mm_t *mm);
+
+/*!
+ * \brief Destroys the given domain name.
+ *
+ * \param name Domain name to be destroyed.
+ * \param mm Memory context.
+ */
+void knot_dname_free(knot_dname_t *name, knot_mm_t *mm);
+
+/*!
+ * \brief Compares two domain names by labels (case sensitive).
+ *
+ * \param d1 First domain name.
+ * \param d2 Second domain name.
+ *
+ * \retval < 0 if \a d1 goes before \a d2 in canonical order.
+ * \retval > 0 if \a d1 goes after \a d2 in canonical order.
+ * \retval 0 if the domain names are identical.
+ */
+_pure_
+int knot_dname_cmp(const knot_dname_t *d1, const knot_dname_t *d2);
+
+/*!
+ * \brief Compares two domain names (case sensitive).
+ *
+ * \param d1 First domain name.
+ * \param d2 Second domain name.
+ *
+ * \retval true if the domain names are identical
+ * \retval false if the domain names are NOT identical
+ */
+_pure_
+bool knot_dname_is_equal(const knot_dname_t *d1, const knot_dname_t *d2);
+
+/*!
+ * \brief Count length of the N first labels.
+ *
+ * \param name Domain name.
+ * \param nlabels First N labels.
+ * \param pkt Related packet (or NULL if not compressed).
+ *
+ * \return Length of the prefix.
+ */
+_pure_
+size_t knot_dname_prefixlen(const uint8_t *name, unsigned nlabels, const uint8_t *pkt);
+
+/*!
+ * \brief Return number of labels in the domain name.
+ *
+ * Terminal nullbyte is not counted.
+ *
+ * \param name Domain name.
+ * \param pkt Related packet (or NULL if not compressed).
+ *
+ * \return Number of labels.
+ */
+_pure_
+size_t knot_dname_labels(const uint8_t *name, const uint8_t *pkt);
+
+/*!
+ * \brief Convert domain name from wire to the lookup format.
+ *
+ * Formats names from rightmost label to the leftmost, separated by the lowest
+ * possible character (\\x00). Sorting such formatted names also gives
+ * correct canonical order (for NSEC/NSEC3). The first byte of the output
+ * contains length of the output.
+ *
+ * Examples:
+ * Name: lake.example.com.
+ * Wire: \\x04lake\\x07example\\x03com\\x00
+ * Lookup: \\x11com\\x00example\\x00lake\\x00
+ *
+ * Name: .
+ * Wire: \\x00
+ * Lookup: \\x00
+ *
+ * \param src Source domain name.
+ * \param storage Memory to store converted name into. Don't use directly!
+ *
+ * \retval Lookup format if successful (pointer into the storage).
+ * \retval NULL on invalid parameters.
+ */
+uint8_t *knot_dname_lf(const knot_dname_t *src, knot_dname_storage_t storage);
+
+/*!
+ * \brief Check whether a domain name is under another one and how deep.
+ *
+ * \param name The longer name to check.
+ * \param bailiwick The shorter name to check.
+ *
+ * \retval >=0 a subdomain nested this many labels.
+ * \retval <0 not a subdomain (KNOT_EOUTOFZONE) or another error (KNOT_EINVAL).
+ */
+int knot_dname_in_bailiwick(const knot_dname_t *name, const knot_dname_t *bailiwick);
+
+/*! @} */
diff --git a/src/libknot/endian.h b/src/libknot/endian.h
new file mode 100644
index 0000000..30bdd77
--- /dev/null
+++ b/src/libknot/endian.h
@@ -0,0 +1,50 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief Endian dependent integer operations.
+ *
+ * \addtogroup wire
+ * @{
+ */
+
+#pragma once
+
+#if defined(__linux__) || defined(__gnu_hurd__) || \
+ (defined(__FreeBSD_kernel__) && defined(__GLIBC__))
+# include <endian.h>
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+# include <sys/endian.h>
+#elif defined(__OpenBSD__)
+# include <endian.h>
+#elif defined(__APPLE__)
+# include <libkern/OSByteOrder.h>
+# define be16toh(x) OSSwapBigToHostInt16(x)
+# define be32toh(x) OSSwapBigToHostInt32(x)
+# define be64toh(x) OSSwapBigToHostInt64(x)
+# define htobe16(x) OSSwapHostToBigInt16(x)
+# define htobe32(x) OSSwapHostToBigInt32(x)
+# define htobe64(x) OSSwapHostToBigInt64(x)
+# define le16toh(x) OSSwapLittleToHostInt16(x)
+# define le32toh(x) OSSwapLittleToHostInt32(x)
+# define le64toh(x) OSSwapLittleToHostInt64(x)
+# define htole16(x) OSSwapHostToLittleInt16(x)
+# define htole32(x) OSSwapHostToLittleInt32(x)
+# define htole64(x) OSSwapHostToLittleInt64(x)
+#endif
+
+/*! @} */
diff --git a/src/libknot/errcode.h b/src/libknot/errcode.h
new file mode 100644
index 0000000..2fd1cea
--- /dev/null
+++ b/src/libknot/errcode.h
@@ -0,0 +1,203 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*!
+* \file
+*
+* \brief Knot error codes.
+*
+* \addtogroup libknot
+* @{
+*/
+
+#pragma once
+
+#include <errno.h>
+
+/*! \brief Error codes used in the library. */
+enum knot_error {
+ KNOT_EOK = 0,
+
+ /* Directly mapped error codes. */
+ KNOT_ENOMEM = -ENOMEM,
+ KNOT_EINVAL = -EINVAL,
+ KNOT_ENOTSUP = -ENOTSUP,
+ KNOT_EBUSY = -EBUSY,
+ KNOT_EAGAIN = -EAGAIN,
+ KNOT_EACCES = -EACCES,
+ KNOT_ECONNREFUSED = -ECONNREFUSED,
+ KNOT_EISCONN = -EISCONN,
+ KNOT_EADDRINUSE = -EADDRINUSE,
+ KNOT_ENOENT = -ENOENT,
+ KNOT_EEXIST = -EEXIST,
+ KNOT_ERANGE = -ERANGE,
+ KNOT_EADDRNOTAVAIL = -EADDRNOTAVAIL,
+
+ KNOT_ERROR_MIN = -1000,
+
+ /* General errors. */
+ KNOT_ERROR = KNOT_ERROR_MIN,
+ KNOT_EPARSEFAIL,
+ KNOT_ESEMCHECK,
+ KNOT_EUPTODATE,
+ KNOT_EFEWDATA,
+ KNOT_ESPACE,
+ KNOT_EMALF,
+ KNOT_ENSEC3PAR,
+ KNOT_ENSEC3CHAIN,
+ KNOT_EOUTOFZONE,
+ KNOT_EZONEINVAL,
+ KNOT_ENOZONE,
+ KNOT_ENONODE,
+ KNOT_ENORECORD,
+ KNOT_ENOMASTER,
+ KNOT_EPREREQ,
+ KNOT_ETTL,
+ KNOT_ENOXFR,
+ KNOT_EDENIED,
+ KNOT_ECONN,
+ KNOT_ETIMEOUT,
+ KNOT_ENODIFF,
+ KNOT_ENOTSIG,
+ KNOT_ELIMIT,
+ KNOT_EZONESIZE,
+ KNOT_EOF,
+ KNOT_ESYSTEM,
+ KNOT_EFILE,
+ KNOT_ESOAINVAL,
+ KNOT_ETRAIL,
+
+ /* Control states. */
+ KNOT_CTL_ESTOP,
+
+ /* Network errors. */
+ KNOT_NET_EADDR,
+ KNOT_NET_ESOCKET,
+ KNOT_NET_ECONNECT,
+ KNOT_NET_ESEND,
+ KNOT_NET_ERECV,
+ KNOT_NET_ETIMEOUT,
+
+ /* Encoding errors. */
+ KNOT_BASE64_ESIZE,
+ KNOT_BASE64_ECHAR,
+ KNOT_BASE32HEX_ESIZE,
+ KNOT_BASE32HEX_ECHAR,
+
+ /* TSIG errors. */
+ KNOT_TSIG_EBADSIG,
+ KNOT_TSIG_EBADKEY,
+ KNOT_TSIG_EBADTIME,
+ KNOT_TSIG_EBADTRUNC,
+
+ /* DNSSEC errors. */
+ KNOT_DNSSEC_EMISSINGKEYTYPE,
+ KNOT_DNSSEC_ENOKEY,
+
+ /* Yparser errors. */
+ KNOT_YP_ECHAR_TAB,
+ KNOT_YP_EINVAL_ITEM,
+ KNOT_YP_EINVAL_ID,
+ KNOT_YP_EINVAL_DATA,
+ KNOT_YP_EINVAL_INDENT,
+ KNOT_YP_ENOTSUP_DATA,
+ KNOT_YP_ENOTSUP_ID,
+ KNOT_YP_ENODATA,
+ KNOT_YP_ENOID,
+
+ /* Configuration errors. */
+ KNOT_CONF_ENOTINIT,
+ KNOT_CONF_EVERSION,
+ KNOT_CONF_EREDEFINE,
+
+ /* Transaction errors. */
+ KNOT_TXN_EEXISTS,
+ KNOT_TXN_ENOTEXISTS,
+
+ /* Processing error. */
+ KNOT_LAYER_ERROR,
+
+ /* DNSSEC errors. */
+ KNOT_INVALID_PUBLIC_KEY,
+ KNOT_INVALID_PRIVATE_KEY,
+ KNOT_INVALID_KEY_ALGORITHM,
+ KNOT_INVALID_KEY_SIZE,
+ KNOT_INVALID_KEY_ID,
+ KNOT_INVALID_KEY_NAME,
+ KNOT_NO_PUBLIC_KEY,
+ KNOT_NO_PRIVATE_KEY,
+
+ KNOT_ERROR_MAX = -501
+};
+
+/*!
+ * \brief Map POSIX errno code to Knot error code.
+ *
+ * \param code Errno code to transform (set -1 to use the current errno).
+ *
+ * \return Mapped errno or KNOT_ERROR if unknown.
+ */
+inline static int knot_map_errno_code(int code)
+{
+ if (code < 0) {
+ code = errno;
+ }
+
+ typedef struct {
+ int errno_code;
+ int libknot_code;
+ } err_table_t;
+
+ #define ERR_ITEM(name) { name, KNOT_##name }
+ static const err_table_t errno_to_errcode[] = {
+ ERR_ITEM(ENOMEM),
+ ERR_ITEM(EINVAL),
+ ERR_ITEM(ENOTSUP),
+ ERR_ITEM(EBUSY),
+ ERR_ITEM(EAGAIN),
+ ERR_ITEM(EACCES),
+ ERR_ITEM(ECONNREFUSED),
+ ERR_ITEM(EISCONN),
+ ERR_ITEM(EADDRINUSE),
+ ERR_ITEM(ENOENT),
+ ERR_ITEM(EEXIST),
+ ERR_ITEM(ERANGE),
+ ERR_ITEM(EADDRNOTAVAIL),
+
+ /* Terminator - default value. */
+ { 0, KNOT_ERROR }
+ };
+ #undef ERR_ITEM
+
+ const err_table_t *err = errno_to_errcode;
+
+ while (err->errno_code != 0 && err->errno_code != code) {
+ err++;
+ }
+
+ return err->libknot_code;
+}
+
+/*!
+ * \brief Get a POSIX errno mapped to Knot error code.
+ *
+ * \return Mapped errno or KNOT_ERROR if unknown.
+ */
+inline static int knot_map_errno(void)
+{
+ return knot_map_errno_code(-1);
+}
+
+/*! @} */
diff --git a/src/libknot/error.c b/src/libknot/error.c
new file mode 100644
index 0000000..1524b79
--- /dev/null
+++ b/src/libknot/error.c
@@ -0,0 +1,206 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <lmdb.h>
+
+#include "libknot/attribute.h"
+#include "libknot/error.h"
+#include "libdnssec/error.h"
+
+struct error {
+ int code;
+ const char *message;
+};
+
+static const struct error errors[] = {
+ { KNOT_EOK, "OK" },
+
+ /* Directly mapped error codes. */
+ { KNOT_ENOMEM, "not enough memory" },
+ { KNOT_EINVAL, "invalid parameter" },
+ { KNOT_ENOTSUP, "operation not supported" },
+ { KNOT_EBUSY, "requested resource is busy" },
+ { KNOT_EAGAIN, "OS lacked necessary resources" },
+ { KNOT_EACCES, "operation not permitted" },
+ { KNOT_ECONNREFUSED, "connection refused" },
+ { KNOT_EISCONN, "already connected" },
+ { KNOT_EADDRINUSE, "address already in use" },
+ { KNOT_ENOENT, "not exists" },
+ { KNOT_EEXIST, "already exists" },
+ { KNOT_ERANGE, "value is out of range" },
+ { KNOT_EADDRNOTAVAIL, "address is not available" },
+
+ /* General errors. */
+ { KNOT_ERROR, "failed" },
+ { KNOT_EPARSEFAIL, "parser failed" },
+ { KNOT_ESEMCHECK, "semantic check" },
+ { KNOT_EUPTODATE, "zone is up-to-date" },
+ { KNOT_EFEWDATA, "not enough data to parse" },
+ { KNOT_ESPACE, "not enough space provided" },
+ { KNOT_EMALF, "malformed data" },
+ { KNOT_ENSEC3PAR, "missing or wrong NSEC3PARAM record" },
+ { KNOT_ENSEC3CHAIN, "missing or wrong NSEC3 chain in the zone" },
+ { KNOT_EOUTOFZONE, "name does not belong to the zone" },
+ { KNOT_EZONEINVAL, "invalid zone file" },
+ { KNOT_ENOZONE, "no such zone found" },
+ { KNOT_ENONODE, "no such node in zone found" },
+ { KNOT_ENORECORD, "no such record in zone found" },
+ { KNOT_ENOMASTER, "no usable master" },
+ { KNOT_EPREREQ, "UPDATE prerequisity not met" },
+ { KNOT_ETTL, "TTL mismatch" },
+ { KNOT_ENOXFR, "transfer was not sent" },
+ { KNOT_EDENIED, "not allowed" },
+ { KNOT_ECONN, "connection reset" },
+ { KNOT_ETIMEOUT, "connection timeout" },
+ { KNOT_ENODIFF, "cannot create zone diff" },
+ { KNOT_ENOTSIG, "expected a TSIG or SIG(0)" },
+ { KNOT_ELIMIT, "exceeded response rate limit" },
+ { KNOT_EZONESIZE, "zone size exceeded" },
+ { KNOT_EOF, "end of file" },
+ { KNOT_ESYSTEM, "system error" },
+ { KNOT_EFILE, "file error" },
+ { KNOT_ESOAINVAL, "SOA mismatch" },
+ { KNOT_ETRAIL, "trailing data" },
+
+ /* Control states. */
+ { KNOT_CTL_ESTOP, "stopping server" },
+
+ /* Network errors. */
+ { KNOT_NET_EADDR, "bad address or host name" },
+ { KNOT_NET_ESOCKET, "can't create socket" },
+ { KNOT_NET_ECONNECT, "can't connect" },
+ { KNOT_NET_ESEND, "can't send data" },
+ { KNOT_NET_ERECV, "can't receive data" },
+ { KNOT_NET_ETIMEOUT, "network timeout" },
+
+ /* Encoding errors. */
+ { KNOT_BASE64_ESIZE, "invalid base64 string length" },
+ { KNOT_BASE64_ECHAR, "invalid base64 character" },
+ { KNOT_BASE32HEX_ESIZE, "invalid base32hex string length" },
+ { KNOT_BASE32HEX_ECHAR, "invalid base32hex character" },
+
+ /* TSIG errors. */
+ { KNOT_TSIG_EBADSIG, "failed to verify TSIG" },
+ { KNOT_TSIG_EBADKEY, "TSIG key not recognized or invalid" },
+ { KNOT_TSIG_EBADTIME, "TSIG out of time window" },
+ { KNOT_TSIG_EBADTRUNC, "TSIG bad truncation" },
+
+ /* DNSSEC errors. */
+ { KNOT_DNSSEC_ENOKEY, "no keys for signing" },
+ { KNOT_DNSSEC_EMISSINGKEYTYPE, "missing active KSK or ZSK" },
+
+ /* Yparser errors. */
+ { KNOT_YP_ECHAR_TAB, "tabulator character is not allowed" },
+ { KNOT_YP_EINVAL_ITEM, "invalid item" },
+ { KNOT_YP_EINVAL_ID, "invalid identifier" },
+ { KNOT_YP_EINVAL_DATA, "invalid value" },
+ { KNOT_YP_EINVAL_INDENT, "invalid indentation" },
+ { KNOT_YP_ENOTSUP_DATA, "value not supported" },
+ { KNOT_YP_ENOTSUP_ID, "identifier not supported" },
+ { KNOT_YP_ENODATA, "missing value" },
+ { KNOT_YP_ENOID, "missing identifier" },
+
+ /* Configuration errors. */
+ { KNOT_CONF_ENOTINIT, "config DB not initialized" },
+ { KNOT_CONF_EVERSION, "invalid config DB version" },
+ { KNOT_CONF_EREDEFINE, "duplicate identifier" },
+
+ /* Transaction errors. */
+ { KNOT_TXN_EEXISTS, "too many transactions" },
+ { KNOT_TXN_ENOTEXISTS, "no active transaction" },
+
+ /* Processing errors. */
+ { KNOT_LAYER_ERROR, "processing layer error" },
+
+ /* DNSSEC errors. */
+ { KNOT_INVALID_PUBLIC_KEY, "invalid public key" },
+ { KNOT_INVALID_PRIVATE_KEY, "invalid private key" },
+ { KNOT_INVALID_KEY_ALGORITHM, "invalid key algorithm" },
+ { KNOT_INVALID_KEY_SIZE, "invalid key size" },
+ { KNOT_INVALID_KEY_ID, "invalid key ID" },
+ { KNOT_INVALID_KEY_NAME, "invalid key name" },
+ { KNOT_NO_PUBLIC_KEY, "no public key" },
+ { KNOT_NO_PRIVATE_KEY, "no private key" },
+
+ { KNOT_ERROR, NULL } /* Terminator */
+};
+
+/*!
+ * \brief Lookup error message by error code.
+ */
+static const char *lookup_message(int code)
+{
+ for (const struct error *e = errors; e->message; e++) {
+ if (e->code == code) {
+ return e->message;
+ }
+ }
+
+ return NULL;
+}
+
+_public_
+int knot_error_from_libdnssec(int libdnssec_errcode)
+{
+ switch (libdnssec_errcode) {
+ case DNSSEC_ERROR:
+ return KNOT_ERROR;
+ case DNSSEC_MALFORMED_DATA:
+ return KNOT_EMALF;
+ case DNSSEC_NOT_FOUND:
+ return KNOT_ENOENT;
+ case DNSSEC_NO_PUBLIC_KEY:
+ case DNSSEC_NO_PRIVATE_KEY:
+ return KNOT_DNSSEC_ENOKEY;
+ // EOK, EINVAL, ENOMEM and ENOENT are identical, no need to translate
+ case DNSSEC_INVALID_PUBLIC_KEY ... DNSSEC_INVALID_KEY_NAME:
+ return libdnssec_errcode
+ - DNSSEC_INVALID_PUBLIC_KEY + KNOT_INVALID_PUBLIC_KEY;
+ default:
+ return libdnssec_errcode;
+ }
+}
+
+_public_
+const char *knot_strerror(int code)
+{
+ const char *msg;
+
+ switch (code) {
+ case INT_MIN: // Cannot convert to a positive value.
+ code = KNOT_ERROR;
+ // FALLTHROUGH
+ case KNOT_ERROR_MIN ... KNOT_EOK:
+ msg = lookup_message(code); break;
+ case DNSSEC_ERROR_MIN ... DNSSEC_ERROR_MAX:
+ msg = dnssec_strerror(code); break;
+ case MDB_KEYEXIST ... MDB_LAST_ERRCODE:
+ msg = mdb_strerror(code); break;
+ default:
+ msg = NULL;
+ }
+
+ if (msg != NULL) {
+ return msg;
+ } else {
+ // strerror_r would be better but it requires thread local storage.
+ return strerror(abs(code));
+ }
+}
diff --git a/src/libknot/error.h b/src/libknot/error.h
new file mode 100644
index 0000000..26fdddc
--- /dev/null
+++ b/src/libknot/error.h
@@ -0,0 +1,49 @@
+/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*!
+* \file
+*
+* \brief Error codes and function for getting error message.
+*
+* \addtogroup libknot
+* @{
+*/
+
+#pragma once
+
+#include "libknot/errcode.h"
+
+/*!
+ * \brief Returns error message for the given error code.
+ *
+ * \param code Error code.
+ *
+ * \return String containing the error message.
+ */
+const char *knot_strerror(int code);
+
+/*!
+ * \brief Translates error code from libdnssec into libknot.
+ *
+ * This is just temporary until everything from libdnssec moved to libknot.
+ *
+ * \param libdnssec_errcode Error code from libdnssec
+ *
+ * \return Error code.
+ */
+int knot_error_from_libdnssec(int libdnssec_errcode);
+
+/*! @} */
diff --git a/src/libknot/libknot.h b/src/libknot/libknot.h
new file mode 100644
index 0000000..472fb8d
--- /dev/null
+++ b/src/libknot/libknot.h
@@ -0,0 +1,65 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief Convenience header for including whole library.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+
+#pragma once
+
+#include "libknot/version.h"
+#include "libknot/cookies.h"
+#include "libknot/codes.h"
+#include "libknot/consts.h"
+#include "libknot/descriptor.h"
+#include "libknot/dname.h"
+#include "libknot/endian.h"
+#include "libknot/errcode.h"
+#include "libknot/error.h"
+#include "libknot/lookup.h"
+#include "libknot/mm_ctx.h"
+#include "libknot/rdata.h"
+#include "libknot/rdataset.h"
+#include "libknot/rrset-dump.h"
+#include "libknot/rrset.h"
+#include "libknot/tsig-op.h"
+#include "libknot/tsig.h"
+#include "libknot/control/control.h"
+#include "libknot/db/db.h"
+#include "libknot/db/db_lmdb.h"
+#include "libknot/db/db_trie.h"
+#include "libknot/packet/compr.h"
+#include "libknot/packet/pkt.h"
+#include "libknot/packet/rrset-wire.h"
+#include "libknot/packet/wire.h"
+#include "libknot/rrtype/dnskey.h"
+#include "libknot/rrtype/ds.h"
+#include "libknot/rrtype/naptr.h"
+#include "libknot/rrtype/nsec.h"
+#include "libknot/rrtype/nsec3.h"
+#include "libknot/rrtype/nsec3param.h"
+#include "libknot/rrtype/opt.h"
+#include "libknot/rrtype/rdname.h"
+#include "libknot/rrtype/rrsig.h"
+#include "libknot/rrtype/soa.h"
+#include "libknot/rrtype/tsig.h"
+#include "libknot/wire.h"
+
+/*! @} */
diff --git a/src/libknot/lookup.h b/src/libknot/lookup.h
new file mode 100644
index 0000000..709713e
--- /dev/null
+++ b/src/libknot/lookup.h
@@ -0,0 +1,88 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief A general purpose lookup table.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+
+#pragma once
+
+#include <string.h>
+#include <strings.h>
+
+/*!
+ * \brief A general purpose lookup table.
+ */
+typedef struct knot_lookup {
+ int id;
+ const char *name;
+} knot_lookup_t;
+
+/*!
+ * \brief Looks up the given name in the lookup table.
+ *
+ * \param table Lookup table.
+ * \param name Name to look up.
+ *
+ * \return Item in the lookup table with the given name or NULL if no such is
+ * present.
+ */
+inline static const knot_lookup_t *knot_lookup_by_name(const knot_lookup_t *table, const char *name)
+{
+ if (table == NULL || name == NULL) {
+ return NULL;
+ }
+
+ while (table->name != NULL) {
+ if (strcasecmp(name, table->name) == 0) {
+ return table;
+ }
+ table++;
+ }
+
+ return NULL;
+}
+
+/*!
+ * \brief Looks up the given id in the lookup table.
+ *
+ * \param table Lookup table.
+ * \param id ID to look up.
+ *
+ * \return Item in the lookup table with the given id or NULL if no such is
+ * present.
+ */
+inline static const knot_lookup_t *knot_lookup_by_id(const knot_lookup_t *table, int id)
+{
+ if (table == NULL) {
+ return NULL;
+ }
+
+ while (table->name != NULL) {
+ if (table->id == id) {
+ return table;
+ }
+ table++;
+ }
+
+ return NULL;
+}
+
+/*! @} */
diff --git a/src/libknot/mm_ctx.h b/src/libknot/mm_ctx.h
new file mode 100644
index 0000000..1d0de70
--- /dev/null
+++ b/src/libknot/mm_ctx.h
@@ -0,0 +1,40 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief Memory allocation context.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+
+#pragma once
+
+#include <stddef.h>
+
+/* Memory allocation function prototypes. */
+typedef void* (*knot_mm_alloc_t)(void *ctx, size_t len);
+typedef void (*knot_mm_free_t)(void *p);
+
+/*! \brief Memory allocation context. */
+typedef struct knot_mm {
+ void *ctx; /* \note Must be first */
+ knot_mm_alloc_t alloc;
+ knot_mm_free_t free;
+} knot_mm_t;
+
+/*! @} */
diff --git a/src/libknot/packet/compr.h b/src/libknot/packet/compr.h
new file mode 100644
index 0000000..22c4a8e
--- /dev/null
+++ b/src/libknot/packet/compr.h
@@ -0,0 +1,100 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief Name compression API.
+ *
+ * \addtogroup pkt
+ * @{
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#include "libknot/packet/wire.h"
+
+/*! \brief Compression hint type. */
+enum knot_compr_hint {
+ KNOT_COMPR_HINT_NONE = 0, /* No hint. */
+ KNOT_COMPR_HINT_NOCOMP = 1, /* Don't compress. */
+ KNOT_COMPR_HINT_QNAME = KNOT_WIRE_HEADER_SIZE /* Name is QNAME. */
+};
+
+/*! \brief Compression hint array offsets. */
+enum knot_compr_offset {
+ KNOT_COMPR_HINT_OWNER = 0, /* First element in the array is RR owner. */
+ KNOT_COMPR_HINT_RDATA = 1, /* First name in RDATA is at offset 1. */
+ KNOT_COMPR_HINT_COUNT = 16 /* Maximum number of stored hints per-RR. */
+};
+
+/*
+ * \note A little bit about how compression hints work.
+ *
+ * We're storing a RRSet say 'abcd. CNAME [0]net. [1]com.' (owner=abcd. 2 RRs).
+ * The owner 'abcd.' is same for both RRs, we put it at the offset 0 in rrinfo.compress_ptr
+ * The names 'net.' and 'com.' are in the RDATA, therefore go to offsets 1 and 2.
+ * Now this is useful when solving additionals for example, because we can scan
+ * rrinfo for this RRSet and we know that 'net.' name is at the hint 1 and that leads
+ * to packet position N. With that, we just put the pointer in without any calculation.
+ * This is also useful for positive answers, where we know the RRSet owner is always QNAME.
+ * All in all, we just remember the positions of written domain names.
+ */
+
+/*! \brief Additional information about RRSet position and compression hints. */
+typedef struct {
+ uint16_t pos; /* RRSet position in the packet. */
+ uint16_t flags; /* RRSet flags. */
+ uint16_t compress_ptr[KNOT_COMPR_HINT_COUNT]; /* Array of compr. ptr hints. */
+} knot_rrinfo_t;
+
+/*!
+ * \brief Name compression context.
+ */
+typedef struct knot_compr {
+ uint8_t *wire; /* Packet wireformat. */
+ knot_rrinfo_t *rrinfo; /* Hints for current RRSet. */
+ struct {
+ uint16_t pos; /* Position of current suffix. */
+ uint8_t labels; /* Label count of the suffix. */
+ } suffix;
+} knot_compr_t;
+
+/*!
+ * \brief Retrieve compression hint from given offset.
+ */
+static inline uint16_t knot_compr_hint(const knot_rrinfo_t *info, uint16_t hint_id)
+{
+ if (hint_id < KNOT_COMPR_HINT_COUNT) {
+ return info->compress_ptr[hint_id];
+ } else {
+ return KNOT_COMPR_HINT_NONE;
+ }
+}
+
+/*!
+ * \brief Store compression hint for given offset.
+ */
+static inline void knot_compr_hint_set(knot_rrinfo_t *info, uint16_t hint_id,
+ uint16_t val, uint16_t len)
+{
+ if ((hint_id < KNOT_COMPR_HINT_COUNT) && (val + len < KNOT_WIRE_PTR_MAX)) {
+ info->compress_ptr[hint_id] = val;
+ }
+}
+
+/*! @} */
diff --git a/src/libknot/packet/pkt.c b/src/libknot/packet/pkt.c
new file mode 100644
index 0000000..602d70d
--- /dev/null
+++ b/src/libknot/packet/pkt.c
@@ -0,0 +1,826 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include "libknot/attribute.h"
+#include "libknot/packet/pkt.h"
+#include "libknot/codes.h"
+#include "libknot/descriptor.h"
+#include "libknot/errcode.h"
+#include "libknot/rrtype/tsig.h"
+#include "libknot/tsig-op.h"
+#include "libknot/packet/wire.h"
+#include "libknot/packet/rrset-wire.h"
+#include "libknot/wire.h"
+#include "contrib/mempattern.h"
+#include "contrib/wire_ctx.h"
+
+/*! \brief Packet RR array growth step. */
+#define NEXT_RR_ALIGN 16
+#define NEXT_RR_COUNT(count) (((count) / NEXT_RR_ALIGN + 1) * NEXT_RR_ALIGN)
+
+/*! \brief Scan packet for RRSet existence. */
+static bool pkt_contains(const knot_pkt_t *packet, const knot_rrset_t *rrset)
+{
+ assert(packet);
+ assert(rrset);
+
+ for (int i = 0; i < packet->rrset_count; ++i) {
+ const uint16_t type = packet->rr[i].type;
+ const knot_rdata_t *data = packet->rr[i].rrs.rdata;
+ if (type == rrset->type && data == rrset->rrs.rdata) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/*! \brief Free all RRSets and reset RRSet count. */
+static void pkt_free_data(knot_pkt_t *pkt)
+{
+ assert(pkt);
+
+ /* Free RRSets if applicable. */
+ for (uint16_t i = 0; i < pkt->rrset_count; ++i) {
+ if (pkt->rr_info[i].flags & KNOT_PF_FREE) {
+ knot_rrset_clear(&pkt->rr[i], &pkt->mm);
+ }
+ }
+ pkt->rrset_count = 0;
+
+ /* Free EDNS option positions. */
+ mm_free(&pkt->mm, pkt->edns_opts);
+ pkt->edns_opts = 0;
+}
+
+/*! \brief Allocate new wireformat of given length. */
+static int pkt_wire_alloc(knot_pkt_t *pkt, uint16_t len)
+{
+ assert(pkt);
+
+ if (len < KNOT_WIRE_HEADER_SIZE) {
+ return KNOT_ERANGE;
+ }
+
+ pkt->wire = mm_alloc(&pkt->mm, len);
+ if (pkt->wire == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ pkt->flags |= KNOT_PF_FREE;
+ pkt->max_size = len;
+
+ knot_pkt_clear(pkt);
+
+ return KNOT_EOK;
+}
+
+/*! \brief Set packet wireformat to an existing memory. */
+static void pkt_wire_set(knot_pkt_t *pkt, void *wire, uint16_t len)
+{
+ assert(pkt);
+
+ pkt->wire = wire;
+ pkt->size = pkt->max_size = len;
+ pkt->parsed = 0;
+}
+
+/*! \brief Calculate remaining size in the packet. */
+static uint16_t pkt_remaining(knot_pkt_t *pkt)
+{
+ assert(pkt);
+
+ return pkt->max_size - pkt->size - pkt->reserved;
+}
+
+/*! \brief Return RR count for given section (from wire xxCOUNT in header). */
+static uint16_t pkt_rr_wirecount(knot_pkt_t *pkt, knot_section_t section_id)
+{
+ assert(pkt);
+ switch (section_id) {
+ case KNOT_ANSWER: return knot_wire_get_ancount(pkt->wire);
+ case KNOT_AUTHORITY: return knot_wire_get_nscount(pkt->wire);
+ case KNOT_ADDITIONAL: return knot_wire_get_arcount(pkt->wire);
+ default: assert(0); return 0;
+ }
+}
+
+/*! \brief Update RR count for given section (wire xxCOUNT in header). */
+static void pkt_rr_wirecount_add(knot_pkt_t *pkt, knot_section_t section_id,
+ int16_t val)
+{
+ assert(pkt);
+ switch (section_id) {
+ case KNOT_ANSWER: knot_wire_add_ancount(pkt->wire, val); break;
+ case KNOT_AUTHORITY: knot_wire_add_nscount(pkt->wire, val); break;
+ case KNOT_ADDITIONAL: knot_wire_add_arcount(pkt->wire, val); break;
+ }
+}
+
+/*! \brief Reserve enough space in the RR arrays. */
+static int pkt_rr_array_alloc(knot_pkt_t *pkt, uint16_t count)
+{
+ /* Enough space. */
+ if (pkt->rrset_allocd >= count) {
+ return KNOT_EOK;
+ }
+
+ /* Allocate rr_info and rr fields to next size. */
+ size_t next_size = NEXT_RR_COUNT(count);
+ knot_rrinfo_t *rr_info = mm_alloc(&pkt->mm, sizeof(knot_rrinfo_t) * next_size);
+ if (rr_info == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ knot_rrset_t *rr = mm_alloc(&pkt->mm, sizeof(knot_rrset_t) * next_size);
+ if (rr == NULL) {
+ mm_free(&pkt->mm, rr_info);
+ return KNOT_ENOMEM;
+ }
+
+ /* Copy the old data. */
+ memcpy(rr_info, pkt->rr_info, pkt->rrset_allocd * sizeof(knot_rrinfo_t));
+ memcpy(rr, pkt->rr, pkt->rrset_allocd * sizeof(knot_rrset_t));
+
+ /* Reassign and free old data. */
+ mm_free(&pkt->mm, pkt->rr);
+ mm_free(&pkt->mm, pkt->rr_info);
+ pkt->rr = rr;
+ pkt->rr_info = rr_info;
+ pkt->rrset_allocd = next_size;
+
+ return KNOT_EOK;
+}
+
+static void compr_clear(knot_compr_t *compr)
+{
+ compr->rrinfo = NULL;
+ compr->suffix.pos = 0;
+ compr->suffix.labels = 0;
+}
+
+static void compr_init(knot_compr_t *compr, uint8_t *wire)
+{
+ compr_clear(compr);
+ compr->wire = wire;
+}
+
+/*! \brief Clear the packet and switch wireformat pointers (possibly allocate new). */
+static int pkt_init(knot_pkt_t *pkt, void *wire, uint16_t len, knot_mm_t *mm)
+{
+ assert(pkt);
+
+ memset(pkt, 0, sizeof(knot_pkt_t));
+
+ /* No data to free, set memory context. */
+ memcpy(&pkt->mm, mm, sizeof(knot_mm_t));
+
+ /* Initialize wire. */
+ int ret = KNOT_EOK;
+ if (wire == NULL) {
+ ret = pkt_wire_alloc(pkt, len);
+ } else {
+ pkt_wire_set(pkt, wire, len);
+ }
+
+ /* Initialize compression context. */
+ compr_init(&pkt->compr, pkt->wire);
+
+ return ret;
+}
+
+/*! \brief Reset packet parse state. */
+static void sections_reset(knot_pkt_t *pkt)
+{
+ pkt->current = KNOT_ANSWER;
+ memset(pkt->sections, 0, sizeof(pkt->sections));
+ (void)knot_pkt_begin(pkt, KNOT_ANSWER);
+}
+
+/*! \brief Allocate new packet using memory context. */
+static knot_pkt_t *pkt_new_mm(void *wire, uint16_t len, knot_mm_t *mm)
+{
+ assert(mm);
+
+ knot_pkt_t *pkt = mm_alloc(mm, sizeof(knot_pkt_t));
+ if (pkt == NULL) {
+ return NULL;
+ }
+
+ if (pkt_init(pkt, wire, len, mm) != KNOT_EOK) {
+ mm_free(mm, pkt);
+ return NULL;
+ }
+
+ return pkt;
+}
+
+_public_
+knot_pkt_t *knot_pkt_new(void *wire, uint16_t len, knot_mm_t *mm)
+{
+ /* Default memory allocator if NULL. */
+ knot_mm_t _mm;
+ if (mm == NULL) {
+ mm_ctx_init(&_mm);
+ mm = &_mm;
+ }
+
+ return pkt_new_mm(wire, len, mm);
+}
+
+static int append_tsig(knot_pkt_t *dst, const knot_pkt_t *src)
+{
+ /* Check if a wire TSIG is available. */
+ if (src->tsig_wire.pos != NULL) {
+ if (dst->max_size < src->size + src->tsig_wire.len) {
+ return KNOT_ESPACE;
+ }
+ memcpy(dst->wire + dst->size, src->tsig_wire.pos,
+ src->tsig_wire.len);
+ dst->size += src->tsig_wire.len;
+
+ /* Increment arcount. */
+ knot_wire_set_arcount(dst->wire,
+ knot_wire_get_arcount(dst->wire) + 1);
+ } else {
+ return knot_tsig_append(dst->wire, &dst->size, dst->max_size,
+ src->tsig_rr);
+ }
+
+ return KNOT_EOK;
+}
+
+_public_
+int knot_pkt_copy(knot_pkt_t *dst, const knot_pkt_t *src)
+{
+ if (dst == NULL || src == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ if (dst->max_size < src->size) {
+ return KNOT_ESPACE;
+ }
+ memcpy(dst->wire, src->wire, src->size);
+ dst->size = src->size;
+
+ /* Append TSIG record. */
+ if (src->tsig_rr) {
+ int ret = append_tsig(dst, src);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ /* Invalidate arrays. */
+ dst->rr = NULL;
+ dst->rr_info = NULL;
+ dst->rrset_count = 0;
+ dst->rrset_allocd = 0;
+
+ /* @note This could be done more effectively if needed. */
+ return knot_pkt_parse(dst, 0);
+}
+
+static void payload_clear(knot_pkt_t *pkt)
+{
+ assert(pkt);
+
+ /* Keep question. */
+ pkt->parsed = 0;
+ pkt->reserved = 0;
+
+ /* Free RRSets if applicable. */
+ pkt_free_data(pkt);
+
+ /* Reset sections. */
+ sections_reset(pkt);
+
+ /* Reset special types. */
+ pkt->opt_rr = NULL;
+ pkt->tsig_rr = NULL;
+
+ /* Reset TSIG wire reference. */
+ pkt->tsig_wire.pos = NULL;
+ pkt->tsig_wire.len = 0;
+}
+
+_public_
+int knot_pkt_init_response(knot_pkt_t *pkt, const knot_pkt_t *query)
+{
+ if (pkt == NULL || query == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ /* Header + question size. */
+ size_t base_size = KNOT_WIRE_HEADER_SIZE + knot_pkt_question_size(query);
+ if (base_size > pkt->max_size) {
+ return KNOT_ESPACE;
+ }
+
+ pkt->size = base_size;
+ memcpy(pkt->wire, query->wire, base_size);
+
+ pkt->qname_size = query->qname_size;
+ if (query->qname_size == 0) {
+ /* Reset question count if malformed. */
+ knot_wire_set_qdcount(pkt->wire, 0);
+ }
+
+ /* Update flags and section counters. */
+ knot_wire_set_ancount(pkt->wire, 0);
+ knot_wire_set_nscount(pkt->wire, 0);
+ knot_wire_set_arcount(pkt->wire, 0);
+
+ knot_wire_set_qr(pkt->wire);
+ knot_wire_clear_tc(pkt->wire);
+ knot_wire_clear_ad(pkt->wire);
+ knot_wire_clear_ra(pkt->wire);
+ knot_wire_clear_aa(pkt->wire);
+ knot_wire_clear_z(pkt->wire);
+
+ /* Clear payload. */
+ payload_clear(pkt);
+
+ return KNOT_EOK;
+}
+
+_public_
+void knot_pkt_clear(knot_pkt_t *pkt)
+{
+ if (pkt == NULL) {
+ return;
+ }
+
+ /* Reset to header size. */
+ pkt->size = KNOT_WIRE_HEADER_SIZE;
+ memset(pkt->wire, 0, pkt->size);
+
+ /* Clear payload. */
+ payload_clear(pkt);
+
+ /* Clear compression context. */
+ compr_clear(&pkt->compr);
+}
+
+_public_
+void knot_pkt_free(knot_pkt_t *pkt)
+{
+ if (pkt == NULL) {
+ return;
+ }
+
+ /* Free temporary RRSets. */
+ pkt_free_data(pkt);
+
+ /* Free RR/RR info arrays. */
+ mm_free(&pkt->mm, pkt->rr);
+ mm_free(&pkt->mm, pkt->rr_info);
+
+ /* Free the space for wireformat. */
+ if (pkt->flags & KNOT_PF_FREE) {
+ mm_free(&pkt->mm, pkt->wire);
+ }
+
+ mm_free(&pkt->mm, pkt);
+}
+
+_public_
+int knot_pkt_reserve(knot_pkt_t *pkt, uint16_t size)
+{
+ if (pkt == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ /* Reserve extra space (if possible). */
+ if (pkt_remaining(pkt) >= size) {
+ pkt->reserved += size;
+ return KNOT_EOK;
+ } else {
+ return KNOT_ERANGE;
+ }
+}
+
+_public_
+int knot_pkt_reclaim(knot_pkt_t *pkt, uint16_t size)
+{
+ if (pkt == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ if (pkt->reserved >= size) {
+ pkt->reserved -= size;
+ return KNOT_EOK;
+ } else {
+ return KNOT_ERANGE;
+ }
+}
+
+_public_
+int knot_pkt_begin(knot_pkt_t *pkt, knot_section_t section_id)
+{
+ if (pkt == NULL || section_id < pkt->current) {
+ return KNOT_EINVAL;
+ }
+
+ /* Remember watermark but not on repeated calls. */
+ pkt->sections[section_id].pkt = pkt;
+ if (section_id > pkt->current) {
+ pkt->sections[section_id].pos = pkt->rrset_count;
+ }
+
+ pkt->current = section_id;
+
+ return KNOT_EOK;
+}
+
+_public_
+int knot_pkt_put_question(knot_pkt_t *pkt, const knot_dname_t *qname, uint16_t qclass, uint16_t qtype)
+{
+ if (pkt == NULL || qname == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ assert(pkt->size == KNOT_WIRE_HEADER_SIZE);
+ assert(pkt->rrset_count == 0);
+
+ /* Copy name wireformat. */
+ wire_ctx_t wire = wire_ctx_init(pkt->wire, pkt->max_size);
+ wire_ctx_set_offset(&wire, KNOT_WIRE_HEADER_SIZE);
+
+ int qname_len = knot_dname_to_wire(wire.position,
+ qname, wire_ctx_available(&wire));
+ if (qname_len < 0) {
+ return qname_len;
+ }
+ wire_ctx_skip(&wire, qname_len);
+
+ /* Copy QTYPE & QCLASS */
+ wire_ctx_write_u16(&wire, qtype);
+ wire_ctx_write_u16(&wire, qclass);
+
+ /* Check errors. */
+ if (wire.error != KNOT_EOK) {
+ return wire.error;
+ }
+
+ /* Update question count and sizes. */
+ knot_wire_set_qdcount(pkt->wire, 1);
+ pkt->size = wire_ctx_offset(&wire);
+ pkt->qname_size = qname_len;
+
+ /* Start writing ANSWER. */
+ return knot_pkt_begin(pkt, KNOT_ANSWER);
+}
+
+_public_
+int knot_pkt_put_rotate(knot_pkt_t *pkt, uint16_t compr_hint, const knot_rrset_t *rr,
+ uint16_t rotate, uint16_t flags)
+{
+ if (pkt == NULL || rr == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ /* Reserve memory for RR descriptors. */
+ int ret = pkt_rr_array_alloc(pkt, pkt->rrset_count + 1);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ /* Check for double insertion. */
+ if ((flags & KNOT_PF_CHECKDUP) && pkt_contains(pkt, rr)) {
+ return KNOT_EOK;
+ }
+
+ knot_rrinfo_t *rrinfo = &pkt->rr_info[pkt->rrset_count];
+ memset(rrinfo, 0, sizeof(knot_rrinfo_t));
+ rrinfo->pos = pkt->size;
+ rrinfo->flags = flags;
+ rrinfo->compress_ptr[0] = compr_hint;
+ memcpy(pkt->rr + pkt->rrset_count, rr, sizeof(knot_rrset_t));
+
+ /* Disable compression if no QNAME is available. */
+ knot_compr_t *compr = NULL;
+ if (knot_pkt_qname(pkt) != NULL) {
+ /* Initialize compression context if it did not happen yet. */
+ pkt->compr.rrinfo = rrinfo;
+ if (pkt->compr.suffix.pos == 0) {
+ pkt->compr.suffix.pos = KNOT_WIRE_HEADER_SIZE;
+ pkt->compr.suffix.labels =
+ knot_dname_labels(pkt->compr.wire + pkt->compr.suffix.pos,
+ pkt->compr.wire);
+ }
+
+ compr = &pkt->compr;
+ }
+
+ uint8_t *pos = pkt->wire + pkt->size;
+ size_t maxlen = pkt_remaining(pkt);
+
+ /* Write RRSet to wireformat. */
+ ret = knot_rrset_to_wire_extra(rr, pos, maxlen, rotate, compr, flags);
+ if (ret < 0) {
+ /* Truncate packet if required. */
+ if (ret == KNOT_ESPACE && !(flags & KNOT_PF_NOTRUNC)) {
+ knot_wire_set_tc(pkt->wire);
+ }
+ return ret;
+ }
+
+ size_t len = ret;
+ uint16_t rr_added = rr->rrs.count;
+
+ /* Keep reference to special types. */
+ if (rr->type == KNOT_RRTYPE_OPT) {
+ pkt->opt_rr = &pkt->rr[pkt->rrset_count];
+ }
+
+ if (rr_added > 0) {
+ pkt->rrset_count += 1;
+ pkt->sections[pkt->current].count += 1;
+ pkt->size += len;
+ pkt_rr_wirecount_add(pkt, pkt->current, rr_added);
+ }
+
+ return KNOT_EOK;
+}
+
+_public_
+int knot_pkt_parse_question(knot_pkt_t *pkt)
+{
+ if (pkt == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ /* Check at least header size. */
+ if (pkt->size < KNOT_WIRE_HEADER_SIZE) {
+ return KNOT_EMALF;
+ }
+
+ /* We have at least some DNS header. */
+ pkt->parsed = KNOT_WIRE_HEADER_SIZE;
+
+ /* Check QD count. */
+ uint16_t qd = knot_wire_get_qdcount(pkt->wire);
+ if (qd > 1) {
+ return KNOT_EMALF;
+ }
+
+ /* No question. */
+ if (qd == 0) {
+ pkt->qname_size = 0;
+ return KNOT_EOK;
+ }
+
+ /* Process question. */
+ int len = knot_dname_wire_check(pkt->wire + pkt->parsed,
+ pkt->wire + pkt->size,
+ NULL /* No compression in QNAME. */);
+ if (len <= 0) {
+ return KNOT_EMALF;
+ }
+
+ /* Check QCLASS/QTYPE size. */
+ uint16_t question_size = len + 2 * sizeof(uint16_t); /* QCLASS + QTYPE */
+ if (pkt->parsed + question_size > pkt->size) {
+ return KNOT_EMALF;
+ }
+
+ pkt->parsed += question_size;
+ pkt->qname_size = len;
+
+ return KNOT_EOK;
+}
+
+/*! \brief Check constraints (position, uniqueness, validity) for special types
+ * (TSIG, OPT).
+ */
+static int check_rr_constraints(knot_pkt_t *pkt, knot_rrset_t *rr, size_t rr_size,
+ unsigned flags)
+{
+ switch (rr->type) {
+ case KNOT_RRTYPE_TSIG:
+ if (pkt->current != KNOT_ADDITIONAL || pkt->tsig_rr != NULL ||
+ !knot_tsig_rdata_is_ok(rr)) {
+ return KNOT_EMALF;
+ }
+
+ /* Strip TSIG RR from wireformat and decrease ARCOUNT. */
+ if (!(flags & KNOT_PF_KEEPWIRE)) {
+ pkt->parsed -= rr_size;
+ pkt->size -= rr_size;
+ pkt->tsig_wire.pos = pkt->wire + pkt->parsed;
+ pkt->tsig_wire.len = rr_size;
+ knot_wire_set_arcount(pkt->wire, knot_wire_get_arcount(pkt->wire) - 1);
+ }
+
+ pkt->tsig_rr = rr;
+ break;
+ case KNOT_RRTYPE_OPT:
+ if (pkt->current != KNOT_ADDITIONAL || pkt->opt_rr != NULL ||
+ knot_edns_get_options(rr, &pkt->edns_opts, &pkt->mm) != KNOT_EOK) {
+ return KNOT_EMALF;
+ }
+
+ pkt->opt_rr = rr;
+ break;
+ default:
+ break;
+ }
+
+ return KNOT_EOK;
+}
+
+static int parse_rr(knot_pkt_t *pkt, unsigned flags)
+{
+ assert(pkt);
+
+ if (pkt->parsed >= pkt->size) {
+ return KNOT_EFEWDATA;
+ }
+
+ /* Reserve memory for RR descriptors. */
+ int ret = pkt_rr_array_alloc(pkt, pkt->rrset_count + 1);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ /* Initialize RR info. */
+ memset(&pkt->rr_info[pkt->rrset_count], 0, sizeof(knot_rrinfo_t));
+ pkt->rr_info[pkt->rrset_count].pos = pkt->parsed;
+ pkt->rr_info[pkt->rrset_count].flags = KNOT_PF_FREE;
+
+ /* Parse wire format. */
+ size_t rr_size = pkt->parsed;
+ knot_rrset_t *rr = &pkt->rr[pkt->rrset_count];
+ ret = knot_rrset_rr_from_wire(pkt->wire, &pkt->parsed, pkt->size,
+ rr, &pkt->mm, !(flags & KNOT_PF_NOCANON));
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ /* Calculate parsed RR size from before/after parsing. */
+ rr_size = (pkt->parsed - rr_size);
+
+ /* Update packet RRSet count. */
+ ++pkt->rrset_count;
+ ++pkt->sections[pkt->current].count;
+
+ /* Check special RRs (OPT and TSIG). */
+ return check_rr_constraints(pkt, rr, rr_size, flags);
+}
+
+static int parse_section(knot_pkt_t *pkt, unsigned flags)
+{
+ assert(pkt);
+
+ uint16_t rr_parsed = 0;
+ uint16_t rr_count = pkt_rr_wirecount(pkt, pkt->current);
+
+ /* Parse all RRs belonging to the section. */
+ for (rr_parsed = 0; rr_parsed < rr_count; ++rr_parsed) {
+ int ret = parse_rr(pkt, flags);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+static int parse_payload(knot_pkt_t *pkt, unsigned flags)
+{
+ assert(pkt);
+ assert(pkt->wire);
+ assert(pkt->size > 0);
+
+ /* Reserve memory in advance to avoid resizing. */
+ size_t rr_count = knot_wire_get_ancount(pkt->wire) +
+ knot_wire_get_nscount(pkt->wire) +
+ knot_wire_get_arcount(pkt->wire);
+
+ if (rr_count > pkt->size / KNOT_WIRE_RR_MIN_SIZE) {
+ return KNOT_EMALF;
+ }
+
+ int ret = pkt_rr_array_alloc(pkt, rr_count);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ for (knot_section_t i = KNOT_ANSWER; i <= KNOT_ADDITIONAL; ++i) {
+ ret = knot_pkt_begin(pkt, i);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ ret = parse_section(pkt, flags);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ /* TSIG must be last record of AR if present. */
+ const knot_pktsection_t *ar = knot_pkt_section(pkt, KNOT_ADDITIONAL);
+ if (pkt->tsig_rr != NULL) {
+ const knot_rrset_t *last_rr = knot_pkt_rr(ar, ar->count - 1);
+ if (ar->count > 0 && pkt->tsig_rr->rrs.rdata != last_rr->rrs.rdata) {
+ return KNOT_EMALF;
+ }
+ }
+
+ /* Check for trailing garbage. */
+ if (pkt->parsed < pkt->size) {
+ return KNOT_ETRAIL;
+ }
+
+ return KNOT_EOK;
+}
+
+_public_
+int knot_pkt_parse(knot_pkt_t *pkt, unsigned flags)
+{
+ if (pkt == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ /* Reset parse state. */
+ sections_reset(pkt);
+
+ int ret = knot_pkt_parse_question(pkt);
+ if (ret == KNOT_EOK) {
+ ret = parse_payload(pkt, flags);
+ }
+
+ return ret;
+}
+
+_public_
+uint16_t knot_pkt_ext_rcode(const knot_pkt_t *pkt)
+{
+ if (pkt == NULL) {
+ return 0;
+ }
+
+ /* Get header RCODE. */
+ uint16_t rcode = knot_wire_get_rcode(pkt->wire);
+
+ /* Update to extended RCODE if EDNS is available. */
+ if (pkt->opt_rr != NULL) {
+ uint8_t opt_rcode = knot_edns_get_ext_rcode(pkt->opt_rr);
+ rcode = knot_edns_whole_rcode(opt_rcode, rcode);
+ }
+
+ /* Return if not NOTAUTH. */
+ if (rcode != KNOT_RCODE_NOTAUTH) {
+ return rcode;
+ }
+
+ /* Get TSIG RCODE. */
+ uint16_t tsig_rcode = KNOT_RCODE_NOERROR;
+ if (pkt->tsig_rr != NULL) {
+ tsig_rcode = knot_tsig_rdata_error(pkt->tsig_rr);
+ }
+
+ /* Return proper RCODE. */
+ if (tsig_rcode != KNOT_RCODE_NOERROR) {
+ return tsig_rcode;
+ } else {
+ return rcode;
+ }
+}
+
+_public_
+const char *knot_pkt_ext_rcode_name(const knot_pkt_t *pkt)
+{
+ if (pkt == NULL) {
+ return "";
+ }
+
+ uint16_t rcode = knot_pkt_ext_rcode(pkt);
+
+ const knot_lookup_t *item = NULL;
+ if (pkt->tsig_rr != NULL) {
+ item = knot_lookup_by_id(knot_tsig_rcode_names, rcode);
+ }
+ if (item == NULL) {
+ item = knot_lookup_by_id(knot_rcode_names, rcode);
+ }
+
+ return (item != NULL) ? item->name : "";
+}
diff --git a/src/libknot/packet/pkt.h b/src/libknot/packet/pkt.h
new file mode 100644
index 0000000..a105d9f
--- /dev/null
+++ b/src/libknot/packet/pkt.h
@@ -0,0 +1,402 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief Structure for holding DNS packet data and metadata.
+ *
+ * \addtogroup pkt
+ * @{
+ */
+
+#pragma once
+
+#include <assert.h>
+#include <stdint.h>
+
+#include "libknot/consts.h"
+#include "libknot/dname.h"
+#include "libknot/mm_ctx.h"
+#include "libknot/rrset.h"
+#include "libknot/rrtype/opt.h"
+#include "libknot/packet/wire.h"
+#include "libknot/packet/compr.h"
+#include "libknot/wire.h"
+
+/* Number of packet sections (ANSWER, AUTHORITY, ADDITIONAL). */
+#define KNOT_PKT_SECTIONS 3
+
+/*!
+ * \brief Packet flags.
+ */
+enum {
+ KNOT_PF_NULL = 0 << 0, /*!< No flags. */
+ KNOT_PF_FREE = 1 << 1, /*!< Free with packet. */
+ KNOT_PF_NOTRUNC = 1 << 2, /*!< Don't truncate. */
+ KNOT_PF_CHECKDUP = 1 << 3, /*!< Check for duplicates. */
+ KNOT_PF_KEEPWIRE = 1 << 4, /*!< Keep wireformat untouched when parsing. */
+ KNOT_PF_NOCANON = 1 << 5, /*!< Don't canonicalize rrsets during parsing. */
+ KNOT_PF_ORIGTTL = 1 << 6, /*!< Write RRSIGs with their original TTL. */
+};
+
+typedef struct knot_pkt knot_pkt_t;
+
+/*!
+ * \brief Packet section.
+ * Points to RRSet and RRSet info arrays in the packet.
+ * This structure is required for random access to packet sections.
+ */
+typedef struct {
+ knot_pkt_t *pkt; /*!< Owner. */
+ uint16_t pos; /*!< Position in the rr/rrinfo fields in packet. */
+ uint16_t count; /*!< Number of RRSets in this section. */
+} knot_pktsection_t;
+
+/*!
+ * \brief Structure representing a DNS packet.
+ */
+struct knot_pkt {
+ uint8_t *wire; /*!< Wire format of the packet. */
+ size_t size; /*!< Current wire size of the packet. */
+ size_t max_size; /*!< Maximum allowed size of the packet. */
+ size_t parsed; /*!< Parsed size. */
+ uint16_t reserved; /*!< Reserved space. */
+ uint16_t qname_size; /*!< QNAME size. */
+ uint16_t rrset_count; /*!< Packet RRSet count. */
+ uint16_t flags; /*!< Packet flags. */
+
+ knot_rrset_t *opt_rr; /*!< OPT RR included in the packet. */
+ knot_rrset_t *tsig_rr; /*!< TSIG RR stored in the packet. */
+
+ /*! EDNS option positions in the wire (if parsed from wire). */
+ knot_edns_options_t *edns_opts;
+
+ /*! TSIG RR position in the wire (if parsed from wire). */
+ struct {
+ uint8_t *pos;
+ size_t len;
+ } tsig_wire;
+
+ /* Packet sections. */
+ knot_section_t current;
+ knot_pktsection_t sections[KNOT_PKT_SECTIONS];
+
+ /* Packet RRSet (meta)data. */
+ size_t rrset_allocd;
+ knot_rrinfo_t *rr_info;
+ knot_rrset_t *rr;
+
+ knot_mm_t mm; /*!< Memory allocation context. */
+
+ knot_compr_t compr; /*!< Compression context. */
+};
+
+/*!
+ * \brief Create new packet over existing memory, or allocate new from memory context.
+ *
+ * \note Packet is allocated from given memory context.
+ *
+ * \param wire If NULL, memory of 'len' size shall be allocated.
+ * Otherwise pointer is used for the wire format of the packet.
+ * \param len Wire format length.
+ * \param mm Memory context (NULL for default).
+ * \return New packet or NULL.
+ */
+knot_pkt_t *knot_pkt_new(void *wire, uint16_t len, knot_mm_t *mm);
+
+/*!
+ * \brief Copy packet.
+ *
+ * \note Current implementation is not very efficient, as it re-parses the wire.
+ *
+ * \param dst Target packet.
+ * \param src Source packet.
+ *
+ * \return new packet or NULL
+ */
+int knot_pkt_copy(knot_pkt_t *dst, const knot_pkt_t *src);
+
+/*!
+ * \brief Initialized response from query packet.
+ *
+ * \note Question is not checked, it is expected to be checked already.
+ *
+ * \param pkt Given packet.
+ * \param query Query.
+ * \return KNOT_EOK, KNOT_EINVAL, KNOT_ESPACE
+ */
+int knot_pkt_init_response(knot_pkt_t *pkt, const knot_pkt_t *query);
+
+/*! \brief Reinitialize packet for another use. */
+void knot_pkt_clear(knot_pkt_t *pkt);
+
+/*! \brief Begone you foul creature of the underworld. */
+void knot_pkt_free(knot_pkt_t *pkt);
+
+/*!
+ * \brief Reserve an arbitrary amount of space in the packet.
+ *
+ * \return KNOT_EOK
+ * \return KNOT_ERANGE if size can't be reserved
+ */
+int knot_pkt_reserve(knot_pkt_t *pkt, uint16_t size);
+
+/*!
+ * \brief Reclaim reserved size.
+ *
+ * \return KNOT_EOK
+ * \return KNOT_ERANGE if size can't be reclaimed
+ */
+int knot_pkt_reclaim(knot_pkt_t *pkt, uint16_t size);
+
+/*
+ * Packet QUESTION accessors.
+ */
+static inline uint16_t knot_pkt_question_size(const knot_pkt_t *pkt)
+{
+ if (pkt == NULL || pkt->qname_size == 0) {
+ return 0;
+ }
+
+ return pkt->qname_size + 2 * sizeof(uint16_t);
+}
+
+static inline knot_dname_t *knot_pkt_qname(const knot_pkt_t *pkt)
+{
+ if (pkt == NULL || pkt->qname_size == 0) {
+ return NULL;
+ }
+
+ return pkt->wire + KNOT_WIRE_HEADER_SIZE;
+}
+
+static inline uint16_t knot_pkt_qtype(const knot_pkt_t *pkt)
+{
+ if (pkt == NULL || pkt->qname_size == 0) {
+ return 0;
+ }
+
+ unsigned off = KNOT_WIRE_HEADER_SIZE + pkt->qname_size;
+ return knot_wire_read_u16(pkt->wire + off);
+}
+
+static inline uint16_t knot_pkt_qclass(const knot_pkt_t *pkt)
+{
+ if (pkt == NULL || pkt->qname_size == 0) {
+ return 0;
+ }
+
+ unsigned off = KNOT_WIRE_HEADER_SIZE + pkt->qname_size + sizeof(uint16_t);
+ return knot_wire_read_u16(pkt->wire + off);
+}
+
+/*
+ * Packet writing API.
+ */
+
+/*!
+ * \brief Begin reading/writing packet section.
+ *
+ * \note You must proceed in the natural order (ANSWER, AUTHORITY, ADDITIONAL).
+ *
+ * \param pkt
+ * \param section_id
+ * \return KNOT_EOK or KNOT_EINVAL
+ */
+int knot_pkt_begin(knot_pkt_t *pkt, knot_section_t section_id);
+
+/*!
+ * \brief Put QUESTION in the packet.
+ *
+ * \note Since we support QD=1 only, QUESTION is a special type of packet section.
+ * \note Must not be used after putting RRsets into the packet.
+ *
+ * \param pkt
+ * \param qname
+ * \param qclass
+ * \param qtype
+ * \return KNOT_EOK or various errors
+ */
+int knot_pkt_put_question(knot_pkt_t *pkt, const knot_dname_t *qname,
+ uint16_t qclass, uint16_t qtype);
+
+/*!
+ * \brief Put RRSet into packet.
+ *
+ * \note See compr.h for description on how compression hints work.
+ * \note Available flags: PF_FREE, KNOT_PF_CHECKDUP, KNOT_PF_NOTRUNC
+ *
+ * \param pkt
+ * \param compr_hint Compression hint, see enum knot_compr_hint or absolute
+ * position.
+ * \param rr Given RRSet.
+ * \param rotate Rotate the RRSet order by this count.
+ * \param flags RRSet flags (set PF_FREE if you want RRSet to be freed
+ * with the packet).
+ *
+ * \return KNOT_EOK, KNOT_ESPACE, various errors
+ */
+int knot_pkt_put_rotate(knot_pkt_t *pkt, uint16_t compr_hint, const knot_rrset_t *rr,
+ uint16_t rotate, uint16_t flags);
+
+/*! \brief Same as knot_pkt_put_rotate but without rrset rotation. */
+static inline int knot_pkt_put(knot_pkt_t *pkt, uint16_t compr_hint,
+ const knot_rrset_t *rr, uint16_t flags)
+{
+ return knot_pkt_put_rotate(pkt, compr_hint, rr, 0, flags);
+}
+
+/*! \brief Get description of the given packet section. */
+static inline const knot_pktsection_t *knot_pkt_section(const knot_pkt_t *pkt,
+ knot_section_t section_id)
+{
+ assert(pkt);
+ return &pkt->sections[section_id];
+}
+
+/*! \brief Get RRSet from the packet section. */
+static inline const knot_rrset_t *knot_pkt_rr(const knot_pktsection_t *section,
+ uint16_t i)
+{
+ assert(section);
+ return section->pkt->rr + section->pos + i;
+}
+
+/*! \brief Get RRSet offset in the packet wire. */
+static inline uint16_t knot_pkt_rr_offset(const knot_pktsection_t *section,
+ uint16_t i)
+{
+ assert(section);
+ return section->pkt->rr_info[section->pos + i].pos;
+}
+
+/*
+ * Packet parsing API.
+ */
+
+/*!
+ * \brief Parse both packet question and payload.
+ *
+ * Parses both QUESTION and all packet sections,
+ * includes semantic checks over specific RRs (TSIG, OPT).
+ *
+ * \note If KNOT_PF_KEEPWIRE is set, TSIG RR is not stripped from the wire
+ * and is processed as any other RR.
+ *
+ * \param pkt Given packet.
+ * \param flags Parsing flags (allowed KNOT_PF_KEEPWIRE)
+ *
+ * \retval KNOT_EOK if success.
+ * \retval KNOT_ETRAIL if success but with some trailing data.
+ * \retval KNOT_EMALF and other errors.
+ */
+int knot_pkt_parse(knot_pkt_t *pkt, unsigned flags);
+
+/*!
+ * \brief Parse packet header and a QUESTION section.
+ */
+int knot_pkt_parse_question(knot_pkt_t *pkt);
+
+/*!
+ * \brief Get packet extended RCODE.
+ *
+ * Extended RCODE is created by considering TSIG RCODE, EDNS RCODE and
+ * DNS Header RCODE. (See RFC 6895, Section 2.3).
+ *
+ * \param pkt Packet to get the response code from.
+ *
+ * \return Whole extended RCODE (0 if pkt == NULL).
+ */
+uint16_t knot_pkt_ext_rcode(const knot_pkt_t *pkt);
+
+/*!
+ * \brief Get packet extended RCODE name.
+ *
+ * The packet parameter is important as the name depends on TSIG.
+ *
+ * \param pkt Packet to get the response code from.
+ *
+ * \return RCODE name (or empty string if not known).
+ */
+const char *knot_pkt_ext_rcode_name(const knot_pkt_t *pkt);
+
+/*!
+ * \brief Checks if there is an OPT RR in the packet.
+ */
+static inline bool knot_pkt_has_edns(const knot_pkt_t *pkt)
+{
+ assert(pkt);
+ return pkt->opt_rr != NULL;
+}
+
+/*!
+ * \brief Checks if TSIG is present.
+ */
+static inline bool knot_pkt_has_tsig(const knot_pkt_t *pkt)
+{
+ assert(pkt);
+ return pkt->tsig_rr != NULL;
+}
+
+/*!
+ * \brief Checks if DO bit is set in the packet's OPT RR.
+ */
+static inline bool knot_pkt_has_dnssec(const knot_pkt_t *pkt)
+{
+ assert(pkt);
+ return knot_pkt_has_edns(pkt) && knot_edns_do(pkt->opt_rr);
+}
+
+/*!
+ * \brief Get specific EDNS option from a parsed packet.
+ */
+static inline uint8_t *knot_pkt_edns_option(const knot_pkt_t *pkt, uint16_t code)
+{
+ assert(pkt);
+ if (pkt->edns_opts != NULL && code <= KNOT_EDNS_MAX_OPTION_CODE) {
+ return pkt->edns_opts->ptr[code];
+ } else {
+ return NULL;
+ }
+}
+
+/*!
+ * \brief Computes a reasonable Padding data length for a given packet and opt RR.
+ *
+ * \param pkt DNS Packet prepared and otherwise ready to go, no OPT yet added.
+ * \param opt_rr OPT RR, not yet including padding.
+ *
+ * \return Required padding length or -1 if padding not required.
+ */
+static inline int knot_pkt_default_padding_size(const knot_pkt_t *pkt,
+ const knot_rrset_t *opt_rr)
+{
+ if (knot_wire_get_qr(pkt->wire)) {
+ return knot_edns_alignment_size(pkt->size, knot_rrset_size(opt_rr),
+ KNOT_EDNS_ALIGNMENT_RESPONSE_DEFAULT);
+ } else {
+ return knot_edns_alignment_size(pkt->size, knot_rrset_size(opt_rr),
+ KNOT_EDNS_ALIGNMENT_QUERY_DEFALT);
+ }
+}
+
+static inline size_t knot_pkt_size(const knot_pkt_t *pkt)
+{
+ assert(pkt);
+ return pkt->size + (knot_pkt_has_tsig(pkt) ? pkt->tsig_wire.len : 0);
+}
+
+/*! @} */
diff --git a/src/libknot/packet/rrset-wire.c b/src/libknot/packet/rrset-wire.c
new file mode 100644
index 0000000..dadadd5
--- /dev/null
+++ b/src/libknot/packet/rrset-wire.c
@@ -0,0 +1,727 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "libknot/attribute.h"
+#include "libknot/consts.h"
+#include "libknot/descriptor.h"
+#include "libknot/packet/pkt.h"
+#include "libknot/packet/rrset-wire.h"
+#include "libknot/rrtype/naptr.h"
+#include "libknot/rrtype/rrsig.h"
+#include "contrib/macros.h"
+#include "contrib/mempattern.h"
+#include "contrib/tolower.h"
+#include "contrib/wire_ctx.h"
+
+/*!
+ * \brief Get maximal size of a domain name in a wire with given capacity.
+ */
+static uint16_t dname_max(size_t wire_avail)
+{
+ return MIN(wire_avail, KNOT_DNAME_MAXLEN);
+}
+
+/*!
+ * \brief Compares two domain name labels.
+ *
+ * \param label1 First label.
+ * \param label2 Second label (may be in upper-case).
+ *
+ * \retval true if the labels are identical
+ * \retval false if the labels are NOT identical
+ */
+static bool label_is_equal(const uint8_t *label1, const uint8_t *label2)
+{
+ assert(label1 && label2);
+
+ if (*label1 != *label2) {
+ return false;
+ }
+
+ uint8_t len = *label1;
+ for (uint8_t i = 1; i <= len; i++) {
+ if (label1[i] != knot_tolower(label2[i])) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/*!
+ * Case insensitive comparison of two dnames in wire format.
+ * The second name may be compressed in a supplied wire.
+ */
+static bool dname_equal_wire(const knot_dname_t *d1, const knot_dname_t *d2,
+ const uint8_t *wire)
+{
+ assert(d1);
+ assert(d2);
+
+ d2 = knot_wire_seek_label(d2, wire);
+
+ while (*d1 != '\0' || *d2 != '\0') {
+ if (!label_is_equal(d1, d2)) {
+ return false;
+ }
+ d1 = knot_wire_next_label(d1, NULL);
+ d2 = knot_wire_next_label(d2, wire);
+ }
+
+ return true;
+}
+
+static uint16_t compr_get_ptr(knot_compr_t *compr, uint16_t hint)
+{
+ if (compr == NULL) {
+ return 0;
+ }
+
+ return knot_compr_hint(compr->rrinfo, hint);
+}
+
+static void compr_set_ptr(knot_compr_t *compr, uint16_t hint,
+ const uint8_t *written_at, uint16_t written_size)
+{
+ if (compr == NULL) {
+ return;
+ }
+
+ assert(written_at >= compr->wire);
+
+ uint16_t offset = written_at - compr->wire;
+
+ knot_compr_hint_set(compr->rrinfo, hint, offset, written_size);
+}
+
+static int write_rdata_fixed(const uint8_t **src, size_t *src_avail,
+ uint8_t **dst, size_t *dst_avail, size_t size)
+{
+ assert(src && *src);
+ assert(src_avail);
+ assert(dst && *dst);
+ assert(dst_avail);
+
+ // Check input/output buffer boundaries.
+ if (size > *src_avail) {
+ return KNOT_EMALF;
+ }
+
+ if (size > *dst_avail) {
+ return KNOT_ESPACE;
+ }
+
+ // Data binary copy.
+ memcpy(*dst, *src, size);
+
+ // Update buffers.
+ *src += size;
+ *src_avail -= size;
+
+ *dst += size;
+ *dst_avail -= size;
+
+ return KNOT_EOK;
+}
+
+static int write_rdata_naptr_header(const uint8_t **src, size_t *src_avail,
+ uint8_t **dst, size_t *dst_avail)
+{
+ assert(src && *src);
+ assert(src_avail);
+ assert(dst && *dst);
+ assert(dst_avail);
+
+ int ret = knot_naptr_header_size(*src, *src + *src_avail);
+ if (ret < 0) {
+ return ret;
+ }
+
+ // Copy the data.
+ return write_rdata_fixed(src, src_avail, dst, dst_avail, ret);
+}
+
+/*! \brief Helper for \ref compr_put_dname, writes label(s) with size checks. */
+#define WRITE_LABEL(dst, written, label, max, len) \
+ if ((written) + (len) > (max)) { \
+ return KNOT_ESPACE; \
+ } else { \
+ memcpy((dst) + (written), (label), (len)); \
+ written += (len); \
+ }
+
+/*!
+ * \brief Write compressed domain name to the destination wire.
+ *
+ * \param dname Name to be written.
+ * \param dst Destination wire.
+ * \param max Maximum number of bytes available.
+ * \param compr Compression context (NULL for no compression)
+ * \return Number of written bytes or an error.
+ */
+static int compr_put_dname(const knot_dname_t *dname, uint8_t *dst, uint16_t max,
+ knot_compr_t *compr)
+{
+ assert(dname && dst);
+
+ // Write uncompressible names directly (zero label dname).
+ if (compr == NULL || *dname == '\0') {
+ return knot_dname_to_wire(dst, dname, max);
+ }
+
+ // Get number of labels (should not be a zero label dname).
+ size_t name_labels = knot_dname_labels(dname, NULL);
+ assert(name_labels > 0);
+
+ // Suffix must not be longer than whole name.
+ const knot_dname_t *suffix = compr->wire + compr->suffix.pos;
+ int suffix_labels = compr->suffix.labels;
+ while (suffix_labels > name_labels) {
+ suffix = knot_wire_next_label(suffix, compr->wire);
+ --suffix_labels;
+ }
+
+ // Suffix is shorter than name, write labels until aligned.
+ uint8_t orig_labels = name_labels;
+ uint16_t written = 0;
+ while (name_labels > suffix_labels) {
+ WRITE_LABEL(dst, written, dname, max, (*dname + 1));
+ dname = knot_wire_next_label(dname, NULL);
+ --name_labels;
+ }
+
+ // Label count is now equal.
+ assert(name_labels == suffix_labels);
+ const knot_dname_t *match_begin = dname;
+ const knot_dname_t *compr_ptr = suffix;
+ while (dname[0] != '\0') {
+ // Next labels.
+ const knot_dname_t *next_dname = knot_wire_next_label(dname, NULL);
+ const knot_dname_t *next_suffix = knot_wire_next_label(suffix, compr->wire);
+
+ // Two labels match, extend suffix length.
+ if (!label_is_equal(dname, suffix)) {
+ // If they don't match, write unmatched labels.
+ uint16_t mismatch_len = (dname - match_begin) + (*dname + 1);
+ WRITE_LABEL(dst, written, match_begin, max, mismatch_len);
+ // Start new potential match.
+ match_begin = next_dname;
+ compr_ptr = next_suffix;
+ }
+
+ // Jump to next labels.
+ dname = next_dname;
+ suffix = next_suffix;
+ }
+
+ // If match begins at the end of the name, write '\0' label.
+ if (match_begin == dname) {
+ WRITE_LABEL(dst, written, dname, max, 1);
+ } else {
+ // Match covers >0 labels, write out compression pointer.
+ if (written + sizeof(uint16_t) > max) {
+ return KNOT_ESPACE;
+ }
+ knot_wire_put_pointer(dst + written, compr_ptr - compr->wire);
+ written += sizeof(uint16_t);
+ }
+
+ assert(dst >= compr->wire);
+ size_t wire_pos = dst - compr->wire;
+ assert(wire_pos < KNOT_WIRE_MAX_PKTSIZE);
+
+ // Heuristics - expect similar names are grouped together.
+ if (written > sizeof(uint16_t) && wire_pos + written < KNOT_WIRE_PTR_MAX) {
+ compr->suffix.pos = wire_pos;
+ compr->suffix.labels = orig_labels;
+ }
+
+ return written;
+}
+
+#define WRITE_OWNER_CHECK(size, dst_avail) \
+ if ((size) > *(dst_avail)) { \
+ return KNOT_ESPACE; \
+ }
+
+#define WRITE_OWNER_INCR(dst, dst_avail, size) \
+ *(dst) += (size); \
+ *(dst_avail) -= (size);
+
+static int write_owner(const knot_rrset_t *rrset, uint8_t **dst, size_t *dst_avail,
+ knot_compr_t *compr)
+{
+ assert(rrset);
+ assert(dst && *dst);
+ assert(dst_avail);
+
+ // Check for zero label owner (don't compress).
+ uint16_t owner_pointer = 0;
+ if (*rrset->owner != '\0') {
+ owner_pointer = compr_get_ptr(compr, KNOT_COMPR_HINT_OWNER);
+ }
+
+ // Write result.
+ if (owner_pointer > 0) {
+ WRITE_OWNER_CHECK(sizeof(uint16_t), dst_avail);
+ knot_wire_put_pointer(*dst, owner_pointer);
+ WRITE_OWNER_INCR(dst, dst_avail, sizeof(uint16_t));
+ // Check for coincidence with previous RR set.
+ } else if (compr != NULL && compr->suffix.pos != 0 && *rrset->owner != '\0' &&
+ dname_equal_wire(rrset->owner, compr->wire + compr->suffix.pos,
+ compr->wire)) {
+ WRITE_OWNER_CHECK(sizeof(uint16_t), dst_avail);
+ knot_wire_put_pointer(*dst, compr->suffix.pos);
+ compr_set_ptr(compr, KNOT_COMPR_HINT_OWNER,
+ compr->wire + compr->suffix.pos,
+ knot_dname_size(rrset->owner));
+ WRITE_OWNER_INCR(dst, dst_avail, sizeof(uint16_t));
+ } else {
+ if (compr != NULL) {
+ compr->suffix.pos = KNOT_WIRE_HEADER_SIZE;
+ compr->suffix.labels =
+ knot_dname_labels(compr->wire + compr->suffix.pos,
+ compr->wire);
+ }
+ // WRITE_OWNER_CHECK not needed, compr_put_dname has a check.
+ int written = compr_put_dname(rrset->owner, *dst,
+ dname_max(*dst_avail), compr);
+ if (written < 0) {
+ return written;
+ }
+
+ compr_set_ptr(compr, KNOT_COMPR_HINT_OWNER, *dst, written);
+ WRITE_OWNER_INCR(dst, dst_avail, written);
+ }
+
+ return KNOT_EOK;
+}
+
+static int write_fixed_header(const knot_rrset_t *rrset, uint16_t rrset_index,
+ uint8_t **dst, size_t *dst_avail, uint16_t flags)
+{
+ assert(rrset);
+ assert(rrset_index < rrset->rrs.count);
+ assert(dst && *dst);
+ assert(dst_avail);
+
+ // Write header.
+ wire_ctx_t write = wire_ctx_init(*dst, *dst_avail);
+
+ wire_ctx_write_u16(&write, rrset->type);
+ wire_ctx_write_u16(&write, rrset->rclass);
+
+ if ((flags & KNOT_PF_ORIGTTL) && rrset->type == KNOT_RRTYPE_RRSIG) {
+ const knot_rdata_t *rdata = knot_rdataset_at(&rrset->rrs, rrset_index);
+ wire_ctx_write_u32(&write, knot_rrsig_original_ttl(rdata));
+ } else {
+ wire_ctx_write_u32(&write, rrset->ttl);
+ }
+
+ // Check write.
+ if (write.error != KNOT_EOK) {
+ return write.error;
+ }
+
+ // Update buffer.
+ *dst = write.position;
+ *dst_avail = wire_ctx_available(&write);
+
+ return KNOT_EOK;
+}
+
+static int compress_rdata_dname(const uint8_t **src, size_t *src_avail,
+ uint8_t **dst, size_t *dst_avail,
+ knot_compr_t *put_compr, knot_compr_t *compr,
+ uint16_t hint)
+{
+ assert(src && *src);
+ assert(src_avail);
+ assert(dst && *dst);
+ assert(dst_avail);
+
+ // Source domain name.
+ const knot_dname_t *dname = *src;
+ size_t dname_size = knot_dname_size(dname);
+
+ // Output domain name.
+ int written = compr_put_dname(dname, *dst, dname_max(*dst_avail), put_compr);
+ if (written < 0) {
+ return written;
+ }
+
+ // Update compression hints.
+ if (compr_get_ptr(compr, hint) == 0) {
+ compr_set_ptr(compr, hint, *dst, written);
+ }
+
+ // Update buffers.
+ *dst += written;
+ *dst_avail -= written;
+
+ *src += dname_size;
+ *src_avail -= dname_size;
+
+ return KNOT_EOK;
+}
+
+static int rdata_traverse_write(const uint8_t **src, size_t *src_avail,
+ uint8_t **dst, size_t *dst_avail,
+ const knot_rdata_descriptor_t *desc,
+ knot_compr_t *compr, uint16_t hint)
+{
+ for (const int *type = desc->block_types; *type != KNOT_RDATA_WF_END; type++) {
+ int ret;
+ knot_compr_t *put_compr = NULL;
+ switch (*type) {
+ case KNOT_RDATA_WF_COMPRESSIBLE_DNAME:
+ put_compr = compr;
+ // FALLTHROUGH
+ case KNOT_RDATA_WF_DECOMPRESSIBLE_DNAME:
+ case KNOT_RDATA_WF_FIXED_DNAME:
+ ret = compress_rdata_dname(src, src_avail, dst, dst_avail,
+ put_compr, compr, hint);
+ break;
+ case KNOT_RDATA_WF_NAPTR_HEADER:
+ ret = write_rdata_naptr_header(src, src_avail, dst, dst_avail);
+ break;
+ case KNOT_RDATA_WF_REMAINDER:
+ ret = write_rdata_fixed(src, src_avail, dst, dst_avail, *src_avail);
+ break;
+ default:
+ // Fixed size block.
+ assert(*type > 0);
+ ret = write_rdata_fixed(src, src_avail, dst, dst_avail, *type);
+ break;
+ }
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+static int write_rdata(const knot_rrset_t *rrset, uint16_t rrset_index,
+ uint8_t **dst, size_t *dst_avail, knot_compr_t *compr)
+{
+ assert(rrset);
+ assert(rrset_index < rrset->rrs.count);
+ assert(dst && *dst);
+ assert(dst_avail);
+
+ const knot_rdata_t *rdata = knot_rdataset_at(&rrset->rrs, rrset_index);
+
+ // Reserve space for RDLENGTH.
+ if (sizeof(uint16_t) > *dst_avail) {
+ return KNOT_ESPACE;
+ }
+
+ uint8_t *wire_rdlength = *dst;
+ *dst += sizeof(uint16_t);
+ *dst_avail -= sizeof(uint16_t);
+ uint8_t *wire_rdata_begin = *dst;
+
+ // Write RDATA.
+ const uint8_t *src = rdata->data;
+ size_t src_avail = rdata->len;
+ if (src_avail > 0) {
+ // Only write non-empty data.
+ const knot_rdata_descriptor_t *desc =
+ knot_get_rdata_descriptor(rrset->type);
+ int ret = rdata_traverse_write(&src, &src_avail, dst, dst_avail,
+ desc, compr, KNOT_COMPR_HINT_RDATA + rrset_index);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ // Check for trailing data in the message.
+ if (src_avail > 0) {
+ return KNOT_EMALF;
+ }
+
+ // Write final RDLENGTH.
+ size_t rdlength = *dst - wire_rdata_begin;
+ knot_wire_write_u16(wire_rdlength, rdlength);
+
+ return KNOT_EOK;
+}
+
+static int write_rr(const knot_rrset_t *rrset, uint16_t rrset_index, uint8_t **dst,
+ size_t *dst_avail, knot_compr_t *compr, uint16_t flags)
+{
+ int ret = write_owner(rrset, dst, dst_avail, compr);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = write_fixed_header(rrset, rrset_index, dst, dst_avail, flags);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ return write_rdata(rrset, rrset_index, dst, dst_avail, compr);
+}
+
+_public_
+int knot_rrset_to_wire_extra(const knot_rrset_t *rrset, uint8_t *wire,
+ uint16_t max_size, uint16_t rotate,
+ knot_compr_t *compr, uint16_t flags)
+{
+ if (rrset == NULL || wire == NULL) {
+ return KNOT_EINVAL;
+ }
+ if (rrset->rrs.count == 0) {
+ return 0;
+ }
+ if (rotate != 0) {
+ rotate %= rrset->rrs.count;
+ }
+
+ uint8_t *write = wire;
+ size_t capacity = max_size;
+
+ uint16_t count = rrset->rrs.count;
+ for (uint16_t i = rotate; i < count + rotate; i++) {
+ uint16_t pos = (i < count) ? i : (i - count);
+ int ret = write_rr(rrset, pos, &write, &capacity, compr, flags);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ return write - wire;
+}
+
+_public_
+int knot_rrset_to_wire_rotate(const knot_rrset_t *rrset, uint8_t *wire,
+ uint16_t max_size, uint16_t rotate,
+ knot_compr_t *compr)
+{
+ return knot_rrset_to_wire_extra(rrset, wire, max_size, rotate, compr, 0);
+}
+
+static int parse_header(const uint8_t *wire, size_t *pos, size_t pkt_size,
+ knot_mm_t *mm, knot_rrset_t *rrset, uint16_t *rdlen)
+{
+ assert(wire);
+ assert(pos);
+ assert(rrset);
+ assert(rdlen);
+
+ wire_ctx_t src = wire_ctx_init_const(wire, pkt_size);
+ wire_ctx_set_offset(&src, *pos);
+
+ int compr_size = knot_dname_wire_check(src.position, wire + pkt_size, wire);
+ if (compr_size <= 0) {
+ return KNOT_EMALF;
+ }
+
+ uint8_t buff[KNOT_DNAME_MAXLEN];
+ int decompr_size = knot_dname_unpack(buff, src.position, sizeof(buff), wire);
+ if (decompr_size <= 0) {
+ return KNOT_EMALF;
+ }
+
+ knot_dname_t *owner = mm_alloc(mm, decompr_size);
+ if (owner == NULL) {
+ return KNOT_ENOMEM;
+ }
+ memcpy(owner, buff, decompr_size);
+ wire_ctx_skip(&src, compr_size);
+
+ uint16_t type = wire_ctx_read_u16(&src);
+ uint16_t rclass = wire_ctx_read_u16(&src);
+ uint32_t ttl = wire_ctx_read_u32(&src);
+ *rdlen = wire_ctx_read_u16(&src);
+
+ if (src.error != KNOT_EOK) {
+ knot_dname_free(owner, mm);
+ return KNOT_EMALF;
+ }
+
+ if (wire_ctx_available(&src) < *rdlen) {
+ knot_dname_free(owner, mm);
+ return KNOT_EMALF;
+ }
+
+ *pos = wire_ctx_offset(&src);
+
+ knot_rrset_init(rrset, owner, type, rclass, ttl);
+
+ return KNOT_EOK;
+}
+
+static int decompress_rdata_dname(const uint8_t **src, size_t *src_avail,
+ uint8_t **dst, size_t *dst_avail,
+ const uint8_t *pkt_wire)
+{
+ assert(src && *src);
+ assert(src_avail);
+ assert(dst && *dst);
+ assert(dst_avail);
+
+ int compr_size = knot_dname_wire_check(*src, *src + *src_avail, pkt_wire);
+ if (compr_size <= 0) {
+ return compr_size;
+ }
+
+ int decompr_size = knot_dname_unpack(*dst, *src, *dst_avail, pkt_wire);
+ if (decompr_size <= 0) {
+ return decompr_size;
+ }
+
+ // Update buffers.
+ *dst += decompr_size;
+ *dst_avail -= decompr_size;
+
+ *src += compr_size;
+ *src_avail -= compr_size;
+
+ return KNOT_EOK;
+}
+
+static int rdata_traverse_parse(const uint8_t **src, size_t *src_avail,
+ uint8_t **dst, size_t *dst_avail,
+ const knot_rdata_descriptor_t *desc,
+ const uint8_t *pkt_wire)
+{
+ for (const int *type = desc->block_types; *type != KNOT_RDATA_WF_END; type++) {
+ int ret;
+ switch (*type) {
+ case KNOT_RDATA_WF_COMPRESSIBLE_DNAME:
+ case KNOT_RDATA_WF_DECOMPRESSIBLE_DNAME:
+ case KNOT_RDATA_WF_FIXED_DNAME:
+ ret = decompress_rdata_dname(src, src_avail, dst, dst_avail,
+ pkt_wire);
+ break;
+ case KNOT_RDATA_WF_NAPTR_HEADER:
+ ret = write_rdata_naptr_header(src, src_avail, dst, dst_avail);
+ break;
+ case KNOT_RDATA_WF_REMAINDER:
+ ret = write_rdata_fixed(src, src_avail, dst, dst_avail, *src_avail);
+ break;
+ default:
+ /* Fixed size block */
+ assert(*type > 0);
+ ret = write_rdata_fixed(src, src_avail, dst, dst_avail, *type);
+ break;
+ }
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+static bool allow_zero_rdata(const knot_rrset_t *rr,
+ const knot_rdata_descriptor_t *desc)
+{
+ return rr->rclass != KNOT_CLASS_IN || // NONE and ANY for DDNS
+ rr->type == KNOT_RRTYPE_APL || // APL RR type
+ desc->type_name == NULL; // Unknown RR type
+}
+
+static int parse_rdata(const uint8_t *pkt_wire, size_t *pos, size_t pkt_size,
+ knot_mm_t *mm, uint16_t rdlength, knot_rrset_t *rrset)
+{
+ assert(pkt_wire);
+ assert(pos);
+ assert(rrset);
+
+ const knot_rdata_descriptor_t *desc = knot_get_rdata_descriptor(rrset->type);
+ if (desc->type_name == NULL) {
+ desc = knot_get_obsolete_rdata_descriptor(rrset->type);
+ }
+
+ if (rdlength == 0) {
+ if (allow_zero_rdata(rrset, desc)) {
+ return knot_rrset_add_rdata(rrset, NULL, 0, mm);
+ } else {
+ return KNOT_EMALF;
+ }
+ } else if (pkt_size - *pos < rdlength) {
+ return KNOT_EMALF;
+ }
+
+ // Buffer for parsed rdata (decompression extends rdata length).
+ const size_t max_rdata_len = UINT16_MAX;
+ uint8_t buf[knot_rdata_size(max_rdata_len)];
+ knot_rdata_t *rdata = (knot_rdata_t *)buf;
+
+ const uint8_t *src = pkt_wire + *pos;
+ size_t src_avail = rdlength;
+ uint8_t *dst = rdata->data;
+ size_t dst_avail = max_rdata_len;
+
+ // Parse RDATA.
+ int ret = rdata_traverse_parse(&src, &src_avail, &dst, &dst_avail, desc, pkt_wire);
+ if (ret != KNOT_EOK) {
+ return KNOT_EMALF;
+ }
+
+ // Check for trailing data.
+ size_t real_len = max_rdata_len - dst_avail;
+ if (real_len < rdlength) {
+ return KNOT_EMALF;
+ }
+ rdata->len = real_len;
+
+ ret = knot_rdataset_add(&rrset->rrs, rdata, mm);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Update position pointer.
+ *pos += rdlength;
+
+ return KNOT_EOK;
+}
+
+_public_
+int knot_rrset_rr_from_wire(const uint8_t *wire, size_t *pos, size_t max_size,
+ knot_rrset_t *rrset, knot_mm_t *mm, bool canonical)
+{
+ if (wire == NULL || pos == NULL || *pos > max_size || rrset == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ uint16_t rdlen = 0;
+ int ret = parse_header(wire, pos, max_size, mm, rrset, &rdlen);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = parse_rdata(wire, pos, max_size, mm, rdlen, rrset);
+ if (ret != KNOT_EOK) {
+ knot_rrset_clear(rrset, mm);
+ return ret;
+ }
+
+ // Convert RR to the canonical format.
+ if (canonical) {
+ ret = knot_rrset_rr_to_canonical(rrset);
+ if (ret != KNOT_EOK) {
+ knot_rrset_clear(rrset, mm);
+ }
+ }
+
+ return KNOT_EOK;
+}
diff --git a/src/libknot/packet/rrset-wire.h b/src/libknot/packet/rrset-wire.h
new file mode 100644
index 0000000..e4370fd
--- /dev/null
+++ b/src/libknot/packet/rrset-wire.h
@@ -0,0 +1,73 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief RRSet from/to wire conversion functions.
+ *
+ * \addtogroup wire
+ * @{
+ */
+
+#pragma once
+
+#include "libknot/rrset.h"
+#include "libknot/packet/compr.h"
+
+/*!
+ * \brief Write RR Set content to a wire.
+ *
+ * \param rrset RRSet to be converted.
+ * \param wire Output wire buffer.
+ * \param max_size Capacity of wire buffer.
+ * \param rotate Rotate the RR order by this count.
+ * \param compr Compression context.
+ * \param flags Flags; currently only KNOT_PF_TTL_ORIG is accepted.
+ *
+ * \return Output size, negative number on error (KNOT_E*).
+ */
+int knot_rrset_to_wire_extra(const knot_rrset_t *rrset, uint8_t *wire,
+ uint16_t max_size, uint16_t rotate,
+ knot_compr_t *compr, uint16_t flags);
+
+/* TODO: remove in next major version. */
+int knot_rrset_to_wire_rotate(const knot_rrset_t *rrset, uint8_t *wire,
+ uint16_t max_size, uint16_t rotate,
+ knot_compr_t *compr);
+
+/*! \brief Same as knot_rrset_to_wire_extra but without rrset rotation and flags. */
+static inline int knot_rrset_to_wire(const knot_rrset_t *rrset, uint8_t *wire,
+ uint16_t max_size, knot_compr_t *compr)
+{
+ return knot_rrset_to_wire_extra(rrset, wire, max_size, 0, compr, 0);
+}
+
+/*!
+* \brief Creates one RR from wire, stores it into \a rrset.
+*
+* \param wire Source wire (the whole packet).
+* \param pos Position in \a wire where to start parsing.
+* \param max_size Total size of data in \a wire (size of the packet).
+* \param rrset Destination RRSet.
+* \param mm Memory context.
+* \param canonical Convert rrset to canonical format indication.
+*
+* \return KNOT_E*
+*/
+int knot_rrset_rr_from_wire(const uint8_t *wire, size_t *pos, size_t max_size,
+ knot_rrset_t *rrset, knot_mm_t *mm, bool canonical);
+
+/*! @} */
diff --git a/src/libknot/packet/wire.h b/src/libknot/packet/wire.h
new file mode 100644
index 0000000..26bc80e
--- /dev/null
+++ b/src/libknot/packet/wire.h
@@ -0,0 +1,980 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief Functions for manipulating and parsing raw data in DNS packets.
+ *
+ * \addtogroup wire
+ * @{
+ */
+
+#pragma once
+
+#include <assert.h>
+#include <stdint.h>
+
+#include "libknot/attribute.h"
+#include "libknot/wire.h"
+
+/*! \brief Offset of DNS header fields in wireformat. */
+enum knot_wire_offsets {
+ KNOT_WIRE_OFFSET_ID = 0,
+ KNOT_WIRE_OFFSET_FLAGS1 = 2,
+ KNOT_WIRE_OFFSET_FLAGS2 = 3,
+ KNOT_WIRE_OFFSET_QDCOUNT = 4,
+ KNOT_WIRE_OFFSET_ANCOUNT = 6,
+ KNOT_WIRE_OFFSET_NSCOUNT = 8,
+ KNOT_WIRE_OFFSET_ARCOUNT = 10
+};
+
+/*! \brief Minimum size for some parts of the DNS packet. */
+enum knot_wire_sizes {
+ KNOT_WIRE_HEADER_SIZE = 12,
+ KNOT_WIRE_QUESTION_MIN_SIZE = 5,
+ KNOT_WIRE_RR_MIN_SIZE = 11,
+ KNOT_WIRE_MIN_PKTSIZE = 512,
+ KNOT_WIRE_MAX_PKTSIZE = 65535,
+ KNOT_WIRE_MAX_PAYLOAD = KNOT_WIRE_MAX_PKTSIZE
+ - KNOT_WIRE_HEADER_SIZE
+ - KNOT_WIRE_QUESTION_MIN_SIZE
+};
+
+/*
+ * Packet header manipulation functions.
+ */
+
+/*!
+ * \brief Returns the ID from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return DNS packet ID.
+ */
+static inline uint16_t knot_wire_get_id(const uint8_t *packet)
+{
+ return knot_wire_read_u16(packet + KNOT_WIRE_OFFSET_ID);
+}
+
+/*!
+ * \brief Sets the ID to the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ * \param id DNS packet ID.
+ */
+static inline void knot_wire_set_id(uint8_t *packet, uint16_t id)
+{
+ knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_ID, id);
+}
+
+/*!
+ * \brief Returns the first byte of flags from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return First byte of DNS flags.
+ */
+static inline uint8_t knot_wire_get_flags1(const uint8_t *packet)
+{
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS1);
+}
+
+/*!
+ * \brief Sets the first byte of flags to the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ * \param flags1 First byte of the DNS flags.
+ */
+static inline uint8_t knot_wire_set_flags1(uint8_t *packet, uint8_t flags1)
+{
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS1) = flags1;
+}
+
+/*!
+ * \brief Returns the second byte of flags from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return Second byte of DNS flags.
+ */
+static inline uint8_t knot_wire_get_flags2(const uint8_t *packet)
+{
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS2);
+}
+
+/*!
+ * \brief Sets the second byte of flags to the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ * \param flags2 Second byte of the DNS flags.
+ */
+static inline uint8_t knot_wire_set_flags2(uint8_t *packet, uint8_t flags2)
+{
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS2) = flags2;
+}
+
+/*!
+ * \brief Returns the QDCOUNT (count of Question entries) from wire format of
+ * the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return QDCOUNT (count of Question entries in the packet).
+ */
+static inline uint16_t knot_wire_get_qdcount(const uint8_t *packet)
+{
+ return knot_wire_read_u16(packet + KNOT_WIRE_OFFSET_QDCOUNT);
+}
+
+/*!
+ * \brief Sets the QDCOUNT (count of Question entries) to wire format of the
+ * packet.
+ *
+ * \param packet Wire format of the packet.
+ * \param qdcount QDCOUNT (count of Question entries in the packet).
+ */
+static inline void knot_wire_set_qdcount(uint8_t *packet, uint16_t qdcount)
+{
+ knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_QDCOUNT, qdcount);
+}
+
+/*!
+ * \brief Adds to QDCOUNT.
+ */
+static inline void knot_wire_add_qdcount(uint8_t *packet, int16_t n)
+{
+ knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_QDCOUNT,
+ knot_wire_get_qdcount(packet) + n);
+}
+
+/*!
+ * \brief Returns the ANCOUNT (count of Answer entries) from wire format of
+ * the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return ANCOUNT (count of Answer entries in the packet).
+ */
+static inline uint16_t knot_wire_get_ancount(const uint8_t *packet)
+{
+ return knot_wire_read_u16(packet + KNOT_WIRE_OFFSET_ANCOUNT);
+}
+
+/*!
+ * \brief Sets the ANCOUNT (count of Answer entries) to wire format of the
+ * packet.
+ *
+ * \param packet Wire format of the packet.
+ * \param ancount ANCOUNT (count of Answer entries in the packet).
+ */
+static inline void knot_wire_set_ancount(uint8_t *packet, uint16_t ancount)
+{
+ knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_ANCOUNT, ancount);
+}
+
+/*!
+ * \brief Adds to ANCOUNT.
+ */
+static inline void knot_wire_add_ancount(uint8_t *packet, int16_t n)
+{
+ knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_ANCOUNT,
+ knot_wire_get_ancount(packet) + n);
+}
+
+/*!
+ * \brief Returns the NSCOUNT (count of Authority entries) from wire format of
+ * the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return NSCOUNT (count of Authority entries in the packet).
+ */
+static inline uint16_t knot_wire_get_nscount(const uint8_t *packet)
+{
+ return knot_wire_read_u16(packet + KNOT_WIRE_OFFSET_NSCOUNT);
+}
+
+/*!
+ * \brief Sets the NSCOUNT (count of Authority entries) to wire format of the
+ * packet.
+ *
+ * \param packet Wire format of the packet.
+ * \param nscount NSCOUNT (count of Authority entries in the packet).
+ */
+static inline void knot_wire_set_nscount(uint8_t *packet, uint16_t nscount)
+{
+ knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_NSCOUNT, nscount);
+}
+
+/*!
+ * \brief Adds to NSCOUNT.
+ */
+static inline void knot_wire_add_nscount(uint8_t *packet, int16_t n)
+{
+ knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_NSCOUNT,
+ knot_wire_get_nscount(packet) + n);
+}
+
+/*!
+ * \brief Returns the ARCOUNT (count of Additional entries) from wire format of
+ * the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return ARCOUNT (count of Additional entries in the packet).
+ */
+static inline uint16_t knot_wire_get_arcount(const uint8_t *packet)
+{
+ return knot_wire_read_u16(packet + KNOT_WIRE_OFFSET_ARCOUNT);
+}
+
+/*!
+ * \brief Sets the ARCOUNT (count of Additional entries) to wire format of the
+ * packet.
+ *
+ * \param packet Wire format of the packet.
+ * \param arcount ARCOUNT (count of Additional entries in the packet).
+ */
+static inline void knot_wire_set_arcount(uint8_t *packet, uint16_t arcount)
+{
+ knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_ARCOUNT, arcount);
+}
+
+/*!
+ * \brief Adds to ARCOUNT.
+ */
+static inline void knot_wire_add_arcount(uint8_t *packet, int16_t n)
+{
+ knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_ARCOUNT,
+ knot_wire_get_arcount(packet) + n);
+}
+
+/*
+ * Packet header flags manipulation functions.
+ */
+/*! \brief Constants for DNS header flags in the first flags byte. */
+enum knot_wire_flags1_consts {
+ KNOT_WIRE_RD_MASK = (uint8_t)0x01U, /*!< RD bit mask. */
+ KNOT_WIRE_RD_SHIFT = 0, /*!< RD bit shift. */
+ KNOT_WIRE_TC_MASK = (uint8_t)0x02U, /*!< TC bit mask. */
+ KNOT_WIRE_TC_SHIFT = 1, /*!< TC bit shift. */
+ KNOT_WIRE_AA_MASK = (uint8_t)0x04U, /*!< AA bit mask. */
+ KNOT_WIRE_AA_SHIFT = 2, /*!< AA bit shift. */
+ KNOT_WIRE_OPCODE_MASK = (uint8_t)0x78U, /*!< OPCODE mask. */
+ KNOT_WIRE_OPCODE_SHIFT = 3, /*!< OPCODE shift. */
+ KNOT_WIRE_QR_MASK = (uint8_t)0x80U, /*!< QR bit mask. */
+ KNOT_WIRE_QR_SHIFT = 7 /*!< QR bit shift. */
+};
+
+/*! \brief Constants for DNS header flags in the second flags byte. */
+enum knot_wire_flags2_consts {
+ KNOT_WIRE_RCODE_MASK = (uint8_t)0x0fU, /*!< RCODE mask. */
+ KNOT_WIRE_RCODE_SHIFT = 0, /*!< RCODE shift. */
+ KNOT_WIRE_CD_MASK = (uint8_t)0x10U, /*!< CD bit mask. */
+ KNOT_WIRE_CD_SHIFT = 4, /*!< CD bit shift. */
+ KNOT_WIRE_AD_MASK = (uint8_t)0x20U, /*!< AD bit mask. */
+ KNOT_WIRE_AD_SHIFT = 5, /*!< AD bit shift. */
+ KNOT_WIRE_Z_MASK = (uint8_t)0x40U, /*!< Zero bit mask. */
+ KNOT_WIRE_Z_SHIFT = 6, /*!< Zero bit shift. */
+ KNOT_WIRE_RA_MASK = (uint8_t)0x80U, /*!< RA bit mask. */
+ KNOT_WIRE_RA_SHIFT = 7 /*!< RA bit shift. */
+};
+
+/*
+ * Functions for getting / setting / clearing flags and codes directly in packet
+ */
+
+/*!
+ * \brief Returns the RD bit from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return Flags with only the RD bit according to its setting in the packet.
+ */
+static inline uint8_t knot_wire_get_rd(const uint8_t *packet)
+{
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS1) & KNOT_WIRE_RD_MASK;
+}
+
+/*!
+ * \brief Sets the RD bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_set_rd(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS1) |= KNOT_WIRE_RD_MASK;
+}
+
+/*!
+ * \brief Clears the RD bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_clear_rd(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS1) &= ~KNOT_WIRE_RD_MASK;
+}
+
+/*!
+ * \brief Returns the TC bit from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return Flags with only the TC bit according to its setting in the packet.
+ */
+static inline uint8_t knot_wire_get_tc(const uint8_t *packet)
+{
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS1) & KNOT_WIRE_TC_MASK;
+}
+
+/*!
+ * \brief Sets the TC bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_set_tc(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS1) |= KNOT_WIRE_TC_MASK;
+}
+
+/*!
+ * \brief Clears the TC bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_clear_tc(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS1) &= ~KNOT_WIRE_TC_MASK;
+}
+
+/*!
+ * \brief Returns the AA bit from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return Flags with only the AA bit according to its setting in the packet.
+ */
+static inline uint8_t knot_wire_get_aa(const uint8_t *packet)
+{
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS1) & KNOT_WIRE_AA_MASK;
+}
+
+/*!
+ * \brief Sets the AA bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_set_aa(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS1) |= KNOT_WIRE_AA_MASK;
+}
+
+/*!
+ * \brief Clears the AA bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_clear_aa(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS1) &= ~KNOT_WIRE_AA_MASK;
+}
+
+/*!
+ * \brief Returns the OPCODE from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return OPCODE of the packet.
+ */
+static inline uint8_t knot_wire_get_opcode(const uint8_t *packet)
+{
+ return (*(packet + KNOT_WIRE_OFFSET_FLAGS1)
+ & KNOT_WIRE_OPCODE_MASK) >> KNOT_WIRE_OPCODE_SHIFT;
+}
+
+/*!
+ * \brief Sets the OPCODE in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ * \param opcode OPCODE to set.
+ */
+static inline void knot_wire_set_opcode(uint8_t *packet, short opcode)
+{
+ uint8_t *flags1 = packet + KNOT_WIRE_OFFSET_FLAGS1;
+ *flags1 = (*flags1 & ~KNOT_WIRE_OPCODE_MASK)
+ | ((opcode) << KNOT_WIRE_OPCODE_SHIFT);
+}
+
+/*!
+ * \brief Returns the QR bit from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return Nonzero for responses and zero for queries.
+ */
+static inline uint8_t knot_wire_get_qr(const uint8_t *packet)
+{
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS1) & KNOT_WIRE_QR_MASK;
+}
+
+/*!
+ * \brief Sets the QR bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_set_qr(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS1) |= KNOT_WIRE_QR_MASK;
+}
+
+/*!
+ * \brief Clears the QR bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_clear_qr(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS1) &= ~KNOT_WIRE_QR_MASK;
+}
+
+/*!
+ * \brief Returns the RCODE from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return RCODE of the packet.
+ */
+static inline uint8_t knot_wire_get_rcode(const uint8_t *packet)
+{
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS2)
+ & KNOT_WIRE_RCODE_MASK;
+}
+
+/*!
+ * \brief Sets the RCODE in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ * \param rcode RCODE to set.
+ */
+static inline void knot_wire_set_rcode(uint8_t *packet, short rcode)
+{
+ uint8_t *flags2 = packet + KNOT_WIRE_OFFSET_FLAGS2;
+ *flags2 = (*flags2 & ~KNOT_WIRE_RCODE_MASK) | (rcode);
+}
+
+/*!
+ * \brief Returns the CD bit from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return Flags with only the CD bit according to its setting in the packet.
+ */
+static inline uint8_t knot_wire_get_cd(const uint8_t *packet)
+{
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS2) & KNOT_WIRE_CD_MASK;
+}
+
+/*!
+ * \brief Sets the CD bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_set_cd(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS2) |= KNOT_WIRE_CD_MASK;
+}
+
+/*!
+ * \brief Clears the CD bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_clear_cd(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS2) &= ~KNOT_WIRE_CD_MASK;
+}
+
+/*!
+ * \brief Returns the AD bit from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return Flags with only the AD bit according to its setting in the packet.
+ */
+static inline uint8_t knot_wire_get_ad(const uint8_t *packet)
+{
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS2) & KNOT_WIRE_AD_MASK;
+}
+
+/*!
+ * \brief Sets the AD bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_set_ad(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS2) |= KNOT_WIRE_AD_MASK;
+}
+
+/*!
+ * \brief Clears the AD bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_clear_ad(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS2) &= ~KNOT_WIRE_AD_MASK;
+}
+
+/*!
+ * \brief Returns the Zero bit from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return Flags with only the Zero bit according to its setting in the packet.
+ */
+static inline uint8_t knot_wire_get_z(const uint8_t *packet)
+{
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS2) & KNOT_WIRE_Z_MASK;
+}
+
+/*!
+ * \brief Sets the Zero bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_set_z(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS2) |= KNOT_WIRE_Z_MASK;
+}
+
+/*!
+ * \brief Clears the Zero bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_clear_z(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS2) &= ~KNOT_WIRE_Z_MASK;
+}
+
+/*!
+ * \brief Returns the RA bit from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return Flags with only the RA bit according to its setting in the packet.
+ */
+static inline uint8_t knot_wire_get_ra(const uint8_t *packet)
+{
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS2) & KNOT_WIRE_RA_MASK;
+}
+
+/*!
+ * \brief Sets the RA bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_set_ra(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS2) |= KNOT_WIRE_RA_MASK;
+}
+
+/*!
+ * \brief Clears the RA bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_clear_ra(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS2) &= ~KNOT_WIRE_RA_MASK;
+}
+
+/*
+ * Functions for getting / setting / clearing flags in flags variable
+ */
+
+/*!
+ * \brief Returns the RD bit from the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ *
+ * \return Flags byte with only the RD bit according to its setting in
+ * \a flags1.
+ */
+static inline uint8_t knot_wire_flags_get_rd(uint8_t flags1)
+{
+ return flags1 & KNOT_WIRE_RD_MASK;
+}
+
+/*!
+ * \brief Sets the RD bit in the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ */
+static inline void knot_wire_flags_set_rd(uint8_t *flags1)
+{
+ *flags1 |= KNOT_WIRE_RD_MASK;
+}
+
+/*!
+ * \brief Clears the RD bit in the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ */
+static inline void knot_wire_flags_clear_rd(uint8_t *flags1)
+{
+ *flags1 &= ~KNOT_WIRE_RD_MASK;
+}
+
+/*!
+ * \brief Returns the TC bit from the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ *
+ * \return Flags byte with only the TC bit according to its setting in
+ * \a flags1.
+ */
+static inline uint8_t knot_wire_flags_get_tc(uint8_t flags1)
+{
+ return flags1 & KNOT_WIRE_TC_MASK;
+}
+
+/*!
+ * \brief Sets the TC bit in the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ */
+static inline void knot_wire_flags_set_tc(uint8_t *flags1)
+{
+ *flags1 |= KNOT_WIRE_TC_MASK;
+}
+
+/*!
+ * \brief Clears the TC bit in the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ */
+static inline void knot_wire_flags_clear_tc(uint8_t *flags1)
+{
+ *flags1 &= ~KNOT_WIRE_TC_MASK;
+}
+
+/*!
+ * \brief Returns the AA bit from the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ *
+ * \return Flags byte with only the AA bit according to its setting in
+ * \a flags1.
+ */
+static inline uint8_t knot_wire_flags_get_aa(uint8_t flags1)
+{
+ return flags1 & KNOT_WIRE_AA_MASK;
+}
+
+/*!
+ * \brief Sets the AA bit in the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ */
+static inline void knot_wire_flags_set_aa(uint8_t *flags1)
+{
+ *flags1 |= KNOT_WIRE_AA_MASK;
+}
+
+/*!
+ * \brief Clears the AA bit in the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ */
+static inline void knot_wire_flags_clear_aa(uint8_t *flags1)
+{
+ *flags1 &= ~KNOT_WIRE_AA_MASK;
+}
+
+/*!
+ * \brief Returns the OPCODE from the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ *
+ * \return OPCODE
+ */
+static inline uint8_t knot_wire_flags_get_opcode(uint8_t flags1)
+{
+ return (flags1 & KNOT_WIRE_OPCODE_MASK)
+ >> KNOT_WIRE_OPCODE_SHIFT;
+}
+
+/*!
+ * \brief Sets the OPCODE in the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ * \param opcode OPCODE to set.
+ */
+static inline void knot_wire_flags_set_opcode(uint8_t *flags1, short opcode)
+{
+ *flags1 = (*flags1 & ~KNOT_WIRE_OPCODE_MASK)
+ | ((opcode) << KNOT_WIRE_OPCODE_SHIFT);
+}
+
+/*!
+ * \brief Returns the QR bit from the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ *
+ * \return Flags byte with only the QR bit according to its setting in
+ * \a flags1.
+ */
+static inline uint8_t knot_wire_flags_get_qr(uint8_t flags1)
+{
+ return flags1 & KNOT_WIRE_QR_MASK;
+}
+
+/*!
+ * \brief Sets the QR bit in the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ */
+static inline void knot_wire_flags_set_qr(uint8_t *flags1)
+{
+ *flags1 |= KNOT_WIRE_QR_MASK;
+}
+
+/*!
+ * \brief Clears the QR bit in the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ */
+static inline void knot_wire_flags_clear_qr(uint8_t *flags1)
+{
+ *flags1 &= ~KNOT_WIRE_QR_MASK;
+}
+
+/*!
+ * \brief Returns the RCODE from the second byte of flags.
+ *
+ * \param flags2 First byte of DNS header flags.
+ *
+ * \return RCODE
+ */
+static inline uint8_t knot_wire_flags_get_rcode(uint8_t flags2)
+{
+ return flags2 & KNOT_WIRE_RCODE_MASK;
+}
+
+/*!
+ * \brief Sets the RCODE in the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ * \param rcode RCODE to set.
+ */
+static inline void knot_wire_flags_set_rcode(uint8_t *flags2, short rcode)
+{
+ *flags2 = (*flags2 & ~KNOT_WIRE_RCODE_MASK) | (rcode);
+}
+
+/*!
+ * \brief Returns the CD bit from the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ *
+ * \return Flags byte with only the CD bit according to its setting in
+ * \a flags2.
+ */
+static inline uint8_t knot_wire_flags_get_cd(uint8_t flags2)
+{
+ return flags2 & KNOT_WIRE_CD_MASK;
+}
+
+/*!
+ * \brief Sets the CD bit in the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ */
+static inline void knot_wire_flags_set_cd(uint8_t *flags2)
+{
+ *flags2 |= KNOT_WIRE_CD_MASK;
+}
+
+/*!
+ * \brief Clears the CD bit in the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ */
+static inline void knot_wire_flags_clear_cd(uint8_t *flags2)
+{
+ *flags2 &= ~KNOT_WIRE_CD_MASK;
+}
+
+/*!
+ * \brief Returns the AD bit from the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ *
+ * \return Flags byte with only the AD bit according to its setting in
+ * \a flags2.
+ */
+static inline uint8_t knot_wire_flags_get_ad(uint8_t flags2)
+{
+ return flags2 & KNOT_WIRE_AD_MASK;
+}
+
+/*!
+ * \brief Sets the AD bit in the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ */
+static inline void knot_wire_flags_set_ad(uint8_t *flags2)
+{
+ *flags2 |= KNOT_WIRE_AD_MASK;
+}
+
+/*!
+ * \brief Clears the AD bit in the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ */
+static inline void knot_wire_flags_clear_ad(uint8_t *flags2)
+{
+ *flags2 &= ~KNOT_WIRE_AD_MASK;
+}
+
+/*!
+ * \brief Returns the Zero bit from the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ *
+ * \return Flags byte with only the Zero bit according to its setting in
+ * \a flags2.
+ */
+static inline uint8_t knot_wire_flags_get_z(uint8_t flags2)
+{
+ return flags2 & KNOT_WIRE_Z_MASK;
+}
+
+/*!
+ * \brief Sets the Zero bit in the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ */
+static inline void knot_wire_flags_set_z(uint8_t *flags2)
+{
+ *flags2 |= KNOT_WIRE_Z_MASK;
+}
+
+/*!
+ * \brief Clears the Zero bit in the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ */
+static inline void knot_wire_flags_clear_z(uint8_t *flags2)
+{
+ *flags2 &= ~KNOT_WIRE_Z_MASK;
+}
+
+/*!
+ * \brief Returns the RA bit from the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ *
+ * \return Flags byte with only the RA bit according to its setting in
+ * \a flags2.
+ */
+static inline uint8_t knot_wire_flags_get_ra(uint8_t flags2)
+{
+ return flags2 & KNOT_WIRE_RA_MASK;
+}
+
+/*!
+ * \brief Sets the RA bit in the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ */
+static inline void knot_wire_flags_set_ra(uint8_t *flags2)
+{
+ *flags2 |= KNOT_WIRE_RA_MASK;
+}
+
+/*!
+ * \brief Clears the RA bit in the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ */
+static inline void knot_wire_flags_clear_ra(uint8_t *flags2)
+{
+ *flags2 &= ~KNOT_WIRE_RA_MASK;
+}
+
+/*
+ * Pointer manipulation
+ */
+
+enum knot_wire_pointer_consts {
+ /*! \brief DNS packet pointer designation (first two bits set to 1). */
+ KNOT_WIRE_PTR = (uint8_t)0xC0,
+ /*! \brief DNS packet minimal pointer (KNOT_WIRE_PTR + 1 zero byte). */
+ KNOT_WIRE_PTR_BASE = (uint16_t)0xC000,
+ /*! \brief DNS packet maximal offset (KNOT_WIRE_BASE complement). */
+ KNOT_WIRE_PTR_MAX = (uint16_t)0x3FFF
+};
+
+static inline int knot_wire_is_pointer(const uint8_t *pos)
+{
+ return pos && ((pos[0] & KNOT_WIRE_PTR) == KNOT_WIRE_PTR);
+}
+
+/*!
+ * \brief Creates a DNS packet pointer and stores it in wire format.
+ *
+ * \param pos Position where tu put the pointer.
+ * \param ptr Relative position of the item to which the pointer should point in
+ * the wire format of the packet.
+ */
+static inline void knot_wire_put_pointer(uint8_t *pos, uint16_t ptr)
+{
+ knot_wire_write_u16(pos, ptr); // Write pointer offset.
+ assert((pos[0] & KNOT_WIRE_PTR) == 0); // Check for maximal offset.
+ pos[0] |= KNOT_WIRE_PTR; // Add pointer mark.
+}
+
+static inline uint16_t knot_wire_get_pointer(const uint8_t *pos)
+{
+ assert(knot_wire_is_pointer(pos)); // Check pointer.
+ return (knot_wire_read_u16(pos) - KNOT_WIRE_PTR_BASE); // Return offset.
+}
+
+_pure_ _mustcheck_
+static inline const uint8_t *knot_wire_seek_label(const uint8_t *lp, const uint8_t *wire)
+{
+ while (knot_wire_is_pointer(lp)) {
+ if (!wire)
+ return NULL;
+ lp = wire + knot_wire_get_pointer(lp);
+ }
+ return lp;
+}
+
+_pure_ _mustcheck_
+static inline const uint8_t *knot_wire_next_label(const uint8_t *lp, const uint8_t *wire)
+{
+ if (!lp || !lp[0]) /* No label after final label. */
+ return NULL;
+ return knot_wire_seek_label(lp + (lp[0] + sizeof(uint8_t)), wire);
+}
+
+/*! @} */
diff --git a/src/libknot/rdata.h b/src/libknot/rdata.h
new file mode 100644
index 0000000..e3a818b
--- /dev/null
+++ b/src/libknot/rdata.h
@@ -0,0 +1,97 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief API for manipulating rdata.
+ *
+ * \addtogroup rr
+ * @{
+ */
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+/*!< \brief Maximum rdata length. */
+#define KNOT_RDATA_MAXLEN 65535
+
+/*!
+ * \brief Structure holding single rdata payload.
+ */
+typedef struct {
+ uint16_t len;
+ uint8_t data[];
+} knot_rdata_t;
+
+/*!
+ * \brief Inits rdata structure.
+ *
+ * \param rdata Rdata structure to be initialized. At least knot_rdata_size bytes
+ * must fit into it!
+ * \param len Rdata length.
+ * \param data Rdata itself.
+ */
+inline static void knot_rdata_init(knot_rdata_t *rdata, uint16_t len, const uint8_t *data)
+{
+ assert(rdata);
+ rdata->len = len;
+ if (rdata->len > 0) {
+ assert(data);
+ memcpy(rdata->data, data, len);
+ }
+}
+
+/*!
+ * \brief Returns actual size of the rdata structure for given rdata length.
+ *
+ * \param len Rdata length.
+ *
+ * \return Actual structure size.
+ */
+inline static size_t knot_rdata_size(uint16_t len)
+{
+ return sizeof(uint16_t) + len + (len & 1);
+}
+
+/*!
+ * \brief Canonical comparison of two rdata structures.
+ *
+ * \param rdata1 First rdata to compare.
+ * \param rdata2 Second rdata to compare.
+ *
+ * \retval = 0 if rdata1 == rdata2.
+ * \retval < 0 if rdata1 < rdata2.
+ * \retval > 0 if rdata1 > rdata2.
+ */
+inline static int knot_rdata_cmp(const knot_rdata_t *rdata1, const knot_rdata_t *rdata2)
+{
+ assert(rdata1);
+ assert(rdata2);
+
+ size_t common_len = (rdata1->len <= rdata2->len) ? rdata1->len : rdata2->len;
+
+ int cmp = memcmp(rdata1->data, rdata2->data, common_len);
+ if (cmp == 0 && rdata1->len != rdata2->len) {
+ cmp = rdata1->len < rdata2->len ? -1 : 1;
+ }
+ return cmp;
+}
+
+/*! @} */
diff --git a/src/libknot/rdataset.c b/src/libknot/rdataset.c
new file mode 100644
index 0000000..4767bf9
--- /dev/null
+++ b/src/libknot/rdataset.c
@@ -0,0 +1,368 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "libknot/attribute.h"
+#include "libknot/rdataset.h"
+#include "libknot/errcode.h"
+#include "contrib/mempattern.h"
+
+static knot_rdata_t *rr_seek(const knot_rdataset_t *rrs, uint16_t pos)
+{
+ assert(rrs);
+ assert(0 < rrs->count);
+ assert(pos < rrs->count);
+
+ uint8_t *raw = (uint8_t *)(rrs->rdata);
+ for (uint16_t i = 0; i < pos; ++i) {
+ raw += knot_rdata_size(((knot_rdata_t *)raw)->len);
+ }
+
+ return (knot_rdata_t *)raw;
+}
+
+static int find_rr_pos(const knot_rdataset_t *rrs, const knot_rdata_t *rr)
+{
+ knot_rdata_t *search_rr = rrs->rdata;
+ for (uint16_t i = 0; i < rrs->count; ++i) {
+ if (knot_rdata_cmp(rr, search_rr) == 0) {
+ return i;
+ }
+ search_rr = knot_rdataset_next(search_rr);
+ }
+
+ return KNOT_ENOENT;
+}
+
+static int add_rr_at(knot_rdataset_t *rrs, const knot_rdata_t *rr, uint16_t pos,
+ knot_mm_t *mm)
+{
+ assert(rrs);
+ assert(rr);
+ assert(pos <= rrs->count);
+
+ if (rrs->count == UINT16_MAX) {
+ return KNOT_ESPACE;
+ }
+
+ size_t total_size = knot_rdataset_size(rrs);
+ size_t new_size = knot_rdata_size(rr->len);
+
+ // Realloc RDATA.
+ knot_rdata_t *tmp = mm_realloc(mm, rrs->rdata, total_size + new_size,
+ total_size);
+ if (tmp == NULL) {
+ return KNOT_ENOMEM;
+ } else {
+ rrs->rdata = tmp;
+ }
+
+ if (rrs->count == 0 || pos == rrs->count) {
+ // No need to rearange RDATA.
+ rrs->count++;
+ knot_rdata_t *new_rr = rr_seek(rrs, pos);
+ knot_rdata_init(new_rr, rr->len, rr->data);
+ return KNOT_EOK;
+ }
+
+ // RDATA have to be rearanged.
+ knot_rdata_t *old_rr = rr_seek(rrs, pos);
+ knot_rdata_t *last_rr = rr_seek(rrs, rrs->count - 1);
+
+ // Make space for new RDATA by moving the array.
+ uint8_t *dst = (uint8_t *)old_rr + new_size;
+ assert(old_rr <= last_rr);
+ size_t len = ((uint8_t *)last_rr - (uint8_t *)old_rr) +
+ knot_rdata_size(last_rr->len);
+ memmove(dst, old_rr, len);
+
+ // Set new RDATA.
+ knot_rdata_init(old_rr, rr->len, rr->data);
+ rrs->count++;
+
+ return KNOT_EOK;
+}
+
+static int remove_rr_at(knot_rdataset_t *rrs, uint16_t pos, knot_mm_t *mm)
+{
+ assert(rrs);
+ assert(0 < rrs->count);
+ assert(pos < rrs->count);
+
+ knot_rdata_t *old_rr = rr_seek(rrs, pos);
+ knot_rdata_t *last_rr = rr_seek(rrs, rrs->count - 1);
+
+ size_t total_size = knot_rdataset_size(rrs);
+ size_t old_size = knot_rdata_size(old_rr->len);
+
+ // Move RDATA.
+ uint8_t *old_threshold = (uint8_t *)old_rr + old_size;
+ uint8_t *last_threshold = (uint8_t *)last_rr + knot_rdata_size(last_rr->len);
+ assert(old_threshold <= last_threshold);
+ memmove(old_rr, old_threshold, last_threshold - old_threshold);
+
+ if (rrs->count > 1) {
+ // Realloc RDATA.
+ knot_rdata_t *tmp = mm_realloc(mm, rrs->rdata, total_size - old_size,
+ total_size);
+ if (tmp == NULL) {
+ return KNOT_ENOMEM;
+ } else {
+ rrs->rdata = tmp;
+ }
+ } else {
+ // Free RDATA.
+ mm_free(mm, rrs->rdata);
+ rrs->rdata = NULL;
+ }
+ rrs->count--;
+
+ return KNOT_EOK;
+}
+
+_public_
+void knot_rdataset_clear(knot_rdataset_t *rrs, knot_mm_t *mm)
+{
+ if (rrs == NULL) {
+ return;
+ }
+
+ mm_free(mm, rrs->rdata);
+ knot_rdataset_init(rrs);
+}
+
+_public_
+int knot_rdataset_copy(knot_rdataset_t *dst, const knot_rdataset_t *src, knot_mm_t *mm)
+{
+ if (dst == NULL || src == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ dst->count = src->count;
+ size_t src_size = knot_rdataset_size(src);
+ dst->rdata = mm_alloc(mm, src_size);
+ if (dst->rdata == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ memcpy(dst->rdata, src->rdata, src_size);
+
+ return KNOT_EOK;
+}
+
+_public_
+knot_rdata_t *knot_rdataset_at(const knot_rdataset_t *rrs, uint16_t pos)
+{
+ if (rrs == NULL || rrs->count == 0 || pos >= rrs->count) {
+ return NULL;
+ }
+
+ return rr_seek(rrs, pos);
+}
+
+_public_
+size_t knot_rdataset_size(const knot_rdataset_t *rrs)
+{
+ if (rrs == NULL || rrs->count == 0) {
+ return 0;
+ }
+
+ const knot_rdata_t *last = rr_seek(rrs, rrs->count - 1);
+ return (uint8_t *)last + knot_rdata_size(last->len) - (uint8_t *)rrs->rdata;
+}
+
+_public_
+int knot_rdataset_add(knot_rdataset_t *rrs, const knot_rdata_t *rr, knot_mm_t *mm)
+{
+ if (rrs == NULL || rr == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ // First insert to empty rdataset.
+ if (rrs->count == 0) {
+ return add_rr_at(rrs, rr, 0, mm);
+ }
+
+ for (int i = rrs->count - 1; i >= 0; --i) {
+ const knot_rdata_t *rrset_rr = rr_seek(rrs, i);
+ int cmp = knot_rdata_cmp(rrset_rr, rr);
+ if (cmp == 0) {
+ // Duplicate - no need to add this RR.
+ return KNOT_EOK;
+ } else if (cmp < 0) {
+ // Found position to insert.
+ return add_rr_at(rrs, rr, i + 1, mm);
+ }
+ }
+
+ // If flow gets here, it means that we should insert at the first position.
+ return add_rr_at(rrs, rr, 0, mm);
+}
+
+_public_
+int knot_rdataset_reserve(knot_rdataset_t *rrs, uint16_t size, knot_mm_t *mm)
+{
+ if (rrs == NULL) {
+ return KNOT_EINVAL;
+ } else if (rrs->count == UINT16_MAX) {
+ return KNOT_ESPACE;
+ }
+
+ size_t old_size = knot_rdataset_size(rrs);
+ size_t new_size = old_size + knot_rdata_size(size);
+
+ knot_rdata_t *tmp = mm_realloc(mm, rrs->rdata, new_size, old_size);
+ if (tmp == NULL) {
+ return KNOT_ENOMEM;
+ }
+ rrs->rdata = tmp;
+ rrs->count++;
+
+ // We have to initialise the 'size' field in the reserved space.
+ rr_seek(rrs, rrs->count - 1)->len = size;
+
+ return KNOT_EOK;
+}
+
+_public_
+int knot_rdataset_unreserve(knot_rdataset_t *rrs, knot_mm_t *mm)
+{
+ if (rrs == NULL || rrs->count == 0) {
+ return KNOT_EINVAL;
+ }
+
+ return remove_rr_at(rrs, rrs->count - 1, mm);
+}
+
+_public_
+bool knot_rdataset_eq(const knot_rdataset_t *rrs1, const knot_rdataset_t *rrs2)
+{
+ if (rrs1 == NULL || rrs2 == NULL || rrs1->count != rrs2->count) {
+ return false;
+ }
+
+ knot_rdata_t *rr1 = rrs1->rdata;
+ knot_rdata_t *rr2 = rrs2->rdata;
+ for (uint16_t i = 0; i < rrs1->count; ++i) {
+ if (knot_rdata_cmp(rr1, rr2) != 0) {
+ return false;
+ }
+ rr1 = knot_rdataset_next(rr1);
+ rr2 = knot_rdataset_next(rr2);
+ }
+
+ return true;
+}
+
+_public_
+bool knot_rdataset_member(const knot_rdataset_t *rrs, const knot_rdata_t *rr)
+{
+ if (rrs == NULL) {
+ return false;
+ }
+
+ knot_rdata_t *cmp_rr = rrs->rdata;
+ for (uint16_t i = 0; i < rrs->count; ++i) {
+ int cmp = knot_rdata_cmp(cmp_rr, rr);
+ if (cmp == 0) {
+ // Match.
+ return true;
+ } else if (cmp > 0) {
+ // 'Greater' RR present, no need to continue.
+ return false;
+ }
+ cmp_rr = knot_rdataset_next(cmp_rr);
+ }
+
+ return false;
+}
+
+_public_
+int knot_rdataset_merge(knot_rdataset_t *rrs1, const knot_rdataset_t *rrs2,
+ knot_mm_t *mm)
+{
+ if (rrs1 == NULL || rrs2 == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ knot_rdata_t *rr2 = rrs2->rdata;
+ for (uint16_t i = 0; i < rrs2->count; ++i) {
+ int ret = knot_rdataset_add(rrs1, rr2, mm);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ rr2 = knot_rdataset_next(rr2);
+ }
+
+ return KNOT_EOK;
+}
+
+_public_
+int knot_rdataset_intersect(const knot_rdataset_t *rrs1, const knot_rdataset_t *rrs2,
+ knot_rdataset_t *out, knot_mm_t *mm)
+{
+ if (rrs1 == NULL || rrs2 == NULL || out == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ knot_rdataset_init(out);
+ knot_rdata_t *rr1 = rrs1->rdata;
+ for (uint16_t i = 0; i < rrs1->count; ++i) {
+ if (knot_rdataset_member(rrs2, rr1)) {
+ // Add RR into output intersection RRSet.
+ int ret = knot_rdataset_add(out, rr1, mm);
+ if (ret != KNOT_EOK) {
+ knot_rdataset_clear(out, mm);
+ return ret;
+ }
+ }
+ rr1 = knot_rdataset_next(rr1);
+ }
+
+ return KNOT_EOK;
+}
+
+_public_
+int knot_rdataset_subtract(knot_rdataset_t *from, const knot_rdataset_t *what,
+ knot_mm_t *mm)
+{
+ if (from == NULL || what == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ if (from->rdata == what->rdata) {
+ knot_rdataset_clear(from, mm);
+ knot_rdataset_init((knot_rdataset_t *) what);
+ return KNOT_EOK;
+ }
+
+ knot_rdata_t *to_remove = what->rdata;
+ for (uint16_t i = 0; i < what->count; ++i) {
+ int pos_to_remove = find_rr_pos(from, to_remove);
+ if (pos_to_remove >= 0) {
+ int ret = remove_rr_at(from, pos_to_remove, mm);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+ to_remove = knot_rdataset_next(to_remove);
+ }
+
+ return KNOT_EOK;
+}
diff --git a/src/libknot/rdataset.h b/src/libknot/rdataset.h
new file mode 100644
index 0000000..fa1d4df
--- /dev/null
+++ b/src/libknot/rdataset.h
@@ -0,0 +1,201 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief API for manipulating RR arrays.
+ *
+ * \addtogroup rr
+ * @{
+ */
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "libknot/mm_ctx.h"
+#include "libknot/rdata.h"
+
+/*!< \brief Set of RRs. */
+typedef struct {
+ uint16_t count; /*!< \brief Count of RRs stored in the structure. */
+ knot_rdata_t *rdata; /*!< \brief Serialized rdata, canonically sorted. */
+} knot_rdataset_t;
+
+/*!
+ * \brief Initializes RRS structure.
+ *
+ * \param rrs Structure to be initialized.
+ */
+inline static void knot_rdataset_init(knot_rdataset_t *rrs)
+{
+ if (rrs != NULL) {
+ rrs->count = 0;
+ rrs->rdata = NULL;
+ }
+}
+
+/*!
+ * \brief Advance to the next rdata in a rdataset.
+ *
+ * Useful for iteration.
+ *
+ * \note Ensure that this operation makes sense!
+ *
+ * \param rr Current RR.
+ *
+ * \return Next RR.
+ */
+static inline knot_rdata_t *knot_rdataset_next(knot_rdata_t *rr)
+{
+ assert(rr);
+ return (knot_rdata_t *)((uint8_t *)rr + knot_rdata_size(rr->len));
+}
+
+/*!
+ * \brief Frees data initialized by RRS structure, but not the structure itself.
+ *
+ * \param rrs Structure to be cleared.
+ * \param mm Memory context used to create allocations.
+ */
+void knot_rdataset_clear(knot_rdataset_t *rrs, knot_mm_t *mm);
+
+/*!
+ * \brief Deep copies RRS structure. All data are duplicated.
+ *
+ * \param dst Copy destination.
+ * \param src Copy source.
+ * \param mm Memory context.
+ *
+ * \return KNOT_E*
+ */
+int knot_rdataset_copy(knot_rdataset_t *dst, const knot_rdataset_t *src, knot_mm_t *mm);
+
+/*!
+ * \brief Gets RR from RRS structure, using given position.
+ *
+ * \param rrs RRS structure to get RR from.
+ * \param pos Position to use (counted from 0).
+ *
+ * \return Pointer to RR at \a pos position.
+ */
+knot_rdata_t *knot_rdataset_at(const knot_rdataset_t *rrs, uint16_t pos);
+
+/*!
+ * \brief Returns size of the structures holding the RR set.
+ *
+ * \param rrs RR array.
+ *
+ * \return Array size.
+ */
+size_t knot_rdataset_size(const knot_rdataset_t *rrs);
+
+/*!
+ * \brief Adds single RR into RRS structure. All data are copied.
+ *
+ * \param rrs RRS structure to add RR into.
+ * \param rr RR to add.
+ * \param mm Memory context.
+ *
+ * \return KNOT_E*
+ */
+int knot_rdataset_add(knot_rdataset_t *rrs, const knot_rdata_t *rr, knot_mm_t *mm);
+
+/*!
+ * \brief Reserves space at the end of the RRS structure.
+ *
+ * \param rrs RRS structure to reserve space at.
+ * \param size How much space to reserve.
+ * \param mm Memory context.
+ *
+ * \return KNOT_E*
+ */
+int knot_rdataset_reserve(knot_rdataset_t *rrs, uint16_t size, knot_mm_t *mm);
+
+/*!
+ * \brief Removes the last RR from RRS structure, i.e. does the opposite of _reserve.
+ *
+ * \param rrs RRS structure to remove RR from.
+ * \param mm Memory context.
+ *
+ * \return KNOT_E*
+ */
+int knot_rdataset_unreserve(knot_rdataset_t *rrs, knot_mm_t *mm);
+
+/*!
+ * \brief RRS equality check.
+ *
+ * \param rrs1 First RRS to be compared.
+ * \param rrs2 Second RRS to be compared.
+ *
+ * \retval true if rrs1 == rrs2.
+ * \retval false if rrs1 != rrs2.
+ */
+bool knot_rdataset_eq(const knot_rdataset_t *rrs1, const knot_rdataset_t *rrs2);
+
+/*!
+ * \brief Returns true if \a rr is present in \a rrs, false otherwise.
+ *
+ * \param rrs RRS to search in.
+ * \param rr RR to compare with.
+ *
+ * \retval true if \a rr is present in \a rrs.
+ * \retval false if \a rr is not present in \a rrs.
+ */
+bool knot_rdataset_member(const knot_rdataset_t *rrs, const knot_rdata_t *rr);
+
+/*!
+ * \brief Merges two RRS into the first one. Second RRS is left intact.
+ * Canonical order is preserved.
+ *
+ * \param rrs1 Destination RRS (merge here).
+ * \param rrs2 RRS to be merged (merge from).
+ * \param mm Memory context.
+ *
+ * \return KNOT_E*
+ */
+int knot_rdataset_merge(knot_rdataset_t *rrs1, const knot_rdataset_t *rrs2,
+ knot_mm_t *mm);
+
+/*!
+ * \brief RRS set-like intersection. Full compare is done.
+ *
+ * \param rrs1 First RRS to intersect.
+ * \param rrs2 Second RRS to intersect.
+ * \param out Output RRS with intersection, RDATA are created anew.
+ * \param mm Memory context. Will be used to create new RDATA.
+ *
+ * \return KNOT_E*
+ */
+int knot_rdataset_intersect(const knot_rdataset_t *rrs1, const knot_rdataset_t *rrs2,
+ knot_rdataset_t *out, knot_mm_t *mm);
+
+/*!
+ * \brief Does set-like RRS subtraction. \a from RRS is changed.
+ *
+ * \param from RRS to subtract from.
+ * \param what RRS to subtract.
+ * \param mm Memory context use to reallocated \a from data.
+ *
+ * \return KNOT_E*
+ */
+int knot_rdataset_subtract(knot_rdataset_t *from, const knot_rdataset_t *what,
+ knot_mm_t *mm);
+
+/*! @} */
diff --git a/src/libknot/rrset-dump.c b/src/libknot/rrset-dump.c
new file mode 100644
index 0000000..a1c410a
--- /dev/null
+++ b/src/libknot/rrset-dump.c
@@ -0,0 +1,2014 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <arpa/inet.h>
+#include <inttypes.h>
+#include <math.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include "libdnssec/binary.h"
+#include "libdnssec/keytag.h"
+#include "libknot/attribute.h"
+#include "libknot/rrset-dump.h"
+#include "libknot/codes.h"
+#include "libknot/consts.h"
+#include "libknot/descriptor.h"
+#include "libknot/errcode.h"
+#include "libknot/lookup.h"
+#include "libknot/rrtype/rrsig.h"
+#include "libknot/wire.h"
+#include "contrib/base32hex.h"
+#include "contrib/base64.h"
+#include "contrib/ctype.h"
+#include "contrib/wire_ctx.h"
+
+#define RRSET_DUMP_LIMIT (2 * 1024 * 1024)
+
+#define TAB_WIDTH 8
+#define BLOCK_WIDTH 40
+#define BLOCK_INDENT "\n\t\t\t\t"
+
+#define LOC_ZERO 2147483648 // 2^31
+
+/*! \brief macros with repetitive (mostly error-checking) code of methods from first section of this file */
+#define CHECK_PRET if (p->ret < 0) return;
+#define CHECK_INMAX(mininmax) if (p->in_max < (mininmax)) { p->ret = -1; return; }
+#define CHECK_RET_OUTMAX_SNPRINTF if (ret <= 0 || (size_t)ret >= p->out_max) { p->ret = -1; return; }
+#define STRING_TERMINATION if (p->out_max > 0) { *p->out = '\0'; } else { p->ret = -1; return; }
+#define FILL_IN_INPUT(pdata) if (memcpy(&(pdata), p->in, in_len) == NULL) { p->ret = -1; return; }
+#define CHECK_RET_POSITIVE if (ret <= 0) { p->ret = -1; return; }
+
+typedef struct {
+ const knot_dump_style_t *style;
+ const uint8_t *in;
+ size_t in_max;
+ char *out;
+ size_t out_max;
+ size_t total;
+ int ret;
+} rrset_dump_params_t;
+
+_public_
+const knot_dump_style_t KNOT_DUMP_STYLE_DEFAULT = {
+ .wrap = false,
+ .show_class = false,
+ .show_ttl = true,
+ .verbose = false,
+ .original_ttl = true,
+ .empty_ttl = false,
+ .human_ttl = false,
+ .human_tmstamp = true,
+ .hide_crypto = false,
+ .ascii_to_idn = NULL
+};
+
+static void dump_string(rrset_dump_params_t *p, const char *str)
+{
+ CHECK_PRET
+
+ size_t in_len = strlen(str);
+
+ // Check input size (+ 1 termination).
+ if (in_len >= p->out_max) {
+ p->ret = -1;
+ return;
+ }
+
+ // Copy string including termination '\0'!
+ if (memcpy(p->out, str, in_len + 1) == NULL) {
+ p->ret = -1;
+ return;
+ }
+
+ // Fill in output.
+ p->out += in_len;
+ p->out_max -= in_len;
+ p->total += in_len;
+}
+
+static void wire_num8_to_str(rrset_dump_params_t *p)
+{
+ CHECK_PRET
+
+ uint8_t data = *(p->in);
+ size_t in_len = sizeof(data);
+ size_t out_len = 0;
+
+ CHECK_INMAX(in_len)
+
+ // Write number.
+ int ret = snprintf(p->out, p->out_max, "%u", data);
+ CHECK_RET_OUTMAX_SNPRINTF
+ out_len = ret;
+
+ // Fill in output.
+ p->in += in_len;
+ p->in_max -= in_len;
+ p->out += out_len;
+ p->out_max -= out_len;
+ p->total += out_len;
+}
+
+static void wire_num16_to_str(rrset_dump_params_t *p)
+{
+ CHECK_PRET
+
+ uint16_t data;
+ size_t in_len = sizeof(data);
+ size_t out_len = 0;
+
+ CHECK_INMAX(in_len)
+
+ // Fill in input data.
+ data = knot_wire_read_u16(p->in);
+
+ // Write number.
+ int ret = snprintf(p->out, p->out_max, "%u", data);
+ CHECK_RET_OUTMAX_SNPRINTF
+ out_len = ret;
+
+ // Fill in output.
+ p->in += in_len;
+ p->in_max -= in_len;
+ p->out += out_len;
+ p->out_max -= out_len;
+ p->total += out_len;
+}
+
+static void wire_num32_to_str(rrset_dump_params_t *p)
+{
+ CHECK_PRET
+
+ uint32_t data;
+ size_t in_len = sizeof(data);
+ size_t out_len = 0;
+
+ CHECK_INMAX(in_len)
+
+ // Fill in input data.
+ data = knot_wire_read_u32(p->in);
+
+ // Write number.
+ int ret = snprintf(p->out, p->out_max, "%u", data);
+ CHECK_RET_OUTMAX_SNPRINTF
+ out_len = ret;
+
+ // Fill in output.
+ p->in += in_len;
+ p->in_max -= in_len;
+ p->out += out_len;
+ p->out_max -= out_len;
+ p->total += out_len;
+}
+
+static void wire_num48_to_str(rrset_dump_params_t *p)
+{
+ CHECK_PRET
+
+ uint64_t data;
+ size_t in_len = 6;
+ size_t out_len = 0;
+
+ CHECK_INMAX(in_len)
+
+ // Fill in input data.
+ data = knot_wire_read_u48(p->in);
+
+ // Write number.
+ int ret = snprintf(p->out, p->out_max, "%"PRIu64"", data);
+ CHECK_RET_OUTMAX_SNPRINTF
+ out_len = ret;
+
+ // Fill in output.
+ p->in += in_len;
+ p->in_max -= in_len;
+ p->out += out_len;
+ p->out_max -= out_len;
+ p->total += out_len;
+}
+
+static void wire_ipv4_to_str(rrset_dump_params_t *p)
+{
+ CHECK_PRET
+
+ struct in_addr addr4;
+ size_t in_len = sizeof(addr4.s_addr);
+ size_t out_len = 0;
+
+ CHECK_INMAX(in_len)
+
+ FILL_IN_INPUT(addr4.s_addr)
+
+ // Write address.
+ if (inet_ntop(AF_INET, &addr4, p->out, p->out_max) == NULL) {
+ p->ret = -1;
+ return;
+ }
+ out_len = strlen(p->out);
+
+ // Fill in output.
+ p->in += in_len;
+ p->in_max -= in_len;
+ p->out += out_len;
+ p->out_max -= out_len;
+ p->total += out_len;
+}
+
+static void wire_ipv6_to_str(rrset_dump_params_t *p)
+{
+ CHECK_PRET
+
+ struct in6_addr addr6;
+ size_t in_len = sizeof(addr6.s6_addr);
+ size_t out_len = 0;
+
+ CHECK_INMAX(in_len)
+
+ FILL_IN_INPUT(addr6.s6_addr)
+
+ // Write address.
+ if (inet_ntop(AF_INET6, &addr6, p->out, p->out_max) == NULL) {
+ p->ret = -1;
+ return;
+ }
+ out_len = strlen(p->out);
+
+ // Fill in output.
+ p->in += in_len;
+ p->in_max -= in_len;
+ p->out += out_len;
+ p->out_max -= out_len;
+ p->total += out_len;
+}
+
+static void wire_type_to_str(rrset_dump_params_t *p)
+{
+ CHECK_PRET
+
+ char type[32];
+ uint16_t data;
+ size_t in_len = sizeof(data);
+ size_t out_len = 0;
+
+ CHECK_INMAX(in_len)
+
+ FILL_IN_INPUT(data)
+
+ // Get record type name string.
+ int ret = knot_rrtype_to_string(ntohs(data), type, sizeof(type));
+ CHECK_RET_POSITIVE
+
+ // Write string.
+ ret = snprintf(p->out, p->out_max, "%s", type);
+ CHECK_RET_OUTMAX_SNPRINTF
+ out_len = ret;
+
+ // Fill in output.
+ p->in += in_len;
+ p->in_max -= in_len;
+ p->out += out_len;
+ p->out_max -= out_len;
+ p->total += out_len;
+}
+
+static int hex_encode(const uint8_t *in,
+ const uint32_t in_len,
+ uint8_t *out,
+ const uint32_t out_len)
+{
+ static const char hex[] = "0123456789ABCDEF";
+
+ if (out_len < 2 * in_len) {
+ return -1;
+ }
+
+ for (uint32_t i = 0; i < in_len; i++) {
+ out[2 * i] = hex[in[i] / 16];
+ out[2 * i + 1] = hex[in[i] % 16];
+ }
+
+ return 2 * in_len;
+}
+
+static int hex_encode_alloc(const uint8_t *in,
+ const uint32_t in_len,
+ uint8_t **out)
+{
+ uint32_t out_len = 2 * in_len;
+
+ // Allocating output buffer.
+ *out = malloc(out_len);
+
+ if (*out == NULL) {
+ return -1;
+ }
+
+ // Encoding data.
+ return hex_encode(in, in_len, *out, out_len);
+}
+
+static int num48_encode(const uint8_t *in,
+ const uint32_t in_len,
+ uint8_t *out,
+ const uint32_t out_len)
+{
+ if (in_len != 6) {
+ return -1;
+ }
+
+ uint64_t data = knot_wire_read_u48(in);
+
+ int ret = snprintf((char *)out, out_len, "%"PRIu64"", data);
+ if (ret <= 0 || (size_t)ret >= out_len) {
+ return -1;
+ }
+
+ return ret;
+}
+
+typedef int (*encode_t)(const uint8_t *in, const uint32_t in_len,
+ uint8_t *out, const uint32_t out_len);
+
+typedef int (*encode_alloc_t)(const uint8_t *in, const uint32_t in_len,
+ uint8_t **out);
+
+static void wire_data_encode_to_str(rrset_dump_params_t *p,
+ encode_t enc, encode_alloc_t enc_alloc)
+{
+ CHECK_PRET
+
+ int ret;
+ size_t in_len = p->in_max;
+
+ // One-line vs multi-line mode.
+ if (p->style->wrap == false) {
+ // Encode data directly to the output.
+ ret = enc(p->in, in_len, (uint8_t *)(p->out), p->out_max);
+ CHECK_RET_POSITIVE
+ size_t out_len = ret;
+
+ p->out += out_len;
+ p->out_max -= out_len;
+ p->total += out_len;
+ } else {
+ int src_begin;
+ uint8_t *buf;
+
+ // Encode data to the temporary buffer.
+ ret = enc_alloc(p->in, in_len, &buf);
+ CHECK_RET_POSITIVE
+
+ // Loop which wraps base64 block in more lines.
+ for (src_begin = 0; src_begin < ret; src_begin += BLOCK_WIDTH) {
+ if (src_begin > 0) {
+ // Write indent block.
+ dump_string(p, BLOCK_INDENT);
+ if (p->ret < 0) {
+ free(buf);
+ return;
+ }
+ }
+
+ // Compute block length (the last one can be shorter).
+ int src_len = (ret - src_begin) < BLOCK_WIDTH ?
+ (ret - src_begin) : BLOCK_WIDTH;
+
+ if ((size_t)src_len > p->out_max) {
+ free(buf);
+ p->ret = -1;
+ return;
+ }
+
+ // Write data block.
+ memcpy(p->out, buf + src_begin, src_len);
+
+ p->out += src_len;
+ p->out_max -= src_len;
+ p->total += src_len;
+ }
+
+ // Destroy temporary buffer.
+ free(buf);
+ }
+
+ STRING_TERMINATION
+
+ // Fill in output.
+ p->in += in_len;
+ p->in_max -= in_len;
+}
+
+static void wire_len_data_encode_to_str(rrset_dump_params_t *p,
+ encode_t enc,
+ const size_t len_len,
+ const bool print_len,
+ const char *empty_str)
+{
+ CHECK_PRET
+
+ size_t in_len;
+
+ // First len_len bytes are data length.
+ CHECK_INMAX(len_len)
+
+ // Read data length.
+ switch (len_len) {
+ case 1:
+ in_len = *(p->in);
+ break;
+ case 2:
+ in_len = knot_wire_read_u16(p->in);
+ break;
+ case 4:
+ in_len = knot_wire_read_u32(p->in);
+ break;
+ default:
+ p->ret = -1;
+ return;
+ }
+
+ // If required print data length.
+ if (print_len == true) {
+ switch (len_len) {
+ case 1:
+ wire_num8_to_str(p);
+ break;
+ case 2:
+ wire_num16_to_str(p);
+ break;
+ case 4:
+ wire_num32_to_str(p);
+ break;
+ }
+
+ CHECK_PRET
+
+ // If something follows, print one space character.
+ if (in_len > 0 || *empty_str != '\0') {
+ dump_string(p, " ");
+ CHECK_PRET
+ }
+ } else {
+ p->in += len_len;
+ p->in_max -= len_len;
+ }
+
+ if (in_len > 0) {
+ // Encode data directly to the output.
+ int ret = enc(p->in, in_len, (uint8_t *)(p->out), p->out_max);
+ CHECK_RET_POSITIVE
+ p->out += ret;
+ p->out_max -= ret;
+ p->total += ret;
+
+ STRING_TERMINATION
+
+ // Fill in output.
+ p->in += in_len;
+ p->in_max -= in_len;
+ } else if (*empty_str != '\0') {
+ dump_string(p, empty_str);
+ CHECK_PRET
+ }
+}
+
+static void wire_data_omit(rrset_dump_params_t *p)
+{
+ CHECK_PRET
+
+ const char *omit_message = "[omitted]";
+ const size_t omlen = strlen(omit_message);
+
+ if (p->out_max < omlen) {
+ p->ret = -1;
+ return;
+ }
+
+ memcpy(p->out, omit_message, omlen);
+ p->out += omlen;
+ p->out_max -= omlen;
+ p->total += omlen;
+
+ STRING_TERMINATION
+
+ p->in += p->in_max;
+ p->in_max = 0;
+}
+
+static void wire_dnskey_to_tag(rrset_dump_params_t *p)
+{
+ CHECK_PRET
+
+ int key_pos = -4; // we expect that key flags, 3 and algorithm
+ // have been already dumped
+
+ uint16_t key_tag = 0;
+ const dnssec_binary_t rdata_bin = {
+ .data = (uint8_t *)(p->in + key_pos),
+ .size = p->in_max - key_pos
+ };
+ dnssec_keytag(&rdata_bin, &key_tag);
+
+ int ret = snprintf(p->out, p->out_max, "[id = %hu]", key_tag);
+ CHECK_RET_OUTMAX_SNPRINTF
+
+ p->in += p->in_max;
+ p->in_max = 0;
+ p->out += ret;
+ p->out_max -= ret;
+ p->total += ret;
+}
+
+static void wire_unknown_to_str(rrset_dump_params_t *p)
+{
+ CHECK_PRET
+
+ int ret;
+ size_t in_len = p->in_max;
+ size_t out_len = 0;
+
+ // Write unknown length header.
+ if (in_len > 0) {
+ ret = snprintf(p->out, p->out_max, "\\# %zu ", in_len);
+ } else {
+ ret = snprintf(p->out, p->out_max, "\\# 0");
+ }
+ CHECK_RET_OUTMAX_SNPRINTF
+ out_len = ret;
+
+ // Fill in output.
+ p->out += out_len;
+ p->out_max -= out_len;
+ p->total += out_len;
+
+ // Write hex data if any.
+ if (in_len > 0) {
+ // If wrap mode wrap line.
+ if (p->style->wrap) {
+ dump_string(p, BLOCK_INDENT);
+ CHECK_PRET
+ }
+
+ wire_data_encode_to_str(p, &hex_encode, &hex_encode_alloc);
+ CHECK_PRET
+ }
+}
+
+static void wire_text_to_str(rrset_dump_params_t *p, bool quote, bool with_header)
+{
+ CHECK_PRET
+
+ size_t in_len = 0;
+
+ if (with_header) {
+ // First byte is string length.
+ CHECK_INMAX(1)
+ in_len = *(p->in);
+ p->in++;
+ p->in_max--;
+
+ // Check if the given length makes sense.
+ CHECK_INMAX(in_len)
+ } else {
+ in_len = p->in_max;
+ }
+
+ // Check if quotation can ever be disabled (parser protection fallback).
+ if (!quote) {
+ for (size_t i = 0; i < in_len; i++) {
+ if (p->in[i] == ' ') { // Other WS characters are encoded.
+ quote = true;
+ break;
+ }
+ }
+ }
+
+ // Opening quotation.
+ if (quote) {
+ dump_string(p, "\"");
+ CHECK_PRET
+ }
+
+ // Loop over all characters.
+ for (size_t i = 0; i < in_len; i++) {
+ uint8_t ch = p->in[i];
+
+ if (is_print(ch)) {
+ // For special character print leading slash.
+ if (ch == '\\' || ch == '"') {
+ dump_string(p, "\\");
+ CHECK_PRET
+ }
+
+ // Print text character.
+ if (p->out_max == 0) {
+ p->ret = -1;
+ return;
+ }
+
+ *p->out = ch;
+ p->out++;
+ p->out_max--;
+ p->total++;
+ } else {
+ // Unprintable character encode via \ddd notation.
+ int ret = snprintf(p->out, p->out_max,"\\%03u", ch);
+ CHECK_RET_OUTMAX_SNPRINTF
+
+ p->out += ret;
+ p->out_max -= ret;
+ p->total += ret;
+ }
+ }
+
+ // Closing quotation.
+ if (quote) {
+ dump_string(p, "\"");
+ CHECK_PRET
+ }
+
+ STRING_TERMINATION
+
+ // Fill in output.
+ p->in += in_len;
+ p->in_max -= in_len;
+}
+
+static void wire_timestamp_to_str(rrset_dump_params_t *p)
+{
+ CHECK_PRET
+
+ uint32_t data;
+ size_t in_len = sizeof(data);
+ size_t out_len = 0;
+ int ret;
+
+ CHECK_INMAX(in_len)
+
+ FILL_IN_INPUT(data)
+
+ time_t timestamp = ntohl(data);
+
+ if (p->style->human_tmstamp) {
+ struct tm result;
+ // Write timestamp in YYYYMMDDhhmmss format.
+ ret = strftime(p->out, p->out_max, "%Y%m%d%H%M%S",
+ gmtime_r(&timestamp, &result));
+ CHECK_RET_POSITIVE
+ } else {
+ // Write timestamp only.
+ ret = snprintf(p->out, p->out_max, "%u", ntohl(data));
+ CHECK_RET_OUTMAX_SNPRINTF
+ }
+ out_len = ret;
+
+ // Fill in output.
+ p->in += in_len;
+ p->in_max -= in_len;
+ p->out += out_len;
+ p->out_max -= out_len;
+ p->total += out_len;
+}
+
+static int time_to_human_str(char *out,
+ const size_t out_len,
+ uint32_t data)
+{
+ size_t total_len = 0;
+ uint32_t num;
+ int ret;
+
+#define tths_process(unit_name, unit_size) \
+ num = data / (unit_size); \
+ if (num > 0) { \
+ ret = snprintf(out + total_len, out_len - total_len, \
+ "%u%s", num, (unit_name)); \
+ if (ret <= 0 || (size_t)ret >= out_len - total_len) { \
+ return -1; \
+ } \
+ total_len += ret; \
+ data -= num * (unit_size); \
+ }
+
+ tths_process("d", 86400);
+ tths_process("h", 3600);
+ tths_process("m", 60);
+ tths_process("s", 1);
+
+#undef tths_process
+
+ return total_len > 0 ? total_len : -1;
+}
+
+static void wire_ttl_to_str(rrset_dump_params_t *p)
+{
+ CHECK_PRET
+
+ uint32_t data;
+ size_t in_len = sizeof(data);
+ size_t out_len = 0;
+ int ret;
+
+ CHECK_INMAX(in_len)
+
+ FILL_IN_INPUT(data)
+
+ if (p->style->human_ttl) {
+ // Write time in human readable format.
+ ret = time_to_human_str(p->out, p->out_max, ntohl(data));
+ CHECK_RET_POSITIVE
+ } else {
+ // Write timestamp only.
+ ret = snprintf(p->out, p->out_max, "%u", ntohl(data));
+ CHECK_RET_OUTMAX_SNPRINTF
+ }
+ out_len = ret;
+
+ // Fill in output.
+ p->in += in_len;
+ p->in_max -= in_len;
+ p->out += out_len;
+ p->out_max -= out_len;
+ p->total += out_len;
+}
+
+static void wire_bitmap_to_str(rrset_dump_params_t *p)
+{
+ CHECK_PRET
+
+ int ret;
+ char type[32];
+ size_t i = 0;
+ size_t in_len = p->in_max;
+ size_t out_len = 0;
+
+ // Loop over bitmap window array (can be empty).
+ while (i < in_len) {
+ // First byte is window number.
+ uint8_t win = p->in[i++];
+
+ // Check window length (length must follow).
+ if (i >= in_len) {
+ p->ret = -1;
+ return;
+ }
+
+ // Second byte is window length.
+ uint8_t bitmap_len = p->in[i++];
+
+ // Check window length (len bytes must follow).
+ if (i + bitmap_len > in_len) {
+ p->ret = -1;
+ return;
+ }
+
+ // Bitmap processing.
+ for (size_t j = 0; j < (bitmap_len * 8); j++) {
+ if ((p->in[i + j / 8] & (128 >> (j % 8))) != 0) {
+ uint16_t type_num = win * 256 + j;
+
+ ret = knot_rrtype_to_string(type_num, type, sizeof(type));
+ CHECK_RET_POSITIVE
+
+ // Print type name to type list.
+ if (out_len > 0) {
+ ret = snprintf(p->out, p->out_max,
+ " %s", type);
+ } else {
+ ret = snprintf(p->out, p->out_max,
+ "%s", type);
+ }
+ CHECK_RET_OUTMAX_SNPRINTF
+ out_len += ret;
+ p->out += ret;
+ p->out_max -= ret;
+ }
+ }
+
+ i += bitmap_len;
+ }
+
+ // Fill in output.
+ p->in += in_len;
+ p->in_max -= in_len;
+ p->total += out_len;
+}
+
+static void wire_dname_to_str(rrset_dump_params_t *p)
+{
+ CHECK_PRET
+
+ size_t in_len = knot_dname_size(p->in);
+ size_t out_len = 0;
+
+ CHECK_INMAX(in_len)
+
+ // Write dname string.
+ if (p->style->ascii_to_idn == NULL) {
+ char *dname_str = knot_dname_to_str(p->out, p->in, p->out_max);
+ if (dname_str == NULL) {
+ p->ret = -1;
+ return;
+ }
+ out_len = strlen(dname_str);
+ } else {
+ char *dname_str = knot_dname_to_str_alloc(p->in);
+ p->style->ascii_to_idn(&dname_str);
+
+ int ret = snprintf(p->out, p->out_max, "%s", dname_str);
+ free(dname_str);
+ CHECK_RET_OUTMAX_SNPRINTF
+ out_len = ret;
+ }
+
+ // Fill in output.
+ p->in += in_len;
+ p->in_max -= in_len;
+ p->out += out_len;
+ p->out_max -= out_len;
+ p->total += out_len;
+}
+
+static void wire_apl_to_str(rrset_dump_params_t *p)
+{
+ CHECK_PRET
+
+ struct in_addr addr4;
+ struct in6_addr addr6;
+ int ret;
+ size_t out_len = 0;
+
+ // Input check: family(2B) + prefix(1B) + afdlen(1B).
+ CHECK_INMAX(4)
+
+ // Read fixed size values.
+ uint16_t family = knot_wire_read_u16(p->in);
+ uint8_t prefix = *(p->in + 2);
+ uint8_t negation = *(p->in + 3) >> 7;
+ uint8_t afdlen = *(p->in + 3) & 0x7F;
+ p->in += 4;
+ p->in_max -= 4;
+
+ // Write negation mark.
+ if (negation != 0) {
+ dump_string(p, "!");
+ CHECK_PRET
+ }
+
+ // Write address family with colon.
+ ret = snprintf(p->out, p->out_max, "%u:", family);
+ CHECK_RET_OUTMAX_SNPRINTF
+ p->out += ret;
+ p->out_max -= ret;
+ p->total += ret;
+
+ // Write address.
+ switch (family) {
+ case 1:
+ memset(&addr4, 0, sizeof(addr4));
+
+ if (afdlen > sizeof(addr4.s_addr) || afdlen > p->in_max) {
+ p->ret = -1;
+ return;
+ }
+
+ if (memcpy(&(addr4.s_addr), p->in, afdlen) == NULL) {
+ p->ret = -1;
+ return;
+ }
+
+ // Write address.
+ if (inet_ntop(AF_INET, &addr4, p->out, p->out_max) == NULL) {
+ p->ret = -1;
+ return;
+ }
+ out_len = strlen(p->out);
+
+ break;
+ case 2:
+ memset(&addr6, 0, sizeof(addr6));
+
+ if (afdlen > sizeof(addr6.s6_addr) || afdlen > p->in_max) {
+ p->ret = -1;
+ return;
+ }
+
+ if (memcpy(&(addr6.s6_addr), p->in, afdlen) == NULL) {
+ p->ret = -1;
+ return;
+ }
+
+ // Write address.
+ if (inet_ntop(AF_INET6, &addr6, p->out, p->out_max) == NULL) {
+ p->ret = -1;
+ return;
+ }
+ out_len = strlen(p->out);
+
+ break;
+ default:
+ p->ret = -1;
+ return;
+ }
+ p->in += afdlen;
+ p->in_max -= afdlen;
+ p->out += out_len;
+ p->out_max -= out_len;
+ p->total += out_len;
+
+ // Write prefix length with forward slash.
+ ret = snprintf(p->out, p->out_max, "/%u", prefix);
+ CHECK_RET_OUTMAX_SNPRINTF
+ p->out += ret;
+ p->out_max -= ret;
+ p->total += ret;
+}
+
+static void wire_loc_to_str(rrset_dump_params_t *p)
+{
+ CHECK_PRET
+
+ // Read values.
+ wire_ctx_t wire = wire_ctx_init_const(p->in, p->in_max);
+ uint8_t version = wire_ctx_read_u8(&wire);
+
+ // Version check.
+ if (version != 0) {
+ wire_unknown_to_str(p);
+ p->ret = -1;
+ return;
+ }
+
+ // Continue to read values.
+ uint8_t size_w = wire_ctx_read_u8(&wire);
+ uint8_t hpre_w = wire_ctx_read_u8(&wire);
+ uint8_t vpre_w = wire_ctx_read_u8(&wire);
+ uint32_t lat_w = wire_ctx_read_u32(&wire);
+ uint32_t lon_w = wire_ctx_read_u32(&wire);
+ uint32_t alt_w = wire_ctx_read_u32(&wire);
+
+ // Check if all reads are correct.
+ if (wire.error != KNOT_EOK) {
+ p->ret = -1;
+ return;
+ }
+
+ p->in += wire_ctx_offset(&wire);
+ p->in_max = wire_ctx_available(&wire);
+
+ // Latitude calculation.
+ char lat_mark;
+ uint32_t lat;
+ if (lat_w >= LOC_ZERO) {
+ lat_mark = 'N';
+ lat = lat_w - LOC_ZERO;
+ } else {
+ lat_mark = 'S';
+ lat = LOC_ZERO - lat_w;
+ }
+
+ uint32_t d1 = lat / 3600000;
+ uint32_t m1 = (lat - 3600000 * d1) / 60000;
+ double s1 = 0.001 * (lat - 3600000 * d1 - 60000 * m1);
+
+ // Longitude calculation.
+ char lon_mark;
+ uint32_t lon;
+ if (lon_w >= LOC_ZERO) {
+ lon_mark = 'E';
+ lon = lon_w - LOC_ZERO;
+ } else {
+ lon_mark = 'W';
+ lon = LOC_ZERO - lon_w;
+ }
+
+ uint32_t d2 = lon / 3600000;
+ uint32_t m2 = (lon - 3600000 * d2) / 60000;
+ double s2 = 0.001 * (lon - 3600000 * d2 - 60000 * m2);
+
+ // Write latitude and longitude.
+ int ret = snprintf(p->out, p->out_max, "%u %u %.*f %c %u %u %.*f %c",
+ d1, m1, (uint32_t)s1 != s1 ? 3 : 0, s1, lat_mark,
+ d2, m2, (uint32_t)s2 != s2 ? 3 : 0, s2, lon_mark);
+ CHECK_RET_OUTMAX_SNPRINTF
+ p->out += ret;
+ p->out_max -= ret;
+ p->total += ret;
+
+ // Altitude calculation.
+ double alt = 0.01 * alt_w - 100000.0;
+
+ // Compute mantisa and exponent for each size.
+ uint8_t size_m = size_w >> 4;
+ uint8_t size_e = size_w & 0xF;
+ uint8_t hpre_m = hpre_w >> 4;
+ uint8_t hpre_e = hpre_w & 0xF;
+ uint8_t vpre_m = vpre_w >> 4;
+ uint8_t vpre_e = vpre_w & 0xF;
+
+ // Sizes check.
+ if (size_m > 9 || size_e > 9 || hpre_m > 9 || hpre_e > 9 ||
+ vpre_m > 9 || vpre_e > 9) {
+ p->ret = -1;
+ return;
+ }
+
+ // Size and precisions calculation.
+ double size = 0.01 * size_m * pow(10, size_e);
+ double hpre = 0.01 * hpre_m * pow(10, hpre_e);
+ double vpre = 0.01 * vpre_m * pow(10, vpre_e);
+
+ // Write altitude and precisions.
+ ret = snprintf(p->out, p->out_max, " %.*fm %.*fm %.*fm %.*fm",
+ (int32_t)alt != alt ? 2 : 0, alt,
+ (uint32_t)size != size ? 2 : 0, size,
+ (uint32_t)hpre != hpre ? 2 : 0, hpre,
+ (uint32_t)vpre != vpre ? 2 : 0, vpre);
+ CHECK_RET_OUTMAX_SNPRINTF
+ p->out += ret;
+ p->out_max -= ret;
+ p->total += ret;
+}
+
+static void wire_gateway_to_str(rrset_dump_params_t *p)
+{
+ CHECK_PRET
+
+ // Input check: type(1B) + algo(1B).
+ CHECK_INMAX(2)
+
+ uint8_t type = *p->in;
+ uint8_t alg = *(p->in + 1);
+
+ // Write gateway type.
+ wire_num8_to_str(p);
+ CHECK_PRET
+
+ // Write space.
+ dump_string(p, " ");
+ CHECK_PRET
+
+ // Write algorithm number.
+ wire_num8_to_str(p);
+ CHECK_PRET
+
+ // Write space.
+ dump_string(p, " ");
+ CHECK_PRET
+
+ // Write appropriate gateway.
+ switch (type) {
+ case 0:
+ dump_string(p, ".");
+ break;
+ case 1:
+ wire_ipv4_to_str(p);
+ break;
+ case 2:
+ wire_ipv6_to_str(p);
+ break;
+ case 3:
+ wire_dname_to_str(p);
+ break;
+ default:
+ p->ret = -1;
+ }
+ CHECK_PRET
+
+ if (alg > 0) {
+ // If wrap mode wrap line.
+ if (p->style->wrap) {
+ dump_string(p, BLOCK_INDENT);
+ } else {
+ dump_string(p, " ");
+ }
+ CHECK_PRET
+
+ // Write ipsec key.
+ wire_data_encode_to_str(p, &base64_encode, &base64_encode_alloc);
+ CHECK_PRET
+ }
+}
+
+static void wire_l64_to_str(rrset_dump_params_t *p)
+{
+ CHECK_PRET
+
+ // Check input size (64-bit identifier).
+ if (p->in_max != 8) {
+ p->ret = -1;
+ return;
+ }
+
+ // Write identifier (2-byte) labels separated with a colon.
+ while (p->in_max > 0) {
+ int ret = hex_encode(p->in, 2, (uint8_t *)(p->out), p->out_max);
+ CHECK_RET_POSITIVE
+ p->in += 2;
+ p->in_max -= 2;
+ p->out += ret;
+ p->out_max -= ret;
+ p->total += ret;
+
+ // Write separation character.
+ if (p->in_max > 0) {
+ dump_string(p, ":");
+ CHECK_PRET
+ }
+ }
+}
+
+static void wire_eui_to_str(rrset_dump_params_t *p)
+{
+ CHECK_PRET
+
+ CHECK_INMAX(2)
+
+ // Write EUI hexadecimal pairs.
+ while (p->in_max > 0) {
+ int ret = hex_encode(p->in, 1, (uint8_t *)(p->out), p->out_max);
+ CHECK_RET_POSITIVE
+ p->in++;
+ p->in_max--;
+ p->out += ret;
+ p->out_max -= ret;
+ p->total += ret;
+
+ // Write separation character.
+ if (p->in_max > 0) {
+ dump_string(p, "-");
+ CHECK_PRET
+ }
+ }
+}
+
+static void wire_tsig_rcode_to_str(rrset_dump_params_t *p)
+{
+ CHECK_PRET
+
+ uint16_t data;
+ size_t in_len = sizeof(data);
+ const char *rcode_str = "Unknown";
+
+ CHECK_INMAX(in_len)
+
+ // Fill in input data.
+ data = knot_wire_read_u16(p->in);
+
+ // Find RCODE name.
+ const knot_lookup_t *rcode = NULL;
+ rcode = knot_lookup_by_id(knot_tsig_rcode_names, data);
+ if (rcode == NULL) {
+ rcode = knot_lookup_by_id(knot_rcode_names, data);
+ }
+ if (rcode != NULL) {
+ rcode_str = rcode->name;
+ }
+
+ // Dump RCODE name.
+ dump_string(p, rcode_str);
+ CHECK_PRET
+
+ // Fill in output.
+ p->in += in_len;
+ p->in_max -= in_len;
+}
+
+static size_t dnskey_len(const uint8_t *rdata,
+ const size_t rdata_len)
+{
+ // Check for empty rdata and empty key.
+ if (rdata_len <= 4) {
+ return 0;
+ }
+
+ const uint8_t *key = rdata + 4;
+ const size_t len = rdata_len - 4;
+
+ switch (rdata[3]) {
+ case KNOT_DNSSEC_ALG_DSA:
+ case KNOT_DNSSEC_ALG_DSA_NSEC3_SHA1:
+ // RFC 2536, key size ~ bit-length of 'modulus' P.
+ return (64 + 8 * key[0]) * 8;
+ case KNOT_DNSSEC_ALG_RSAMD5:
+ case KNOT_DNSSEC_ALG_RSASHA1:
+ case KNOT_DNSSEC_ALG_RSASHA1_NSEC3_SHA1:
+ case KNOT_DNSSEC_ALG_RSASHA256:
+ case KNOT_DNSSEC_ALG_RSASHA512:
+ // RFC 3110, key size ~ bit-length of 'modulus'.
+ if (key[0] == 0) {
+ if (len < 3) {
+ return 0;
+ }
+ uint16_t exp;
+ memcpy(&exp, key + 1, sizeof(uint16_t));
+ return (len - 3 - ntohs(exp)) * 8;
+ } else {
+ return (len - 1 - key[0]) * 8;
+ }
+ case KNOT_DNSSEC_ALG_ECC_GOST:
+ // RFC 5933, key size of GOST public keys MUST be 512 bits.
+ return 512;
+ case KNOT_DNSSEC_ALG_ECDSAP256SHA256:
+ // RFC 6605.
+ return 256;
+ case KNOT_DNSSEC_ALG_ECDSAP384SHA384:
+ // RFC 6605.
+ return 384;
+ case KNOT_DNSSEC_ALG_ED25519:
+ // RFC 8080.
+ return 256;
+ case KNOT_DNSSEC_ALG_ED448:
+ // RFC 8080.
+ return 456;
+ default:
+ return 0;
+ }
+}
+
+static void dnskey_info(const uint8_t *rdata,
+ const size_t rdata_len,
+ char *out,
+ const size_t out_len)
+{
+ // TODO: migrate key info to libdnssec
+
+ const uint8_t sep = *(rdata + 1) & 0x01;
+ uint16_t key_tag = 0;
+ const size_t key_len = dnskey_len(rdata, rdata_len);
+ const uint8_t alg_id = rdata[3];
+
+ const dnssec_binary_t rdata_bin = { .data = (uint8_t *)rdata,
+ .size = rdata_len };
+ dnssec_keytag(&rdata_bin, &key_tag);
+
+ const knot_lookup_t *alg = NULL;
+ alg = knot_lookup_by_id(knot_dnssec_alg_names, alg_id);
+
+ int ret = snprintf(out, out_len, "%s, %s (%zub), id = %u",
+ sep ? "KSK" : "ZSK",
+ alg ? alg->name : "UNKNOWN",
+ key_len, key_tag );
+
+ if (ret <= 0) { // Truncated return is acceptable. Just check for errors.
+ out[0] = '\0';
+ }
+}
+
+#define DUMP_PARAMS rrset_dump_params_t *const p
+#define DUMP_END return (p->in_max == 0 ? (int)p->total : KNOT_EPARSEFAIL);
+
+#define CHECK_RET(p) if (p->ret < 0) return p->ret;
+
+#define WRAP_INIT dump_string(p, "(" BLOCK_INDENT); CHECK_RET(p);
+#define WRAP_END dump_string(p, BLOCK_INDENT ")"); CHECK_RET(p);
+#define WRAP_LINE dump_string(p, BLOCK_INDENT); CHECK_RET(p);
+
+#define COMMENT(s) if (p->style->verbose) { \
+ dump_string(p, " ; "); CHECK_RET(p); \
+ dump_string(p, s); CHECK_RET(p); \
+ }
+
+#define DUMP_SPACE dump_string(p, " "); CHECK_RET(p);
+#define DUMP_NUM8 wire_num8_to_str(p); CHECK_RET(p);
+#define DUMP_NUM16 wire_num16_to_str(p); CHECK_RET(p);
+#define DUMP_NUM32 wire_num32_to_str(p); CHECK_RET(p);
+#define DUMP_NUM48 wire_num48_to_str(p); CHECK_RET(p);
+#define DUMP_DNAME wire_dname_to_str(p); CHECK_RET(p);
+#define DUMP_TIME wire_ttl_to_str(p); CHECK_RET(p);
+#define DUMP_TIMESTAMP wire_timestamp_to_str(p); CHECK_RET(p);
+#define DUMP_IPV4 wire_ipv4_to_str(p); CHECK_RET(p);
+#define DUMP_IPV6 wire_ipv6_to_str(p); CHECK_RET(p);
+#define DUMP_TYPE wire_type_to_str(p); CHECK_RET(p);
+#define DUMP_HEX wire_data_encode_to_str(p, &hex_encode, \
+ &hex_encode_alloc); CHECK_RET(p);
+#define DUMP_BASE64 wire_data_encode_to_str(p, &base64_encode, \
+ &base64_encode_alloc); CHECK_RET(p);
+#define DUMP_HASH wire_len_data_encode_to_str(p, &base32hex_encode, \
+ 1, false, ""); CHECK_RET(p);
+#define DUMP_SALT wire_len_data_encode_to_str(p, &hex_encode, \
+ 1, false, "-"); CHECK_RET(p);
+#define DUMP_TSIG_DGST wire_len_data_encode_to_str(p, &base64_encode, \
+ 2, true, ""); CHECK_RET(p);
+#define DUMP_TSIG_DATA wire_len_data_encode_to_str(p, &num48_encode, \
+ 2, true, ""); CHECK_RET(p);
+#define DUMP_OMIT wire_data_omit(p); CHECK_RET(p);
+#define DUMP_KEY_OMIT wire_dnskey_to_tag(p); CHECK_RET(p);
+#define DUMP_TEXT wire_text_to_str(p, true, true); CHECK_RET(p);
+#define DUMP_LONG_TEXT wire_text_to_str(p, true, false); CHECK_RET(p);
+#define DUMP_UNQUOTED wire_text_to_str(p, false, true); CHECK_RET(p);
+#define DUMP_BITMAP wire_bitmap_to_str(p); CHECK_RET(p);
+#define DUMP_APL wire_apl_to_str(p); CHECK_RET(p);
+#define DUMP_LOC wire_loc_to_str(p); CHECK_RET(p);
+#define DUMP_GATEWAY wire_gateway_to_str(p); CHECK_RET(p);
+#define DUMP_L64 wire_l64_to_str(p); CHECK_RET(p);
+#define DUMP_EUI wire_eui_to_str(p); CHECK_RET(p);
+#define DUMP_TSIG_RCODE wire_tsig_rcode_to_str(p); CHECK_RET(p);
+#define DUMP_UNKNOWN wire_unknown_to_str(p); CHECK_RET(p);
+
+static int dump_a(DUMP_PARAMS)
+{
+ DUMP_IPV4;
+
+ DUMP_END;
+}
+
+static int dump_ns(DUMP_PARAMS)
+{
+ DUMP_DNAME;
+
+ DUMP_END;
+}
+
+static int dump_soa(DUMP_PARAMS)
+{
+ if (p->style->wrap) {
+ DUMP_DNAME; DUMP_SPACE;
+ DUMP_DNAME; DUMP_SPACE; WRAP_INIT;
+ DUMP_NUM32; COMMENT("serial"); WRAP_LINE;
+ DUMP_TIME; COMMENT("refresh"); WRAP_LINE;
+ DUMP_TIME; COMMENT("retry"); WRAP_LINE;
+ DUMP_TIME; COMMENT("expire"); WRAP_LINE;
+ DUMP_TIME; COMMENT("minimum"); WRAP_END;
+ } else {
+ DUMP_DNAME; DUMP_SPACE;
+ DUMP_DNAME; DUMP_SPACE;
+ DUMP_NUM32; DUMP_SPACE;
+ DUMP_TIME; DUMP_SPACE;
+ DUMP_TIME; DUMP_SPACE;
+ DUMP_TIME; DUMP_SPACE;
+ DUMP_TIME;
+ }
+
+ DUMP_END;
+}
+
+static int dump_hinfo(DUMP_PARAMS)
+{
+ DUMP_TEXT; DUMP_SPACE;
+ DUMP_TEXT;
+
+ DUMP_END;
+}
+
+static int dump_minfo(DUMP_PARAMS)
+{
+ DUMP_DNAME; DUMP_SPACE;
+ DUMP_DNAME;
+
+ DUMP_END;
+}
+
+static int dump_mx(DUMP_PARAMS)
+{
+ DUMP_NUM16; DUMP_SPACE;
+ DUMP_DNAME;
+
+ DUMP_END;
+}
+
+static int dump_txt(DUMP_PARAMS)
+{
+ // First text string.
+ DUMP_TEXT;
+
+ // Other text strings if any.
+ while (p->in_max > 0) {
+ DUMP_SPACE; DUMP_TEXT;
+ }
+
+ DUMP_END;
+}
+
+static int dump_dnskey(DUMP_PARAMS)
+{
+ if (p->style->wrap) {
+ char info[512] = "";
+ dnskey_info(p->in, p->in_max, info, sizeof(info));
+
+ DUMP_NUM16; DUMP_SPACE;
+ DUMP_NUM8; DUMP_SPACE;
+ DUMP_NUM8; DUMP_SPACE;
+ if (p->style->hide_crypto) {
+ DUMP_OMIT;
+ WRAP_LINE;
+ } else {
+ WRAP_INIT;
+ DUMP_BASE64;
+ WRAP_END;
+ }
+ COMMENT(info);
+ } else {
+ DUMP_NUM16; DUMP_SPACE;
+ DUMP_NUM8; DUMP_SPACE;
+ DUMP_NUM8; DUMP_SPACE;
+ if (p->style->hide_crypto) {
+ DUMP_KEY_OMIT;
+ } else {
+ DUMP_BASE64;
+ }
+ }
+
+ DUMP_END;
+}
+
+static int dump_aaaa(DUMP_PARAMS)
+{
+ DUMP_IPV6;
+
+ DUMP_END;
+}
+
+static int dump_loc(DUMP_PARAMS)
+{
+ DUMP_LOC;
+
+ DUMP_END;
+}
+
+static int dump_srv(DUMP_PARAMS)
+{
+ DUMP_NUM16; DUMP_SPACE;
+ DUMP_NUM16; DUMP_SPACE;
+ DUMP_NUM16; DUMP_SPACE;
+ DUMP_DNAME;
+
+ DUMP_END;
+}
+
+static int dump_naptr(DUMP_PARAMS)
+{
+ DUMP_NUM16; DUMP_SPACE;
+ DUMP_NUM16; DUMP_SPACE;
+ DUMP_TEXT; DUMP_SPACE;
+ DUMP_TEXT; DUMP_SPACE;
+ DUMP_TEXT; DUMP_SPACE;
+ DUMP_DNAME;
+
+ DUMP_END;
+}
+
+static int dump_cert(DUMP_PARAMS)
+{
+ if (p->style->wrap) {
+ DUMP_NUM16; DUMP_SPACE;
+ DUMP_NUM16; DUMP_SPACE;
+ DUMP_NUM8; DUMP_SPACE; WRAP_INIT;
+ DUMP_BASE64;
+ WRAP_END;
+ } else {
+ DUMP_NUM16; DUMP_SPACE;
+ DUMP_NUM16; DUMP_SPACE;
+ DUMP_NUM8; DUMP_SPACE;
+ DUMP_BASE64;
+ }
+
+ DUMP_END;
+}
+
+static int dump_apl(DUMP_PARAMS)
+{
+ // Print list of APLs (empty list is allowed).
+ while (p->in_max > 0) {
+ if (p->total > 0) {
+ DUMP_SPACE;
+ }
+ DUMP_APL;
+ }
+
+ DUMP_END;
+}
+
+static int dump_ds(DUMP_PARAMS)
+{
+ if (p->style->wrap) {
+ DUMP_NUM16; DUMP_SPACE;
+ DUMP_NUM8; DUMP_SPACE;
+ DUMP_NUM8; DUMP_SPACE; WRAP_INIT;
+ DUMP_HEX;
+ WRAP_END;
+ } else {
+ DUMP_NUM16; DUMP_SPACE;
+ DUMP_NUM8; DUMP_SPACE;
+ DUMP_NUM8; DUMP_SPACE;
+ DUMP_HEX;
+ }
+
+ DUMP_END;
+}
+
+static int dump_sshfp(DUMP_PARAMS)
+{
+ if (p->style->wrap) {
+ DUMP_NUM8; DUMP_SPACE;
+ DUMP_NUM8; DUMP_SPACE; WRAP_INIT;
+ DUMP_HEX;
+ WRAP_END;
+ } else {
+ DUMP_NUM8; DUMP_SPACE;
+ DUMP_NUM8; DUMP_SPACE;
+ DUMP_HEX;
+ }
+
+ DUMP_END;
+}
+
+static int dump_ipseckey(DUMP_PARAMS)
+{
+ if (p->style->wrap) {
+ DUMP_NUM8; DUMP_SPACE; WRAP_INIT;
+ DUMP_GATEWAY;
+ WRAP_END;
+ } else {
+ DUMP_NUM8; DUMP_SPACE;
+ DUMP_GATEWAY;
+ }
+
+ DUMP_END;
+}
+
+static int dump_rrsig(DUMP_PARAMS)
+{
+ DUMP_TYPE; DUMP_SPACE;
+ DUMP_NUM8; DUMP_SPACE;
+ DUMP_NUM8; DUMP_SPACE;
+ DUMP_NUM32; DUMP_SPACE;
+ DUMP_TIMESTAMP; DUMP_SPACE;
+ if (p->style->wrap) {
+ WRAP_INIT;
+ }
+ DUMP_TIMESTAMP; DUMP_SPACE;
+ DUMP_NUM16; DUMP_SPACE;
+ DUMP_DNAME; DUMP_SPACE;
+ if (p->style->wrap) {
+ WRAP_LINE;
+ }
+ if (p->style->hide_crypto) {
+ DUMP_OMIT;
+ } else {
+ DUMP_BASE64;
+ }
+ if (p->style->wrap) {
+ WRAP_END;
+ }
+ DUMP_END;
+}
+
+static int dump_nsec(DUMP_PARAMS)
+{
+ DUMP_DNAME; DUMP_SPACE;
+ DUMP_BITMAP;
+
+ DUMP_END;
+}
+
+static int dump_dhcid(DUMP_PARAMS)
+{
+ if (p->style->wrap) {
+ WRAP_INIT;
+ DUMP_BASE64;
+ WRAP_END;
+ } else {
+ DUMP_BASE64;
+ }
+
+ DUMP_END;
+}
+
+static int dump_nsec3(DUMP_PARAMS)
+{
+ if (p->style->wrap) {
+ DUMP_NUM8; DUMP_SPACE;
+ DUMP_NUM8; DUMP_SPACE;
+ DUMP_NUM16; DUMP_SPACE;
+ DUMP_SALT; DUMP_SPACE; WRAP_INIT;
+ DUMP_HASH; DUMP_SPACE; WRAP_LINE;
+ DUMP_BITMAP;
+ WRAP_END;
+ } else {
+ DUMP_NUM8; DUMP_SPACE;
+ DUMP_NUM8; DUMP_SPACE;
+ DUMP_NUM16; DUMP_SPACE;
+ DUMP_SALT; DUMP_SPACE;
+ DUMP_HASH; DUMP_SPACE;
+ DUMP_BITMAP;
+ }
+
+ DUMP_END;
+}
+
+static int dump_nsec3param(DUMP_PARAMS)
+{
+ DUMP_NUM8; DUMP_SPACE;
+ DUMP_NUM8; DUMP_SPACE;
+ DUMP_NUM16; DUMP_SPACE;
+ DUMP_SALT;
+
+ DUMP_END;
+}
+
+static int dump_tlsa(DUMP_PARAMS)
+{
+ if (p->style->wrap) {
+ DUMP_NUM8; DUMP_SPACE;
+ DUMP_NUM8; DUMP_SPACE;
+ DUMP_NUM8; DUMP_SPACE; WRAP_INIT;
+ DUMP_HEX;
+ WRAP_END;
+ } else {
+ DUMP_NUM8; DUMP_SPACE;
+ DUMP_NUM8; DUMP_SPACE;
+ DUMP_NUM8; DUMP_SPACE;
+ DUMP_HEX;
+ }
+
+ DUMP_END;
+}
+
+static int dump_l64(DUMP_PARAMS)
+{
+ DUMP_NUM16; DUMP_SPACE;
+ DUMP_L64;
+
+ DUMP_END;
+}
+
+static int dump_l32(DUMP_PARAMS)
+{
+ DUMP_NUM16; DUMP_SPACE;
+ DUMP_IPV4;
+
+ DUMP_END;
+}
+
+static int dump_eui(DUMP_PARAMS)
+{
+ DUMP_EUI;
+
+ DUMP_END;
+}
+
+static int dump_tsig(DUMP_PARAMS)
+{
+ if (p->style->wrap) {
+ DUMP_DNAME; DUMP_SPACE;
+ DUMP_NUM48; DUMP_SPACE;
+ DUMP_NUM16; DUMP_SPACE; WRAP_INIT;
+ DUMP_TSIG_DGST; DUMP_SPACE; WRAP_LINE;
+ DUMP_NUM16; DUMP_SPACE;
+ DUMP_TSIG_RCODE; DUMP_SPACE;
+ DUMP_TSIG_DATA;
+ WRAP_END;
+ } else {
+ DUMP_DNAME; DUMP_SPACE;
+ DUMP_NUM48; DUMP_SPACE;
+ DUMP_NUM16; DUMP_SPACE;
+ DUMP_TSIG_DGST; DUMP_SPACE;
+ DUMP_NUM16; DUMP_SPACE;
+ DUMP_TSIG_RCODE; DUMP_SPACE;
+ DUMP_TSIG_DATA;
+ }
+
+ DUMP_END;
+}
+
+static int dump_uri(DUMP_PARAMS)
+{
+ DUMP_NUM16; DUMP_SPACE;
+ DUMP_NUM16; DUMP_SPACE;
+ DUMP_LONG_TEXT; DUMP_SPACE;
+
+ DUMP_END;
+}
+
+static int dump_caa(DUMP_PARAMS)
+{
+ DUMP_NUM8; DUMP_SPACE;
+ DUMP_UNQUOTED; DUMP_SPACE;
+ DUMP_LONG_TEXT; DUMP_SPACE;
+
+ DUMP_END;
+}
+
+static int dump_unknown(DUMP_PARAMS)
+{
+ if (p->style->wrap) {
+ WRAP_INIT;
+ DUMP_UNKNOWN;
+ WRAP_END;
+ } else {
+ DUMP_UNKNOWN;
+ }
+
+ DUMP_END;
+}
+
+static int txt_dump_data(rrset_dump_params_t *p, uint16_t type)
+{
+ switch (type) {
+ case KNOT_RRTYPE_A:
+ return dump_a(p);
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ return dump_ns(p);
+ case KNOT_RRTYPE_SOA:
+ return dump_soa(p);
+ case KNOT_RRTYPE_HINFO:
+ return dump_hinfo(p);
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ return dump_minfo(p);
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ return dump_mx(p);
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ return dump_txt(p);
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ return dump_dnskey(p);
+ case KNOT_RRTYPE_AAAA:
+ return dump_aaaa(p);
+ case KNOT_RRTYPE_LOC:
+ return dump_loc(p);
+ case KNOT_RRTYPE_SRV:
+ return dump_srv(p);
+ case KNOT_RRTYPE_NAPTR:
+ return dump_naptr(p);
+ case KNOT_RRTYPE_CERT:
+ return dump_cert(p);
+ case KNOT_RRTYPE_APL:
+ return dump_apl(p);
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ return dump_ds(p);
+ case KNOT_RRTYPE_SSHFP:
+ return dump_sshfp(p);
+ case KNOT_RRTYPE_IPSECKEY:
+ return dump_ipseckey(p);
+ case KNOT_RRTYPE_RRSIG:
+ return dump_rrsig(p);
+ case KNOT_RRTYPE_NSEC:
+ return dump_nsec(p);
+ case KNOT_RRTYPE_DHCID:
+ return dump_dhcid(p);
+ case KNOT_RRTYPE_NSEC3:
+ return dump_nsec3(p);
+ case KNOT_RRTYPE_NSEC3PARAM:
+ return dump_nsec3param(p);
+ case KNOT_RRTYPE_TLSA:
+ return dump_tlsa(p);
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ return dump_l64(p);
+ case KNOT_RRTYPE_L32:
+ return dump_l32(p);
+ case KNOT_RRTYPE_EUI48:
+ case KNOT_RRTYPE_EUI64:
+ return dump_eui(p);
+ case KNOT_RRTYPE_TSIG:
+ return dump_tsig(p);
+ case KNOT_RRTYPE_URI:
+ return dump_uri(p);
+ case KNOT_RRTYPE_CAA:
+ return dump_caa(p);
+ default:
+ return dump_unknown(p);
+ }
+}
+
+_public_
+int knot_rrset_txt_dump_data(const knot_rrset_t *rrset,
+ const size_t pos,
+ char *dst,
+ const size_t maxlen,
+ const knot_dump_style_t *style)
+{
+ if (rrset == NULL || dst == NULL || style == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ knot_rdata_t *rr_data = knot_rdataset_at(&rrset->rrs, pos);
+ if (rr_data == NULL) {
+ return KNOT_EINVAL; /* bad pos or rrset->rrs */
+ }
+
+ uint8_t *data = rr_data->data;
+ uint16_t data_len = rr_data->len;
+
+ rrset_dump_params_t p = {
+ .style = style,
+ .in = data,
+ .in_max = data_len,
+ .out = dst,
+ .out_max = maxlen,
+ .total = 0,
+ .ret = 0
+ };
+
+ int ret;
+
+ // Allow empty rdata with the CH class (knsupdate).
+ if (data_len == 0 && rrset->rclass != KNOT_CLASS_IN) {
+ ret = 0;
+ } else if (style->generic) {
+ ret = dump_unknown(&p);
+ } else {
+ ret = txt_dump_data(&p, rrset->type);
+ }
+
+ // Terminate the string just in case.
+ if (ret < 0 || ret >= maxlen) {
+ return KNOT_ESPACE;
+ }
+ dst[ret] = '\0';
+
+ return ret;
+}
+
+#define SNPRINTF_CHECK(ret, max_len) \
+ if ((ret) < 0 || (size_t)(ret) >= (max_len)) { \
+ return KNOT_ESPACE; \
+ }
+
+_public_
+int knot_rrset_txt_dump_header(const knot_rrset_t *rrset,
+ const uint32_t ttl,
+ char *dst,
+ const size_t maxlen,
+ const knot_dump_style_t *style)
+{
+ if (rrset == NULL || dst == NULL || style == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ size_t len = 0;
+ char buf[32];
+ int ret;
+
+ // Dump rrset owner.
+ char *name = knot_dname_to_str_alloc(rrset->owner);
+ if (style->ascii_to_idn != NULL) {
+ style->ascii_to_idn(&name);
+ }
+ char sep = strlen(name) < 4 * TAB_WIDTH ? '\t' : ' ';
+ ret = snprintf(dst + len, maxlen - len, "%-20s%c", name, sep);
+ free(name);
+ SNPRINTF_CHECK(ret, maxlen - len);
+ len += ret;
+
+ // Set white space separation character.
+ sep = style->wrap ? ' ' : '\t';
+
+ // Dump rrset ttl.
+ if (style->show_ttl) {
+ if (style->empty_ttl) {
+ ret = snprintf(dst + len, maxlen - len, "%c", sep);
+ } else if (style->human_ttl) {
+ // Create human readable ttl string.
+ if (time_to_human_str(buf, sizeof(buf), ttl) < 0) {
+ return KNOT_ESPACE;
+ }
+ ret = snprintf(dst + len, maxlen - len, "%s%c",
+ buf, sep);
+ } else {
+ ret = snprintf(dst + len, maxlen - len, "%u%c", ttl, sep);
+ }
+ SNPRINTF_CHECK(ret, maxlen - len);
+ len += ret;
+ }
+
+ // Dump rrset class.
+ if (style->show_class) {
+ if (knot_rrclass_to_string(rrset->rclass, buf, sizeof(buf)) < 0) {
+ return KNOT_ESPACE;
+ }
+ ret = snprintf(dst + len, maxlen - len, "%-2s%c", buf, sep);
+ SNPRINTF_CHECK(ret, maxlen - len);
+ len += ret;
+ }
+
+ // Dump rrset type.
+ if (style->generic) {
+ if (snprintf(buf, sizeof(buf), "TYPE%u", rrset->type) < 0) {
+ return KNOT_ESPACE;
+ }
+ } else if (knot_rrtype_to_string(rrset->type, buf, sizeof(buf)) < 0) {
+ return KNOT_ESPACE;
+ }
+ if (rrset->rrs.count > 0) {
+ ret = snprintf(dst + len, maxlen - len, "%s%c", buf, sep);
+ } else {
+ ret = snprintf(dst + len, maxlen - len, "%s", buf);
+ }
+ SNPRINTF_CHECK(ret, maxlen - len);
+ len += ret;
+
+ return len;
+}
+
+static int rrset_txt_dump(const knot_rrset_t *rrset,
+ char *dst,
+ const size_t maxlen,
+ const knot_dump_style_t *style)
+{
+ if (rrset == NULL || dst == NULL || style == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ size_t len = 0;
+
+ dst[0] = '\0';
+
+ // Loop over rdata in rrset.
+ uint16_t rr_count = rrset->rrs.count;
+ knot_rdata_t *rr = rrset->rrs.rdata;
+ for (uint16_t i = 0; i < rr_count; i++) {
+ // Dump rdata owner, class, ttl and type.
+ uint32_t ttl = ((style->original_ttl && rrset->type == KNOT_RRTYPE_RRSIG) ?
+ knot_rrsig_original_ttl(rr) : rrset->ttl);
+
+ int ret = knot_rrset_txt_dump_header(rrset, ttl, dst + len,
+ maxlen - len, style);
+ if (ret < 0) {
+ return KNOT_ESPACE;
+ }
+ len += ret;
+
+ // Dump rdata as such.
+ ret = knot_rrset_txt_dump_data(rrset, i, dst + len,
+ maxlen - len, style);
+ if (ret < 0) {
+ return KNOT_ESPACE;
+ }
+ len += ret;
+
+ // Terminate line.
+ if (len >= maxlen - 1) {
+ return KNOT_ESPACE;
+ }
+ dst[len++] = '\n';
+ dst[len] = '\0';
+
+ rr = knot_rdataset_next(rr);
+ }
+
+ return len;
+}
+
+_public_
+int knot_rrset_txt_dump(const knot_rrset_t *rrset,
+ char **dst,
+ size_t *dst_size,
+ const knot_dump_style_t *style)
+{
+ if (dst == NULL || dst_size == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ while (1) {
+ int ret = rrset_txt_dump(rrset, *dst, *dst_size, style);
+ if (ret != KNOT_ESPACE) {
+ return ret;
+ }
+
+ size_t new_dst_size = 2 * (*dst_size);
+ if (new_dst_size > RRSET_DUMP_LIMIT) {
+ return KNOT_ESPACE;
+ }
+
+ char * new_dst = malloc(new_dst_size);
+ if (new_dst == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ free(*dst);
+ *dst = new_dst;
+ *dst_size = new_dst_size;
+ }
+}
diff --git a/src/libknot/rrset-dump.h b/src/libknot/rrset-dump.h
new file mode 100644
index 0000000..3bd05de
--- /dev/null
+++ b/src/libknot/rrset-dump.h
@@ -0,0 +1,112 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief RRset text dump facility.
+ *
+ * \addtogroup rr
+ * @{
+ */
+
+#pragma once
+
+#include <stdbool.h>
+
+#include "libknot/rrset.h"
+
+/*! \brief Text output settings. */
+typedef struct {
+ /*!< Wrap long records. */
+ bool wrap;
+ /*!< Show class. */
+ bool show_class;
+ /*!< Show TTL. */
+ bool show_ttl;
+ /*!< Print extra information. */
+ bool verbose;
+ /*!< Print RRSIG original TTL instead of rrset TTL. */
+ bool original_ttl;
+ /*!< Show empty TTL value (keep indentation). */
+ bool empty_ttl;
+ /*!< Format TTL as DHMS. */
+ bool human_ttl;
+ /*!< Format timestamp as YYYYMMDDHHmmSS. */
+ bool human_tmstamp;
+ /*!< Force generic data representation. */
+ bool generic;
+ /*!< Hide binary parts of RRSIGs and DNSKEYs. */
+ bool hide_crypto;
+ /*!< ASCII string to IDN string transformation callback. */
+ void (*ascii_to_idn)(char **name);
+} knot_dump_style_t;
+
+/*! \brief Default dump style. */
+extern const knot_dump_style_t KNOT_DUMP_STYLE_DEFAULT;
+
+/*!
+ * \brief Dumps rrset header.
+ *
+ * \param rrset RRset to dump.
+ * \param ttl TTL to dump.
+ * \param dst Output buffer.
+ * \param maxlen Output buffer size.
+ * \param style Output style.
+ *
+ * \retval output length if success.
+ * \retval < 0 if error.
+ */
+int knot_rrset_txt_dump_header(const knot_rrset_t *rrset,
+ const uint32_t ttl,
+ char *dst,
+ const size_t maxlen,
+ const knot_dump_style_t *style);
+
+/*!
+ * \brief Dumps rrset data.
+ *
+ * \param rrset RRset to dump.
+ * \param pos Position of the record to dump.
+ * \param dst Output buffer.
+ * \param maxlen Output buffer size.
+ * \param style Output style.
+ *
+ * \retval output length if success.
+ * \retval < 0 if error.
+ */
+int knot_rrset_txt_dump_data(const knot_rrset_t *rrset,
+ const size_t pos,
+ char *dst,
+ const size_t maxlen,
+ const knot_dump_style_t *style);
+
+/*!
+ * \brief Dumps rrset, re-allocates dst to double (4x, 8x, ...) if too small.
+ *
+ * \param rrset RRset to dump.
+ * \param dst Output buffer.
+ * \param dst_size Output buffer size (changed if *dst re-allocated).
+ * \param style Output style.
+ *
+ * \retval output length if success.
+ * \retval < 0 if error.
+ */
+int knot_rrset_txt_dump(const knot_rrset_t *rrset,
+ char **dst,
+ size_t *dst_size,
+ const knot_dump_style_t *style);
+
+/*! @} */
diff --git a/src/libknot/rrset.c b/src/libknot/rrset.c
new file mode 100644
index 0000000..67d7aed
--- /dev/null
+++ b/src/libknot/rrset.c
@@ -0,0 +1,227 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "libknot/attribute.h"
+#include "libknot/errcode.h"
+#include "libknot/rrset.h"
+#include "libknot/rrtype/naptr.h"
+#include "libknot/rrtype/rrsig.h"
+#include "contrib/mempattern.h"
+
+_public_
+knot_rrset_t *knot_rrset_new(const knot_dname_t *owner, uint16_t type,
+ uint16_t rclass, uint32_t ttl, knot_mm_t *mm)
+{
+ knot_dname_t *owner_cpy = knot_dname_copy(owner, mm);
+ if (owner_cpy == NULL) {
+ return NULL;
+ }
+
+ knot_rrset_t *ret = mm_alloc(mm, sizeof(knot_rrset_t));
+ if (ret == NULL) {
+ knot_dname_free(owner_cpy, mm);
+ return NULL;
+ }
+
+ knot_rrset_init(ret, owner_cpy, type, rclass, ttl);
+
+ return ret;
+}
+
+_public_
+knot_rrset_t *knot_rrset_copy(const knot_rrset_t *src, knot_mm_t *mm)
+{
+ if (src == NULL) {
+ return NULL;
+ }
+
+ knot_rrset_t *rrset = knot_rrset_new(src->owner, src->type,
+ src->rclass, src->ttl, mm);
+ if (rrset == NULL) {
+ return NULL;
+ }
+
+ int ret = knot_rdataset_copy(&rrset->rrs, &src->rrs, mm);
+ if (ret != KNOT_EOK) {
+ knot_rrset_free(rrset, mm);
+ return NULL;
+ }
+
+ return rrset;
+}
+
+_public_
+void knot_rrset_free(knot_rrset_t *rrset, knot_mm_t *mm)
+{
+ if (rrset == NULL) {
+ return;
+ }
+
+ knot_rrset_clear(rrset, mm);
+ mm_free(mm, rrset);
+}
+
+_public_
+void knot_rrset_clear(knot_rrset_t *rrset, knot_mm_t *mm)
+{
+ if (rrset == NULL) {
+ return;
+ }
+
+ knot_rdataset_clear(&rrset->rrs, mm);
+ knot_dname_free(rrset->owner, mm);
+ rrset->owner = NULL;
+}
+
+_public_
+int knot_rrset_add_rdata(knot_rrset_t *rrset, const uint8_t *data, uint16_t len,
+ knot_mm_t *mm)
+{
+ if (rrset == NULL || (data == NULL && len > 0)) {
+ return KNOT_EINVAL;
+ }
+
+ uint8_t buf[knot_rdata_size(len)];
+ knot_rdata_t *rdata = (knot_rdata_t *)buf;
+ knot_rdata_init(rdata, len, data);
+
+ return knot_rdataset_add(&rrset->rrs, rdata, mm);
+}
+
+_public_
+bool knot_rrset_equal(const knot_rrset_t *r1,
+ const knot_rrset_t *r2,
+ knot_rrset_compare_type_t cmp)
+{
+ if (cmp == KNOT_RRSET_COMPARE_PTR) {
+ return r1 == r2;
+ }
+
+ if (r1->type != r2->type) {
+ return false;
+ }
+
+ if (r1->owner && r2->owner) {
+ if (!knot_dname_is_equal(r1->owner, r2->owner)) {
+ return false;
+ }
+ } else if (r1->owner != r2->owner) { // At least one is NULL.
+ return false;
+ }
+
+ if (cmp == KNOT_RRSET_COMPARE_WHOLE) {
+ return knot_rdataset_eq(&r1->rrs, &r2->rrs);
+ }
+
+ return true;
+}
+
+_public_
+bool knot_rrset_is_nsec3rel(const knot_rrset_t *rr)
+{
+ if (rr == NULL) {
+ return false;
+ }
+
+ /* Is NSEC3 or non-empty RRSIG covering NSEC3. */
+ return ((rr->type == KNOT_RRTYPE_NSEC3) ||
+ (rr->type == KNOT_RRTYPE_RRSIG
+ && knot_rrsig_type_covered(rr->rrs.rdata) == KNOT_RRTYPE_NSEC3));
+}
+
+_public_
+int knot_rrset_rr_to_canonical(knot_rrset_t *rrset)
+{
+ if (rrset == NULL || rrset->rrs.count != 1) {
+ return KNOT_EINVAL;
+ }
+
+ /* Convert owner for all RRSets. */
+ knot_dname_to_lower(rrset->owner);
+
+ /* Convert DNAMEs in RDATA only for RFC4034 types. */
+ if (!knot_rrtype_should_be_lowercased(rrset->type)) {
+ return KNOT_EOK;
+ }
+
+ const knot_rdata_descriptor_t *desc = knot_get_rdata_descriptor(rrset->type);
+ if (desc->type_name == NULL) {
+ desc = knot_get_obsolete_rdata_descriptor(rrset->type);
+ }
+
+ uint16_t rdlen = rrset->rrs.rdata->len;
+ uint8_t *pos = rrset->rrs.rdata->data;
+ uint8_t *endpos = pos + rdlen;
+
+ /* No RDATA */
+ if (rdlen == 0) {
+ return KNOT_EOK;
+ }
+
+ /* Otherwise, whole and not malformed RDATA are expected. */
+ for (int i = 0; desc->block_types[i] != KNOT_RDATA_WF_END; ++i) {
+ int type = desc->block_types[i];
+ switch (type) {
+ case KNOT_RDATA_WF_COMPRESSIBLE_DNAME:
+ case KNOT_RDATA_WF_DECOMPRESSIBLE_DNAME:
+ case KNOT_RDATA_WF_FIXED_DNAME:
+ knot_dname_to_lower(pos);
+ pos += knot_dname_size(pos);
+ break;
+ case KNOT_RDATA_WF_NAPTR_HEADER:
+ ; int ret = knot_naptr_header_size(pos, endpos);
+ if (ret < 0) {
+ return ret;
+ }
+
+ pos += ret;
+ break;
+ case KNOT_RDATA_WF_REMAINDER:
+ break;
+ default:
+ /* Fixed size block */
+ assert(type > 0);
+ pos += type;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+_public_
+size_t knot_rrset_size(const knot_rrset_t *rrset)
+{
+ if (rrset == NULL) {
+ return 0;
+ }
+
+ uint16_t rr_count = rrset->rrs.count;
+
+ size_t total_size = knot_dname_size(rrset->owner) * rr_count;
+
+ knot_rdata_t *rr = rrset->rrs.rdata;
+ for (size_t i = 0; i < rr_count; ++i) {
+ /* 10B = TYPE + CLASS + TTL + RDLENGTH */
+ total_size += rr->len + 10;
+ rr = knot_rdataset_next(rr);
+ }
+
+ return total_size;
+}
diff --git a/src/libknot/rrset.h b/src/libknot/rrset.h
new file mode 100644
index 0000000..aac9a4c
--- /dev/null
+++ b/src/libknot/rrset.h
@@ -0,0 +1,200 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief RRSet structure and API for manipulating it.
+ *
+ * \addtogroup rr
+ * @{
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "libknot/dname.h"
+#include "libknot/descriptor.h"
+#include "libknot/mm_ctx.h"
+#include "libknot/rdataset.h"
+
+/*!
+ * \brief Structure for representing RRSet.
+ *
+ * For RRSet definition see RFC2181, Section 5.
+ */
+typedef struct {
+ knot_dname_t *owner; /*!< Domain name being the owner of the RRSet. */
+ uint32_t ttl; /*!< TTL of the RRset. */
+ uint16_t type; /*!< TYPE of the RRset. */
+ uint16_t rclass; /*!< CLASS of the RRSet. */
+ knot_rdataset_t rrs; /*!< RRSet's RRs */
+ /* Optional fields. */
+ void *additional; /*!< Additional records. */
+} knot_rrset_t;
+
+/*! \todo Documentation */
+typedef enum {
+ KNOT_RRSET_COMPARE_PTR,
+ KNOT_RRSET_COMPARE_HEADER,
+ KNOT_RRSET_COMPARE_WHOLE
+} knot_rrset_compare_type_t;
+
+/*!
+ * \brief Creates a new RRSet with the given properties.
+ *
+ * The created RRSet contains no RDATAs (i.e. is actually empty).
+ *
+ * \param owner OWNER of the RRSet.
+ * \param type TYPE of the RRSet.
+ * \param rclass CLASS of the RRSet.
+ * \param ttl TTL of the RRSet.
+ * \param mm Memory context.
+ *
+ * \return New RRSet structure or NULL if an error occurred.
+ */
+knot_rrset_t *knot_rrset_new(const knot_dname_t *owner, uint16_t type,
+ uint16_t rclass, uint32_t ttl, knot_mm_t *mm);
+
+/*!
+ * \brief Initializes RRSet structure with given data.
+ *
+ * \param rrset RRSet to init.
+ * \param owner RRSet owner to use.
+ * \param type RR type to use.
+ * \param rclass Class to use.
+ * \param ttl TTL to use.
+ */
+inline static void knot_rrset_init(knot_rrset_t *rrset, knot_dname_t *owner,
+ uint16_t type, uint16_t rclass, uint32_t ttl)
+{
+ if (rrset != NULL) {
+ rrset->owner = owner;
+ rrset->type = type;
+ rrset->rclass = rclass;
+ rrset->ttl = ttl;
+ knot_rdataset_init(&rrset->rrs);
+ rrset->additional = NULL;
+ }
+}
+
+/*!
+ * \brief Initializes given RRSet structure.
+ *
+ * \param rrset RRSet to init.
+ */
+inline static void knot_rrset_init_empty(knot_rrset_t *rrset)
+{
+ knot_rrset_init(rrset, NULL, 0, KNOT_CLASS_IN, 0);
+}
+
+/*!
+ * \brief Creates new RRSet from \a src RRSet.
+ *
+ * \param src Source RRSet.
+ * \param mm Memory context.
+ *
+ * \retval Pointer to new RRSet if all went OK.
+ * \retval NULL on error.
+ */
+knot_rrset_t *knot_rrset_copy(const knot_rrset_t *src, knot_mm_t *mm);
+
+/*!
+ * \brief Destroys the RRSet structure and all its substructures.
+ *
+ * \param rrset RRset to be destroyed.
+ * \param mm Memory context.
+ */
+void knot_rrset_free(knot_rrset_t *rrset, knot_mm_t *mm);
+
+/*!
+ * \brief Frees structures inside RRSet, but not the RRSet itself.
+ *
+ * \param rrset RRSet to be cleared.
+ * \param mm Memory context used for allocations.
+ */
+void knot_rrset_clear(knot_rrset_t *rrset, knot_mm_t *mm);
+
+/*!
+ * \brief Adds the given RDATA to the RRSet.
+ *
+ * \param rrset RRSet to add the RDATA to.
+ * \param data RDATA to add to the RRSet.
+ * \param len Length of RDATA.
+ * \param mm Memory context.
+ *
+ * \return KNOT_E*
+ */
+int knot_rrset_add_rdata(knot_rrset_t *rrset, const uint8_t *data, uint16_t len,
+ knot_mm_t *mm);
+
+/*!
+ * \brief Compares two RRSets for equality.
+ *
+ * \param r1 First RRSet.
+ * \param r2 Second RRSet.
+ * \param cmp Type of comparison to perform.
+ *
+ * \retval True if RRSets are equal.
+ * \retval False if RRSets are not equal.
+ */
+bool knot_rrset_equal(const knot_rrset_t *r1, const knot_rrset_t *r2,
+ knot_rrset_compare_type_t cmp);
+
+/*!
+ * \brief Checks whether RRSet is empty.
+ *
+ * \param rrset RRSet to check.
+ *
+ * \retval True if RRSet is empty.
+ * \retval False if RRSet is not empty.
+ */
+inline static bool knot_rrset_empty(const knot_rrset_t *rrset)
+{
+ return rrset == NULL || rrset->rrs.count == 0;
+}
+
+/*!
+ * \brief Return whether the RR type is NSEC3 related (NSEC3 or RRSIG).
+ */
+bool knot_rrset_is_nsec3rel(const knot_rrset_t *rr);
+
+/*!
+ * \brief Convert one RR into canonical format.
+ *
+ * Owner is always converted to lowercase. RDATA domain names are converted only
+ * for types listed in RFC 4034, Section 6.2, except for NSEC (updated by
+ * RFC 6840, Section 5.1) and A6 (not supported).
+ *
+ * \note If RRSet with more RRs is given to this function, only the first RR
+ * will be converted.
+ * \warning This function expects either empty RDATA or full, not malformed
+ * RDATA. If malformed RRSet is passed to this function, memory errors
+ * may occur.
+ *
+ * \param rrset RR to convert.
+ */
+int knot_rrset_rr_to_canonical(knot_rrset_t *rrset);
+
+/*!
+ * \brief Size of rrset in wire format.
+ *
+ * \retval size in bytes
+ */
+size_t knot_rrset_size(const knot_rrset_t *rrset);
+
+/*! @} */
diff --git a/src/libknot/rrtype/dnskey.h b/src/libknot/rrtype/dnskey.h
new file mode 100644
index 0000000..ff6f4b9
--- /dev/null
+++ b/src/libknot/rrtype/dnskey.h
@@ -0,0 +1,71 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \addtogroup rrtype
+ * @{
+ */
+
+#pragma once
+
+#include "libknot/rdata.h"
+#include "libknot/wire.h"
+
+/*! See https://www.iana.org/assignments/dnskey-flags */
+/*! /brief "Secure entry point" marks KSK and CSK in practice. */
+#define KNOT_DNSKEY_FLAG_SEP 1
+/*! /brief The key is ALLOWED to be used for zone contents signing. */
+#define KNOT_DNSKEY_FLAG_ZONE 256
+/*! /brief The key MUST NOT be used for validation. */
+#define KNOT_DNSKEY_FLAG_REVOKE 128
+
+static inline
+uint16_t knot_dnskey_flags(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return knot_wire_read_u16(rdata->data);
+}
+
+static inline
+uint8_t knot_dnskey_proto(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return *(rdata->data + 2);
+}
+
+static inline
+uint8_t knot_dnskey_alg(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return *(rdata->data + 3);
+}
+
+static inline
+uint16_t knot_dnskey_key_len(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return rdata->len - 4;
+}
+
+static inline
+const uint8_t *knot_dnskey_key(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return rdata->data + 4;
+}
+
+/*! @} */
diff --git a/src/libknot/rrtype/ds.h b/src/libknot/rrtype/ds.h
new file mode 100644
index 0000000..d447929
--- /dev/null
+++ b/src/libknot/rrtype/ds.h
@@ -0,0 +1,63 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \addtogroup rrtype
+ * @{
+ */
+
+#pragma once
+
+#include "libknot/rdata.h"
+#include "libknot/wire.h"
+
+static inline
+uint16_t knot_ds_key_tag(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return knot_wire_read_u16(rdata->data);
+}
+
+static inline
+uint8_t knot_ds_alg(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return *(rdata->data + 2);
+}
+
+static inline
+uint8_t knot_ds_digest_type(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return *(rdata->data + 3);
+}
+
+static inline
+uint16_t knot_ds_digest_len(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return rdata->len - 4;
+}
+
+static inline
+const uint8_t *knot_ds_digest(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return rdata->data + 4;
+}
+
+/*! @} */
diff --git a/src/libknot/rrtype/naptr.c b/src/libknot/rrtype/naptr.c
new file mode 100644
index 0000000..ec513ca
--- /dev/null
+++ b/src/libknot/rrtype/naptr.c
@@ -0,0 +1,47 @@
+/* Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <stdint.h>
+
+#include "libknot/attribute.h"
+#include "libknot/rrtype/naptr.h"
+#include "contrib/wire_ctx.h"
+
+_public_
+int knot_naptr_header_size(const uint8_t *naptr, const uint8_t *maxp)
+{
+ if (!naptr || !maxp || naptr >= maxp) {
+ return KNOT_EINVAL;
+ }
+
+ wire_ctx_t wire = wire_ctx_init_const(naptr, maxp - naptr);
+
+ /* Fixed fields size (order, preference) */
+ wire_ctx_skip(&wire, 2 * sizeof(uint16_t));
+
+ /* Variable fields size (flags, services, regexp) */
+ for (int i = 0; i < 3; i++) {
+ uint8_t size = wire_ctx_read_u8(&wire);
+ wire_ctx_skip(&wire, size);
+ }
+
+ if (wire.error != KNOT_EOK) {
+ return KNOT_EMALF;
+ }
+
+ return wire_ctx_offset(&wire);
+}
diff --git a/src/libknot/rrtype/naptr.h b/src/libknot/rrtype/naptr.h
new file mode 100644
index 0000000..a067f64
--- /dev/null
+++ b/src/libknot/rrtype/naptr.h
@@ -0,0 +1,40 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \addtogroup rrtype
+ * @{
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+/*!
+ * \brief Counts the size of the NAPTR RDATA before the Replacement domain name.
+ *
+ * See RFC 2915.
+ *
+ * \param naptr Wire format of NAPTR record.
+ * \param maxp Limit of the wire format.
+ *
+ * \retval KNOT_EMALF if the record is malformed.
+ * \retval Size of the RDATA before the Replacement domain name.
+ */
+int knot_naptr_header_size(const uint8_t *naptr, const uint8_t *maxp);
+
+/*! @} */
diff --git a/src/libknot/rrtype/nsec.h b/src/libknot/rrtype/nsec.h
new file mode 100644
index 0000000..896ab3a
--- /dev/null
+++ b/src/libknot/rrtype/nsec.h
@@ -0,0 +1,49 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \addtogroup rrtype
+ * @{
+ */
+
+#pragma once
+
+#include "libknot/dname.h"
+#include "libknot/rdata.h"
+
+static inline
+const knot_dname_t *knot_nsec_next(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return rdata->data;
+}
+
+static inline
+uint16_t knot_nsec_bitmap_len(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return rdata->len - knot_dname_size(knot_nsec_next(rdata));
+}
+
+static inline
+const uint8_t *knot_nsec_bitmap(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return rdata->data + knot_dname_size(knot_nsec_next(rdata));
+}
+
+/*! @} */
diff --git a/src/libknot/rrtype/nsec3.h b/src/libknot/rrtype/nsec3.h
new file mode 100644
index 0000000..f69c774
--- /dev/null
+++ b/src/libknot/rrtype/nsec3.h
@@ -0,0 +1,97 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \addtogroup rrtype
+ * @{
+ */
+
+#pragma once
+
+#include "libknot/rdata.h"
+#include "libknot/wire.h"
+
+/*!
+ * \brief NSEC3 rdata constants.
+ */
+#define KNOT_NSEC3_ALGORITHM_SHA1 1
+#define KNOT_NSEC3_FLAG_OPT_OUT 1
+
+static inline
+uint8_t knot_nsec3_alg(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return *(rdata->data);
+}
+
+static inline
+uint8_t knot_nsec3_flags(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return *(rdata->data + 1);
+}
+
+static inline
+uint16_t knot_nsec3_iters(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return knot_wire_read_u16(rdata->data + 2);
+}
+
+static inline
+uint8_t knot_nsec3_salt_len(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return *(rdata->data + 4);
+}
+
+static inline
+const uint8_t *knot_nsec3_salt(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return rdata->data + 5;
+}
+
+static inline
+uint8_t knot_nsec3_next_len(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return *(rdata->data + 5 + knot_nsec3_salt_len(rdata));
+}
+
+static inline
+const uint8_t *knot_nsec3_next(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return rdata->data + 6 + knot_nsec3_salt_len(rdata);
+}
+
+static inline
+uint16_t knot_nsec3_bitmap_len(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return rdata->len - 6 - knot_nsec3_salt_len(rdata) - knot_nsec3_next_len(rdata);
+}
+
+static inline
+const uint8_t *knot_nsec3_bitmap(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return rdata->data + 6 + knot_nsec3_salt_len(rdata) + knot_nsec3_next_len(rdata);
+}
+
+/*! @} */
diff --git a/src/libknot/rrtype/nsec3param.h b/src/libknot/rrtype/nsec3param.h
new file mode 100644
index 0000000..239271a
--- /dev/null
+++ b/src/libknot/rrtype/nsec3param.h
@@ -0,0 +1,63 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \addtogroup rrtype
+ * @{
+ */
+
+#pragma once
+
+#include "libknot/rdata.h"
+#include "libknot/wire.h"
+
+static inline
+uint8_t knot_nsec3param_alg(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return *(rdata->data);
+}
+
+static inline
+uint8_t knot_nsec3param_flags(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return *(rdata->data + 1);
+}
+
+static inline
+uint16_t knot_nsec3param_iters(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return knot_wire_read_u16(rdata->data + 2);
+}
+
+static inline
+uint8_t knot_nsec3param_salt_len(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return *(rdata->data + 4);
+}
+
+static inline
+const uint8_t *knot_nsec3param_salt(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return rdata->data + 5;
+}
+
+/*! @} */
diff --git a/src/libknot/rrtype/opt.c b/src/libknot/rrtype/opt.c
new file mode 100644
index 0000000..3784858
--- /dev/null
+++ b/src/libknot/rrtype/opt.c
@@ -0,0 +1,675 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include "libknot/attribute.h"
+#include "libknot/consts.h"
+#include "libknot/descriptor.h"
+#include "libknot/rrtype/opt.h"
+#include "libknot/packet/pkt.h"
+#include "contrib/mempattern.h"
+#include "contrib/wire_ctx.h"
+
+/*! \brief Some implementation-related constants. */
+enum {
+ /*! \brief Byte offset of the extended RCODE field in TTL. */
+ EDNS_OFFSET_RCODE = 0,
+ /*! \brief Byte offset of the version field in TTL. */
+ EDNS_OFFSET_VERSION = 1,
+
+ /*! \brief Byte offset of the family field in option data. */
+ EDNS_OFFSET_CLIENT_SUBNET_FAMILY = 0,
+ /*! \brief Byte offset of the source mask field in option data. */
+ EDNS_OFFSET_CLIENT_SUBNET_SRC_MASK = 2,
+ /*! \brief Byte offset of the destination mask field in option data. */
+ EDNS_OFFSET_CLIENT_SUBNET_DST_MASK = 3,
+ /*! \brief Byte offset of the address field in option data. */
+ EDNS_OFFSET_CLIENT_SUBNET_ADDR = 4,
+};
+
+_public_
+int knot_edns_init(knot_rrset_t *opt_rr, uint16_t max_pld,
+ uint8_t ext_rcode, uint8_t ver, knot_mm_t *mm)
+{
+ if (opt_rr == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ /* Initialize RRSet. */
+ knot_dname_t *owner = knot_dname_copy((const uint8_t *)"", mm);
+ if (owner == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ knot_rrset_init(opt_rr, owner, KNOT_RRTYPE_OPT, max_pld, 0);
+
+ /* Create empty RDATA */
+ int ret = knot_rrset_add_rdata(opt_rr, NULL, 0, mm);
+ if (ret == KNOT_EOK) {
+ knot_edns_set_ext_rcode(opt_rr, ext_rcode);
+ knot_edns_set_version(opt_rr, ver);
+ }
+
+ return ret;
+}
+
+_public_
+uint8_t knot_edns_get_ext_rcode(const knot_rrset_t *opt_rr)
+{
+ assert(opt_rr != NULL);
+ uint32_t ttl = 0;
+ wire_ctx_t w = wire_ctx_init((uint8_t *)&ttl, sizeof(ttl));
+ // TTL is stored in machine byte order. Convert it to wire order first.
+ wire_ctx_write_u32(&w, opt_rr->ttl);
+ wire_ctx_set_offset(&w, EDNS_OFFSET_RCODE);
+ return wire_ctx_read_u8(&w);
+}
+
+static void set_value_to_ttl(knot_rrset_t *opt_rr, size_t offset, uint8_t value)
+{
+ uint32_t ttl = 0;
+ wire_ctx_t w = wire_ctx_init((uint8_t *)&ttl, sizeof(ttl));
+ // TTL is stored in machine byte order. Convert it to wire order first.
+ wire_ctx_write_u32(&w, opt_rr->ttl);
+ // Set the Extended RCODE in the converted TTL
+ wire_ctx_set_offset(&w, offset);
+ wire_ctx_write_u8(&w, value);
+ // Convert it back to machine byte order
+ wire_ctx_set_offset(&w, 0);
+ uint32_t ttl_local = wire_ctx_read_u32(&w);
+ // Store the TTL to the RDATA
+ opt_rr->ttl = ttl_local;
+}
+
+_public_
+void knot_edns_set_ext_rcode(knot_rrset_t *opt_rr, uint8_t ext_rcode)
+{
+ assert(opt_rr != NULL);
+ set_value_to_ttl(opt_rr, EDNS_OFFSET_RCODE, ext_rcode);
+}
+
+_public_
+uint8_t knot_edns_get_version(const knot_rrset_t *opt_rr)
+{
+ assert(opt_rr != NULL);
+ uint32_t ttl = 0;
+ wire_ctx_t w = wire_ctx_init((uint8_t *)&ttl, sizeof(ttl));
+ // TTL is stored in machine byte order. Convert it to wire order first.
+ wire_ctx_write_u32(&w, opt_rr->ttl);
+ wire_ctx_set_offset(&w, EDNS_OFFSET_VERSION);
+ return wire_ctx_read_u8(&w);
+}
+
+_public_
+void knot_edns_set_version(knot_rrset_t *opt_rr, uint8_t version)
+{
+ assert(opt_rr != NULL);
+ set_value_to_ttl(opt_rr, EDNS_OFFSET_VERSION, version);
+}
+
+/*!
+ * \brief Add new EDNS option by replacing RDATA of OPT RR.
+ *
+ * \param opt OPT RR structure to add the Option to.
+ * \param code Option code.
+ * \param size Option data length in bytes.
+ * \param mm Memory context.
+ *
+ * \return Pointer to uninitialized option data.
+ */
+static uint8_t *edns_add(knot_rrset_t *opt, uint16_t code, uint16_t size,
+ knot_mm_t *mm)
+{
+ assert(opt->rrs.count == 1);
+
+ // extract old RDATA
+
+ uint8_t *old_data = opt->rrs.rdata->data;
+ uint16_t old_data_len = opt->rrs.rdata->len;
+
+ // construct new RDATA
+
+ uint16_t new_data_len = old_data_len + KNOT_EDNS_OPTION_HDRLEN + size;
+ uint8_t new_data[new_data_len];
+
+ wire_ctx_t wire = wire_ctx_init(new_data, new_data_len);
+ wire_ctx_write(&wire, old_data, old_data_len);
+ wire_ctx_write_u16(&wire, code);
+ wire_ctx_write_u16(&wire, size);
+
+ // prepare EDNS option data
+
+ size_t offset = wire_ctx_offset(&wire);
+ wire_ctx_clear(&wire, size);
+
+ assert(wire_ctx_available(&wire) == 0);
+ assert(wire.error == KNOT_EOK);
+
+ // replace RDATA
+
+ knot_rdataset_clear(&opt->rrs, mm);
+ if (knot_rrset_add_rdata(opt, new_data, new_data_len, mm) != KNOT_EOK) {
+ return NULL;
+ }
+
+ return opt->rrs.rdata->data + offset;
+}
+
+_public_
+int knot_edns_reserve_option(knot_rrset_t *opt_rr, uint16_t code,
+ uint16_t size, uint8_t **wire_ptr, knot_mm_t *mm)
+{
+ if (!opt_rr) {
+ return KNOT_EINVAL;
+ }
+
+ uint8_t *wire = edns_add(opt_rr, code, size, mm);
+ if (!wire) {
+ return KNOT_ENOMEM;
+ }
+
+ if (wire_ptr) {
+ *wire_ptr = wire;
+ }
+
+ return KNOT_EOK;
+}
+
+_public_
+int knot_edns_add_option(knot_rrset_t *opt_rr, uint16_t code,
+ uint16_t size, const uint8_t *data, knot_mm_t *mm)
+{
+ if (!opt_rr || (size > 0 && !data)) {
+ return KNOT_EINVAL;
+ }
+
+ uint8_t *wire = edns_add(opt_rr, code, size, mm);
+ if (!wire) {
+ return KNOT_ENOMEM;
+ }
+
+ memcpy(wire, data, size);
+
+ return KNOT_EOK;
+}
+
+_public_
+uint8_t *knot_edns_get_option(const knot_rrset_t *opt_rr, uint16_t code)
+{
+ if (opt_rr == NULL) {
+ return NULL;
+ }
+
+ knot_rdata_t *rdata = opt_rr->rrs.rdata;
+ if (rdata == NULL || rdata->len == 0) {
+ return NULL;
+ }
+
+ wire_ctx_t wire = wire_ctx_init_const(rdata->data, rdata->len);
+
+ while (wire_ctx_available(&wire) > 0 && wire.error == KNOT_EOK) {
+ uint8_t *pos = wire.position;
+ uint16_t opt_code = wire_ctx_read_u16(&wire);
+ uint16_t opt_len = wire_ctx_read_u16(&wire);
+ wire_ctx_skip(&wire, opt_len);
+ if (wire.error == KNOT_EOK && opt_code == code) {
+ return pos;
+ }
+ }
+
+ return NULL;
+}
+
+_public_
+int knot_edns_get_options(knot_rrset_t *opt_rr, knot_edns_options_t **out,
+ knot_mm_t *mm)
+{
+ if (opt_rr == NULL || opt_rr->rrs.count > 1 || out == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ knot_rdata_t *rdata = opt_rr->rrs.rdata;
+ if (rdata == NULL || rdata->len == 0) {
+ return KNOT_EOK;
+ }
+
+ knot_edns_options_t *options = mm_calloc(mm, 1, sizeof(*options));
+
+ wire_ctx_t wire = wire_ctx_init_const(rdata->data, rdata->len);
+
+ while (wire_ctx_available(&wire) > 0 && wire.error == KNOT_EOK) {
+ uint8_t *pos = wire.position;
+ uint16_t opt_code = wire_ctx_read_u16(&wire);
+ uint16_t opt_len = wire_ctx_read_u16(&wire);
+ wire_ctx_skip(&wire, opt_len);
+ if (wire.error == KNOT_EOK && opt_code <= KNOT_EDNS_MAX_OPTION_CODE) {
+ options->ptr[opt_code] = pos;
+ }
+ }
+
+ if (wire.error != KNOT_EOK) {
+ mm_free(mm, options);
+ return wire.error;
+ }
+
+ *out = options;
+ return KNOT_EOK;
+}
+
+_public_
+int knot_edns_alignment_size(size_t current_pkt_size,
+ size_t current_opt_size,
+ size_t block_size)
+{
+ if (current_opt_size == 0 || block_size == 0) {
+ return -1;
+ }
+
+ size_t current_size = current_pkt_size + current_opt_size;
+ if (current_size % block_size == 0) {
+ return -1;
+ }
+
+ size_t modulo = (current_size + KNOT_EDNS_OPTION_HDRLEN) % block_size;
+
+ return (modulo == 0) ? 0 : block_size - modulo;
+}
+
+/*!
+ * \brief EDNS Client Subnet family data.
+ */
+typedef struct {
+ int platform; //!< Platform family identifier.
+ uint16_t iana; //!< IANA family identifier.
+ size_t offset; //!< Socket address offset.
+ size_t size; //!< Socket address size.
+} ecs_family_t;
+
+#define ECS_INIT(platform, iana, type, member) \
+ { platform, iana, offsetof(type, member), sizeof(((type *)0)->member) }
+
+/*!
+ * \brief Supported EDNS Client Subnet families.
+ *
+ * http://www.iana.org/assignments/address-family-numbers/address-family-numbers.xml
+ */
+static const ecs_family_t ECS_FAMILIES[] = {
+ ECS_INIT(AF_INET, KNOT_ADDR_FAMILY_IPV4, struct sockaddr_in, sin_addr),
+ ECS_INIT(AF_INET6, KNOT_ADDR_FAMILY_IPV6, struct sockaddr_in6, sin6_addr),
+ { 0 }
+};
+
+/*!
+ * \brief Lookup ECS family by platform identifier.
+ */
+static const ecs_family_t *ecs_family_by_platform(int family)
+{
+ for (const ecs_family_t *f = ECS_FAMILIES; f->size > 0; f++) {
+ if (f->platform == family) {
+ return f;
+ }
+ }
+
+ return NULL;
+}
+
+/*!
+ * \brief Lookup ECS family by IANA identifier.
+ */
+static const ecs_family_t *ecs_family_by_iana(uint16_t family)
+{
+ for (const ecs_family_t *f = ECS_FAMILIES; f->size > 0; f++) {
+ if (f->iana == family) {
+ return f;
+ }
+ }
+
+ return NULL;
+}
+
+/*!
+ * \brief Get ECS address prefix size in bytes.
+ */
+static uint16_t ecs_prefix_size(uint8_t prefix)
+{
+ return (prefix + 7) / 8;
+}
+
+static uint8_t ecs_prefix_lsb_mask(uint8_t prefix)
+{
+ int modulo = prefix % 8;
+ if (modulo == 0) {
+ return 0xff;
+ } else {
+ return 0xff << (8 - modulo);
+ }
+}
+
+/*!
+ * \brief Write raw network address prefix and clear the rest of the buffer.
+ */
+static void ecs_write_address(wire_ctx_t *dst, wire_ctx_t *src, int8_t prefix)
+{
+ size_t count = ecs_prefix_size(prefix);
+ uint8_t lsb_mask = ecs_prefix_lsb_mask(prefix);
+
+ if (count > 0) {
+ wire_ctx_copy(dst, src, count);
+ if (dst->error != KNOT_EOK) {
+ return;
+ }
+ dst->position[-1] &= lsb_mask;
+ }
+
+ size_t blank = wire_ctx_available(dst);
+ wire_ctx_memset(dst, 0, blank);
+}
+
+/*!
+ * \brief Check if ECS parameters are valid.
+ */
+static bool ecs_is_valid(const knot_edns_client_subnet_t *ecs)
+{
+ if (ecs == NULL) {
+ return false;
+ }
+
+ const ecs_family_t *f = ecs_family_by_iana(ecs->family);
+
+ return f != NULL && // known family check
+ (ecs->source_len <= f->size * 8) && // family address maximum check
+ (ecs->scope_len <= f->size * 8); // family address maximum check
+}
+
+_public_
+uint16_t knot_edns_client_subnet_size(const knot_edns_client_subnet_t *ecs)
+{
+ if (!ecs_is_valid(ecs)) {
+ return 0;
+ }
+
+ return sizeof(ecs->family) +
+ sizeof(ecs->source_len) +
+ sizeof(ecs->scope_len) +
+ ecs_prefix_size(ecs->source_len);
+}
+
+_public_
+int knot_edns_client_subnet_write(uint8_t *option, uint16_t option_len,
+ const knot_edns_client_subnet_t *ecs)
+{
+ if (option == NULL || ecs == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ if (!ecs_is_valid(ecs)) {
+ return KNOT_EINVAL;
+ }
+
+ wire_ctx_t wire = wire_ctx_init(option, option_len);
+ wire_ctx_t addr = wire_ctx_init_const(ecs->address, sizeof(ecs->address));
+
+ wire_ctx_write_u16(&wire, ecs->family);
+ wire_ctx_write_u8(&wire, ecs->source_len);
+ wire_ctx_write_u8(&wire, ecs->scope_len);
+ ecs_write_address(&wire, &addr, ecs->source_len);
+
+ if (wire.error != KNOT_EOK) {
+ return wire.error;
+ }
+
+ return KNOT_EOK;
+}
+
+_public_
+int knot_edns_client_subnet_parse(knot_edns_client_subnet_t *ecs,
+ const uint8_t *option, uint16_t option_len)
+{
+ if (ecs == NULL || option == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ knot_edns_client_subnet_t result = { 0 };
+
+ wire_ctx_t wire = wire_ctx_init_const(option, option_len);
+ wire_ctx_t addr = wire_ctx_init(result.address, sizeof(result.address));
+
+ result.family = wire_ctx_read_u16(&wire);
+ result.source_len = wire_ctx_read_u8(&wire);
+ result.scope_len = wire_ctx_read_u8(&wire);
+ ecs_write_address(&addr, &wire, result.source_len);
+
+ if (addr.error != KNOT_EOK || wire.error != KNOT_EOK) {
+ return KNOT_EMALF;
+ }
+
+ if (!ecs_is_valid(&result)) {
+ return KNOT_EMALF;
+ }
+
+ *ecs = result;
+ return KNOT_EOK;
+}
+
+_public_
+int knot_edns_client_subnet_set_addr(knot_edns_client_subnet_t *ecs,
+ const struct sockaddr_storage *addr)
+{
+ if (ecs == NULL || addr == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ const ecs_family_t *f = ecs_family_by_platform(addr->ss_family);
+ if (f == NULL) {
+ return KNOT_ENOTSUP;
+ }
+
+ ecs->family = f->iana;
+ ecs->source_len = f->size * 8;
+ ecs->scope_len = 0;
+
+ wire_ctx_t dst = wire_ctx_init(ecs->address, sizeof(ecs->address));
+ wire_ctx_t src = wire_ctx_init_const((uint8_t *)addr + f->offset, f->size);
+ ecs_write_address(&dst, &src, ecs->source_len);
+
+ assert(dst.error == KNOT_EOK);
+
+ return KNOT_EOK;
+}
+
+_public_
+int knot_edns_client_subnet_get_addr(struct sockaddr_storage *addr,
+ const knot_edns_client_subnet_t *ecs)
+{
+ if (addr == NULL || ecs == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ const ecs_family_t *f = ecs_family_by_iana(ecs->family);
+ if (f == NULL) {
+ return KNOT_ENOTSUP;
+ }
+
+ addr->ss_family = f->platform;
+
+ wire_ctx_t dst = wire_ctx_init((uint8_t *)addr + f->offset, f->size);
+ wire_ctx_t src = wire_ctx_init_const(ecs->address, sizeof(ecs->address));
+ ecs_write_address(&dst, &src, ecs->source_len);
+
+ assert(dst.error == KNOT_EOK);
+
+ return KNOT_EOK;
+}
+
+_public_
+uint16_t knot_edns_keepalive_size(uint16_t timeout)
+{
+ return (timeout > 0) ? sizeof(uint16_t) : 0;
+}
+
+_public_
+int knot_edns_keepalive_write(uint8_t *option, uint16_t option_len, uint16_t timeout)
+{
+ if (option == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ if (timeout == 0) {
+ return KNOT_EOK;
+ }
+
+ wire_ctx_t wire = wire_ctx_init(option, option_len);
+ wire_ctx_write_u16(&wire, timeout);
+
+ return wire.error;
+}
+
+_public_
+int knot_edns_keepalive_parse(uint16_t *timeout, const uint8_t *option,
+ uint16_t option_len)
+{
+ if (timeout == NULL || option == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ *timeout = 0;
+
+ if (option_len > 0) {
+ wire_ctx_t wire = wire_ctx_init_const(option, option_len);
+ *timeout = wire_ctx_read_u16(&wire);
+
+ if (wire.error != KNOT_EOK) {
+ return KNOT_EMALF;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+_public_
+uint16_t knot_edns_chain_size(const knot_dname_t *point)
+{
+ return knot_dname_size(point);
+}
+
+_public_
+int knot_edns_chain_write(uint8_t *option, uint16_t option_len,
+ const knot_dname_t *point)
+{
+ if (option == NULL || point == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ wire_ctx_t wire = wire_ctx_init(option, option_len);
+ wire_ctx_write(&wire, point, knot_dname_size(point));
+
+ return wire.error;
+}
+
+_public_
+int knot_edns_chain_parse(knot_dname_t **point, const uint8_t *option,
+ uint16_t option_len, knot_mm_t *mm)
+{
+ if (point == NULL || option == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = knot_dname_wire_check(option, option + option_len, NULL);
+ if (ret <= 0) {
+ return KNOT_EMALF;
+ }
+
+ *point = knot_dname_copy(option, mm);
+ if (*point == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ return KNOT_EOK;
+}
+
+_public_
+uint16_t knot_edns_cookie_size(const knot_edns_cookie_t *cc,
+ const knot_edns_cookie_t *sc)
+{
+ if (cc == NULL || cc->len != KNOT_EDNS_COOKIE_CLNT_SIZE) {
+ return 0;
+ } else if (sc == NULL || sc->len == 0) {
+ return KNOT_EDNS_COOKIE_CLNT_SIZE;
+ } else if (sc->len < KNOT_EDNS_COOKIE_SRVR_MIN_SIZE ||
+ sc->len > KNOT_EDNS_COOKIE_SRVR_MAX_SIZE) {
+ return 0;
+ } else {
+ return cc->len + sc->len;
+ }
+}
+
+_public_
+int knot_edns_cookie_write(uint8_t *option, uint16_t option_len,
+ const knot_edns_cookie_t *cc,
+ const knot_edns_cookie_t *sc)
+{
+ if (option == NULL || cc == NULL || cc->len != KNOT_EDNS_COOKIE_CLNT_SIZE) {
+ return KNOT_EINVAL;
+ }
+
+ wire_ctx_t wire = wire_ctx_init(option, option_len);
+ wire_ctx_write(&wire, cc->data, cc->len);
+
+ if (sc != NULL && sc->len > 0) {
+ if (sc->len < KNOT_EDNS_COOKIE_SRVR_MIN_SIZE ||
+ sc->len > KNOT_EDNS_COOKIE_SRVR_MAX_SIZE) {
+ return KNOT_EINVAL;
+ }
+ wire_ctx_write(&wire, sc->data, sc->len);
+ }
+
+ return wire.error;
+}
+
+_public_
+int knot_edns_cookie_parse(knot_edns_cookie_t *cc, knot_edns_cookie_t *sc,
+ const uint8_t *option, uint16_t option_len)
+{
+ if (cc == NULL || sc == NULL || option == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ if (option_len != KNOT_EDNS_COOKIE_CLNT_SIZE &&
+ (option_len < KNOT_EDNS_COOKIE_CLNT_SIZE + KNOT_EDNS_COOKIE_SRVR_MIN_SIZE ||
+ option_len > KNOT_EDNS_COOKIE_CLNT_SIZE + KNOT_EDNS_COOKIE_SRVR_MAX_SIZE)) {
+ return KNOT_EMALF;
+ }
+ assert(option_len >= KNOT_EDNS_COOKIE_CLNT_SIZE);
+
+ memcpy(cc->data, option, KNOT_EDNS_COOKIE_CLNT_SIZE);
+ cc->len = KNOT_EDNS_COOKIE_CLNT_SIZE;
+
+ size_t sc_len = option_len - KNOT_EDNS_COOKIE_CLNT_SIZE;
+ if (sc_len == 0) {
+ sc->len = 0;
+ } else {
+ memcpy(sc->data, option + KNOT_EDNS_COOKIE_CLNT_SIZE, sc_len);
+ sc->len = sc_len;
+ }
+
+ return KNOT_EOK;
+}
diff --git a/src/libknot/rrtype/opt.h b/src/libknot/rrtype/opt.h
new file mode 100644
index 0000000..24d80f5
--- /dev/null
+++ b/src/libknot/rrtype/opt.h
@@ -0,0 +1,574 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief Functions for manipulating the EDNS OPT pseudo-RR.
+ *
+ * \addtogroup rrtype
+ * @{
+ */
+
+#pragma once
+
+#include <assert.h>
+#include <sys/socket.h>
+
+#include "libknot/consts.h"
+#include "libknot/rrset.h"
+#include "libknot/wire.h"
+
+/*! \brief Constants related to EDNS. */
+enum {
+ /*! \brief Supported EDNS version. */
+ KNOT_EDNS_VERSION = 0,
+
+ /*! \brief Bit mask for DO bit. */
+ KNOT_EDNS_DO_MASK = (uint32_t)(1 << 15),
+
+ /*! \brief Minimal UDP payload with EDNS enabled. */
+ KNOT_EDNS_MIN_UDP_PAYLOAD = 512,
+ /*! \brief Minimal payload when using DNSSEC (RFC4035/sec.3). */
+ KNOT_EDNS_MIN_DNSSEC_PAYLOAD = 1220,
+ /*! \brief Maximal UDP payload with EDNS enabled. */
+ KNOT_EDNS_MAX_UDP_PAYLOAD = 4096,
+
+ /*! \brief Minimum size of EDNS OPT RR in wire format. */
+ KNOT_EDNS_MIN_SIZE = 11,
+ /*! \brief Position of the Ext RCODE field in wire format of OPT RR. */
+ KNOT_EDNS_EXT_RCODE_POS = 5,
+ /*! \brief EDNS OPTION header size. */
+ KNOT_EDNS_OPTION_HDRLEN = 4,
+
+ /*! \brief Maximal size of EDNS client subnet address in bytes (IPv6). */
+ KNOT_EDNS_CLIENT_SUBNET_ADDRESS_MAXLEN = 16,
+
+ /*! \brief Default EDNS alignment size for a query. */
+ KNOT_EDNS_ALIGNMENT_QUERY_DEFALT = 128,
+ /*! \brief Default EDNS alignment size for a response. */
+ KNOT_EDNS_ALIGNMENT_RESPONSE_DEFAULT = 468,
+
+ /*! \brief EDNS client cookie size. */
+ KNOT_EDNS_COOKIE_CLNT_SIZE = 8,
+ /*! \brief EDNS minimum server cookie size. */
+ KNOT_EDNS_COOKIE_SRVR_MIN_SIZE = 8,
+ /*! \brief EDNS maximum server cookie size. */
+ KNOT_EDNS_COOKIE_SRVR_MAX_SIZE = 32,
+
+ /*! \brief NSID option code. */
+ KNOT_EDNS_OPTION_NSID = 3,
+ /*! \brief EDNS Client subnet option code. */
+ KNOT_EDNS_OPTION_CLIENT_SUBNET = 8,
+ /*! \brief EDNS DNS Cookie option code. */
+ KNOT_EDNS_OPTION_COOKIE = 10,
+ /*! \brief EDNS TCP Keepalive option code. */
+ KNOT_EDNS_OPTION_TCP_KEEPALIVE = 11,
+ /*! \brief EDNS Padding option code. */
+ KNOT_EDNS_OPTION_PADDING = 12,
+ /*! \brief EDNS Chain query option code. */
+ KNOT_EDNS_OPTION_CHAIN = 13,
+
+ /*! \brief Maximal currently relevant option code. */
+ KNOT_EDNS_MAX_OPTION_CODE = 14,
+};
+
+/* Helpers for splitting extended RCODE. */
+#define KNOT_EDNS_RCODE_HI(rc) ((rc >> 4) & 0x00ff)
+#define KNOT_EDNS_RCODE_LO(rc) (rc & 0x000f)
+
+/*!
+ * \brief Initialize OPT RR.
+ *
+ * \param opt_rr OPT RR to initialize.
+ * \param max_pld Max UDP payload.
+ * \param ext_rcode Extended RCODE.
+ * \param ver Version.
+ * \param mm Memory context.
+ *
+ * \return KNOT_EOK or an error
+ */
+int knot_edns_init(knot_rrset_t *opt_rr, uint16_t max_pld,
+ uint8_t ext_rcode, uint8_t ver, knot_mm_t *mm);
+
+/*!
+ * \brief Returns size of the OPT RR in wire format.
+ *
+ * \warning This function does not check the parameter, so ensure to check it
+ * before calling the function. It must not be NULL.
+ *
+ * \param opt_rr OPT RR to count the wire size of.
+ *
+ * \return Size of the OPT RR in bytes.
+ */
+static inline
+size_t knot_edns_wire_size(knot_rrset_t *opt_rr)
+{
+ assert(opt_rr != NULL);
+ return KNOT_EDNS_MIN_SIZE + opt_rr->rrs.rdata->len;
+}
+
+/*!
+ * \brief Returns the Max UDP payload value stored in the OPT RR.
+ *
+ * \warning This function does not check the parameter, so ensure to check it
+ * before calling the function. It must not be NULL.
+ *
+ * \param opt_rr OPT RR to get the value from.
+ *
+ * \return Max UDP payload in bytes.
+ */
+static inline
+uint16_t knot_edns_get_payload(const knot_rrset_t *opt_rr)
+{
+ assert(opt_rr != NULL);
+ return opt_rr->rclass;
+}
+
+/*!
+ * \brief Sets the Max UDP payload field in the OPT RR.
+ *
+ * \warning This function does not check the parameter, so ensure to check it
+ * before calling the function. It must not be NULL.
+ *
+ * \param opt_rr OPT RR to set the value to.
+ * \param payload UDP payload in bytes.
+ */
+static inline
+void knot_edns_set_payload(knot_rrset_t *opt_rr, uint16_t payload)
+{
+ assert(opt_rr != NULL);
+ opt_rr->rclass = payload;
+}
+
+/*!
+ * \brief Returns the Extended RCODE stored in the OPT RR.
+ *
+ * \warning This function does not check the parameter, so ensure to check it
+ * before calling the function. It must not be NULL.
+ * \note There is an assert() for debug checking of the parameter.
+ *
+ * \param opt_rr OPT RR to get the Extended RCODE from.
+ *
+ * \return Extended RCODE.
+ */
+uint8_t knot_edns_get_ext_rcode(const knot_rrset_t *opt_rr);
+
+/*!
+ * \brief Concatenates OPT RR Extended RCODE field and normal RCODE to get the
+ * whole Extended RCODE.
+ *
+ * Extended RCODE is created by using the Extended RCODE field from OPT RR as
+ * higher 8 bits and the RCODE from DNS Header as the lower 4 bits, resulting
+ * in a 12-bit unsigned integer. (See RFC 6891, Section 6.1.3).
+ *
+ * \param ext_rcode Extended RCODE field from OPT RR.
+ * \param rcode RCODE from DNS Header.
+ *
+ * \return 12-bit Extended RCODE.
+ */
+static inline
+uint16_t knot_edns_whole_rcode(uint8_t ext_rcode, uint8_t rcode)
+{
+ uint16_t high = ext_rcode;
+ return (high << 4) | rcode;
+}
+
+/*!
+ * \brief Sets the Extended RCODE field in the OPT RR.
+ *
+ * \warning This function does not check the parameter, so ensure to check it
+ * before calling the function. It must not be NULL.
+ * \note There is an assert() for debug checking of the parameter.
+ *
+ * \param opt_rr OPT RR to set the Extended RCODE to.
+ * \param ext_rcode Extended RCODE to set.
+ */
+void knot_edns_set_ext_rcode(knot_rrset_t *opt_rr, uint8_t ext_rcode);
+
+/*!
+ * \brief Sets the Extended RCODE field in OPT RR wire.
+ *
+ * \param opt_rr Position of the OPT RR in packet.
+ * \param ext_rcode Higher 8 bits of Extended RCODE.
+ */
+static inline
+void knot_edns_set_ext_rcode_wire(uint8_t *opt_rr, uint8_t ext_rcode)
+{
+ assert(opt_rr != NULL);
+ *(opt_rr + KNOT_EDNS_EXT_RCODE_POS) = ext_rcode;
+}
+
+/*!
+ * \brief Returns the EDNS version stored in the OPT RR.
+ *
+ * \warning This function does not check the parameter, so ensure to check it
+ * before calling the function. It must not be NULL.
+ * \note There is an assert() for debug checking of the parameter.
+ *
+ * \param opt_rr OPT RR to get the EDNS version from.
+ *
+ * \return EDNS version.
+ */
+uint8_t knot_edns_get_version(const knot_rrset_t *opt_rr);
+
+/*!
+ * \brief Sets the EDNS version field in the OPT RR.
+ *
+ * \warning This function does not check the parameter, so ensure to check it
+ * before calling the function. It must not be NULL.
+ * \note There is an assert() for debug checking of the parameter.
+ *
+ * \param opt_rr OPT RR to set the EDNS version to.
+ * \param version EDNS version to set.
+ */
+void knot_edns_set_version(knot_rrset_t *opt_rr, uint8_t version);
+
+/*!
+ * \brief Returns the state of the DO bit in the OPT RR flags.
+ *
+ * \warning This function does not check the parameter, so ensure to check it
+ * before calling the function. It must not be NULL.
+ *
+ * \param opt_rr OPT RR to get the DO bit from.
+ *
+ * \return true if the DO bit is set.
+ * \return false if the DO bit is not set.
+ */
+static inline
+bool knot_edns_do(const knot_rrset_t *opt_rr)
+{
+ assert(opt_rr != NULL);
+ return opt_rr->ttl & KNOT_EDNS_DO_MASK;
+}
+
+/*!
+ * \brief Sets the DO bit in the OPT RR.
+ *
+ * \warning This function does not check the parameter, so ensure to check it
+ * before calling the function. It must not be NULL.
+ *
+ * \param opt_rr OPT RR to set the DO bit in.
+ */
+static inline
+void knot_edns_set_do(knot_rrset_t *opt_rr)
+{
+ assert(opt_rr != NULL);
+ opt_rr->ttl |= KNOT_EDNS_DO_MASK;
+}
+
+/*!
+ * \brief Add EDNS option into the package with empty (zeroed) content.
+ *
+ * \param[in] opt_rr OPT RR structure to reserve the option in.
+ * \param[in] code Option code.
+ * \param[in] size Desired option size.
+ * \param[out] wire_ptr Pointer to reserved option data (can be NULL).
+ * \param[in] mm Memory context.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_edns_reserve_option(knot_rrset_t *opt_rr, uint16_t code,
+ uint16_t size, uint8_t **wire_ptr, knot_mm_t *mm);
+
+/*!
+ * \brief Adds EDNS Option to the OPT RR.
+ *
+ * \note The function now supports adding empty OPTION (just having its code).
+ *
+ * \param opt_rr OPT RR structure to add the Option to.
+ * \param code Option code.
+ * \param size Option data length in bytes.
+ * \param data Option data.
+ * \param mm Memory context.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_ENOMEM
+ */
+int knot_edns_add_option(knot_rrset_t *opt_rr, uint16_t code,
+ uint16_t size, const uint8_t *data, knot_mm_t *mm);
+
+/*!
+ * \brief Searches the OPT RR for option with the specified code.
+ *
+ * \param opt_rr OPT RR structure to search in.
+ * \param code Option code to search for.
+ *
+ * \retval pointer to option if found
+ * \retval NULL otherwise.
+ */
+uint8_t *knot_edns_get_option(const knot_rrset_t *opt_rr, uint16_t code);
+
+/*!
+ * \brief Pointers to every option in the OPT RR wire.
+ */
+typedef struct {
+ uint8_t *ptr[KNOT_EDNS_MAX_OPTION_CODE + 1];
+} knot_edns_options_t;
+
+/*!
+ * \brief Initializes pointers to options in a given OPT RR.
+ *
+ * \note If the OPT RR has no options, the output is NULL.
+ *
+ * \param opt_rr OPT RR structure to be used.
+ * \param out Structure to be initialized.
+ * \param mm Memory context.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_edns_get_options(knot_rrset_t *opt_rr, knot_edns_options_t **out,
+ knot_mm_t *mm);
+
+/*!
+ * \brief Returns the option code.
+ *
+ * \param opt EDNS option (including code, length and data portion).
+ *
+ * \return EDNS option code
+ */
+static inline uint16_t knot_edns_opt_get_code(const uint8_t *opt)
+{
+ assert(opt != NULL);
+ return knot_wire_read_u16(opt);
+}
+
+/*!
+ * \brief Returns the option data length.
+ *
+ * \param opt EDNS option (including code, length and data portion).
+ *
+ * \return EDNS option length
+ */
+static inline uint16_t knot_edns_opt_get_length(const uint8_t *opt)
+{
+ assert(opt != NULL);
+ return knot_wire_read_u16(opt + sizeof(uint16_t));
+}
+
+/*!
+ * \brief Returns pointer to option data.
+ *
+ * \warning No safety checks are performed on the supplied data.
+ *
+ * \param opt EDNS option (including code, length and data portion).
+ *
+ * \retval pointer to place where ENDS option data would reside
+ */
+static inline uint8_t *knot_edns_opt_get_data(uint8_t *opt)
+{
+ return opt + KNOT_EDNS_OPTION_HDRLEN;
+}
+
+/*!
+ * \brief Computes additional Padding data length for required packet alignment.
+ *
+ * \param current_pkt_size Current packet size.
+ * \param current_opt_size Current OPT rrset size (OPT must be used).
+ * \param block_size Required packet block length (must be non-zero).
+ *
+ * \return Required padding length or -1 if padding not required.
+ */
+int knot_edns_alignment_size(size_t current_pkt_size,
+ size_t current_opt_size,
+ size_t block_size);
+
+/*!
+ * \brief EDNS Client Subnet content.
+ *
+ * \see draft-ietf-dnsop-edns-client-subnet
+ */
+typedef struct {
+ /*! \brief FAMILY */
+ uint16_t family;
+ /*! \brief SOURCE PREFIX-LENGTH */
+ uint8_t source_len;
+ /*! \brief SCOPE PREFIX-LENGTH */
+ uint8_t scope_len;
+ /*! \brief ADDRESS */
+ uint8_t address[KNOT_EDNS_CLIENT_SUBNET_ADDRESS_MAXLEN];
+} knot_edns_client_subnet_t;
+
+/*!
+ * \brief Get the wire size of the EDNS Client Subnet option.
+ *
+ * \param ecs EDNS Client Subnet data.
+ *
+ * \return Size of the EDNS option data.
+ */
+uint16_t knot_edns_client_subnet_size(const knot_edns_client_subnet_t *ecs);
+
+/*!
+ * \brief Write EDNS Client Subnet data from the ECS structure to wire.
+ *
+ * \param option EDNS option data buffer.
+ * \param option_len EDNS option data buffer size.
+ * \param ecs EDNS Client Subnet data.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_edns_client_subnet_write(uint8_t *option, uint16_t option_len,
+ const knot_edns_client_subnet_t *ecs);
+
+/*!
+ * \brief Parse EDNS Client Subnet data from wire to the ECS structure.
+ *
+ * \param[out] ecs EDNS Client Subnet data.
+ * \param[in] option EDNS option data.
+ * \param[in] option_len EDNS option size.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_edns_client_subnet_parse(knot_edns_client_subnet_t *ecs,
+ const uint8_t *option, uint16_t option_len);
+
+/*!
+ * \brief Set address to the ECS structure.
+ *
+ * \note It also resets the lengths.
+ *
+ * \param ecs ECS structure to set address into.
+ * \param addr Address to be set.
+ *
+ * \return Error code. KNOT_EOK if successful.
+ */
+int knot_edns_client_subnet_set_addr(knot_edns_client_subnet_t *ecs,
+ const struct sockaddr_storage *addr);
+
+/*!
+ * \brief Get address from the ECS structure.
+ *
+ * Only the family and raw address is set in the structure. The bits not
+ * covered by the prefix length are cleared.
+ *
+ * \param addr Address to be set.
+ * \param ecs ECS structure to retrieve address from.
+ */
+int knot_edns_client_subnet_get_addr(struct sockaddr_storage *addr,
+ const knot_edns_client_subnet_t *ecs);
+
+/*!
+ * \brief Get size of the EDNS Keepalive option wire size.
+ *
+ * \param[in] timeout EDNS TCP Keepalive timeout.
+ *
+ * \return Size of the EDNS option data.
+ */
+uint16_t knot_edns_keepalive_size(uint16_t timeout);
+
+/*!
+ * \brief Writes EDNS TCP Keepalive wire data.
+ *
+ * \param[out] option EDNS option data buffer.
+ * \param[in] option_len EDNS option data buffer size.
+ * \param[in] timeout EDNS TCP Keepalive timeout.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_edns_keepalive_write(uint8_t *option, uint16_t option_len, uint16_t timeout);
+
+/*!
+ * \brief Parses EDNS TCP Keepalive wire data.
+ *
+ * \param[out] timeout EDNS TCP Keepalive timeout.
+ * \param[in] option EDNS option data.
+ * \param[in] option_len EDNS option size.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_edns_keepalive_parse(uint16_t *timeout, const uint8_t *option,
+ uint16_t option_len);
+
+/*!
+ * \brief Get size of the EDNS Chain option wire size.
+ *
+ * \param[in] point EDNS Chain closest trusted point.
+ *
+ * \return Size of the EDNS option data or 0 if invalid input.
+ */
+uint16_t knot_edns_chain_size(const knot_dname_t *point);
+
+/*!
+ * \brief Writes EDNS Chain wire data.
+ *
+ * \param[out] option EDNS option data buffer.
+ * \param[in] option_len EDNS option data buffer size.
+ * \param[in] point EDNS Chain closest trusted point.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_edns_chain_write(uint8_t *option, uint16_t option_len,
+ const knot_dname_t *point);
+
+/*!
+ * \brief Parses EDNS Chain wire data.
+ *
+ * \param[out] point EDNS Chain closest trusted point.
+ * \param[in] option EDNS option data.
+ * \param[in] option_len EDNS option size.
+ * \param[in] mm Memory context.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_edns_chain_parse(knot_dname_t **point, const uint8_t *option,
+ uint16_t option_len, knot_mm_t *mm);
+
+/*!
+ * \brief DNS Cookie content.
+ */
+typedef struct {
+ uint8_t data[KNOT_EDNS_COOKIE_SRVR_MAX_SIZE]; /*!< Cookie data. */
+ uint16_t len; /*!< Cookie length. */
+} knot_edns_cookie_t;
+
+/*!
+ * \brief Get size of the EDNS Cookie option wire size.
+ *
+ * \param[in] cc Client cookie.
+ * \param[in] sc Server cookie (can be NULL).
+ *
+ * \return Size of the EDNS option data or 0 if invalid input.
+ */
+uint16_t knot_edns_cookie_size(const knot_edns_cookie_t *cc,
+ const knot_edns_cookie_t *sc);
+
+/*!
+ * \brief Writes EDNS cookie wire data.
+ *
+ * \param[out] option EDNS option data buffer.
+ * \param[in] option_len EDNS option data buffer size.
+ * \param[in] cc EDNS client cookie.
+ * \param[in] sc EDNS server cookie (can be NULL).
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_edns_cookie_write(uint8_t *option, uint16_t option_len,
+ const knot_edns_cookie_t *cc,
+ const knot_edns_cookie_t *sc);
+
+/*!
+ * \brief Parses EDNS Cookie wire data.
+ *
+ * \param[out] cc EDNS client cookie.
+ * \param[out] sc EDNS server cookie.
+ * \param[in] option EDNS option data.
+ * \param[in] option_len EDNS option size.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_edns_cookie_parse(knot_edns_cookie_t *cc, knot_edns_cookie_t *sc,
+ const uint8_t *option, uint16_t option_len);
+
+/*! @} */
diff --git a/src/libknot/rrtype/rdname.h b/src/libknot/rrtype/rdname.h
new file mode 100644
index 0000000..4354a6b
--- /dev/null
+++ b/src/libknot/rrtype/rdname.h
@@ -0,0 +1,84 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \addtogroup rrtype
+ * @{
+ */
+
+#pragma once
+
+#include "libknot/descriptor.h"
+#include "libknot/dname.h"
+#include "libknot/rdata.h"
+
+static inline
+const knot_dname_t *knot_cname_name(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return rdata->data;
+}
+
+static inline
+const knot_dname_t *knot_dname_target(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return rdata->data;
+}
+
+static inline
+const knot_dname_t *knot_ns_name(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return rdata->data;
+}
+
+static inline
+const knot_dname_t *knot_mx_name(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return rdata->data + 2;
+}
+
+static inline
+const knot_dname_t *knot_srv_name(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return rdata->data + 6;
+}
+
+static inline
+const knot_dname_t *knot_rdata_name(const knot_rdata_t *rdata, uint16_t type)
+{
+ assert(rdata);
+ switch (type) {
+ case KNOT_RRTYPE_NS:
+ return knot_ns_name(rdata);
+ case KNOT_RRTYPE_MX:
+ return knot_mx_name(rdata);
+ case KNOT_RRTYPE_SRV:
+ return knot_srv_name(rdata);
+ case KNOT_RRTYPE_CNAME:
+ return knot_cname_name(rdata);
+ case KNOT_RRTYPE_DNAME:
+ return knot_dname_target(rdata);
+ }
+
+ return NULL;
+}
+
+/*! @} */
diff --git a/src/libknot/rrtype/rrsig.h b/src/libknot/rrtype/rrsig.h
new file mode 100644
index 0000000..3a4872f
--- /dev/null
+++ b/src/libknot/rrtype/rrsig.h
@@ -0,0 +1,99 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \addtogroup rrtype
+ * @{
+ */
+
+#pragma once
+
+#include "libknot/dname.h"
+#include "libknot/rdata.h"
+#include "libknot/wire.h"
+
+static inline
+uint16_t knot_rrsig_type_covered(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return knot_wire_read_u16(rdata->data);
+}
+
+static inline
+uint8_t knot_rrsig_alg(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return *(rdata->data + 2);
+}
+
+static inline
+uint8_t knot_rrsig_labels(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return *(rdata->data + 3);
+}
+
+static inline
+uint32_t knot_rrsig_original_ttl(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return knot_wire_read_u32(rdata->data + 4);
+}
+
+static inline
+uint32_t knot_rrsig_sig_expiration(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return knot_wire_read_u32(rdata->data + 8);
+}
+
+static inline
+uint32_t knot_rrsig_sig_inception(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return knot_wire_read_u32(rdata->data + 12);
+}
+
+static inline
+uint16_t knot_rrsig_key_tag(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return knot_wire_read_u16(rdata->data + 16);
+}
+
+static inline
+const knot_dname_t *knot_rrsig_signer_name(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return rdata->data + 18;
+}
+
+static inline
+uint16_t knot_rrsig_signature_len(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return rdata->len - 18 - knot_dname_size(knot_rrsig_signer_name(rdata));
+}
+
+static inline
+const uint8_t *knot_rrsig_signature(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return rdata->data + 18 + knot_dname_size(knot_rrsig_signer_name(rdata));
+}
+
+/*! @} */
diff --git a/src/libknot/rrtype/soa.h b/src/libknot/rrtype/soa.h
new file mode 100644
index 0000000..a7aebfc
--- /dev/null
+++ b/src/libknot/rrtype/soa.h
@@ -0,0 +1,93 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \addtogroup rrtype
+ * @{
+ */
+
+#pragma once
+
+#include "libknot/dname.h"
+#include "libknot/rdata.h"
+#include "libknot/wire.h"
+
+static inline
+const knot_dname_t *knot_soa_primary(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return rdata->data;
+}
+
+static inline
+const knot_dname_t *knot_soa_mailbox(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return rdata->data + knot_dname_size(knot_soa_primary(rdata));
+}
+
+static inline
+size_t knot_soa_names_len(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return knot_dname_size(knot_soa_primary(rdata)) +
+ knot_dname_size(knot_soa_mailbox(rdata));
+}
+
+static inline
+uint32_t knot_soa_serial(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return knot_wire_read_u32(rdata->data + knot_soa_names_len(rdata));
+}
+
+static inline
+void knot_soa_serial_set(knot_rdata_t *rdata, uint32_t serial)
+{
+ assert(rdata);
+ knot_wire_write_u32(rdata->data + knot_soa_names_len(rdata), serial);
+}
+
+static inline
+uint32_t knot_soa_refresh(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return knot_wire_read_u32(rdata->data + knot_soa_names_len(rdata) + 4);
+}
+
+static inline
+uint32_t knot_soa_retry(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return knot_wire_read_u32(rdata->data + knot_soa_names_len(rdata) + 8);
+}
+
+static inline
+uint32_t knot_soa_expire(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return knot_wire_read_u32(rdata->data + knot_soa_names_len(rdata) + 12);
+}
+
+static inline
+uint32_t knot_soa_minimum(const knot_rdata_t *rdata)
+{
+ assert(rdata);
+ return knot_wire_read_u32(rdata->data + knot_soa_names_len(rdata) + 16);
+}
+
+/*! @} */
diff --git a/src/libknot/rrtype/tsig.c b/src/libknot/rrtype/tsig.c
new file mode 100644
index 0000000..f4b9b71
--- /dev/null
+++ b/src/libknot/rrtype/tsig.c
@@ -0,0 +1,404 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <time.h>
+
+#include "libdnssec/tsig.h"
+#include "libknot/attribute.h"
+#include "libknot/rrtype/tsig.h"
+#include "libknot/consts.h"
+#include "libknot/dname.h"
+#include "libknot/errcode.h"
+#include "libknot/rrset.h"
+#include "libknot/wire.h"
+#include "contrib/wire_ctx.h"
+
+/*! \brief TSIG field offsets. */
+typedef enum tsig_off_t {
+ TSIG_ALGNAME_O = 0,
+ TSIG_TSIGNED_O,
+ TSIG_FUDGE_O,
+ TSIG_MACLEN_O,
+ TSIG_MAC_O,
+ TSIG_ORIGID_O,
+ TSIG_ERROR_O,
+ TSIG_OLEN_O,
+ TSIG_OTHER_O
+} tsig_off_t;
+
+/* Helpers for RDATA offset calculation. */
+#define TSIG_OFF_MACLEN (4 * sizeof(uint16_t))
+#define TSIG_FIXED_RDLEN (8 * sizeof(uint16_t))
+#define TSIG_OTHER_MAXLEN (3 * sizeof(uint16_t))
+
+/*!
+ * \brief Seek offset of a TSIG RR field.
+ *
+ * \param rr TSIG RR.
+ * \param id Field index.
+ * \param nb Required number of bytes after the offset (for boundaries check).
+ * \return pointer to field on wire or NULL.
+ */
+static uint8_t* rdata_seek(const knot_rrset_t *rr, tsig_off_t id, size_t nb)
+{
+ const knot_rdata_t *rr_data = knot_rdataset_at(&rr->rrs, 0);
+ if (!rr_data || rr_data->len == 0) {
+ return NULL;
+ }
+
+ wire_ctx_t wire = wire_ctx_init_const(rr_data->data, rr_data->len);
+
+ /* TSIG RR names should be already sanitized on parse. */
+ size_t alg_len = knot_dname_size(wire.wire);
+
+ /* Not pretty, but fast. */
+ switch (id) {
+ case TSIG_ALGNAME_O: break;
+ case TSIG_TSIGNED_O:
+ wire_ctx_skip(&wire, alg_len); break;
+ case TSIG_FUDGE_O:
+ wire_ctx_skip(&wire, alg_len + 3 * sizeof(uint16_t));
+ break;
+ case TSIG_MACLEN_O:
+ wire_ctx_skip(&wire, alg_len + 4 * sizeof(uint16_t));
+ break;
+ case TSIG_MAC_O:
+ wire_ctx_skip(&wire, alg_len + 5 * sizeof(uint16_t));
+ break;
+ case TSIG_ORIGID_O:
+ wire_ctx_skip(&wire, alg_len + 4 * sizeof(uint16_t));
+ wire_ctx_skip(&wire, wire_ctx_read_u16(&wire));
+ break;
+ case TSIG_ERROR_O:
+ wire_ctx_skip(&wire, alg_len + 4 * sizeof(uint16_t));
+ wire_ctx_skip(&wire, wire_ctx_read_u16(&wire));
+ wire_ctx_skip(&wire, sizeof(uint16_t));
+ break;
+ case TSIG_OLEN_O:
+ wire_ctx_skip(&wire, alg_len + 4 * sizeof(uint16_t));
+ wire_ctx_skip(&wire, wire_ctx_read_u16(&wire));
+ wire_ctx_skip(&wire, 2 * sizeof(uint16_t));
+ break;
+ case TSIG_OTHER_O:
+ wire_ctx_skip(&wire, alg_len + 4 * sizeof(uint16_t));
+ wire_ctx_skip(&wire, wire_ctx_read_u16(&wire));
+ wire_ctx_skip(&wire, 3 * sizeof(uint16_t));
+ break;
+ }
+
+ if (wire.error != KNOT_EOK) {
+ return NULL;
+ }
+
+ /* Check remaining bytes. */
+
+ if (wire_ctx_available(&wire) < nb){
+ return NULL;
+ }
+
+ return wire.position;
+}
+
+static int rdata_set_tsig_error(knot_rrset_t *tsig, uint16_t tsig_error)
+{
+ uint8_t *rd = rdata_seek(tsig, TSIG_ERROR_O, sizeof(uint16_t));
+ if (!rd) {
+ return KNOT_ERROR;
+ }
+
+ knot_wire_write_u16(rd, tsig_error);
+ return KNOT_EOK;
+}
+
+_public_
+int knot_tsig_create_rdata(knot_rrset_t *rr, const knot_dname_t *alg,
+ uint16_t maclen, uint16_t tsig_err)
+{
+ if (rr == NULL || alg == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ size_t alg_len = knot_dname_size(alg);
+ size_t rdlen = alg_len + TSIG_FIXED_RDLEN + maclen;
+ if (tsig_err == KNOT_RCODE_BADTIME) {
+ rdlen += TSIG_OTHER_MAXLEN;
+ }
+ uint8_t rd[rdlen];
+ memset(rd, 0, rdlen);
+
+ /* Copy alg name. */
+ knot_dname_to_wire(rd, alg, rdlen);
+
+ /* Set MAC variable length in advance. */
+ size_t offset = alg_len + TSIG_OFF_MACLEN;
+ knot_wire_write_u16(rd + offset, maclen);
+
+ int ret = knot_rrset_add_rdata(rr, rd, rdlen, NULL);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ /* Set error. */
+ rdata_set_tsig_error(rr, tsig_err);
+
+ return KNOT_EOK;
+}
+
+_public_
+int knot_tsig_rdata_set_time_signed(knot_rrset_t *tsig, uint64_t time)
+{
+ uint8_t *rd = rdata_seek(tsig, TSIG_TSIGNED_O, 3*sizeof(uint16_t));
+ if (!rd) {
+ return KNOT_ERROR;
+ }
+
+ knot_wire_write_u48(rd, time);
+ return KNOT_EOK;
+}
+
+_public_
+int knot_tsig_rdata_set_fudge(knot_rrset_t *tsig, uint16_t fudge)
+{
+ uint8_t *rd = rdata_seek(tsig, TSIG_FUDGE_O, sizeof(uint16_t));
+ if (!rd) {
+ return KNOT_ERROR;
+ }
+
+ knot_wire_write_u16(rd, fudge);
+ return KNOT_EOK;
+}
+
+_public_
+int knot_tsig_rdata_set_mac(knot_rrset_t *tsig, uint16_t length, const uint8_t *mac)
+{
+ uint8_t *rd = rdata_seek(tsig, TSIG_MAC_O, length);
+ if (!rd) {
+ return KNOT_ERROR;
+ }
+
+ /*! \note Cannot change length, as rdata is already preallocd. */
+
+ /* Copy the actual MAC. */
+ memcpy(rd, mac, length);
+ return KNOT_EOK;
+}
+
+_public_
+int knot_tsig_rdata_set_orig_id(knot_rrset_t *tsig, uint16_t id)
+{
+ uint8_t *rd = rdata_seek(tsig, TSIG_ORIGID_O, sizeof(uint16_t));
+ if (!rd) {
+ return KNOT_ERROR;
+ }
+
+ /* Write the length - 2. */
+ knot_wire_write_u16(rd, id);
+ return KNOT_EOK;
+}
+
+_public_
+int knot_tsig_rdata_set_other_data(knot_rrset_t *tsig, uint16_t len,
+ const uint8_t *other_data)
+{
+ if (len > TSIG_OTHER_MAXLEN) {
+ return KNOT_EINVAL;
+ }
+
+ uint8_t *rd = rdata_seek(tsig, TSIG_OLEN_O, len + sizeof(uint16_t));
+ if (!rd) {
+ return KNOT_ERROR;
+ }
+
+ /* Write the length. */
+ knot_wire_write_u16(rd, len);
+
+ /* Copy the actual data. */
+ memcpy(rd + sizeof(uint16_t), other_data, len);
+ return KNOT_EOK;
+}
+
+_public_
+const knot_dname_t *knot_tsig_rdata_alg_name(const knot_rrset_t *tsig)
+{
+ return knot_rdataset_at(&tsig->rrs, 0)->data;
+}
+
+_public_
+dnssec_tsig_algorithm_t knot_tsig_rdata_alg(const knot_rrset_t *tsig)
+{
+ /* Get the algorithm name. */
+ const knot_dname_t *alg_name = knot_tsig_rdata_alg_name(tsig);
+ if (!alg_name) {
+ return DNSSEC_TSIG_UNKNOWN;
+ }
+
+ return dnssec_tsig_algorithm_from_dname(alg_name);
+}
+
+_public_
+uint64_t knot_tsig_rdata_time_signed(const knot_rrset_t *tsig)
+{
+ /*! \todo How to return invalid value? */
+ uint8_t *rd = rdata_seek(tsig, TSIG_TSIGNED_O, 3*sizeof(uint16_t));
+ if (!rd) {
+ return 0;
+ }
+ return knot_wire_read_u48(rd);
+}
+
+_public_
+uint16_t knot_tsig_rdata_fudge(const knot_rrset_t *tsig)
+{
+ uint8_t *rd = rdata_seek(tsig, TSIG_FUDGE_O, sizeof(uint16_t));
+ if (!rd) {
+ return 0;
+ }
+ return knot_wire_read_u16(rd);
+}
+
+_public_
+const uint8_t *knot_tsig_rdata_mac(const knot_rrset_t *tsig)
+{
+ uint8_t *rd = rdata_seek(tsig, TSIG_MAC_O, 0);
+ if (!rd) {
+ return NULL;
+ }
+ return rd;
+}
+
+_public_
+size_t knot_tsig_rdata_mac_length(const knot_rrset_t *tsig)
+{
+ uint8_t *rd = rdata_seek(tsig, TSIG_MACLEN_O, sizeof(uint16_t));
+ if (!rd) {
+ return 0;
+ }
+ return knot_wire_read_u16(rd);
+}
+
+_public_
+uint16_t knot_tsig_rdata_orig_id(const knot_rrset_t *tsig)
+{
+ uint8_t *rd = rdata_seek(tsig, TSIG_ORIGID_O, sizeof(uint16_t));
+ if (!rd) {
+ return 0;
+ }
+ return knot_wire_read_u16(rd);
+}
+
+_public_
+uint16_t knot_tsig_rdata_error(const knot_rrset_t *tsig)
+{
+ uint8_t *rd = rdata_seek(tsig, TSIG_ERROR_O, sizeof(uint16_t));
+ if (!rd) {
+ return 0;
+ }
+ return knot_wire_read_u16(rd);
+}
+
+_public_
+const uint8_t *knot_tsig_rdata_other_data(const knot_rrset_t *tsig)
+{
+ uint8_t *rd = rdata_seek(tsig, TSIG_OTHER_O, 0);
+ if (!rd) {
+ return NULL;
+ }
+ return rd;
+}
+
+_public_
+uint16_t knot_tsig_rdata_other_data_length(const knot_rrset_t *tsig)
+{
+ uint8_t *rd = rdata_seek(tsig, TSIG_OLEN_O, sizeof(uint16_t));
+ if (!rd) {
+ return 0;
+ }
+ return knot_wire_read_u16(rd);
+}
+
+_public_
+size_t knot_tsig_rdata_tsig_variables_length(const knot_rrset_t *tsig)
+{
+ if (tsig == NULL) {
+ return 0;
+ }
+ /* Key name, Algorithm name and Other data have variable lengths. */
+ const knot_dname_t *key_name = tsig->owner;
+ if (!key_name) {
+ return 0;
+ }
+
+ const knot_dname_t *alg_name = knot_tsig_rdata_alg_name(tsig);
+ if (!alg_name) {
+ return 0;
+ }
+
+ uint16_t other_data_length = knot_tsig_rdata_other_data_length(tsig);
+
+ return knot_dname_size(key_name) + knot_dname_size(alg_name) +
+ other_data_length + KNOT_TSIG_VARIABLES_LENGTH;
+}
+
+_public_
+size_t knot_tsig_rdata_tsig_timers_length(void)
+{
+ /*! \todo Cleanup */
+ return KNOT_TSIG_TIMERS_LENGTH;
+}
+
+_public_
+size_t knot_tsig_wire_size(const knot_tsig_key_t *key)
+{
+ if (key == NULL || key->name == NULL) {
+ return 0;
+ }
+
+ return knot_dname_size(key->name) + TSIG_FIXED_RDLEN +
+ sizeof(uint16_t) + /* TYPE */
+ sizeof(uint16_t) + /* CLASS */
+ sizeof(uint32_t) + /* TTL */
+ sizeof(uint16_t) + /* RDATA length. */
+ knot_dname_size(dnssec_tsig_algorithm_to_dname(key->algorithm)) +
+ dnssec_tsig_algorithm_size(key->algorithm); /* MAC length. */
+}
+
+_public_
+size_t knot_tsig_wire_maxsize(const knot_tsig_key_t *key)
+{
+ size_t size = knot_tsig_wire_size(key);
+ if (size == 0) {
+ return 0;
+ }
+
+ /* In case of BADTIME other data. */
+ return size + TSIG_OTHER_MAXLEN;
+}
+
+_public_
+bool knot_tsig_rdata_is_ok(const knot_rrset_t *tsig)
+{
+ /*! \todo Check size, needs to check variable-length fields. */
+ return (tsig != NULL
+ && knot_rdataset_at(&tsig->rrs, 0) != NULL
+ && rdata_seek(tsig, TSIG_OTHER_O, 0) != NULL
+ && knot_tsig_rdata_alg_name(tsig) != NULL
+ && knot_tsig_rdata_time_signed(tsig) != 0);
+}
diff --git a/src/libknot/rrtype/tsig.h b/src/libknot/rrtype/tsig.h
new file mode 100644
index 0000000..2dd3696
--- /dev/null
+++ b/src/libknot/rrtype/tsig.h
@@ -0,0 +1,121 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief TSIG manipulation.
+ *
+ * \addtogroup rrtype
+ * @{
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#include "libdnssec/binary.h"
+#include "libdnssec/tsig.h"
+#include "libknot/consts.h"
+#include "libknot/rrset.h"
+#include "libknot/tsig.h"
+
+enum tsig_consts {
+ KNOT_TSIG_ITEM_COUNT = 7,
+ KNOT_TSIG_VARIABLES_LENGTH = sizeof(uint16_t) // class
+ + sizeof(uint32_t) // ttl
+ + 6 // time signed
+ + sizeof(uint16_t) // fudge
+ + sizeof(uint16_t) // error
+ + sizeof(uint16_t),// other data length
+ KNOT_TSIG_TIMERS_LENGTH = sizeof(uint16_t) //fugde
+ + 6 // time signed
+};
+
+/*!
+ * \brief Create TSIG RDATA.
+ *
+ * \param rr TSIG RR to contain created data.
+ * \param alg Algorithm name.
+ * \param maclen Algorithm MAC len (may be set to 0 for empty MAC).
+ * \param tsig_err TSIG error code.
+ *
+ * \retval KNOT_EINVAL
+ * \retval KNOT_EOK
+ */
+int knot_tsig_create_rdata(knot_rrset_t *rr, const knot_dname_t *alg,
+ uint16_t maclen, uint16_t tsig_err);
+
+int knot_tsig_rdata_set_time_signed(knot_rrset_t *tsig, uint64_t time);
+
+int knot_tsig_rdata_store_current_time(knot_rrset_t *tsig);
+
+int knot_tsig_rdata_set_fudge(knot_rrset_t *tsig, uint16_t fudge);
+
+int knot_tsig_rdata_set_mac(knot_rrset_t *tsig, uint16_t length, const uint8_t *mac);
+
+int knot_tsig_rdata_set_orig_id(knot_rrset_t *tsig, uint16_t id);
+
+int knot_tsig_rdata_set_other_data(knot_rrset_t *tsig, uint16_t length,
+ const uint8_t *other_data);
+
+const knot_dname_t *knot_tsig_rdata_alg_name(const knot_rrset_t *tsig);
+
+dnssec_tsig_algorithm_t knot_tsig_rdata_alg(const knot_rrset_t *tsig);
+
+uint64_t knot_tsig_rdata_time_signed(const knot_rrset_t *tsig);
+
+uint16_t knot_tsig_rdata_fudge(const knot_rrset_t *tsig);
+
+const uint8_t *knot_tsig_rdata_mac(const knot_rrset_t *tsig);
+
+size_t knot_tsig_rdata_mac_length(const knot_rrset_t *tsig);
+
+uint16_t knot_tsig_rdata_orig_id(const knot_rrset_t *tsig);
+
+uint16_t knot_tsig_rdata_error(const knot_rrset_t *tsig);
+
+const uint8_t *knot_tsig_rdata_other_data(const knot_rrset_t *tsig);
+
+uint16_t knot_tsig_rdata_other_data_length(const knot_rrset_t *tsig);
+
+size_t knot_tsig_rdata_tsig_variables_length(const knot_rrset_t *tsig);
+
+size_t knot_tsig_rdata_tsig_timers_length(void);
+
+/*!
+ * \brief Return standard TSIG RRSET wire size for given algorithm.
+ *
+ * \param key Signing key descriptor.
+ *
+ * \return RRSET wire size.
+ */
+size_t knot_tsig_wire_size(const knot_tsig_key_t *key);
+
+/*!
+ * \brief Return TSIG RRSET maximum wire size for given algorithm.
+ *
+ * This size is reached if error reply with BADTIME.
+ *
+ * \param key Signing key descriptor.
+ *
+ * \return RRSET wire size.
+ */
+size_t knot_tsig_wire_maxsize(const knot_tsig_key_t *key);
+
+/*! \todo Documentation. */
+bool knot_tsig_rdata_is_ok(const knot_rrset_t *tsig);
+
+/*! @} */
diff --git a/src/libknot/tsig-op.c b/src/libknot/tsig-op.c
new file mode 100644
index 0000000..acbcafb
--- /dev/null
+++ b/src/libknot/tsig-op.c
@@ -0,0 +1,683 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <time.h>
+#include <stdint.h>
+
+#include "libdnssec/error.h"
+#include "libdnssec/tsig.h"
+#include "libknot/attribute.h"
+#include "libknot/tsig-op.h"
+#include "libknot/errcode.h"
+#include "libknot/descriptor.h"
+#include "libknot/rrtype/tsig.h"
+#include "libknot/packet/wire.h"
+#include "libknot/consts.h"
+#include "libknot/packet/rrset-wire.h"
+#include "libknot/wire.h"
+#include "contrib/string.h"
+
+const int KNOT_TSIG_MAX_DIGEST_SIZE = 64; // size of HMAC-SHA512 digest
+const uint16_t KNOT_TSIG_FUDGE_DEFAULT = 300; // default Fudge value
+
+static int check_algorithm(const knot_rrset_t *tsig_rr)
+{
+ if (tsig_rr == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ const knot_dname_t *alg_name = knot_tsig_rdata_alg_name(tsig_rr);
+ if (!alg_name) {
+ return KNOT_EMALF;
+ }
+
+ dnssec_tsig_algorithm_t alg = dnssec_tsig_algorithm_from_dname(alg_name);
+ if (alg == DNSSEC_TSIG_UNKNOWN) {
+ return KNOT_TSIG_EBADKEY;
+ }
+
+ return KNOT_EOK;
+}
+
+static int check_key(const knot_rrset_t *tsig_rr, const knot_tsig_key_t *tsig_key)
+{
+ if (tsig_rr == NULL || tsig_key == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ const knot_dname_t *tsig_name = tsig_rr->owner;
+ if (!tsig_name) {
+ return KNOT_EMALF;
+ }
+
+ if (!knot_dname_is_equal(tsig_name, tsig_key->name)) {
+ return KNOT_TSIG_EBADKEY;
+ }
+
+ return KNOT_EOK;
+}
+
+static int compute_digest(const uint8_t *wire, size_t wire_len,
+ uint8_t *digest, size_t *digest_len,
+ const knot_tsig_key_t *key)
+{
+ if (!wire || !digest || !digest_len || !key) {
+ return KNOT_EINVAL;
+ }
+
+ if (!key->name) {
+ return KNOT_EMALF;
+ }
+
+ dnssec_tsig_ctx_t *ctx = NULL;
+ int result = dnssec_tsig_new(&ctx, key->algorithm, &key->secret);
+ if (result != DNSSEC_EOK) {
+ return KNOT_TSIG_EBADSIG;
+ }
+
+ dnssec_binary_t cover = { .data = (uint8_t *)wire, .size = wire_len };
+ dnssec_tsig_add(ctx, &cover);
+
+ *digest_len = dnssec_tsig_size(ctx);
+ dnssec_tsig_write(ctx, digest);
+ dnssec_tsig_free(ctx);
+
+ return KNOT_EOK;
+}
+
+static int check_time_signed(const knot_rrset_t *tsig_rr, uint64_t prev_time_signed)
+{
+ if (!tsig_rr) {
+ return KNOT_EINVAL;
+ }
+
+ /* Get the time signed and fudge values. */
+ uint64_t time_signed = knot_tsig_rdata_time_signed(tsig_rr);
+ if (time_signed == 0) {
+ return KNOT_TSIG_EBADTIME;
+ }
+ uint16_t fudge = knot_tsig_rdata_fudge(tsig_rr);
+ if (fudge == 0) {
+ return KNOT_TSIG_EBADTIME;
+ }
+
+ /* Get the current time. */
+ time_t curr_time = time(NULL);
+
+ /*!< \todo bleeding eyes. */
+ double diff = difftime(curr_time, (time_t)time_signed);
+
+ if (diff > fudge || diff < -fudge) {
+ return KNOT_TSIG_EBADTIME;
+ }
+
+ diff = difftime((time_t)time_signed, prev_time_signed);
+
+ if (diff < 0) {
+ return KNOT_TSIG_EBADTIME;
+ }
+
+ return KNOT_EOK;
+}
+
+static int write_tsig_variables(uint8_t *wire, const knot_rrset_t *tsig_rr)
+{
+ if (wire == NULL || tsig_rr == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ /* Copy TSIG variables - starting with key name. */
+ const knot_dname_t *tsig_owner = tsig_rr->owner;
+ if (!tsig_owner) {
+ return KNOT_EINVAL;
+ }
+
+ int offset = 0;
+
+ offset += knot_dname_to_wire(wire + offset, tsig_owner, KNOT_DNAME_MAXLEN);
+
+ /*!< \todo which order? */
+
+ /* Copy class. */
+ knot_wire_write_u16(wire + offset, tsig_rr->rclass);
+ offset += sizeof(uint16_t);
+
+ /* Copy TTL - always 0. */
+ knot_wire_write_u32(wire + offset, tsig_rr->ttl);
+ offset += sizeof(uint32_t);
+
+ /* Copy alg name. */
+ const knot_dname_t *alg_name = knot_tsig_rdata_alg_name(tsig_rr);
+ if (!alg_name) {
+ return KNOT_EINVAL;
+ }
+
+ /* Te algorithm name must be in canonical form, i.e. in lowercase. */
+ uint8_t *alg_name_wire = wire + offset;
+ offset += knot_dname_to_wire(alg_name_wire, alg_name, KNOT_DNAME_MAXLEN);
+ knot_dname_to_lower(alg_name_wire);
+
+ /* Following data are written in network order. */
+ /* Time signed. */
+ knot_wire_write_u48(wire + offset, knot_tsig_rdata_time_signed(tsig_rr));
+ offset += 6;
+ /* Fudge. */
+ knot_wire_write_u16(wire + offset, knot_tsig_rdata_fudge(tsig_rr));
+ offset += sizeof(uint16_t);
+ /* TSIG error. */
+ knot_wire_write_u16(wire + offset, knot_tsig_rdata_error(tsig_rr));
+ offset += sizeof(uint16_t);
+ /* Get other data length. */
+ uint16_t other_data_length = knot_tsig_rdata_other_data_length(tsig_rr);
+ /* Get other data. */
+ const uint8_t *other_data = knot_tsig_rdata_other_data(tsig_rr);
+ if (!other_data) {
+ return KNOT_EINVAL;
+ }
+
+ /*
+ * We cannot write the whole other_data, as it contains its length in
+ * machine order.
+ */
+ knot_wire_write_u16(wire + offset, other_data_length);
+ offset += sizeof(uint16_t);
+
+ /* Skip the length. */
+ memcpy(wire + offset, other_data, other_data_length);
+
+ return KNOT_EOK;
+}
+
+static int wire_write_timers(uint8_t *wire, const knot_rrset_t *tsig_rr)
+{
+ if (wire == NULL || tsig_rr == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ //write time signed
+ knot_wire_write_u48(wire, knot_tsig_rdata_time_signed(tsig_rr));
+ //write fudge
+ knot_wire_write_u16(wire + 6, knot_tsig_rdata_fudge(tsig_rr));
+
+ return KNOT_EOK;
+}
+
+static int create_sign_wire(const uint8_t *msg, size_t msg_len,
+ const uint8_t *request_mac, size_t request_mac_len,
+ uint8_t *digest, size_t *digest_len,
+ const knot_rrset_t *tmp_tsig,
+ const knot_tsig_key_t *key)
+{
+ if (!msg || !key || digest_len == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ /* Create tmp TSIG. */
+ int ret = KNOT_EOK;
+
+ /*
+ * Create tmp wire, it should contain message
+ * plus request mac plus tsig varibles.
+ */
+ size_t wire_len = msg_len + request_mac_len + (request_mac_len > 0 ? 2 : 0) +
+ knot_tsig_rdata_tsig_variables_length(tmp_tsig);
+ uint8_t *wire = malloc(wire_len);
+ if (!wire) {
+ return KNOT_ENOMEM;
+ }
+
+ memset(wire, 0, wire_len);
+
+ uint8_t *pos = wire;
+
+ /* Copy the request MAC - should work even if NULL. */
+ if (request_mac_len > 0) {
+ knot_wire_write_u16(pos, request_mac_len);
+ pos += 2;
+ memcpy(pos, request_mac, request_mac_len);
+ }
+ pos += request_mac_len;
+ /* Copy the original message. */
+ memcpy(pos, msg, msg_len);
+ pos += msg_len;
+ /* Copy TSIG variables. */
+ ret = write_tsig_variables(pos, tmp_tsig);
+ if (ret != KNOT_EOK) {
+ free(wire);
+ return ret;
+ }
+
+ /* Compute digest. */
+ ret = compute_digest(wire, wire_len, digest, digest_len, key);
+ if (ret != KNOT_EOK) {
+ *digest_len = 0;
+ free(wire);
+ return ret;
+ }
+
+ free(wire);
+
+ return KNOT_EOK;
+}
+
+static int create_sign_wire_next(const uint8_t *msg, size_t msg_len,
+ const uint8_t *prev_mac, size_t prev_mac_len,
+ uint8_t *digest, size_t *digest_len,
+ const knot_rrset_t *tmp_tsig,
+ const knot_tsig_key_t *key)
+{
+ if (!msg || !key || digest_len == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ /* Create tmp TSIG. */
+ int ret = KNOT_EOK;
+
+ /*
+ * Create tmp wire, it should contain message
+ * plus request mac plus tsig varibles.
+ */
+ size_t wire_len = msg_len + prev_mac_len + knot_tsig_rdata_tsig_timers_length() + 2;
+ uint8_t *wire = malloc(wire_len);
+ if (!wire) {
+ return KNOT_ENOMEM;
+ }
+
+ memset(wire, 0, wire_len);
+
+ /* Copy the request MAC - should work even if NULL. */
+ knot_wire_write_u16(wire, prev_mac_len);
+ memcpy(wire + 2, prev_mac, prev_mac_len);
+ /* Copy the original message. */
+ memcpy(wire + prev_mac_len + 2, msg, msg_len);
+ /* Copy TSIG variables. */
+
+ ret = wire_write_timers(wire + prev_mac_len + msg_len + 2, tmp_tsig);
+ if (ret != KNOT_EOK) {
+ free(wire);
+ return ret;
+ }
+
+ /* Compute digest. */
+ ret = compute_digest(wire, wire_len, digest, digest_len, key);
+ if (ret != KNOT_EOK) {
+ *digest_len = 0;
+ free(wire);
+ return ret;
+ }
+
+ free(wire);
+
+ return KNOT_EOK;
+}
+
+_public_
+int knot_tsig_sign(uint8_t *msg, size_t *msg_len, size_t msg_max_len,
+ const uint8_t *request_mac, size_t request_mac_len,
+ uint8_t *digest, size_t *digest_len,
+ const knot_tsig_key_t *key, uint16_t tsig_rcode,
+ uint64_t request_time_signed)
+{
+ if (!msg || !msg_len || !key || digest == NULL || digest_len == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ knot_rrset_t *tmp_tsig = knot_rrset_new(key->name, KNOT_RRTYPE_TSIG,
+ KNOT_CLASS_ANY, 0, NULL);
+ if (!tmp_tsig) {
+ return KNOT_ENOMEM;
+ }
+
+ /* Create rdata for TSIG RR. */
+ uint16_t rdata_rcode = KNOT_RCODE_NOERROR;
+ if (tsig_rcode == KNOT_RCODE_BADTIME) {
+ rdata_rcode = tsig_rcode;
+ }
+
+ const uint8_t *alg_name = dnssec_tsig_algorithm_to_dname(key->algorithm);
+ size_t alg_size = dnssec_tsig_algorithm_size(key->algorithm);
+ knot_tsig_create_rdata(tmp_tsig, alg_name, alg_size, rdata_rcode);
+
+ /* Distinguish BADTIME response. */
+ if (tsig_rcode == KNOT_RCODE_BADTIME) {
+ /* Set client's time signed into the time signed field. */
+ knot_tsig_rdata_set_time_signed(tmp_tsig, request_time_signed);
+
+ /* Store current time into Other data. */
+ uint8_t time_signed[6];
+ time_t now = time(NULL);
+ knot_wire_write_u48(time_signed, now);
+
+ knot_tsig_rdata_set_other_data(tmp_tsig, 6, time_signed);
+ } else {
+ knot_tsig_rdata_set_time_signed(tmp_tsig, time(NULL));
+
+ /* Set other len. */
+ knot_tsig_rdata_set_other_data(tmp_tsig, 0, 0);
+ }
+
+ knot_tsig_rdata_set_fudge(tmp_tsig, KNOT_TSIG_FUDGE_DEFAULT);
+
+ /* Set original ID */
+ knot_tsig_rdata_set_orig_id(tmp_tsig, knot_wire_get_id(msg));
+
+ uint8_t digest_tmp[KNOT_TSIG_MAX_DIGEST_SIZE];
+ size_t digest_tmp_len = 0;
+
+ int ret = create_sign_wire(msg, *msg_len, /*msg_max_len,*/
+ request_mac, request_mac_len,
+ digest_tmp, &digest_tmp_len, tmp_tsig, key);
+ if (ret != KNOT_EOK) {
+ knot_rrset_free(tmp_tsig, NULL);
+ return ret;
+ }
+
+ /* Set the digest. */
+ knot_tsig_rdata_set_mac(tmp_tsig, digest_tmp_len, digest_tmp);
+
+ /* Write RRSet to wire */
+ ret = knot_rrset_to_wire(tmp_tsig, msg + *msg_len,
+ msg_max_len - *msg_len, NULL);
+ if (ret < 0) {
+ *digest_len = 0;
+ knot_rrset_free(tmp_tsig, NULL);
+ return ret;
+ }
+
+ size_t tsig_wire_len = ret;
+
+ knot_rrset_free(tmp_tsig, NULL);
+
+ *msg_len += tsig_wire_len;
+
+ uint16_t arcount = knot_wire_get_arcount(msg);
+ knot_wire_set_arcount(msg, ++arcount);
+
+ /* everything went ok, save the digest to the output parameter */
+ memcpy(digest, digest_tmp, digest_tmp_len);
+ *digest_len = digest_tmp_len;
+
+ return KNOT_EOK;
+}
+
+_public_
+int knot_tsig_sign_next(uint8_t *msg, size_t *msg_len, size_t msg_max_len,
+ const uint8_t *prev_digest, size_t prev_digest_len,
+ uint8_t *digest, size_t *digest_len,
+ const knot_tsig_key_t *key, uint8_t *to_sign,
+ size_t to_sign_len)
+{
+ if (!msg || !msg_len || !key || !digest || !digest_len) {
+ return KNOT_EINVAL;
+ }
+
+ uint8_t digest_tmp[KNOT_TSIG_MAX_DIGEST_SIZE];
+ size_t digest_tmp_len = 0;
+ knot_rrset_t *tmp_tsig = knot_rrset_new(key->name, KNOT_RRTYPE_TSIG,
+ KNOT_CLASS_ANY, 0, NULL);
+ if (!tmp_tsig) {
+ return KNOT_ENOMEM;
+ }
+
+ /* Create rdata for TSIG RR. */
+ const uint8_t *alg_name = dnssec_tsig_algorithm_to_dname(key->algorithm);
+ size_t alg_size = dnssec_tsig_algorithm_size(key->algorithm);
+ knot_tsig_create_rdata(tmp_tsig, alg_name, alg_size, 0);
+ knot_tsig_rdata_set_time_signed(tmp_tsig, time(NULL));
+ knot_tsig_rdata_set_fudge(tmp_tsig, KNOT_TSIG_FUDGE_DEFAULT);
+
+ /* Create wire to be signed. */
+ size_t wire_len = prev_digest_len + to_sign_len + KNOT_TSIG_TIMERS_LENGTH + 2;
+ uint8_t *wire = malloc(wire_len);
+ if (!wire) {
+ knot_rrset_free(tmp_tsig, NULL);
+ return KNOT_ENOMEM;
+ }
+ memset(wire, 0, wire_len);
+
+ /* Write previous digest length. */
+ knot_wire_write_u16(wire, prev_digest_len);
+ /* Write previous digest. */
+ memcpy(wire + 2, prev_digest, prev_digest_len);
+ /* Write original message. */
+ memcpy(wire + prev_digest_len + 2, to_sign, to_sign_len);
+ /* Write timers. */
+ wire_write_timers(wire + prev_digest_len + to_sign_len + 2, tmp_tsig);
+
+ int ret = compute_digest(wire, wire_len, digest_tmp, &digest_tmp_len, key);
+ free(wire);
+ if (ret != KNOT_EOK) {
+ knot_rrset_free(tmp_tsig, NULL);
+ *digest_len = 0;
+ return ret;
+ }
+
+ if (digest_tmp_len > *digest_len) {
+ knot_rrset_free(tmp_tsig, NULL);
+ *digest_len = 0;
+ return KNOT_ESPACE;
+ }
+
+ /* Set the MAC. */
+ knot_tsig_rdata_set_mac(tmp_tsig, digest_tmp_len, digest_tmp);
+
+ /* Set original id. */
+ knot_tsig_rdata_set_orig_id(tmp_tsig, knot_wire_get_id(msg));
+
+ /* Set other data. */
+ knot_tsig_rdata_set_other_data(tmp_tsig, 0, NULL);
+
+ ret = knot_rrset_to_wire(tmp_tsig, msg + *msg_len,
+ msg_max_len - *msg_len, NULL);
+ if (ret < 0) {
+ knot_rrset_free(tmp_tsig, NULL);
+ *digest_len = 0;
+ return ret;
+ }
+
+ size_t tsig_wire_size = ret;
+
+ knot_rrset_free(tmp_tsig, NULL);
+
+ *msg_len += tsig_wire_size;
+ uint16_t arcount = knot_wire_get_arcount(msg);
+ knot_wire_set_arcount(msg, ++arcount);
+
+ memcpy(digest, digest_tmp, digest_tmp_len);
+ *digest_len = digest_tmp_len;
+
+ return KNOT_EOK;
+}
+
+static int check_digest(const knot_rrset_t *tsig_rr,
+ const uint8_t *wire, size_t size,
+ const uint8_t *request_mac, size_t request_mac_len,
+ const knot_tsig_key_t *tsig_key,
+ uint64_t prev_time_signed, int use_times)
+{
+ if (!wire || !tsig_key) {
+ return KNOT_EINVAL;
+ }
+
+ /* No TSIG record means verification failure. */
+ if (tsig_rr == NULL) {
+ return KNOT_TSIG_EBADKEY;
+ }
+
+ /* Check that libknot knows the algorithm. */
+ int ret = check_algorithm(tsig_rr);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ /* Check that key is valid, ie. the same as given in args. */
+ ret = check_key(tsig_rr, tsig_key);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ uint8_t *wire_to_sign = malloc(size);
+ if (!wire_to_sign) {
+ return KNOT_ENOMEM;
+ }
+
+ memcpy(wire_to_sign, wire, size);
+
+ // restore message ID to which the signature had been created with
+ knot_wire_set_id(wire_to_sign, knot_tsig_rdata_orig_id(tsig_rr));
+
+ uint8_t digest_tmp[KNOT_TSIG_MAX_DIGEST_SIZE];
+ size_t digest_tmp_len = 0;
+ assert(tsig_rr->rrs.count > 0);
+
+ if (use_times) {
+ /* Wire is not a single packet, TSIG RRs must be stripped already. */
+ ret = create_sign_wire_next(wire_to_sign, size,
+ request_mac, request_mac_len,
+ digest_tmp, &digest_tmp_len,
+ tsig_rr, tsig_key);
+ } else {
+ ret = create_sign_wire(wire_to_sign, size,
+ request_mac, request_mac_len,
+ digest_tmp, &digest_tmp_len,
+ tsig_rr, tsig_key);
+ }
+
+ assert(tsig_rr->rrs.count > 0);
+ free(wire_to_sign);
+
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ /* Compare MAC from TSIG RR RDATA with just computed digest. */
+
+ /*!< \todo move to function. */
+ const knot_dname_t *alg_name = knot_tsig_rdata_alg_name(tsig_rr);
+ dnssec_tsig_algorithm_t alg = dnssec_tsig_algorithm_from_dname(alg_name);
+
+ /*! \todo [TSIG] TRUNCATION */
+ uint16_t mac_length = knot_tsig_rdata_mac_length(tsig_rr);
+ const uint8_t *tsig_mac = knot_tsig_rdata_mac(tsig_rr);
+
+ if (mac_length != dnssec_tsig_algorithm_size(alg)) {
+ return KNOT_TSIG_EBADSIG;
+ }
+
+ if (const_time_memcmp(tsig_mac, digest_tmp, mac_length) != 0) {
+ return KNOT_TSIG_EBADSIG;
+ }
+
+ /* Check TSIG validity period, must be after the signature check! */
+ ret = check_time_signed(tsig_rr, prev_time_signed);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ return KNOT_EOK;
+}
+
+_public_
+int knot_tsig_server_check(const knot_rrset_t *tsig_rr,
+ const uint8_t *wire, size_t size,
+ const knot_tsig_key_t *tsig_key)
+{
+ return check_digest(tsig_rr, wire, size, NULL, 0, tsig_key, 0, 0);
+}
+
+_public_
+int knot_tsig_client_check(const knot_rrset_t *tsig_rr,
+ const uint8_t *wire, size_t size,
+ const uint8_t *request_mac, size_t request_mac_len,
+ const knot_tsig_key_t *tsig_key,
+ uint64_t prev_time_signed)
+{
+ return check_digest(tsig_rr, wire, size, request_mac, request_mac_len,
+ tsig_key, prev_time_signed, 0);
+}
+
+_public_
+int knot_tsig_client_check_next(const knot_rrset_t *tsig_rr,
+ const uint8_t *wire, size_t size,
+ const uint8_t *prev_digest,
+ size_t prev_digest_len,
+ const knot_tsig_key_t *tsig_key,
+ uint64_t prev_time_signed)
+{
+ return check_digest(tsig_rr, wire, size, prev_digest,
+ prev_digest_len, tsig_key, prev_time_signed, 1);
+}
+
+_public_
+int knot_tsig_add(uint8_t *msg, size_t *msg_len, size_t msg_max_len,
+ uint16_t tsig_rcode, const knot_rrset_t *tsig_rr)
+{
+ /*! \todo Revise!! */
+
+ if (!msg || !msg_len || !tsig_rr) {
+ return KNOT_EINVAL;
+ }
+
+ /*! \todo What key to use, when we do not sign? Does this even work? */
+ knot_rrset_t *tmp_tsig = knot_rrset_new(tsig_rr->owner, KNOT_RRTYPE_TSIG,
+ KNOT_CLASS_ANY, 0, NULL);
+ if (!tmp_tsig) {
+ return KNOT_ENOMEM;
+ }
+
+ assert(tsig_rcode != KNOT_RCODE_BADTIME);
+ knot_tsig_create_rdata(tmp_tsig, knot_tsig_rdata_alg_name(tsig_rr), 0, tsig_rcode);
+ knot_tsig_rdata_set_time_signed(tmp_tsig, knot_tsig_rdata_time_signed(tsig_rr));
+
+ /* Comparing to BIND it was found out that the Fudge should always be
+ * set to the server's value.
+ */
+ knot_tsig_rdata_set_fudge(tmp_tsig, KNOT_TSIG_FUDGE_DEFAULT);
+
+ /* Set original ID */
+ knot_tsig_rdata_set_orig_id(tmp_tsig, knot_wire_get_id(msg));
+
+ /* Set other len. */
+ knot_tsig_rdata_set_other_data(tmp_tsig, 0, 0);
+
+ /* Append TSIG RR. */
+ int ret = knot_tsig_append(msg, msg_len, msg_max_len, tmp_tsig);
+
+ /* key_name already referenced in RRSet, no need to free separately. */
+ knot_rrset_free(tmp_tsig, NULL);
+
+ return ret;
+}
+
+_public_
+int knot_tsig_append(uint8_t *msg, size_t *msg_len, size_t msg_max_len,
+ const knot_rrset_t *tsig_rr)
+{
+ /* Write RRSet to wire */
+ int ret = knot_rrset_to_wire(tsig_rr, msg + *msg_len,
+ msg_max_len - *msg_len, NULL);
+ if (ret < 0) {
+ return ret;
+ }
+
+ *msg_len += ret;
+
+ knot_wire_set_arcount(msg, knot_wire_get_arcount(msg) + 1);
+
+ return KNOT_EOK;
+}
diff --git a/src/libknot/tsig-op.h b/src/libknot/tsig-op.h
new file mode 100644
index 0000000..b3e091d
--- /dev/null
+++ b/src/libknot/tsig-op.h
@@ -0,0 +1,186 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief TSIG signing and validating.
+ *
+ * \addtogroup knot-tsig
+ * @{
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#include "libknot/rrtype/tsig.h"
+#include "libknot/rrset.h"
+
+/*!
+ * \brief Generate TSIG signature of a message.
+ *
+ * This function generates TSIG digest of the given message prepended with the
+ * given Request MAC (if any) and appended with TSIG Variables. It also appends
+ * the resulting TSIG RR to the message wire format and accordingly adjusts
+ * the message size.
+ *
+ * \note This function does not save the new digest to the 'digest' parameter
+ * unless everything went OK. This allows sending the same buffer to
+ * the 'request_mac' and 'digest' parameters.
+ *
+ * \param msg Message to be signed.
+ * \param msg_len Size of the message in bytes.
+ * \param msg_max_len Maximum size of the message in bytes.
+ * \param request_mac Request MAC. (may be NULL).
+ * \param request_mac_len Size of the request MAC in bytes.
+ * \param digest Buffer to save the digest in.
+ * \param digest_len In: size of the buffer. Out: real size of the digest saved.
+ * \param key TSIG used for signing.
+ * \param tsig_rcode RCODE of the TSIG.
+ * \param request_time_signed Clients time signed.
+ *
+ * \retval KNOT_EOK if everything went OK.
+ * \retval TODO
+ *
+ * \todo This function should return TSIG errors by their codes which are
+ * positive values - this will be recognized by the caller.
+ */
+int knot_tsig_sign(uint8_t *msg, size_t *msg_len, size_t msg_max_len,
+ const uint8_t *request_mac, size_t request_mac_len,
+ uint8_t *digest, size_t *digest_len,
+ const knot_tsig_key_t *key, uint16_t tsig_rcode,
+ uint64_t request_time_signed);
+
+/*!
+ * \brief Generate TSIG signature of a 2nd or later message in a TCP session.
+ *
+ * This function generates TSIG digest of the given message prepended with the
+ * given Request MAC (if any) and appended with TSIG Variables. It also appends
+ * the resulting TSIG RR to the message wire format and accordingly adjusts
+ * the message size.
+ *
+ * \note This function does not save the new digest to the 'digest' parameter
+ * unless everything went OK. This allows sending the same buffer to
+ * the 'request_mac' and 'digest' parameters.
+ *
+ * \param msg Message to be signed.
+ * \param msg_len Size of the message in bytes.
+ * \param msg_max_len Maximum size of the message in bytes.
+ * \param prev_digest Previous digest sent by the server in the session.
+ * \param prev_digest_len Size of the previous digest in bytes.
+ * \param digest Buffer to save the digest in.
+ * \param digest_len In: size of the buffer. Out: real size of the digest saved.
+ * \param key TSIG key for signing.
+ * \param to_sign Data being signed.
+ * \param to_sign_len Size of the data being signed.
+ *
+ * \retval KNOT_EOK if successful.
+ * \retval TODO
+ *
+ * \todo This function should return TSIG errors by their codes which are
+ * positive values - this will be recognized by the caller.
+ */
+int knot_tsig_sign_next(uint8_t *msg, size_t *msg_len, size_t msg_max_len,
+ const uint8_t *prev_digest, size_t prev_digest_len,
+ uint8_t *digest, size_t *digest_len,
+ const knot_tsig_key_t *key, uint8_t *to_sign,
+ size_t to_sign_len);
+
+/*!
+ * \brief Checks incoming request.
+ *
+ * \param tsig_rr TSIG extracted from the packet.
+ * \param wire Wire format of the packet (including the TSIG RR).
+ * \param size Size of the wire format of packet in bytes.
+ * \param tsig_key TSIG key.
+ *
+ * \retval KNOT_EOK If the signature is valid.
+ * \retval TODO
+ *
+ * \todo This function should return TSIG errors by their codes which are
+ * positive values - this will be recognized by the caller.
+ */
+int knot_tsig_server_check(const knot_rrset_t *tsig_rr,
+ const uint8_t *wire, size_t size,
+ const knot_tsig_key_t *tsig_key);
+
+/*!
+ * \brief Checks incoming response.
+ *
+ * \param tsig_rr TSIG extracted from the packet.
+ * \param wire Wire format of the packet (including the TSIG RR).
+ * \param size Size of the wire format of packet in bytes.
+ * \param request_mac Request MAC. (may be NULL).
+ * \param request_mac_len Size of the request MAC in bytes.
+ * \param key TSIG key.
+ * \param prev_time_signed Time for TSIG period validity.
+ *
+ * \retval KNOT_EOK If the signature is valid.
+ * \retval TODO
+ *
+ * \todo This function should return TSIG errors by their codes which are
+ * positive values - this will be recognized by the caller.
+ */
+int knot_tsig_client_check(const knot_rrset_t *tsig_rr,
+ const uint8_t *wire, size_t size,
+ const uint8_t *request_mac, size_t request_mac_len,
+ const knot_tsig_key_t *key,
+ uint64_t prev_time_signed);
+
+/*!
+ * \brief Checks signature of 2nd or next packet in a TCP session.
+ *
+ * \param tsig_rr TSIG extracted from the packet.
+ * \param wire Wire format of the packet (including the TSIG RR).
+ * \param size Size of the wire format of packet in bytes.
+ * \param prev_digest Previous digest sent by the server in the session.
+ * \param prev_digest_len Size of the previous digest in bytes.
+ * \param key TSIG key.
+ * \param prev_time_signed Time for TSIG period validity.
+ *
+ * \retval KNOT_EOK If the signature is valid.
+ * \retval TODO
+ *
+ * \todo This function should return TSIG errors by their codes which are
+ * positive values - this will be recognized by the caller.
+ */
+int knot_tsig_client_check_next(const knot_rrset_t *tsig_rr,
+ const uint8_t *wire, size_t size,
+ const uint8_t *prev_digest,
+ size_t prev_digest_len,
+ const knot_tsig_key_t *key,
+ uint64_t prev_time_signed);
+
+/*!
+ * \todo Documentation!
+ */
+int knot_tsig_add(uint8_t *msg, size_t *msg_len, size_t msg_max_len,
+ uint16_t tsig_rcode, const knot_rrset_t *tsig_rr);
+
+/*! \brief Append TSIG RR to message.
+ * \todo Proper documentation.
+ */
+int knot_tsig_append(uint8_t *msg, size_t *msg_len, size_t msg_max_len,
+ const knot_rrset_t *tsig_rr);
+
+/*! \brief Return true if the TSIG RCODE allows signing the packet.
+ * \todo Proper documentation.
+ */
+static inline bool knot_tsig_can_sign(uint16_t tsig_rcode) {
+ return tsig_rcode == KNOT_RCODE_NOERROR || tsig_rcode == KNOT_RCODE_BADTIME;
+}
+
+/*! @} */
diff --git a/src/libknot/tsig.c b/src/libknot/tsig.c
new file mode 100644
index 0000000..465307b
--- /dev/null
+++ b/src/libknot/tsig.c
@@ -0,0 +1,186 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <string.h>
+
+#include "contrib/getline.h"
+#include "contrib/string.h"
+#include "libdnssec/error.h"
+#include "libknot/attribute.h"
+#include "libknot/errcode.h"
+#include "libknot/tsig.h"
+
+_public_
+void knot_tsig_key_deinit(knot_tsig_key_t *key)
+{
+ if (!key) {
+ return;
+ }
+
+ knot_dname_free(key->name, NULL);
+
+ memset(key->secret.data, 0, key->secret.size);
+ dnssec_binary_free(&key->secret);
+
+ memset(key, '\0', sizeof(*key));
+}
+
+_public_
+int knot_tsig_key_init(knot_tsig_key_t *key, const char *algorithm_name,
+ const char *name, const char *secret_b64)
+{
+ if (!name || !secret_b64 || !key) {
+ return KNOT_EINVAL;
+ }
+
+ dnssec_tsig_algorithm_t algorithm = DNSSEC_TSIG_HMAC_SHA256;
+ if (algorithm_name != NULL) {
+ algorithm = dnssec_tsig_algorithm_from_name(algorithm_name);
+ if (algorithm == DNSSEC_TSIG_UNKNOWN) {
+ return KNOT_EMALF;
+ }
+ }
+
+ knot_dname_t *dname = knot_dname_from_str_alloc(name);
+ if (!dname) {
+ return KNOT_ENOMEM;
+ }
+ knot_dname_to_lower(dname);
+
+ dnssec_binary_t b64secret = { 0 };
+ b64secret.data = (uint8_t *)secret_b64;
+ b64secret.size = strlen(secret_b64);
+
+ dnssec_binary_t secret = { 0 };
+ int result = dnssec_binary_from_base64(&b64secret, &secret);
+ if (result != KNOT_EOK) {
+ knot_dname_free(dname, NULL);
+ return result;
+ }
+
+ key->name = dname;
+ key->algorithm = algorithm;
+ key->secret = secret;
+
+ return KNOT_EOK;
+}
+
+_public_
+int knot_tsig_key_init_str(knot_tsig_key_t *key, const char *params)
+{
+ if (!params) {
+ return KNOT_EINVAL;
+ }
+
+ char *copy = strstrip(params);
+ if (!copy) {
+ return KNOT_ENOMEM;
+ }
+
+ size_t copy_size = strlen(copy) + 1;
+
+ // format [algorithm:]name:secret
+
+ char *algorithm = NULL;
+ char *name = NULL;
+ char *secret = NULL;
+
+ // find secret
+
+ char *pos = strrchr(copy, ':');
+ if (pos) {
+ *pos = '\0';
+ secret = pos + 1;
+ } else {
+ memset(copy, 0, copy_size);
+ free(copy);
+ return KNOT_EMALF;
+ }
+
+ // find name and optionally algorithm
+
+ pos = strchr(copy, ':');
+ if (pos) {
+ *pos = '\0';
+ algorithm = copy;
+ name = pos + 1;
+ } else {
+ name = copy;
+ }
+
+ int result = knot_tsig_key_init(key, algorithm, name, secret);
+
+ memset(copy, 0, copy_size);
+ free(copy);
+
+ return result;
+}
+
+_public_
+int knot_tsig_key_init_file(knot_tsig_key_t *key, const char *filename)
+{
+ if (!filename) {
+ return KNOT_EINVAL;
+ }
+
+ FILE *file = fopen(filename, "r");
+ if (!file) {
+ return KNOT_EACCES;
+ }
+
+ char *line = NULL;
+ size_t line_size = 0;
+ ssize_t read = knot_getline(&line, &line_size, file);
+
+ fclose(file);
+
+ if (read == -1) {
+ return KNOT_EMALF;
+ }
+
+ int result = knot_tsig_key_init_str(key, line);
+
+ memset(line, 0, line_size);
+ free(line);
+
+ return result;
+}
+
+_public_
+int knot_tsig_key_copy(knot_tsig_key_t *dst, const knot_tsig_key_t *src)
+{
+ if (!src || !dst) {
+ return KNOT_EINVAL;
+ }
+
+ knot_tsig_key_t copy = { 0 };
+ copy.algorithm = src->algorithm;
+
+ copy.name = knot_dname_copy(src->name, NULL);
+ if (!copy.name) {
+ return KNOT_ENOMEM;
+ }
+
+ if (dnssec_binary_dup(&src->secret, &copy.secret) != DNSSEC_EOK) {
+ knot_tsig_key_deinit(&copy);
+ return KNOT_ENOMEM;
+ }
+
+ *dst = copy;
+
+ return KNOT_EOK;
+}
diff --git a/src/libknot/tsig.h b/src/libknot/tsig.h
new file mode 100644
index 0000000..f3e4bba
--- /dev/null
+++ b/src/libknot/tsig.h
@@ -0,0 +1,92 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*!
+ * \file
+ *
+ * \brief TSIG operations
+ *
+ * \addtogroup knot-tsig
+ * @{
+ */
+
+#pragma once
+
+#include "libknot/dname.h"
+#include "libdnssec/tsig.h"
+
+/*!
+ * \brief TSIG key.
+ */
+struct knot_tsig_key {
+ dnssec_tsig_algorithm_t algorithm;
+ knot_dname_t *name;
+ dnssec_binary_t secret;
+};
+typedef struct knot_tsig_key knot_tsig_key_t;
+
+/*!
+ * \brief Packet signing context.
+ */
+typedef struct knot_sign_context {
+ knot_tsig_key_t tsig_key;
+ uint8_t *tsig_buf;
+ uint8_t *tsig_digest;
+ size_t tsig_buflen;
+ size_t tsig_digestlen;
+ uint8_t tsig_runlen;
+ uint64_t tsig_time_signed;
+ size_t pkt_count;
+} knot_sign_context_t;
+
+/*!
+ * \brief Initialize a new TSIG key from individual key parameters.
+ *
+ * \param[out] key Key to be initialized.
+ * \param[in] algorithm Algorithm name. NULL for default (hmac-md5).
+ * \param[in] name Key name (domain name in presentation format).
+ * \param[in] secret_b64 Secret encoded using Base 64.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_tsig_key_init(knot_tsig_key_t *key, const char *algorithm,
+ const char *name, const char *secret_b64);
+
+/*!
+ * \brief Create a new TSIG key from a string encoding all parameters.
+ *
+ * \param[out] key Key to be initialized.
+ * \param[in] params Parameters in a form \a [algorithm:]name:base64_secret
+ */
+int knot_tsig_key_init_str(knot_tsig_key_t *key, const char *params);
+
+/*!
+ * \brief Create a new TSIG key by reading the parameters from a file.
+ *
+ * The file content is parsed by \a tsig_key_create_str.
+ */
+int knot_tsig_key_init_file(knot_tsig_key_t *key, const char *filename);
+
+/*!
+ * \brief Deinitialize TSIG key.
+ */
+void knot_tsig_key_deinit(knot_tsig_key_t *key);
+
+/*!
+ * \brief Duplicate a TSIG key.
+ */
+int knot_tsig_key_copy(knot_tsig_key_t *dst, const knot_tsig_key_t *src);
+
+/*! @} */
diff --git a/src/libknot/version.h b/src/libknot/version.h
new file mode 100644
index 0000000..df15570
--- /dev/null
+++ b/src/libknot/version.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#define KNOT_VERSION_MAJOR 2
+#define KNOT_VERSION_MINOR 7
+#define KNOT_VERSION_PATCH 0x06
+
+#define KNOT_VERSION_HEX ((KNOT_VERSION_MAJOR << 16) | \
+ (KNOT_VERSION_MINOR << 8) | \
+ (KNOT_VERSION_PATCH))
diff --git a/src/libknot/version.h.in b/src/libknot/version.h.in
new file mode 100644
index 0000000..bbe8742
--- /dev/null
+++ b/src/libknot/version.h.in
@@ -0,0 +1,25 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#define KNOT_VERSION_MAJOR @KNOT_VERSION_MAJOR@
+#define KNOT_VERSION_MINOR @KNOT_VERSION_MINOR@
+#define KNOT_VERSION_PATCH 0x0@KNOT_VERSION_PATCH@
+
+#define KNOT_VERSION_HEX ((KNOT_VERSION_MAJOR << 16) | \
+ (KNOT_VERSION_MINOR << 8) | \
+ (KNOT_VERSION_PATCH))
diff --git a/src/libknot/wire.h b/src/libknot/wire.h
new file mode 100644
index 0000000..5f69d9f
--- /dev/null
+++ b/src/libknot/wire.h
@@ -0,0 +1,153 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief Wire integer operations.
+ *
+ * \addtogroup wire
+ * @{
+ */
+
+#pragma once
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "libknot/endian.h"
+
+/*!
+ * \brief Reads 2 bytes from the wireformat data.
+ *
+ * \param pos Data to read the 2 bytes from.
+ *
+ * \return The 2 bytes read, in host byte order.
+ */
+inline static uint16_t knot_wire_read_u16(const uint8_t *pos)
+{
+ assert(pos);
+ uint16_t result;
+ memcpy(&result, pos, sizeof(result));
+ return be16toh(result);
+}
+
+/*!
+ * \brief Reads 4 bytes from the wireformat data.
+ *
+ * \param pos Data to read the 4 bytes from.
+ *
+ * \return The 4 bytes read, in host byte order.
+ */
+inline static uint32_t knot_wire_read_u32(const uint8_t *pos)
+{
+ assert(pos);
+ uint32_t result;
+ memcpy(&result, pos, sizeof(result));
+ return be32toh(result);
+}
+
+/*!
+ * \brief Reads 6 bytes from the wireformat data.
+ *
+ * \param pos Data to read the 6 bytes from.
+ *
+ * \return The 6 bytes read, in host byte order.
+ */
+inline static uint64_t knot_wire_read_u48(const uint8_t *pos)
+{
+ assert(pos);
+ uint64_t input = 0;
+ memcpy((uint8_t *)&input + 1, pos, 6);
+ return be64toh(input) >> 8;
+}
+
+/*!
+ * \brief Read 8 bytes from the wireformat data.
+ *
+ * \param pos Data to read the 8 bytes from.
+ *
+ * \return The 8 bytes read, in host byte order.
+ */
+inline static uint64_t knot_wire_read_u64(const uint8_t *pos)
+{
+ assert(pos);
+ uint64_t result;
+ memcpy(&result, pos, sizeof(result));
+ return be64toh(result);
+}
+
+/*!
+ * \brief Writes 2 bytes in wireformat.
+ *
+ * The data are stored in network byte order (big endian).
+ *
+ * \param pos Position where to put the 2 bytes.
+ * \param data Data to put.
+ */
+inline static void knot_wire_write_u16(uint8_t *pos, uint16_t data)
+{
+ assert(pos);
+ uint16_t beval = htobe16(data);
+ memcpy(pos, &beval, sizeof(beval));
+}
+
+/*!
+ * \brief Writes 4 bytes in wireformat.
+ *
+ * The data are stored in network byte order (big endian).
+ *
+ * \param pos Position where to put the 4 bytes.
+ * \param data Data to put.
+ */
+inline static void knot_wire_write_u32(uint8_t *pos, uint32_t data)
+{
+ assert(pos);
+ uint32_t beval = htobe32(data);
+ memcpy(pos, &beval, sizeof(beval));
+}
+
+/*!
+ * \brief Writes 6 bytes in wireformat.
+ *
+ * The data are stored in network byte order (big endian).
+ *
+ * \param pos Position where to put the 4 bytes.
+ * \param data Data to put.
+ */
+inline static void knot_wire_write_u48(uint8_t *pos, uint64_t data)
+{
+ assert(pos);
+ uint64_t swapped = htobe64(data << 8);
+ memcpy(pos, (uint8_t *)&swapped + 1, 6);
+}
+
+/*!
+ * \brief Writes 8 bytes in wireformat.
+ *
+ * The data are stored in network byte order (big endian).
+ *
+ * \param pos Position where to put the 8 bytes.
+ * \param data Data to put.
+ */
+inline static void knot_wire_write_u64(uint8_t *pos, uint64_t data)
+{
+ assert(pos);
+ uint64_t beval = htobe64(data);
+ memcpy(pos, &beval, sizeof(beval));
+}
+
+/*! @} */
diff --git a/src/libknot/yparser/yparser.c b/src/libknot/yparser/yparser.c
new file mode 100644
index 0000000..91d472d
--- /dev/null
+++ b/src/libknot/yparser/yparser.c
@@ -0,0 +1,172 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include "libknot/yparser/yparser.h"
+#include "libknot/attribute.h"
+#include "libknot/errcode.h"
+
+extern int _yp_start_state;
+extern int _yp_parse(yp_parser_t *parser);
+
+_public_
+void yp_init(
+ yp_parser_t *parser)
+{
+ if (parser == NULL) {
+ return;
+ }
+
+ memset(parser, 0, sizeof(*parser));
+
+ parser->cs = _yp_start_state;
+ parser->file.descriptor = -1;
+ parser->line_count = 1;
+}
+
+_public_
+void yp_deinit(
+ yp_parser_t *parser)
+{
+ if (parser == NULL) {
+ return;
+ }
+
+ if (parser->file.descriptor != -1) {
+ munmap((void *)parser->input.start,
+ parser->input.end - parser->input.start);
+ close(parser->file.descriptor);
+ free(parser->file.name);
+ }
+}
+
+_public_
+int yp_set_input_string(
+ yp_parser_t *parser,
+ const char *input,
+ size_t size)
+{
+ if (parser == NULL || input == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ // Reinitialize the parser.
+ yp_deinit(parser);
+ yp_init(parser);
+
+ // Set the parser input limits.
+ parser->input.start = input;
+ parser->input.current = input;
+ parser->input.end = input + size;
+ parser->input.eof = false;
+
+ return KNOT_EOK;
+}
+
+_public_
+int yp_set_input_file(
+ yp_parser_t *parser,
+ const char *file_name)
+{
+ if (parser == NULL || file_name == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ // Reinitialize the parser.
+ yp_deinit(parser);
+ yp_init(parser);
+
+ // Try to open the file.
+ parser->file.descriptor = open(file_name, O_RDONLY);
+ if (parser->file.descriptor == -1) {
+ return knot_map_errno();
+ }
+
+ // Check for regular file input.
+ struct stat file_stat;
+ if (fstat(parser->file.descriptor, &file_stat) == -1) {
+ close(parser->file.descriptor);
+ return knot_map_errno();
+ } else if (!S_ISREG(file_stat.st_mode)) {
+ close(parser->file.descriptor);
+ return KNOT_EFILE;
+ }
+
+ char *start = NULL;
+
+ // Check for empty file (cannot mmap).
+ if (file_stat.st_size > 0) {
+ // Map the file to the memory.
+ start = mmap(0, file_stat.st_size, PROT_READ, MAP_SHARED,
+ parser->file.descriptor, 0);
+ if (start == MAP_FAILED) {
+ close(parser->file.descriptor);
+ return KNOT_ENOMEM;
+ }
+
+ // Try to set the mapped memory advise to sequential.
+ (void)madvise(start, file_stat.st_size, MADV_SEQUENTIAL);
+
+ parser->input.eof = false;
+ } else {
+ parser->input.eof = true;
+ }
+
+ parser->file.name = strdup(file_name);
+
+ // Set the parser input limits.
+ parser->input.start = start;
+ parser->input.current = start;
+ parser->input.end = start + file_stat.st_size;
+
+ return KNOT_EOK;
+}
+
+_public_
+int yp_parse(
+ yp_parser_t *parser)
+{
+ if (parser == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = KNOT_EPARSEFAIL;
+
+ // Run the parser until found new item, error or end of input.
+ do {
+ // Check for the end of the input.
+ if (parser->input.current == parser->input.end) {
+ if (parser->input.eof) {
+ // End of parsing.
+ return KNOT_EOF;
+ } else {
+ // Set the parser to final parsing.
+ parser->input.eof = true;
+ }
+ }
+
+ // Parse the next item.
+ ret = _yp_parse(parser);
+ } while (ret == KNOT_EFEWDATA);
+
+ return ret;
+}
diff --git a/src/libknot/yparser/yparser.h b/src/libknot/yparser/yparser.h
new file mode 100644
index 0000000..b01870d
--- /dev/null
+++ b/src/libknot/yparser/yparser.h
@@ -0,0 +1,148 @@
+/* Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*!
+ * \file
+ *
+ * \brief Simple parser (Yparser) of a YAML-inspired data format.
+ *
+ * \addtogroup yparser
+ * @{
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <stddef.h>
+
+/*! Maximal length of textual key value. */
+#define YP_MAX_TXT_KEY_LEN 128
+/*! Maximal length of textual data value. */
+#define YP_MAX_TXT_DATA_LEN 32768
+
+/*! Parser events indicating type of lastly parsed item. */
+typedef enum {
+ YP_ENULL = 0, /*!< No valid data. */
+ YP_EKEY0, /*!< First level item. */
+ YP_EKEY1, /*!< Second level item. */
+ YP_EID, /*!< Second level identifier. */
+} yp_event_t;
+
+/*! Context structure of yparser. */
+typedef struct {
+ /*! Current parser state (Ragel internals). */
+ int cs;
+ /*! Indication if the current item was already processed. */
+ bool processed;
+ /*! Current block indentation. */
+ size_t indent;
+ /*! Last id dash position. */
+ size_t id_pos;
+
+ /*! Input parameters. */
+ struct {
+ /*! Start of the block. */
+ const char *start;
+ /*! Current parser position. */
+ const char *current;
+ /*! End of the block. */
+ const char *end;
+ /*! Indication for the final block parsing. */
+ bool eof;
+ } input;
+
+ /*! File input parameters. */
+ struct {
+ /*! File name. */
+ char *name;
+ /*! File descriptor. */
+ int descriptor;
+ } file;
+
+ /*! [out] Current line number (error location). */
+ size_t line_count;
+ /*! [out] Current event. */
+ yp_event_t event;
+ /*! [out] Parsed key (zero terminated string). */
+ char key[YP_MAX_TXT_KEY_LEN];
+ /*! [out] Key length. */
+ size_t key_len;
+ /*! [out] Parsed data (zero terminated string). */
+ char data[YP_MAX_TXT_DATA_LEN];
+ /*! [out] Data length. */
+ size_t data_len;
+} yp_parser_t;
+
+/*!
+ * Initializes the parser.
+ *
+ * \param[in] parser Parser context.
+ */
+void yp_init(
+ yp_parser_t *parser
+);
+
+/*!
+ * Deinitializes the parser.
+ *
+ * \param[in] parser Parser context.
+ */
+void yp_deinit(
+ yp_parser_t *parser
+);
+
+/*!
+ * Sets the parser to parse given string.
+ *
+ * \param[in] parser Parser context.
+ * \param[in] input The string to parse.
+ * \param[in] size Length of the string.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int yp_set_input_string(
+ yp_parser_t *parser,
+ const char *input,
+ size_t size
+);
+
+/*!
+ * Sets the parser to parse given file.
+ *
+ * \param[in] parser Parser context.
+ * \param[in] file_name The filename to parse.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int yp_set_input_file(
+ yp_parser_t *parser,
+ const char *file_name
+);
+
+/*!
+ * Parses one item from the input.
+ *
+ * If the item has more values, this function returns for each value. The item
+ * can also have no value.
+ *
+ * \param[in] parser Parser context.
+ *
+ * \return Error code, KNOT_EOK if success, KNOT_EOF if end of data.
+ */
+int yp_parse(
+ yp_parser_t *parser
+);
+
+/*! @} */
diff --git a/src/libknot/yparser/ypbody.c b/src/libknot/yparser/ypbody.c
new file mode 100644
index 0000000..bfceaf0
--- /dev/null
+++ b/src/libknot/yparser/ypbody.c
@@ -0,0 +1,456 @@
+
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <string.h>
+
+#include "libknot/yparser/yparser.h"
+#include "libknot/errcode.h"
+
+
+
+
+// Include parser static data (Ragel internals).
+
+static const char _yparser_actions[] = {
+ 0, 1, 0, 1, 1, 1, 2, 1,
+ 3, 1, 4, 1, 6, 1, 8, 1,
+ 9, 1, 10, 1, 11, 1, 12, 1,
+ 15, 2, 1, 0, 2, 1, 2, 2,
+ 2, 0, 2, 3, 4, 2, 5, 4,
+ 2, 6, 0, 2, 7, 8, 2, 12,
+ 13, 2, 14, 12, 3, 1, 2, 0,
+ 3, 1, 7, 8, 3, 1, 12, 13,
+ 3, 1, 14, 12, 3, 2, 7, 8,
+ 3, 2, 12, 13, 3, 2, 14, 12,
+ 4, 1, 2, 7, 8, 4, 1, 2,
+ 12, 13, 4, 1, 2, 14, 12
+};
+
+static const unsigned char _yparser_key_offsets[] = {
+ 0, 0, 13, 15, 16, 25, 36, 38,
+ 39, 49, 60, 71, 73, 76, 89, 93,
+ 96, 100, 102, 105, 115, 124, 127, 130,
+ 133, 137, 140, 143, 146, 157, 170, 183,
+ 196
+};
+
+static const char _yparser_trans_keys[] = {
+ 10, 13, 32, 35, 45, 46, 92, 48,
+ 57, 65, 90, 97, 122, 10, 13, 32,
+ 32, 46, 92, 48, 57, 65, 90, 97,
+ 122, 32, 58, 92, 45, 46, 48, 57,
+ 65, 90, 97, 122, 32, 58, 32, 32,
+ 33, 34, 92, 36, 43, 45, 90, 94,
+ 126, 10, 13, 32, 33, 92, 36, 43,
+ 45, 90, 94, 126, 32, 58, 92, 45,
+ 46, 48, 57, 65, 90, 97, 122, 32,
+ 58, 10, 13, 32, 10, 13, 32, 34,
+ 35, 91, 92, 33, 43, 45, 90, 94,
+ 126, 34, 92, 32, 126, 10, 13, 32,
+ 10, 13, 32, 35, 10, 13, 34, 32,
+ 126, 32, 33, 34, 92, 36, 43, 45,
+ 90, 94, 126, 32, 33, 44, 92, 93,
+ 36, 90, 94, 126, 32, 44, 93, 10,
+ 13, 32, 34, 32, 126, 34, 92, 32,
+ 126, 32, 44, 93, 34, 32, 126, 34,
+ 32, 126, 32, 58, 92, 45, 46, 48,
+ 57, 65, 90, 97, 122, 10, 13, 32,
+ 35, 45, 46, 92, 48, 57, 65, 90,
+ 97, 122, 10, 13, 32, 35, 45, 46,
+ 92, 48, 57, 65, 90, 97, 122, 10,
+ 13, 32, 35, 45, 46, 92, 48, 57,
+ 65, 90, 97, 122, 10, 13, 32, 35,
+ 45, 46, 92, 48, 57, 65, 90, 97,
+ 122, 0
+};
+
+static const char _yparser_single_lengths[] = {
+ 0, 7, 2, 1, 3, 3, 2, 1,
+ 4, 5, 3, 2, 3, 7, 2, 3,
+ 4, 2, 1, 4, 5, 3, 3, 1,
+ 2, 3, 1, 1, 3, 7, 7, 7,
+ 7
+};
+
+static const char _yparser_range_lengths[] = {
+ 0, 3, 0, 0, 3, 4, 0, 0,
+ 3, 3, 4, 0, 0, 3, 1, 0,
+ 0, 0, 1, 3, 2, 0, 0, 1,
+ 1, 0, 1, 1, 4, 3, 3, 3,
+ 3
+};
+
+static const unsigned char _yparser_index_offsets[] = {
+ 0, 0, 11, 14, 16, 23, 31, 34,
+ 36, 44, 53, 61, 64, 68, 79, 83,
+ 87, 92, 95, 98, 106, 114, 118, 122,
+ 125, 129, 133, 136, 139, 147, 158, 169,
+ 180
+};
+
+static const char _yparser_indicies[] = {
+ 1, 2, 3, 4, 5, 6, 6, 6,
+ 6, 6, 0, 1, 2, 4, 7, 0,
+ 7, 8, 8, 8, 8, 8, 0, 9,
+ 11, 10, 10, 10, 10, 10, 0, 12,
+ 13, 0, 14, 0, 14, 15, 16, 17,
+ 15, 15, 15, 0, 18, 19, 20, 21,
+ 22, 21, 21, 21, 0, 23, 25, 24,
+ 24, 24, 24, 24, 0, 26, 27, 0,
+ 28, 29, 30, 0, 28, 29, 30, 16,
+ 31, 32, 17, 15, 15, 15, 0, 34,
+ 35, 33, 0, 18, 19, 20, 0, 28,
+ 29, 36, 31, 0, 28, 29, 31, 37,
+ 33, 0, 32, 38, 39, 40, 38, 38,
+ 38, 0, 41, 42, 43, 44, 45, 42,
+ 42, 0, 46, 32, 47, 0, 28, 29,
+ 36, 0, 48, 42, 0, 50, 51, 49,
+ 0, 41, 43, 45, 0, 52, 49, 0,
+ 53, 21, 0, 54, 56, 55, 55, 55,
+ 55, 55, 0, 1, 2, 3, 4, 5,
+ 57, 57, 57, 57, 57, 0, 58, 59,
+ 60, 61, 62, 63, 63, 63, 63, 63,
+ 0, 64, 65, 66, 67, 68, 69, 69,
+ 69, 69, 69, 0, 70, 71, 72, 73,
+ 74, 75, 75, 75, 75, 75, 0, 0
+};
+
+static const char _yparser_trans_targs[] = {
+ 0, 30, 31, 1, 2, 3, 28, 4,
+ 5, 6, 5, 7, 6, 7, 8, 9,
+ 14, 27, 32, 29, 16, 9, 27, 11,
+ 10, 12, 11, 12, 32, 29, 13, 17,
+ 19, 14, 15, 18, 16, 14, 20, 24,
+ 23, 21, 20, 19, 23, 22, 21, 22,
+ 20, 24, 25, 26, 24, 9, 11, 28,
+ 12, 10, 30, 31, 1, 2, 3, 10,
+ 30, 31, 1, 2, 3, 10, 30, 31,
+ 1, 2, 3, 10
+};
+
+static const char _yparser_trans_actions[] = {
+ 23, 1, 0, 46, 0, 49, 43, 21,
+ 43, 19, 13, 19, 0, 0, 0, 34,
+ 7, 34, 40, 11, 11, 9, 9, 15,
+ 13, 15, 0, 0, 1, 0, 0, 0,
+ 0, 9, 0, 9, 0, 37, 34, 7,
+ 34, 11, 9, 11, 9, 11, 0, 0,
+ 37, 9, 0, 9, 37, 37, 17, 13,
+ 17, 43, 52, 28, 85, 28, 90, 80,
+ 31, 5, 72, 5, 76, 68, 25, 3,
+ 60, 3, 64, 56
+};
+
+static const char _yparser_eof_actions[] = {
+ 0, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 0, 28, 5,
+ 3
+};
+
+
+
+
+
+int _yp_start_state = 29;
+
+int _yp_parse(
+ yp_parser_t *parser)
+{
+ // Parser input limits (Ragel internals).
+ const char *p, *pe, *eof;
+
+ // Current item indent.
+ size_t indent = 0;
+ // Current id dash position.
+ size_t id_pos = 0;
+ // Indicates if the current parsing step contains an item.
+ bool found = false;
+
+ if (!parser->input.eof) { // Restore parser input limits.
+ p = parser->input.current;
+ pe = parser->input.end;
+ eof = NULL;
+ } else { // Set the last artificial block with just one new line char.
+ p = "\n";
+ pe = p + 1;
+ eof = pe;
+ }
+
+ // Include parser body.
+
+ {
+ int _klen;
+ unsigned int _trans;
+ const char *_acts;
+ unsigned int _nacts;
+ const char *_keys;
+
+ if ( p == pe )
+ goto _test_eof;
+ if ( parser->cs == 0 )
+ goto _out;
+_resume:
+ _keys = _yparser_trans_keys + _yparser_key_offsets[ parser->cs];
+ _trans = _yparser_index_offsets[ parser->cs];
+
+ _klen = _yparser_single_lengths[ parser->cs];
+ if ( _klen > 0 ) {
+ const char *_lower = _keys;
+ const char *_mid;
+ const char *_upper = _keys + _klen - 1;
+ while (1) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + ((_upper-_lower) >> 1);
+ if ( (*p) < *_mid )
+ _upper = _mid - 1;
+ else if ( (*p) > *_mid )
+ _lower = _mid + 1;
+ else {
+ _trans += (unsigned int)(_mid - _keys);
+ goto _match;
+ }
+ }
+ _keys += _klen;
+ _trans += _klen;
+ }
+
+ _klen = _yparser_range_lengths[ parser->cs];
+ if ( _klen > 0 ) {
+ const char *_lower = _keys;
+ const char *_mid;
+ const char *_upper = _keys + (_klen<<1) - 2;
+ while (1) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + (((_upper-_lower) >> 1) & ~1);
+ if ( (*p) < _mid[0] )
+ _upper = _mid - 2;
+ else if ( (*p) > _mid[1] )
+ _lower = _mid + 2;
+ else {
+ _trans += (unsigned int)((_mid - _keys)>>1);
+ goto _match;
+ }
+ }
+ _trans += _klen;
+ }
+
+_match:
+ _trans = _yparser_indicies[_trans];
+ parser->cs = _yparser_trans_targs[_trans];
+
+ if ( _yparser_trans_actions[_trans] == 0 )
+ goto _again;
+
+ _acts = _yparser_actions + _yparser_trans_actions[_trans];
+ _nacts = (unsigned int) *_acts++;
+ while ( _nacts-- > 0 )
+ {
+ switch ( *_acts++ )
+ {
+ case 0:
+ {
+ // Return if key without value.
+ if (parser->event != YP_ENULL && !parser->processed) {
+ parser->processed = true;
+ found = true;
+ {p++; goto _out; }
+ }
+ }
+ break;
+ case 1:
+ {
+ parser->line_count++;
+ parser->event = YP_ENULL;
+ parser->processed = false;
+ }
+ break;
+ case 2:
+ {
+ indent = 0;
+ id_pos = 0;
+ }
+ break;
+ case 3:
+ {
+ parser->data_len = 0;
+ }
+ break;
+ case 4:
+ {
+ if (parser->data_len >= sizeof(parser->data) - 1) {
+ return KNOT_ESPACE;
+ }
+ parser->data[parser->data_len++] = (*p);
+ }
+ break;
+ case 5:
+ {
+ parser->data_len--;
+ }
+ break;
+ case 6:
+ {
+ // Return if a value parsed.
+ parser->data[parser->data_len] = '\0';
+ parser->processed = true;
+ found = true;
+ {p++; goto _out; }
+ }
+ break;
+ case 7:
+ {
+ if (indent > 0 && parser->indent > 0 &&
+ indent != parser->indent) {
+ return KNOT_YP_EINVAL_INDENT;
+ }
+ parser->processed = false;
+ parser->key_len = 0;
+ parser->data_len = 0;
+ parser->event = YP_ENULL;
+ }
+ break;
+ case 8:
+ {
+ if (parser->key_len >= sizeof(parser->key) - 1) {
+ return KNOT_ESPACE;
+ }
+ parser->key[parser->key_len++] = (*p);
+ }
+ break;
+ case 9:
+ {
+ parser->key[parser->key_len] = '\0';
+ parser->indent = 0;
+ parser->id_pos = 0;
+ parser->event = YP_EKEY0;
+ }
+ break;
+ case 10:
+ {
+ parser->key[parser->key_len] = '\0';
+ parser->indent = indent;
+ parser->event = YP_EKEY1;
+ }
+ break;
+ case 11:
+ {
+ parser->key[parser->key_len] = '\0';
+ parser->indent = indent;
+ parser->id_pos = id_pos;
+ parser->event = YP_EID;
+ }
+ break;
+ case 12:
+ {
+ indent++;
+ }
+ break;
+ case 13:
+ {
+ id_pos++;
+ }
+ break;
+ case 14:
+ {
+ if (id_pos > 0 && parser->id_pos > 0 &&
+ id_pos != parser->id_pos) {
+ return KNOT_YP_EINVAL_INDENT;
+ }
+ parser->indent = 0;
+ }
+ break;
+ case 15:
+ {
+ switch ((*p)) {
+ case '\t':
+ return KNOT_YP_ECHAR_TAB;
+ default:
+ return KNOT_EPARSEFAIL;
+ }
+ }
+ break;
+ }
+ }
+
+_again:
+ if ( parser->cs == 0 )
+ goto _out;
+ if ( ++p != pe )
+ goto _resume;
+ _test_eof: {}
+ if ( p == eof )
+ {
+ const char *__acts = _yparser_actions + _yparser_eof_actions[ parser->cs];
+ unsigned int __nacts = (unsigned int) *__acts++;
+ while ( __nacts-- > 0 ) {
+ switch ( *__acts++ ) {
+ case 1:
+ {
+ parser->line_count++;
+ parser->event = YP_ENULL;
+ parser->processed = false;
+ }
+ break;
+ case 2:
+ {
+ indent = 0;
+ id_pos = 0;
+ }
+ break;
+ case 15:
+ {
+ switch ((*p)) {
+ case '\t':
+ return KNOT_YP_ECHAR_TAB;
+ default:
+ return KNOT_EPARSEFAIL;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ _out: {}
+ }
+
+
+ // Store the current parser position.
+ if (!parser->input.eof) {
+ parser->input.current = p;
+ } else {
+ parser->input.current = parser->input.end;
+ }
+
+ // Check for general parser error.
+ if (parser->cs == 0) {
+ return KNOT_EPARSEFAIL;
+ }
+
+ // Check if parsed an item.
+ if (found) {
+ return KNOT_EOK;
+ } else {
+ return KNOT_EFEWDATA;
+ }
+}
diff --git a/src/libknot/yparser/ypformat.c b/src/libknot/yparser/ypformat.c
new file mode 100644
index 0000000..2648c75
--- /dev/null
+++ b/src/libknot/yparser/ypformat.c
@@ -0,0 +1,121 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdio.h>
+
+#include "libknot/yparser/yptrafo.h"
+#include "libknot/attribute.h"
+#include "libknot/errcode.h"
+
+static int format_item(
+ const yp_item_t *item,
+ const uint8_t *data,
+ size_t data_len,
+ char *out,
+ size_t out_len,
+ yp_style_t style,
+ const char *prefix,
+ bool first_value,
+ bool last_value)
+{
+ if (item == NULL || out == NULL || prefix == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ // Format key part.
+ int ret = snprintf(out, out_len, "%s%s%s%s",
+ first_value ? prefix : "",
+ first_value ? item->name + 1 : "",
+ first_value ? ":" : "",
+ item->type == YP_TGRP ?
+ "\n" : (first_value && !last_value ? " [ " : " "));
+ if (ret < 0 || ret >= out_len) {
+ return KNOT_ESPACE;
+ }
+ out += ret;
+ out_len -= ret;
+
+ // Finish if group.
+ if (item->type == YP_TGRP) {
+ return KNOT_EOK;
+ }
+
+ // Format data part.
+ size_t aux_len = out_len;
+ ret = yp_item_to_txt(item, data, data_len, out, &aux_len, style);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ out += aux_len;
+ out_len -= aux_len;
+
+ // Format data end.
+ ret = snprintf(out, out_len, "%s%s",
+ last_value && !first_value ? " ]" : "",
+ last_value ? "\n" : ",");
+ if (ret < 0 || ret >= out_len) {
+ return KNOT_ESPACE;
+ }
+
+ return KNOT_EOK;
+}
+
+_public_
+int yp_format_key0(
+ const yp_item_t *item,
+ const uint8_t *data,
+ size_t data_len,
+ char *out,
+ size_t out_len,
+ yp_style_t style,
+ bool first_value,
+ bool last_value)
+{
+ return format_item(item, data, data_len, out, out_len, style, "",
+ first_value, last_value);
+}
+
+_public_
+int yp_format_id(
+ const yp_item_t *item,
+ const uint8_t *data,
+ size_t data_len,
+ char *out,
+ size_t out_len,
+ yp_style_t style)
+{
+ if (data == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ return format_item(item, data, data_len, out, out_len, style, " - ",
+ true, true);
+}
+
+_public_
+int yp_format_key1(
+ const yp_item_t *item,
+ const uint8_t *data,
+ size_t data_len,
+ char *out,
+ size_t out_len,
+ yp_style_t style,
+ bool first_value,
+ bool last_value)
+{
+ return format_item(item, data, data_len, out, out_len, style, " ",
+ first_value, last_value);
+}
diff --git a/src/libknot/yparser/ypformat.h b/src/libknot/yparser/ypformat.h
new file mode 100644
index 0000000..605d509
--- /dev/null
+++ b/src/libknot/yparser/ypformat.h
@@ -0,0 +1,100 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*!
+ * \file
+ *
+ * \brief Tools for Yparser format creation.
+ *
+ * \addtogroup yparser
+ * @{
+ */
+
+#pragma once
+
+#include "libknot/yparser/ypschema.h"
+
+/*!
+ * Formats key0 item.
+ *
+ * \param[in] item Schema item to format.
+ * \param[in] data Data to format.
+ * \param[in] data_len Data length.
+ * \param[out] out Output buffer.
+ * \param[in, out] out_len Output buffer length, output length.
+ * \param[in] style Value style.
+ * \param[in] first_value First value indication (multivalued support).
+ * \param[in] last_value Last value indication (multivalued support).
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int yp_format_key0(
+ const yp_item_t *item,
+ const uint8_t *data,
+ size_t data_len,
+ char *out,
+ size_t out_len,
+ yp_style_t style,
+ bool first_value,
+ bool last_value
+);
+
+/*!
+ * Formats identifier item.
+ *
+ * \param[in] item Schema item to format.
+ * \param[in] data Data to format.
+ * \param[in] data_len Data length.
+ * \param[out] out Output buffer.
+ * \param[in, out] out_len Output buffer length, output length.
+ * \param[in] style Value style.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int yp_format_id(
+ const yp_item_t *item,
+ const uint8_t *data,
+ size_t data_len,
+ char *out,
+ size_t out_len,
+ yp_style_t style
+);
+
+/*!
+ * Formats key1 item.
+ *
+ * \param[in] item Schema item to format.
+ * \param[in] data Data to format.
+ * \param[in] data_len Data length.
+ * \param[out] out Output buffer.
+ * \param[in, out] out_len Output buffer length, output length.
+ * \param[in] style Value style.
+ * \param[in] first_value First value indication (multivalued support).
+ * \param[in] last_value Last value indication (multivalued support).
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int yp_format_key1(
+ const yp_item_t *item,
+ const uint8_t *data,
+ size_t data_len,
+ char *out,
+ size_t out_len,
+ yp_style_t style,
+ bool first_value,
+ bool last_value
+);
+
+/*! @} */
diff --git a/src/libknot/yparser/ypschema.c b/src/libknot/yparser/ypschema.c
new file mode 100644
index 0000000..7ffb7b7
--- /dev/null
+++ b/src/libknot/yparser/ypschema.c
@@ -0,0 +1,575 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libknot/yparser/ypschema.h"
+#include "libknot/yparser/yptrafo.h"
+#include "libknot/attribute.h"
+#include "libknot/errcode.h"
+
+static size_t schema_count(
+ const yp_item_t *src)
+{
+ size_t count = 0;
+ for (const yp_item_t *item = src; item->name != NULL; item++) {
+ count++;
+ }
+
+ return count;
+}
+
+/*! Initializes the referenced item. */
+static int set_ref_item(
+ yp_item_t *dst,
+ const yp_item_t *schema)
+{
+ if (schema == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ // Get reference category.
+ const yp_name_t *ref_name = dst->var.r.ref_name;
+ const yp_item_t *ref = yp_schema_find(ref_name, NULL, schema);
+ if (ref == NULL) {
+ return KNOT_YP_EINVAL_ITEM;
+ }
+
+ dst->var.r.ref = ref;
+
+ return KNOT_EOK;
+}
+
+/*! Copies the sub_items list and initializes pointer to the identifier item. */
+static int set_grp_item(
+ yp_item_t *dst,
+ const yp_item_t *src,
+ const yp_item_t *schema)
+{
+ // Count subitems.
+ size_t count = schema_count(src->var.g.sub_items);
+
+ // Allocate space for subitems + terminal zero item.
+ size_t memsize = (count + 1) * sizeof(yp_item_t);
+ dst->sub_items = malloc(memsize);
+ if (dst->sub_items == NULL) {
+ return KNOT_ENOMEM;
+ }
+ memset(dst->sub_items, 0, memsize);
+
+ // Copy subitems.
+ for (size_t i = 0; i < count; i++) {
+ // The first item is an identifier if multi group.
+ if (i == 0 && (dst->flags & YP_FMULTI)) {
+ dst->var.g.id = &dst->sub_items[0];
+ }
+
+ // Copy sub-item.
+ dst->sub_items[i] = src->var.g.sub_items[i];
+
+ // Initialize sub-item.
+ int ret = KNOT_EOK;
+ switch (dst->sub_items[i].type) {
+ case YP_TREF:
+ ret = set_ref_item(dst->sub_items + i, schema);
+ break;
+ case YP_TGRP: // Deeper hierarchy is not supported.
+ ret = KNOT_ENOTSUP;
+ break;
+ default:
+ break;
+ }
+
+ // Set the parent item.
+ dst->sub_items[i].parent = dst;
+
+ if (ret != KNOT_EOK) {
+ free(dst->sub_items);
+ dst->sub_items = NULL;
+ return ret;
+ }
+ }
+
+ if (src->flags & YP_FALLOC) {
+ dst->var.g.sub_items = malloc(memsize);
+ if (dst->var.g.sub_items == NULL) {
+ free(dst->sub_items);
+ dst->sub_items = NULL;
+ return KNOT_ENOMEM;
+ }
+ memcpy((void *)dst->var.g.sub_items, src->var.g.sub_items, memsize);
+ }
+
+ return KNOT_EOK;
+}
+
+static int set_item(
+ yp_item_t *dst,
+ const yp_item_t *src,
+ const yp_item_t *schema)
+{
+ // Check maximal item name length.
+ if ((uint8_t)src->name[0] > YP_MAX_ITEM_NAME_LEN) {
+ return KNOT_ERANGE;
+ }
+
+ // Copy the static data.
+ *dst = *src;
+
+ // Copy item name into dynamic memory.
+ if (src->flags & YP_FALLOC) {
+ dst->name = malloc(src->name[0] + 2);
+ if (dst->name == NULL) {
+ return KNOT_ENOMEM;
+ }
+ memcpy((void *)dst->name, src->name, src->name[0] + 2);
+ }
+
+ // Item type specific preparation.
+ switch (src->type) {
+ case YP_TREF:
+ return set_ref_item(dst, schema);
+ case YP_TGRP:
+ return set_grp_item(dst, src, schema);
+ default:
+ return KNOT_EOK;
+ }
+}
+
+static void unset_item(
+ yp_item_t *item)
+{
+ if (item->flags & YP_FALLOC) {
+ free((void *)item->name);
+ if (item->flags & YP_FALLOC) {
+ free((void *)item->var.g.sub_items);
+ }
+ }
+ if (item->sub_items != NULL) {
+ free(item->sub_items);
+ }
+
+ memset(item, 0, sizeof(yp_item_t));
+}
+
+static int schema_copy(
+ yp_item_t *dst,
+ const yp_item_t *src,
+ const yp_item_t *schema)
+{
+ // Copy the schema.
+ for (int i = 0; src[i].name != NULL; i++) {
+ int ret = set_item(dst + i, src + i, schema);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+_public_
+int yp_schema_copy(
+ yp_item_t **dst,
+ const yp_item_t *src)
+{
+ if (dst == NULL || src == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ // Allocate space for new schema (+ terminal NULL item).
+ size_t size = (schema_count(src) + 1) * sizeof(yp_item_t);
+ *dst = malloc(size);
+ if (*dst == NULL) {
+ return KNOT_ENOMEM;
+ }
+ memset(*dst, 0, size);
+
+ // Copy the schema.
+ int ret = schema_copy(*dst, src, *dst);
+ if (ret != KNOT_EOK) {
+ yp_schema_free(*dst);
+ return ret;
+ }
+
+ return KNOT_EOK;
+}
+
+_public_
+int yp_schema_merge(
+ yp_item_t **dst,
+ const yp_item_t *src1,
+ const yp_item_t *src2)
+{
+ if (dst == NULL || src1 == NULL || src2 == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ size_t count1 = schema_count(src1);
+ size_t count2 = schema_count(src2);
+
+ // Allocate space for new schema (+ terminal NULL item).
+ size_t size = (count1 + count2 + 1) * sizeof(yp_item_t);
+ *dst = malloc(size);
+ if (*dst == NULL) {
+ return KNOT_ENOMEM;
+ }
+ memset(*dst, 0, size);
+
+ // Copy the first schema.
+ int ret = schema_copy(*dst, src1, *dst);
+ if (ret != KNOT_EOK) {
+ yp_schema_free(*dst);
+ return ret;
+ }
+
+ // Copy the second schema.
+ ret = schema_copy(*dst + count1, src2, *dst);
+ if (ret != KNOT_EOK) {
+ yp_schema_free(*dst);
+ return ret;
+ }
+
+ return KNOT_EOK;
+}
+
+_public_
+void yp_schema_purge_dynamic(
+ yp_item_t *schema)
+{
+ if (schema == NULL) {
+ return;
+ }
+
+ for (yp_item_t *item = schema; item->name != NULL; item++) {
+ if (item->flags & YP_FALLOC) {
+ unset_item(item);
+ }
+ }
+}
+
+_public_
+void yp_schema_free(
+ yp_item_t *schema)
+{
+ if (schema == NULL) {
+ return;
+ }
+
+ for (yp_item_t *item = schema; item->name != NULL; item++) {
+ unset_item(item);
+ }
+ free(schema);
+}
+
+/*! Search the schema for an item with the given name. */
+static const yp_item_t* find_item(
+ const char *name,
+ size_t name_len,
+ const yp_item_t *schema)
+{
+ if (name == NULL || schema == NULL) {
+ return NULL;
+ }
+
+ for (const yp_item_t *item = schema; item->name != NULL; item++) {
+ if (item->name[0] != name_len) {
+ continue;
+ }
+ if (memcmp(item->name + 1, name, name_len) == 0) {
+ return item;
+ }
+ }
+
+ return NULL;
+}
+
+_public_
+const yp_item_t* yp_schema_find(
+ const yp_name_t *name,
+ const yp_name_t *parent_name,
+ const yp_item_t *schema)
+{
+ if (name == NULL || schema == NULL) {
+ return NULL;
+ }
+
+ if (parent_name == NULL) {
+ return find_item(name + 1, name[0], schema);
+ } else {
+ const yp_item_t *parent = find_item(parent_name + 1,
+ parent_name[0], schema);
+ if (parent == NULL) {
+ return NULL;
+ }
+ return find_item(name + 1, name[0], parent->sub_items);
+ }
+}
+
+_public_
+yp_check_ctx_t* yp_schema_check_init(
+ yp_item_t **schema)
+{
+ if (schema == NULL) {
+ return NULL;
+ }
+
+ yp_check_ctx_t *ctx = malloc(sizeof(yp_check_ctx_t));
+ if (ctx == NULL) {
+ return NULL;
+ }
+ memset(ctx, 0, sizeof(yp_check_ctx_t));
+
+ ctx->schema = schema;
+
+ return ctx;
+}
+
+static void reset_ctx(
+ yp_check_ctx_t *ctx,
+ size_t index)
+{
+ assert(index < YP_MAX_NODE_DEPTH);
+
+ yp_node_t *node = &ctx->nodes[index];
+
+ node->parent = (index > 0) ? &ctx->nodes[index - 1] : NULL;
+ node->item = NULL;
+ node->id_len = 0;
+ node->data_len = 0;
+
+ ctx->current = index;
+}
+
+static int check_item(
+ const char *key,
+ size_t key_len,
+ const char *data,
+ size_t data_len,
+ yp_check_ctx_t *ctx,
+ bool allow_key1_without_id)
+{
+ yp_node_t *node = &ctx->nodes[ctx->current];
+ yp_node_t *parent = node->parent;
+ bool is_id = false;
+
+ if (parent != NULL) {
+ // Check for invalid indentation.
+ if (parent->item == NULL) {
+ return KNOT_YP_EINVAL_INDENT;
+ }
+
+ // Check if valid group parent.
+ if (parent->item->type != YP_TGRP) {
+ return KNOT_YP_EINVAL_ITEM;
+ }
+
+ // Check if valid subitem.
+ node->item = find_item(key, key_len, parent->item->sub_items);
+ } else {
+ node->item = find_item(key, key_len, *ctx->schema);
+ }
+ if (node->item == NULL) {
+ return KNOT_YP_EINVAL_ITEM;
+ }
+
+ // Check if the parent requires id specification.
+ if (parent != NULL && parent->item->var.g.id != NULL) {
+ // Check if id.
+ if (node->item == parent->item->var.g.id) {
+ is_id = true;
+ // Move current to the parent.
+ --(ctx->current);
+ // Check for missing id.
+ } else if (parent->id_len == 0 && !allow_key1_without_id) {
+ return KNOT_YP_ENOID;
+ }
+ }
+
+ // Return if no data provided.
+ if (data == NULL) {
+ return KNOT_EOK;
+ }
+
+ // Group cannot have data.
+ if (data_len != 0 && node->item->type == YP_TGRP) {
+ return KNOT_YP_ENOTSUP_DATA;
+ }
+
+ // Convert item data to binary format.
+ const yp_item_t *item = (node->item->type != YP_TREF) ?
+ node->item : node->item->var.r.ref->var.g.id;
+ if (is_id) {
+ // Textual id must not be empty.
+ if (data_len == 0) {
+ return KNOT_YP_ENODATA;
+ }
+
+ parent->id_len = sizeof(((yp_node_t *)NULL)->id);
+ int ret = yp_item_to_bin(item, data, data_len, parent->id,
+ &parent->id_len);
+
+ // Binary id must not be empty.
+ if (ret == KNOT_EOK && parent->id_len == 0) {
+ return KNOT_YP_EINVAL_DATA;
+ }
+
+ return ret;
+ } else {
+ node->data_len = sizeof(((yp_node_t *)NULL)->data);
+ int ret = yp_item_to_bin(item, data, data_len, node->data,
+ &node->data_len);
+ return ret;
+ }
+}
+
+_public_
+int yp_schema_check_parser(
+ yp_check_ctx_t *ctx,
+ const yp_parser_t *parser)
+{
+ if (ctx == NULL || parser == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int ret;
+
+ switch (parser->event) {
+ case YP_EKEY0:
+ reset_ctx(ctx, 0);
+ ret = check_item(parser->key, parser->key_len, parser->data,
+ parser->data_len, ctx, false);
+ break;
+ case YP_EKEY1:
+ reset_ctx(ctx, 1);
+ ret = check_item(parser->key, parser->key_len, parser->data,
+ parser->data_len, ctx, false);
+ if (ret != KNOT_EOK) {
+ break;
+ }
+
+ // Check for KEY1 event with id item.
+ if (ctx->current != 1) {
+ return KNOT_YP_ENOTSUP_ID;
+ }
+
+ break;
+ case YP_EID:
+ reset_ctx(ctx, 1);
+ ret = check_item(parser->key, parser->key_len, parser->data,
+ parser->data_len, ctx, false);
+ if (ret != KNOT_EOK) {
+ break;
+ }
+
+ // Check for ID event with nonid item.
+ if (ctx->current != 0) {
+ return KNOT_YP_EINVAL_ID;
+ }
+
+ break;
+ default:
+ ret = KNOT_EPARSEFAIL;
+ break;
+ }
+
+ return ret;
+}
+
+_public_
+int yp_schema_check_str(
+ yp_check_ctx_t *ctx,
+ const char *key0,
+ const char *key1,
+ const char *id,
+ const char *data)
+{
+ if (ctx == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ size_t key0_len = (key0 != NULL) ? strlen(key0) : 0;
+ size_t key1_len = (key1 != NULL) ? strlen(key1) : 0;
+ size_t id_len = (id != NULL) ? strlen(id) : 0;
+ size_t data_len = (data != NULL) ? strlen(data) : 0;
+
+ // Key0 must always be non-empty.
+ if (key0_len == 0) {
+ return KNOT_YP_EINVAL_ITEM;
+ }
+
+ // Process key0.
+ reset_ctx(ctx, 0);
+ if (key1_len == 0) {
+ int ret = check_item(key0, key0_len, data, data_len, ctx, false);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ } else {
+ int ret = check_item(key0, key0_len, NULL, 0, ctx, false);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ // Process id.
+ if (id_len != 0) {
+ if (ctx->nodes[0].item->type != YP_TGRP ||
+ ctx->nodes[0].item->var.g.id == NULL) {
+ return KNOT_YP_ENOTSUP_ID;
+ }
+ const yp_name_t *name = ctx->nodes[0].item->var.g.id->name;
+
+ reset_ctx(ctx, 1);
+ int ret = check_item(name + 1, name[0], id, id_len, ctx, true);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Check for non-id item (should not happen).
+ assert(ctx->current == 0);
+
+ // Check for group id with data.
+ if (key1_len == 0 && data != NULL) {
+ return KNOT_YP_ENOTSUP_DATA;
+ }
+ }
+
+ // Process key1.
+ if (key1_len != 0) {
+ reset_ctx(ctx, 1);
+ int ret = check_item(key1, key1_len, data, data_len, ctx, true);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Check for id in key1 with extra data.
+ if (ctx->current != 1 && id_len != 0 && data != NULL) {
+ return KNOT_YP_ENOTSUP_DATA;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+_public_
+void yp_schema_check_deinit(
+ yp_check_ctx_t* ctx)
+{
+ free(ctx);
+}
diff --git a/src/libknot/yparser/ypschema.h b/src/libknot/yparser/ypschema.h
new file mode 100644
index 0000000..972a781
--- /dev/null
+++ b/src/libknot/yparser/ypschema.h
@@ -0,0 +1,347 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*!
+ * \file
+ *
+ * \brief Schema layer for Yparser.
+ *
+ * \addtogroup yparser
+ * @{
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include "libknot/yparser/yparser.h"
+#include "libknot/lookup.h"
+
+struct wire_ctx;
+
+/*! Maximal length of item name. */
+#define YP_MAX_ITEM_NAME_LEN 64
+/*! Maximal length of binary identifier name (maximal dname length). */
+#define YP_MAX_ID_LEN 255
+/*! Maximal length of binary data (rough limit). */
+#define YP_MAX_DATA_LEN 32768
+/*! Integer item nil definition. */
+#define YP_NIL INT64_MIN
+/*! Maximal number of miscellaneous callbacks/pointers. */
+#define YP_MAX_MISC_COUNT 4
+/*! Maximal node stack depth. */
+#define YP_MAX_NODE_DEPTH 2
+
+#define YP_TXT_BIN_PARAMS struct wire_ctx *in, struct wire_ctx *out, const uint8_t *stop
+#define YP_BIN_TXT_PARAMS struct wire_ctx *in, struct wire_ctx *out
+
+/*! Helper macros for item variables definition. */
+#define YP_VNONE .var.i = { 0 }
+#define YP_VINT .var.i
+#define YP_VBOOL .var.b
+#define YP_VOPT .var.o
+#define YP_VSTR .var.s
+#define YP_VADDR .var.a
+#define YP_VNET .var.d
+#define YP_VDNAME .var.d
+#define YP_VHEX .var.d
+#define YP_VB64 .var.d
+#define YP_VDATA .var.d
+#define YP_VREF .var.r
+#define YP_VGRP .var.g
+
+/*! Schema item name is a char string with a leading byte (string length). */
+typedef char yp_name_t;
+
+/*! Schema item type. */
+typedef enum {
+ YP_TNONE = 0, /*!< Unspecified. */
+ YP_TINT, /*!< Integer. */
+ YP_TBOOL, /*!< Boolean. */
+ YP_TOPT, /*!< Option from the list. */
+ YP_TSTR, /*!< String. */
+ YP_THEX, /*!< String or hexadecimal string if "0x" prefix. */
+ YP_TADDR, /*!< Address (address[\@port] or UNIX socket path). */
+ YP_TNET, /*!< Network address range (address[/mask] or address-address). */
+ YP_TDNAME, /*!< Domain name. */
+ YP_TB64, /*!< Base64 encoded string. */
+ YP_TDATA, /*!< Customized data. */
+ YP_TREF, /*!< Reference to another item. */
+ YP_TGRP, /*!< Group of sub-items. */
+} yp_type_t;
+
+/*! Schema item flags. */
+typedef enum {
+ YP_FNONE = 0, /*!< Unspecified. */
+ YP_FMULTI = 1 << 0, /*!< Multivalued item. */
+ YP_FALLOC = 1 << 1, /*!< Allocated item. */
+ YP_FUSR1 = 1 << 5, /*!< User-defined flag1. */
+ YP_FUSR2 = 1 << 6, /*!< User-defined flag2. */
+ YP_FUSR3 = 1 << 7, /*!< User-defined flag3. */
+ YP_FUSR4 = 1 << 8, /*!< User-defined flag4. */
+ YP_FUSR5 = 1 << 9, /*!< User-defined flag5. */
+ YP_FUSR6 = 1 << 10, /*!< User-defined flag6. */
+ YP_FUSR7 = 1 << 11, /*!< User-defined flag7. */
+ YP_FUSR8 = 1 << 12, /*!< User-defined flag8. */
+ YP_FUSR9 = 1 << 13, /*!< User-defined flag9. */
+ YP_FUSR10 = 1 << 14, /*!< User-defined flag10. */
+ YP_FUSR11 = 1 << 15, /*!< User-defined flag11. */
+ YP_FUSR12 = 1 << 16, /*!< User-defined flag12. */
+ YP_FUSR13 = 1 << 17, /*!< User-defined flag13. */
+ YP_FUSR14 = 1 << 18, /*!< User-defined flag14. */
+ YP_FUSR15 = 1 << 19, /*!< User-defined flag15. */
+ YP_FUSR16 = 1 << 20, /*!< User-defined flag16. */
+} yp_flag_t;
+
+/*! Schema item style. */
+typedef enum {
+ YP_SNONE = 0, /*!< Unspecified. */
+ YP_SSIZE = 1 << 0, /*!< Size unit (B, K, M, G) (in, out). */
+ YP_STIME = 1 << 1, /*!< Time unit (s, m, h, d) (in, out). */
+ YP_SUNIT = YP_SSIZE | YP_STIME, /*!< Unit (in, out). */
+ YP_SNOQUOTE = 1 << 2 /*!< Unquoted value (out). */
+} yp_style_t;
+
+typedef struct yp_item yp_item_t;
+
+/*! Schema item variables (type dependent). */
+typedef union {
+ /*! Integer variables. */
+ struct {
+ /*! Minimal value. */
+ int64_t min;
+ /*! Maximal value. */
+ int64_t max;
+ /*! Default value. */
+ int64_t dflt;
+ /*! Possible unit type. */
+ yp_style_t unit;
+ } i;
+ /*! Boolen variables. */
+ struct {
+ /*! Default value. */
+ bool dflt;
+ } b;
+ /*! Option variables. */
+ struct {
+ /*! List of options (maximal value is 255). */
+ struct knot_lookup const *opts;
+ /*! Default value. */
+ unsigned dflt;
+ } o;
+ /*! String variables. */
+ struct {
+ /*! Default value. */
+ char const *dflt;
+ } s;
+ /*! Address variables. */
+ struct {
+ /*! Default port. */
+ uint16_t dflt_port;
+ /*! Default socket. */
+ char const *dflt_socket;
+ } a;
+ /*! Customized data variables. */
+ struct {
+ /*! Length of default data. */
+ size_t dflt_len;
+ /*! Default data. */
+ uint8_t const *dflt;
+ /*! Text to binary transformation function. */
+ int (*to_bin)(YP_TXT_BIN_PARAMS);
+ /*! Binary to text transformatio function. */
+ int (*to_txt)(YP_BIN_TXT_PARAMS);
+ } d;
+ /*! Reference variables. */
+ struct {
+ /*! Referenced group name. */
+ yp_name_t const *ref_name;
+ /*! Referenced item (dynamic value). */
+ yp_item_t const *ref;
+ } r;
+ /*! Group variables. */
+ struct {
+ /*! List of sub-items. */
+ yp_item_t const *sub_items;
+ /*! ID item of sub-items (dynamic value). */
+ yp_item_t const *id;
+ } g;
+} yp_var_t;
+
+/*! Schema item specification. */
+struct yp_item {
+ /*! Item name. */
+ const yp_name_t *name;
+ /*! Item type. */
+ yp_type_t type;
+ /*! Item parameters. */
+ yp_var_t var;
+ /*! Item flags. */
+ yp_flag_t flags;
+ /*! Arbitrary data/callbacks. */
+ const void *misc[YP_MAX_MISC_COUNT];
+ /*! Parent item. */
+ yp_item_t *parent;
+ /*! Item group subitems (name=NULL terminated array). */
+ yp_item_t *sub_items;
+};
+
+typedef struct yp_node yp_node_t;
+struct yp_node {
+ /*! Parent node. */
+ yp_node_t *parent;
+ /*! Node item descriptor. */
+ const yp_item_t *item;
+ /*! Current binary id length. */
+ size_t id_len;
+ /*! Current binary id. */
+ uint8_t id[YP_MAX_ID_LEN];
+ /*! Current item data length. */
+ size_t data_len;
+ /*! Current item data. */
+ uint8_t data[YP_MAX_DATA_LEN];
+};
+
+/*! Context parameters for check operations. */
+typedef struct {
+ /*! Used schema. */
+ yp_item_t **schema;
+ /*! Index of the current node. */
+ size_t current;
+ /*! Node stack. */
+ yp_node_t nodes[YP_MAX_NODE_DEPTH];
+} yp_check_ctx_t;
+
+/*!
+ * Copies the schema and reinitializes dynamic parameters.
+ *
+ * \param[out] dst New copy of the schema.
+ * \param[in] src Source schema.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int yp_schema_copy(
+ yp_item_t **dst,
+ const yp_item_t *src
+);
+
+/*!
+ * Merges two schemas.
+ *
+ * \param[out] dst Merged schema.
+ * \param[in] src1 Source schema1.
+ * \param[in] src2 Source schema2.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int yp_schema_merge(
+ yp_item_t **dst,
+ const yp_item_t *src1,
+ const yp_item_t *src2
+);
+
+/*!
+ * Purges dynamic items from the schema.
+ *
+ * \param[in] schema Schema to purge.
+ */
+void yp_schema_purge_dynamic(
+ yp_item_t *schema
+);
+
+/*!
+ * Deallocates the schema.
+ *
+ * \param[in] schema A schema returned by #yp_schema_copy().
+ */
+void yp_schema_free(
+ yp_item_t *schema
+);
+
+/*!
+ * Tries to find given parent_name/name in the schema.
+ *
+ * \param[in] name Name of the item.
+ * \param[in] parent_name Name of the parent item (NULL if no parent).
+ * \param[in] schema Schema.
+ *
+ * \return Item, NULL if not found or error.
+ */
+const yp_item_t* yp_schema_find(
+ const yp_name_t *name,
+ const yp_name_t *parent_name,
+ const yp_item_t *schema
+);
+
+/*!
+ * Prepares a context for item check against the schema.
+ *
+ * \param[in] schema Schema.
+ *
+ * \return Context, NULL if error.
+ */
+yp_check_ctx_t* yp_schema_check_init(
+ yp_item_t **schema
+);
+
+/*!
+ * Checks the current parser output against the schema.
+ *
+ * If the item is correct, context also contains binary value of the item.
+ *
+ * \param[in,out] ctx Check context.
+ * \param[in] parser Parser context.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int yp_schema_check_parser(
+ yp_check_ctx_t *ctx,
+ const yp_parser_t *parser
+);
+
+/*!
+ * Checks the string data against the schema.
+ *
+ * Description: key0[id].key1 data
+ *
+ * If the item is correct, context also contains binary value of the item.
+ *
+ * \param[in,out] ctx Check context.
+ * \param[in] key0 Key0 item name.
+ * \param[in] key1 Key1 item name.
+ * \param[in] id Item identifier.
+ * \param[in] data Item data (NULL means no data provided).
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int yp_schema_check_str(
+ yp_check_ctx_t *ctx,
+ const char *key0,
+ const char *key1,
+ const char *id,
+ const char *data
+);
+
+/*!
+ * Deallocates the context.
+ *
+ * \param[in,out] ctx Check context.
+ */
+void yp_schema_check_deinit(
+ yp_check_ctx_t *ctx
+);
+
+/*! @} */
diff --git a/src/libknot/yparser/yptrafo.c b/src/libknot/yparser/yptrafo.c
new file mode 100644
index 0000000..581aa32
--- /dev/null
+++ b/src/libknot/yparser/yptrafo.c
@@ -0,0 +1,1094 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <arpa/inet.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libknot/yparser/yptrafo.h"
+#include "libknot/attribute.h"
+#include "libknot/consts.h"
+#include "libknot/dname.h"
+#include "contrib/base64.h"
+#include "contrib/ctype.h"
+#include "contrib/sockaddr.h"
+#include "contrib/wire_ctx.h"
+
+enum {
+ UNIT_BYTE = 'B',
+ UNIT_KILO = 'K',
+ UNIT_MEGA = 'M',
+ UNIT_GIGA = 'G',
+ UNIT_SEC = 's',
+ UNIT_MIN = 'm',
+ UNIT_HOUR = 'h',
+ UNIT_DAY = 'd'
+};
+
+enum {
+ MULTI_BYTE = 1,
+ MULTI_KILO = 1024,
+ MULTI_MEGA = 1024 * 1024,
+ MULTI_GIGA = 1024 * 1024 * 1024,
+ MULTI_SEC = 1,
+ MULTI_MIN = 60,
+ MULTI_HOUR = 3600,
+ MULTI_DAY = 24 * 3600
+};
+
+static wire_ctx_t copy_in(
+ wire_ctx_t *in,
+ size_t in_len,
+ char *buf,
+ size_t buf_len)
+{
+ wire_ctx_t ctx = wire_ctx_init((uint8_t *)buf, buf_len);
+ wire_ctx_write(&ctx, in->position, in_len);
+ wire_ctx_skip(in, in_len);
+ // Write the terminator.
+ wire_ctx_write_u8(&ctx, '\0');
+ wire_ctx_skip(&ctx, -1);
+ return ctx;
+}
+
+_public_
+int yp_str_to_bin(
+ YP_TXT_BIN_PARAMS)
+{
+ YP_CHECK_PARAMS_BIN;
+
+ wire_ctx_write(out, in->position, YP_LEN);
+ wire_ctx_skip(in, YP_LEN);
+ // Write string terminator.
+ wire_ctx_write_u8(out, '\0');
+
+ YP_CHECK_RET;
+}
+
+_public_
+int yp_str_to_txt(
+ YP_BIN_TXT_PARAMS)
+{
+ YP_CHECK_PARAMS_TXT;
+
+ size_t len = strlen((char *)in->position) + 1;
+
+ wire_ctx_write(out, in->position, len);
+ wire_ctx_skip(in, len);
+ // Set the terminator as a current position.
+ wire_ctx_skip(out, -1);
+
+ YP_CHECK_RET;
+}
+
+_public_
+int yp_bool_to_bin(
+ YP_TXT_BIN_PARAMS)
+{
+ YP_CHECK_PARAMS_BIN;
+
+ if (strncasecmp((char *)in->position, "on", YP_LEN) == 0 ||
+ strncasecmp((char *)in->position, "true", YP_LEN) == 0) {
+ wire_ctx_write_u8(out, 1);
+ } else if (strncasecmp((char *)in->position, "off", YP_LEN) == 0 ||
+ strncasecmp((char *)in->position, "false", YP_LEN) == 0) {
+ wire_ctx_write_u8(out, 0);
+ } else {
+ return KNOT_EINVAL;
+ }
+
+ wire_ctx_skip(in, YP_LEN);
+
+ YP_CHECK_RET;
+}
+
+_public_
+int yp_bool_to_txt(
+ YP_BIN_TXT_PARAMS)
+{
+ YP_CHECK_PARAMS_TXT;
+
+ const char *value;
+
+ switch (wire_ctx_read_u8(in)) {
+ case 0:
+ value = "off";
+ break;
+ case 1:
+ value = "on";
+ break;
+ default:
+ return KNOT_EINVAL;
+ }
+
+ int ret = snprintf((char *)out->position, wire_ctx_available(out), "%s",
+ value);
+ if (ret <= 0 || ret >= wire_ctx_available(out)) {
+ return KNOT_ESPACE;
+ }
+ wire_ctx_skip(out, ret);
+
+ YP_CHECK_RET;
+}
+
+static int remove_unit(
+ int64_t *number,
+ char unit,
+ yp_style_t style)
+{
+ int64_t multiplier = 1;
+
+ // Get the multiplier for the unit.
+ if (style & YP_SSIZE) {
+ switch (unit) {
+ case UNIT_BYTE:
+ multiplier = MULTI_BYTE;
+ break;
+ case UNIT_KILO:
+ multiplier = MULTI_KILO;
+ break;
+ case UNIT_MEGA:
+ multiplier = MULTI_MEGA;
+ break;
+ case UNIT_GIGA:
+ multiplier = MULTI_GIGA;
+ break;
+ default:
+ return KNOT_EINVAL;
+ }
+ } else if (style & YP_STIME) {
+ switch (unit) {
+ case UNIT_SEC:
+ multiplier = MULTI_SEC;
+ break;
+ case UNIT_MIN:
+ multiplier = MULTI_MIN;
+ break;
+ case UNIT_HOUR:
+ multiplier = MULTI_HOUR;
+ break;
+ case UNIT_DAY:
+ multiplier = MULTI_DAY;
+ break;
+ default:
+ return KNOT_EINVAL;
+ }
+ } else {
+ return KNOT_EINVAL;
+ }
+
+ // Check for possible number overflow.
+ if (INT64_MAX / multiplier < (*number >= 0 ? *number : -*number)) {
+ return KNOT_ERANGE;
+ }
+
+ *number *= multiplier;
+
+ return KNOT_EOK;
+}
+
+_public_
+int yp_int_to_bin(
+ YP_TXT_BIN_PARAMS,
+ int64_t min,
+ int64_t max,
+ yp_style_t style)
+{
+ YP_CHECK_PARAMS_BIN;
+
+ // Copy input string to the buffer to limit strtoll overread.
+ char buf[32];
+ wire_ctx_t buf_ctx = copy_in(in, YP_LEN, buf, sizeof(buf));
+ if (buf_ctx.error != KNOT_EOK) {
+ return buf_ctx.error;
+ }
+
+ // Parse the number.
+ char *end;
+ errno = 0;
+ int64_t number = strtoll(buf, &end, 10);
+
+ // Check for number overflow.
+ if (errno == ERANGE && (number == LLONG_MAX || number == LLONG_MIN)) {
+ return KNOT_ERANGE;
+ }
+ // Check if the whole string is invalid.
+ if ((errno != 0 && number == 0) || end == buf) {
+ return KNOT_EINVAL;
+ }
+ // Check the rest of the string for a unit.
+ if (*end != '\0') {
+ // Check just for one-char rest.
+ if (*(end + 1) != '\0') {
+ return KNOT_EINVAL;
+ }
+
+ // Try to apply a unit on the number.
+ int ret = remove_unit(&number, *end, style);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ // Check for the result number overflow.
+ if (number < min || number > max) {
+ return KNOT_ERANGE;
+ }
+
+ // Write the result.
+ wire_ctx_write_u64(out, number);
+
+ YP_CHECK_RET;
+}
+
+static void add_unit(
+ int64_t *number,
+ char *unit,
+ yp_style_t style)
+{
+ int64_t multiplier = 1;
+ char basic_unit = '\0';
+ char new_unit = '\0';
+
+ // Get the multiplier for the unit.
+ if (style & YP_SSIZE) {
+ basic_unit = UNIT_BYTE;
+
+ if (*number < MULTI_KILO) {
+ multiplier = MULTI_BYTE;
+ new_unit = UNIT_BYTE;
+ } else if (*number < MULTI_MEGA) {
+ multiplier = MULTI_KILO;
+ new_unit = UNIT_KILO;
+ } else if (*number < MULTI_GIGA) {
+ multiplier = MULTI_MEGA;
+ new_unit = UNIT_MEGA;
+ } else {
+ multiplier = MULTI_GIGA;
+ new_unit = UNIT_GIGA;
+ }
+ } else if (style & YP_STIME) {
+ basic_unit = UNIT_SEC;
+
+ if (*number < MULTI_MIN) {
+ multiplier = MULTI_SEC;
+ new_unit = UNIT_SEC;
+ } else if (*number < MULTI_HOUR) {
+ multiplier = MULTI_MIN;
+ new_unit = UNIT_MIN;
+ } else if (*number < MULTI_DAY) {
+ multiplier = MULTI_HOUR;
+ new_unit = UNIT_HOUR;
+ } else {
+ multiplier = MULTI_DAY;
+ new_unit = UNIT_DAY;
+ }
+ }
+
+ // Check for unit application without any remainder.
+ if ((*number % multiplier) == 0) {
+ *number /= multiplier;
+ *unit = new_unit;
+ } else {
+ *unit = basic_unit;
+ }
+}
+
+_public_
+int yp_int_to_txt(
+ YP_BIN_TXT_PARAMS,
+ yp_style_t style)
+{
+ YP_CHECK_PARAMS_TXT;
+
+ char unit[2] = { '\0' };
+ int64_t number = wire_ctx_read_u64(in);
+ add_unit(&number, unit, style);
+
+ int ret = snprintf((char *)out->position, wire_ctx_available(out),
+ "%"PRId64"%s", number, unit);
+ if (ret <= 0 || ret >= wire_ctx_available(out)) {
+ return KNOT_ESPACE;
+ }
+ wire_ctx_skip(out, ret);
+
+ YP_CHECK_RET;
+}
+
+static uint8_t sock_type_guess(
+ const uint8_t *str,
+ size_t len)
+{
+ size_t dots = 0;
+ size_t semicolons = 0;
+ size_t digits = 0;
+
+ // Analyze the string.
+ for (size_t i = 0; i < len; i++) {
+ if (str[i] == '.') dots++;
+ else if (str[i] == ':') semicolons++;
+ else if (is_digit(str[i])) digits++;
+ }
+
+ // Guess socket type.
+ if (semicolons >= 1) {
+ return 6;
+ } else if (semicolons == 0 && dots == 3 && digits >= 3) {
+ return 4;
+ } else {
+ return 0;
+ }
+}
+
+_public_
+int yp_addr_noport_to_bin(
+ YP_TXT_BIN_PARAMS,
+ bool allow_unix)
+{
+ YP_CHECK_PARAMS_BIN;
+
+ struct in_addr addr4;
+ struct in6_addr addr6;
+
+ uint8_t type = sock_type_guess(in->position, YP_LEN);
+
+ // Copy address to the buffer to limit inet_pton overread.
+ char buf[INET6_ADDRSTRLEN];
+ if (type == 4 || type == 6) {
+ wire_ctx_t buf_ctx = copy_in(in, YP_LEN, buf, sizeof(buf));
+ if (buf_ctx.error != KNOT_EOK) {
+ return buf_ctx.error;
+ }
+ }
+
+ // Write address type.
+ wire_ctx_write_u8(out, type);
+
+ // Write address as such.
+ if (type == 4 && inet_pton(AF_INET, buf, &addr4) == 1) {
+ wire_ctx_write(out, (uint8_t *)&(addr4.s_addr),
+ sizeof(addr4.s_addr));
+ } else if (type == 6 && inet_pton(AF_INET6, buf, &addr6) == 1) {
+ wire_ctx_write(out, (uint8_t *)&(addr6.s6_addr),
+ sizeof(addr6.s6_addr));
+ } else if (type == 0 && allow_unix) {
+ int ret = yp_str_to_bin(in, out, stop);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ } else {
+ return KNOT_EINVAL;
+ }
+
+ YP_CHECK_RET;
+}
+
+_public_
+int yp_addr_noport_to_txt(
+ YP_BIN_TXT_PARAMS)
+{
+ YP_CHECK_PARAMS_TXT;
+
+ struct in_addr addr4;
+ struct in6_addr addr6;
+
+ int ret;
+
+ switch (wire_ctx_read_u8(in)) {
+ case 0:
+ ret = yp_str_to_txt(in, out);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ break;
+ case 4:
+ wire_ctx_read(in, &(addr4.s_addr), sizeof(addr4.s_addr));
+ if (inet_ntop(AF_INET, &addr4, (char *)out->position,
+ wire_ctx_available(out)) == NULL) {
+ return KNOT_EINVAL;
+ }
+ wire_ctx_skip(out, strlen((char *)out->position));
+ break;
+ case 6:
+ wire_ctx_read(in, &(addr6.s6_addr), sizeof(addr6.s6_addr));
+ if (inet_ntop(AF_INET6, &addr6, (char *)out->position,
+ wire_ctx_available(out)) == NULL) {
+ return KNOT_EINVAL;
+ }
+ wire_ctx_skip(out, strlen((char *)out->position));
+ break;
+ default:
+ return KNOT_EINVAL;
+ }
+
+ YP_CHECK_RET;
+}
+
+_public_
+int yp_addr_to_bin(
+ YP_TXT_BIN_PARAMS)
+{
+ YP_CHECK_PARAMS_BIN;
+
+ // Check for address@port separator.
+ const uint8_t *pos = (uint8_t *)strrchr((char *)in->position, '@');
+ // Ignore out-of-bounds result.
+ if (pos >= stop) {
+ pos = NULL;
+ }
+
+ // Store address type position.
+ uint8_t *type = out->position;
+
+ // Write address (UNIX socket can't have a port).
+ int ret = yp_addr_noport_to_bin(in, out, pos, pos == NULL);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ if (pos != NULL) {
+ // Skip the separator.
+ wire_ctx_skip(in, sizeof(uint8_t));
+
+ // Write port.
+ ret = yp_int_to_bin(in, out, stop, 0, UINT16_MAX, YP_SNONE);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ } else if (*type == 4 || *type == 6) {
+ wire_ctx_write_u64(out, (uint64_t)-1);
+ }
+
+ YP_CHECK_RET;
+}
+
+_public_
+int yp_addr_to_txt(
+ YP_BIN_TXT_PARAMS)
+{
+ YP_CHECK_PARAMS_TXT;
+
+ // Store address type position.
+ uint8_t *type = in->position;
+
+ // Write address.
+ int ret = yp_addr_noport_to_txt(in, out);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Write port.
+ if (*type == 4 || *type == 6) {
+ int64_t port = wire_ctx_read_u64(in);
+
+ if (port >= 0) {
+ // Write separator.
+ wire_ctx_write_u8(out, '@');
+
+ // Write port.
+ wire_ctx_skip(in, -sizeof(uint64_t));
+ int ret = yp_int_to_txt(in, out, YP_SNONE);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+ }
+
+ YP_CHECK_RET;
+}
+
+_public_
+int yp_addr_range_to_bin(
+ YP_TXT_BIN_PARAMS)
+{
+ YP_CHECK_PARAMS_BIN;
+
+ // Format: 0 - single address, 1 - address prefix, 2 - address range.
+ uint8_t format = 0;
+
+ // Check for the "addr/mask" format.
+ const uint8_t *pos = (uint8_t *)strchr((char *)in->position, '/');
+ if (pos >= stop) {
+ pos = NULL;
+ }
+
+ if (pos != NULL) {
+ format = 1;
+ } else {
+ // Check for the "addr1-addr2" format.
+ pos = (uint8_t *)strchr((char *)in->position, '-');
+ if (pos >= stop) {
+ pos = NULL;
+ }
+ if (pos != NULL) {
+ format = 2;
+ }
+ }
+
+ // Store address1 type position.
+ uint8_t *type1 = out->position;
+
+ // Write the first address.
+ int ret = yp_addr_noport_to_bin(in, out, pos, false);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ wire_ctx_write_u8(out, format);
+
+ switch (format) {
+ case 1:
+ // Skip the separator.
+ wire_ctx_skip(in, sizeof(uint8_t));
+
+ // Write the prefix length.
+ ret = yp_int_to_bin(in, out, stop, 0, (*type1 == 4) ? 32 : 128,
+ YP_SNONE);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ break;
+ case 2:
+ // Skip the separator.
+ wire_ctx_skip(in, sizeof(uint8_t));
+
+ // Store address2 type position.
+ uint8_t *type2 = out->position;
+
+ // Write the second address.
+ ret = yp_addr_noport_to_bin(in, out, stop, false);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Check for address mismatch.
+ if (*type1 != *type2) {
+ return KNOT_EINVAL;
+ }
+ break;
+ default:
+ break;
+ }
+
+ YP_CHECK_RET;
+}
+
+_public_
+int yp_addr_range_to_txt(
+ YP_BIN_TXT_PARAMS)
+{
+ YP_CHECK_PARAMS_TXT;
+
+ // Write the first address.
+ int ret = yp_addr_noport_to_txt(in, out);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ uint8_t format = wire_ctx_read_u8(in);
+
+ switch (format) {
+ case 1:
+ // Write the separator.
+ wire_ctx_write_u8(out, '/');
+
+ // Write the prefix length.
+ ret = yp_int_to_txt(in, out, YP_SNONE);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ break;
+ case 2:
+ // Write the separator.
+ wire_ctx_write_u8(out, '-');
+
+ // Write the second address.
+ ret = yp_addr_noport_to_txt(in, out);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ break;
+ default:
+ break;
+ }
+
+ YP_CHECK_RET;
+}
+
+_public_
+int yp_option_to_bin(
+ YP_TXT_BIN_PARAMS,
+ const knot_lookup_t *opts)
+{
+ YP_CHECK_PARAMS_BIN;
+
+ while (opts->name != NULL) {
+ if (YP_LEN == strlen(opts->name) &&
+ strncasecmp((char *)in->position, opts->name, YP_LEN) == 0) {
+ wire_ctx_write_u8(out, opts->id);
+ wire_ctx_skip(in, YP_LEN);
+ YP_CHECK_RET;
+ }
+ opts++;
+ }
+
+ return KNOT_EINVAL;
+}
+
+_public_
+int yp_option_to_txt(
+ YP_BIN_TXT_PARAMS,
+ const knot_lookup_t *opts)
+{
+ uint8_t id = wire_ctx_read_u8(in);
+
+ while (opts->name != NULL) {
+ if (id == opts->id) {
+ int ret = snprintf((char *)out->position,
+ wire_ctx_available(out), "%s",
+ opts->name);
+ if (ret <= 0 || ret >= wire_ctx_available(out)) {
+ return KNOT_ESPACE;
+ }
+ wire_ctx_skip(out, ret);
+ YP_CHECK_RET;
+ }
+ opts++;
+ }
+
+ return KNOT_EINVAL;
+}
+
+_public_
+int yp_dname_to_bin(
+ YP_TXT_BIN_PARAMS)
+{
+ YP_CHECK_PARAMS_BIN;
+
+ // Copy dname string to the buffer to limit dname_from_str overread.
+ char buf[KNOT_DNAME_TXT_MAXLEN + 1];
+ wire_ctx_t buf_ctx = copy_in(in, YP_LEN, buf, sizeof(buf));
+ if (buf_ctx.error != KNOT_EOK) {
+ return buf_ctx.error;
+ }
+
+ // Convert the dname.
+ knot_dname_t *dname = knot_dname_from_str(out->position, buf,
+ wire_ctx_available(out));
+ if (dname == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ // Check the result and count the length.
+ int ret = knot_dname_wire_check(out->position,
+ out->position + wire_ctx_available(out),
+ NULL);
+ if (ret <= 0) {
+ return KNOT_EINVAL;
+ }
+
+ // Convert the result to lower case.
+ knot_dname_to_lower(out->position);
+
+ wire_ctx_skip(out, ret);
+
+ YP_CHECK_RET;
+}
+
+_public_
+int yp_dname_to_txt(
+ YP_BIN_TXT_PARAMS)
+{
+ YP_CHECK_PARAMS_TXT;
+
+ char *name = knot_dname_to_str((char *)out->position, in->position,
+ wire_ctx_available(out));
+ if (name == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ wire_ctx_skip(out, strlen((char *)out->position));
+
+ YP_CHECK_RET;
+}
+
+static int hex_to_num(char hex) {
+ if (hex >= '0' && hex <= '9') return hex - '0';
+ if (hex >= 'a' && hex <= 'f') return hex - 'a' + 10;
+ if (hex >= 'A' && hex <= 'F') return hex - 'A' + 10;
+ return -1;
+}
+
+_public_
+int yp_hex_to_bin(
+ YP_TXT_BIN_PARAMS)
+{
+ YP_CHECK_PARAMS_BIN;
+
+ // Check for hex notation (leading "0x").
+ if (wire_ctx_available(in) >= 2 &&
+ in->position[0] == '0' && in->position[1] == 'x') {
+ wire_ctx_skip(in, 2);
+
+ if (YP_LEN % 2 != 0) {
+ return KNOT_EINVAL;
+ }
+
+ // Write data length.
+ wire_ctx_write_u16(out, YP_LEN / 2);
+
+ // Decode hex string.
+ while (YP_LEN > 0) {
+ uint8_t buf[2] = { 0 };
+ wire_ctx_read(in, buf, sizeof(buf));
+
+ if (!is_xdigit(buf[0]) ||
+ !is_xdigit(buf[1])) {
+ return KNOT_EINVAL;
+ }
+
+ wire_ctx_write_u8(out, 16 * hex_to_num(buf[0]) +
+ hex_to_num(buf[1]));
+ }
+ } else {
+ // Write data length.
+ wire_ctx_write_u16(out, YP_LEN);
+
+ // Write textual string (without terminator).
+ wire_ctx_write(out, in->position, YP_LEN);
+ wire_ctx_skip(in, YP_LEN);
+ }
+
+ YP_CHECK_RET;
+}
+
+_public_
+int yp_hex_to_txt(
+ YP_BIN_TXT_PARAMS)
+{
+ YP_CHECK_PARAMS_TXT;
+
+ size_t len = wire_ctx_read_u16(in);
+
+ bool printable = true;
+
+ // Check for printable string.
+ for (size_t i = 0; i < len; i++) {
+ if (!is_print(in->position[i])) {
+ printable = false;
+ break;
+ }
+ }
+
+ if (printable) {
+ wire_ctx_write(out, in->position, len);
+ wire_ctx_skip(in, len);
+ } else {
+ const char *prefix = "0x";
+ const char *hex = "0123456789ABCDEF";
+
+ // Write hex prefix.
+ wire_ctx_write(out, (uint8_t *)prefix, strlen(prefix));
+
+ // Encode data to hex.
+ for (size_t i = 0; i < len; i++) {
+ uint8_t bin = wire_ctx_read_u8(in);
+ wire_ctx_write_u8(out, hex[bin / 16]);
+ wire_ctx_write_u8(out, hex[bin % 16]);
+ }
+ }
+
+ // Write the terminator.
+ wire_ctx_write_u8(out, '\0');
+ wire_ctx_skip(out, -1);
+
+ YP_CHECK_RET;
+}
+
+_public_
+int yp_base64_to_bin(
+ YP_TXT_BIN_PARAMS)
+{
+ YP_CHECK_PARAMS_BIN;
+
+ // Reserve some space for data length.
+ wire_ctx_skip(out, sizeof(uint16_t));
+
+ int ret = base64_decode(in->position, YP_LEN, out->position,
+ wire_ctx_available(out));
+ if (ret < 0) {
+ return ret;
+ }
+ wire_ctx_skip(in, YP_LEN);
+
+ // Write the data length.
+ wire_ctx_skip(out, -sizeof(uint16_t));
+ wire_ctx_write_u16(out, ret);
+ wire_ctx_skip(out, ret);
+
+ YP_CHECK_RET;
+}
+
+_public_
+int yp_base64_to_txt(
+ YP_BIN_TXT_PARAMS)
+{
+ YP_CHECK_PARAMS_TXT;
+
+ // Read the data length.
+ uint16_t len = wire_ctx_read_u16(in);
+
+ int ret = base64_encode(in->position, len, out->position,
+ wire_ctx_available(out));
+ if (ret < 0) {
+ return ret;
+ }
+ wire_ctx_skip(out, ret);
+
+ // Write the terminator.
+ wire_ctx_write_u8(out, '\0');
+ wire_ctx_skip(out, -1);
+
+ YP_CHECK_RET;
+}
+
+_public_
+int yp_item_to_bin(
+ const yp_item_t *item,
+ const char *txt,
+ size_t txt_len,
+ uint8_t *bin,
+ size_t *bin_len)
+{
+ if (item == NULL || txt == NULL || bin == NULL || bin_len == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ wire_ctx_t in = wire_ctx_init_const((const uint8_t *)txt, txt_len);
+ wire_ctx_t out = wire_ctx_init(bin, *bin_len);
+
+ int ret;
+ size_t ref_len;
+
+ switch (item->type) {
+ case YP_TINT:
+ ret = yp_int_to_bin(&in, &out, NULL, item->var.i.min,
+ item->var.i.max, item->var.i.unit);
+ break;
+ case YP_TBOOL:
+ ret = yp_bool_to_bin(&in, &out, NULL);
+ break;
+ case YP_TOPT:
+ ret = yp_option_to_bin(&in, &out, NULL, item->var.o.opts);
+ break;
+ case YP_TSTR:
+ ret = yp_str_to_bin(&in, &out, NULL);
+ break;
+ case YP_TADDR:
+ ret = yp_addr_to_bin(&in, &out, NULL);
+ break;
+ case YP_TNET:
+ ret = yp_addr_range_to_bin(&in, &out, NULL);
+ break;
+ case YP_TDNAME:
+ ret = yp_dname_to_bin(&in, &out, NULL);
+ break;
+ case YP_THEX:
+ ret = yp_hex_to_bin(&in, &out, NULL);
+ break;
+ case YP_TB64:
+ ret = yp_base64_to_bin(&in, &out, NULL);
+ break;
+ case YP_TDATA:
+ ret = item->var.d.to_bin(&in, &out, NULL);
+ break;
+ case YP_TREF:
+ ref_len = wire_ctx_available(&out);
+ ret = yp_item_to_bin(item->var.r.ref->var.g.id,
+ (char *)in.position, wire_ctx_available(&in),
+ out.position, &ref_len);
+ wire_ctx_skip(&out, ref_len);
+ break;
+ default:
+ ret = KNOT_EOK;
+ }
+
+ if (ret != KNOT_EOK) {
+ return ret;
+ } else if (in.error != KNOT_EOK) {
+ return in.error;
+ } else if (out.error != KNOT_EOK) {
+ return out.error;
+ }
+
+ *bin_len = wire_ctx_offset(&out);
+
+ return KNOT_EOK;
+}
+
+_public_
+int yp_item_to_txt(
+ const yp_item_t *item,
+ const uint8_t *bin,
+ size_t bin_len,
+ char *txt,
+ size_t *txt_len,
+ yp_style_t style)
+{
+ if (item == NULL || bin == NULL || txt == NULL || txt_len == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ wire_ctx_t in = wire_ctx_init_const(bin, bin_len);
+ wire_ctx_t out = wire_ctx_init((uint8_t *)txt, *txt_len);
+
+ // Write leading quote.
+ if (!(style & YP_SNOQUOTE)) {
+ wire_ctx_write_u8(&out, '"');
+ }
+
+ int ret;
+ size_t ref_len;
+
+ switch (item->type) {
+ case YP_TINT:
+ ret = yp_int_to_txt(&in, &out, item->var.i.unit & style);
+ break;
+ case YP_TBOOL:
+ ret = yp_bool_to_txt(&in, &out);
+ break;
+ case YP_TOPT:
+ ret = yp_option_to_txt(&in, &out, item->var.o.opts);
+ break;
+ case YP_TSTR:
+ ret = yp_str_to_txt(&in, &out);
+ break;
+ case YP_TADDR:
+ ret = yp_addr_to_txt(&in, &out);
+ break;
+ case YP_TNET:
+ ret = yp_addr_range_to_txt(&in, &out);
+ break;
+ case YP_TDNAME:
+ ret = yp_dname_to_txt(&in, &out);
+ break;
+ case YP_THEX:
+ ret = yp_hex_to_txt(&in, &out);
+ break;
+ case YP_TB64:
+ ret = yp_base64_to_txt(&in, &out);
+ break;
+ case YP_TDATA:
+ ret = item->var.d.to_txt(&in, &out);
+ break;
+ case YP_TREF:
+ ref_len = wire_ctx_available(&out);
+ ret = yp_item_to_txt(item->var.r.ref->var.g.id,
+ in.position, wire_ctx_available(&in),
+ (char *)out.position,
+ &ref_len, style | YP_SNOQUOTE);
+ wire_ctx_skip(&out, ref_len);
+ break;
+ default:
+ ret = KNOT_EOK;
+ }
+
+ // Write trailing quote.
+ if (!(style & YP_SNOQUOTE)) {
+ wire_ctx_write_u8(&out, '"');
+ }
+
+ // Write string terminator.
+ wire_ctx_write_u8(&out, '\0');
+ wire_ctx_skip(&out, -1);
+
+ if (ret != KNOT_EOK) {
+ return ret;
+ } else if (in.error != KNOT_EOK) {
+ return in.error;
+ } else if (out.error != KNOT_EOK) {
+ return out.error;
+ }
+
+ *txt_len = wire_ctx_offset(&out);
+
+ return KNOT_EOK;
+}
+
+_public_
+struct sockaddr_storage yp_addr_noport(
+ const uint8_t *data)
+{
+ struct sockaddr_storage ss = { AF_UNSPEC };
+
+ // Read address type.
+ uint8_t type = *data;
+ data += sizeof(type);
+
+ // Set address.
+ switch (type) {
+ case 0:
+ sockaddr_set(&ss, AF_UNIX, (char *)data, 0);
+ break;
+ case 4:
+ sockaddr_set_raw(&ss, AF_INET, data,
+ sizeof(((struct in_addr *)NULL)->s_addr));
+ break;
+ case 6:
+ sockaddr_set_raw(&ss, AF_INET6, data,
+ sizeof(((struct in6_addr *)NULL)->s6_addr));
+ break;
+ }
+
+ return ss;
+}
+
+_public_
+struct sockaddr_storage yp_addr(
+ const uint8_t *data,
+ bool *no_port)
+{
+ struct sockaddr_storage ss = yp_addr_noport(data);
+
+ size_t addr_len;
+
+ // Get binary address length.
+ switch (ss.ss_family) {
+ case AF_INET:
+ addr_len = sizeof(((struct in_addr *)NULL)->s_addr);
+ break;
+ case AF_INET6:
+ addr_len = sizeof(((struct in6_addr *)NULL)->s6_addr);
+ break;
+ default:
+ addr_len = 0;
+ *no_port = true;
+ }
+
+ if (addr_len > 0) {
+ int64_t port = knot_wire_read_u64(data + sizeof(uint8_t) + addr_len);
+ if (port >= 0) {
+ sockaddr_port_set((struct sockaddr *)&ss, port);
+ *no_port = false;
+ } else {
+ *no_port = true;
+ }
+ }
+
+ return ss;
+}
diff --git a/src/libknot/yparser/yptrafo.h b/src/libknot/yparser/yptrafo.h
new file mode 100644
index 0000000..59fd4c8
--- /dev/null
+++ b/src/libknot/yparser/yptrafo.h
@@ -0,0 +1,310 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*!
+ * \file
+ *
+ * \brief Value transformations for Yparser.
+ *
+ * \addtogroup yparser
+ * @{
+ */
+
+#pragma once
+
+#include "libknot/yparser/ypschema.h"
+#include "libknot/lookup.h"
+#include "libknot/wire.h"
+
+/*!
+ * Transforms textual item value to binary form.
+ *
+ * \param[in] item Schema item to transform.
+ * \param[in] txt Value to transform.
+ * \param[in] txt_len Value length.
+ * \param[out] bin Output buffer.
+ * \param[in, out] bin_len Output buffer length, output length.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int yp_item_to_bin(
+ const yp_item_t *item,
+ const char *txt,
+ size_t txt_len,
+ uint8_t *bin,
+ size_t *bin_len
+);
+
+/*!
+ * Transforms binary item value to textual form.
+ *
+ * \param[in] item Schema item to transform.
+ * \param[in] bin Value to transform.
+ * \param[in] bin_len Value length.
+ * \param[out] txt Output buffer.
+ * \param[in, out] txt_len Output buffer length, output length.
+ * \param[in] style Value style.
+ *
+ * \return Error code, KNOT_EOK if success.
+ */
+int yp_item_to_txt(
+ const yp_item_t *item,
+ const uint8_t *bin,
+ size_t bin_len,
+ char *txt,
+ size_t *txt_len,
+ yp_style_t style
+);
+
+/*!
+ * Converts binary value to string pointer.
+ *
+ * \param[in] data Binary value to transform.
+ *
+ * \return String pointer.
+ */
+inline static const char* yp_str(
+ const uint8_t *data)
+{
+ return (const char *)data;
+}
+
+/*!
+ * Converts binary value to boolean value.
+ *
+ * \param[in] data Binary value to transform.
+ *
+ * \return Boolean value.
+ */
+inline static bool yp_bool(
+ const uint8_t *data)
+{
+ return (data[0] == 0) ? false : true;
+}
+
+/*!
+ * Converts binary value to integer value.
+ *
+ * \param[in] data Binary value to transform.
+ *
+ * \return Integer value.
+ */
+inline static int64_t yp_int(
+ const uint8_t *data)
+{
+ return (int64_t)knot_wire_read_u64(data);
+}
+
+/*!
+ * Converts binary value to address value.
+ *
+ * \param[in] data Binary value to transform.
+ *
+ * \return Address value.
+ */
+struct sockaddr_storage yp_addr_noport(
+ const uint8_t *data
+);
+
+/*!
+ * Converts binary value to address value with an optional port.
+ *
+ * \param[in] data Binary value to transform.
+ * \param[out] no_port No port indicator.
+ *
+ * \return Address value.
+ */
+struct sockaddr_storage yp_addr(
+ const uint8_t *data,
+ bool *no_port
+);
+
+/*!
+ * Converts binary value to option value.
+ *
+ * \param[in] data Binary value to transform.
+ *
+ * \return Unsigned value.
+ */
+inline static unsigned yp_opt(
+ const uint8_t *data)
+{
+ return (unsigned)data[0];
+}
+
+/*!
+ * Converts binary value to dname pointer.
+ *
+ * \param[in] data Binary value to transform.
+ *
+ * \return Dname pointer.
+ */
+inline static const uint8_t* yp_dname(
+ const uint8_t *data)
+{
+ return data;
+}
+
+/*!
+ * Converts binary value to data pointer.
+ *
+ * Applies to all data types with 2-byte length prefix (YP_THEX, YP_TB64).
+ *
+ * \param[in] data Binary value to transform.
+ *
+ * \return Data pointer.
+ */
+inline static const uint8_t* yp_bin(
+ const uint8_t *data)
+{
+ return data + 2;
+}
+
+/*!
+ * Gets binary value length.
+ *
+ * Applies to all data types with 2-byte length prefix (YP_THEX, YP_TB64).
+ *
+ * \param[in] data Binary value to transform.
+ *
+ * \return Data length.
+ */
+inline static size_t yp_bin_len(
+ const uint8_t *data)
+{
+ return knot_wire_read_u16(data);
+}
+
+/*!
+ * \brief Helper macros for conversion functions.
+ */
+
+#define YP_CHECK_CTX \
+ if (in->error != KNOT_EOK) { \
+ return in->error; \
+ } else if (out->error != KNOT_EOK) { \
+ return out->error; \
+ } \
+
+#define YP_CHECK_STOP \
+ if (stop != NULL) { \
+ assert(stop <= in->position + wire_ctx_available(in)); \
+ } else { \
+ stop = in->position + wire_ctx_available(in); \
+ }
+
+#define YP_LEN (stop - in->position)
+
+#define YP_CHECK_PARAMS_BIN \
+ YP_CHECK_CTX YP_CHECK_STOP
+
+#define YP_CHECK_PARAMS_TXT \
+ YP_CHECK_CTX
+
+#define YP_CHECK_RET \
+ YP_CHECK_CTX return KNOT_EOK;
+
+/*!
+ * \brief Conversion functions for basic types.
+ */
+
+int yp_str_to_bin(
+ YP_TXT_BIN_PARAMS
+);
+
+int yp_str_to_txt(
+ YP_BIN_TXT_PARAMS
+);
+
+int yp_bool_to_bin(
+ YP_TXT_BIN_PARAMS
+);
+
+int yp_bool_to_txt(
+ YP_BIN_TXT_PARAMS
+);
+
+int yp_int_to_bin(
+ YP_TXT_BIN_PARAMS,
+ int64_t min,
+ int64_t max,
+ yp_style_t style
+);
+
+int yp_int_to_txt(
+ YP_BIN_TXT_PARAMS,
+ yp_style_t style
+);
+
+int yp_addr_noport_to_bin(
+ YP_TXT_BIN_PARAMS,
+ bool allow_unix
+);
+
+int yp_addr_noport_to_txt(
+ YP_BIN_TXT_PARAMS
+);
+
+int yp_addr_to_bin(
+ YP_TXT_BIN_PARAMS
+);
+
+int yp_addr_to_txt(
+ YP_BIN_TXT_PARAMS
+);
+
+int yp_addr_range_to_bin(
+ YP_TXT_BIN_PARAMS
+);
+
+int yp_addr_range_to_txt(
+ YP_BIN_TXT_PARAMS
+);
+
+int yp_option_to_bin(
+ YP_TXT_BIN_PARAMS,
+ const struct knot_lookup *opts
+);
+
+int yp_option_to_txt(
+ YP_BIN_TXT_PARAMS,
+ const struct knot_lookup *opts
+);
+
+int yp_dname_to_bin(
+ YP_TXT_BIN_PARAMS
+);
+
+int yp_dname_to_txt(
+ YP_BIN_TXT_PARAMS
+);
+
+int yp_hex_to_bin(
+ YP_TXT_BIN_PARAMS
+);
+
+int yp_hex_to_txt(
+ YP_BIN_TXT_PARAMS
+);
+
+int yp_base64_to_bin(
+ YP_TXT_BIN_PARAMS
+);
+
+int yp_base64_to_txt(
+ YP_BIN_TXT_PARAMS
+);
+
+/*! @} */
diff --git a/src/libzscanner.pc.in b/src/libzscanner.pc.in
new file mode 100644
index 0000000..35a8dab
--- /dev/null
+++ b/src/libzscanner.pc.in
@@ -0,0 +1,13 @@
+prefix=@prefix@
+exec_prefix=@prefix@
+libdir=@libdir@
+includedir=@includedir@
+soname=@libzscanner_SONAME@
+
+Name: libzscanner
+Description: Knot DNS Zone Parsing library
+URL: https://www.knot-dns.cz
+Version: @PACKAGE_VERSION@
+Libs: -L${libdir} -lzscanner
+Libs.private: -lm
+Cflags: -I${includedir}
diff --git a/src/libzscanner/Makefile.inc b/src/libzscanner/Makefile.inc
new file mode 100644
index 0000000..1a03536
--- /dev/null
+++ b/src/libzscanner/Makefile.inc
@@ -0,0 +1,39 @@
+lib_LTLIBRARIES += libzscanner.la
+pkgconfig_DATA += libzscanner.pc
+
+libzscanner_la_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAG_VISIBILITY)
+libzscanner_la_LDFLAGS = $(AM_LDFLAGS) $(libzscanner_VERSION_INFO) $(LDFLAG_EXCLUDE_LIBS)
+libzscanner_la_LIBADD = $(math_LIBS)
+
+EXTRA_DIST += \
+ libzscanner/scanner.rl \
+ libzscanner/scanner_body.rl \
+ libzscanner/scanner.c.g2 \
+ libzscanner/scanner.c.t0
+include_libzscannerdir = $(includedir)/libzscanner
+
+include_libzscanner_HEADERS = \
+ libzscanner/error.h \
+ libzscanner/scanner.h \
+ libzscanner/version.h
+
+libzscanner_la_SOURCES = \
+ libzscanner/error.c \
+ libzscanner/functions.h \
+ libzscanner/functions.c \
+ $(include_libzscanner_HEADERS)
+
+BUILT_SOURCES += libzscanner/scanner.c
+CLEANFILES += libzscanner/scanner.c
+
+nodist_libzscanner_la_SOURCES = \
+ libzscanner/scanner.c
+
+if FAST_PARSER
+libzscanner/scanner.c: libzscanner/scanner.c.g2
+ @cp $(srcdir)/$@.g2 $@
+ @echo "NOTE: Compilation of scanner.c can take several minutes!"
+else
+libzscanner/scanner.c: libzscanner/scanner.c.t0
+ @cp $(srcdir)/$@.t0 $@
+endif
diff --git a/src/libzscanner/error.c b/src/libzscanner/error.c
new file mode 100644
index 0000000..da487fb
--- /dev/null
+++ b/src/libzscanner/error.c
@@ -0,0 +1,188 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+
+#include "libzscanner/error.h"
+
+typedef struct {
+ int code;
+ const char *text;
+ const char *code_name;
+} err_table_t;
+
+#define ERR_ITEM(code, text) { code, text, #code }
+
+static const err_table_t err_msgs[] = {
+ ERR_ITEM( ZS_OK,
+ "ok" ),
+ ERR_ITEM( ZS_EINVAL,
+ "invalid parameter" ),
+ ERR_ITEM( ZS_ENOMEM,
+ "not enough memory" ),
+ ERR_ITEM( ZS_FILE_OPEN,
+ "file open error" ),
+ ERR_ITEM( ZS_FILE_INVALID,
+ "invalid file" ),
+ ERR_ITEM( ZS_DOS_NEWLINE,
+ "unsupported CRLF newline, remove CR bytes" ),
+ ERR_ITEM( ZS_UNCOVERED_STATE,
+ "general scanner error" ),
+ ERR_ITEM( ZS_UNCLOSED_MULTILINE,
+ "unclosed last multiline block" ),
+ ERR_ITEM( ZS_LEFT_PARENTHESIS,
+ "too many left parentheses" ),
+ ERR_ITEM( ZS_RIGHT_PARENTHESIS,
+ "too many right parentheses" ),
+ ERR_ITEM( ZS_UNSUPPORTED_TYPE,
+ "unsupported record type" ),
+ ERR_ITEM( ZS_BAD_PREVIOUS_OWNER,
+ "previous owner is invalid" ),
+ ERR_ITEM( ZS_BAD_DNAME_CHAR,
+ "invalid domain name character" ),
+ ERR_ITEM( ZS_BAD_OWNER,
+ "owner is invalid" ),
+ ERR_ITEM( ZS_LABEL_OVERFLOW,
+ "maximal domain name label length has exceeded" ),
+ ERR_ITEM( ZS_DNAME_OVERFLOW,
+ "maximal domain name length has exceeded" ),
+ ERR_ITEM( ZS_BAD_NUMBER,
+ "invalid number" ),
+ ERR_ITEM( ZS_NUMBER64_OVERFLOW,
+ "number is too big" ),
+ ERR_ITEM( ZS_NUMBER32_OVERFLOW,
+ "number is bigger than 32 bits" ),
+ ERR_ITEM( ZS_NUMBER16_OVERFLOW,
+ "number is bigger than 16 bits" ),
+ ERR_ITEM( ZS_NUMBER8_OVERFLOW,
+ "number is bigger than 8 bits" ),
+ ERR_ITEM( ZS_FLOAT_OVERFLOW,
+ "float number overflow" ),
+ ERR_ITEM( ZS_RDATA_OVERFLOW,
+ "maximal record data length has exceeded" ),
+ ERR_ITEM( ZS_ITEM_OVERFLOW,
+ "maximal item length has exceeded" ),
+ ERR_ITEM( ZS_BAD_ADDRESS_CHAR,
+ "invalid address character" ),
+ ERR_ITEM( ZS_BAD_IPV4,
+ "invalid IPv4 address" ),
+ ERR_ITEM( ZS_BAD_IPV6,
+ "invalid IPv6 address" ),
+ ERR_ITEM( ZS_BAD_GATEWAY,
+ "invalid gateway" ),
+ ERR_ITEM( ZS_BAD_GATEWAY_KEY,
+ "invalid gateway key" ),
+ ERR_ITEM( ZS_BAD_APL,
+ "invalid address prefix list" ),
+ ERR_ITEM( ZS_BAD_RDATA,
+ "invalid record data" ),
+ ERR_ITEM( ZS_BAD_HEX_RDATA,
+ "invalid record data in hex format" ),
+ ERR_ITEM( ZS_BAD_HEX_CHAR,
+ "invalid hexadecimal character" ),
+ ERR_ITEM( ZS_BAD_BASE64_CHAR,
+ "invalid Base64 character" ),
+ ERR_ITEM( ZS_BAD_BASE32HEX_CHAR,
+ "invalid Base32hex character" ),
+ ERR_ITEM( ZS_BAD_REST,
+ "unexpected data" ),
+ ERR_ITEM( ZS_BAD_TIMESTAMP_CHAR,
+ "invalid timestamp character" ),
+ ERR_ITEM( ZS_BAD_TIMESTAMP_LENGTH,
+ "invalid timestamp length" ),
+ ERR_ITEM( ZS_BAD_TIMESTAMP,
+ "invalid timestamp" ),
+ ERR_ITEM( ZS_BAD_DATE,
+ "invalid date" ),
+ ERR_ITEM( ZS_BAD_TIME,
+ "invalid time" ),
+ ERR_ITEM( ZS_BAD_TIME_UNIT,
+ "invalid time unit" ),
+ ERR_ITEM( ZS_BAD_BITMAP,
+ "invalid bitmap" ),
+ ERR_ITEM( ZS_TEXT_OVERFLOW,
+ "text is too long" ),
+ ERR_ITEM( ZS_BAD_TEXT_CHAR,
+ "invalid text character" ),
+ ERR_ITEM( ZS_BAD_TEXT,
+ "invalid text string" ),
+ ERR_ITEM( ZS_BAD_DIRECTIVE,
+ "invalid directive" ),
+ ERR_ITEM( ZS_BAD_TTL,
+ "invalid zone TTL" ),
+ ERR_ITEM( ZS_BAD_ORIGIN,
+ "invalid FQDN zone origin" ),
+ ERR_ITEM( ZS_BAD_INCLUDE_FILENAME,
+ "invalid filename in include directive" ),
+ ERR_ITEM( ZS_BAD_INCLUDE_ORIGIN,
+ "invalid origin in include directive" ),
+ ERR_ITEM( ZS_UNPROCESSED_INCLUDE,
+ "include file processing error" ),
+ ERR_ITEM( ZS_UNOPENED_INCLUDE,
+ "include file opening error" ),
+ ERR_ITEM( ZS_BAD_RDATA_LENGTH,
+ "the rdata length statement is incorrect" ),
+ ERR_ITEM( ZS_CANNOT_TEXT_DATA,
+ "unable to process text form for this type" ),
+ ERR_ITEM( ZS_BAD_LOC_DATA,
+ "invalid zone location data" ),
+ ERR_ITEM( ZS_UNKNOWN_BLOCK,
+ "unknown rdata block" ),
+ ERR_ITEM( ZS_BAD_ALGORITHM,
+ "invalid algorithm" ),
+ ERR_ITEM( ZS_BAD_CERT_TYPE,
+ "invalid certificate type" ),
+ ERR_ITEM( ZS_BAD_EUI_LENGTH,
+ "invalid EUI length" ),
+ ERR_ITEM( ZS_BAD_L64_LENGTH,
+ "invalid 64-bit locator" ),
+ ERR_ITEM( ZS_BAD_CHAR_COLON,
+ "missing colon character" ),
+ ERR_ITEM( ZS_BAD_CHAR_DASH,
+ "missing dash character" ),
+
+ ERR_ITEM( 0, NULL ) // Terminator
+};
+
+__attribute__((visibility("default")))
+const char* zs_strerror(const int code)
+{
+ const err_table_t *err = err_msgs;
+
+ while (err->text != NULL) {
+ if (err->code == code) {
+ return err->text;
+ }
+ err++;
+ }
+
+ return NULL;
+}
+
+__attribute__((visibility("default")))
+const char* zs_errorname(const int code)
+{
+ const err_table_t *err = err_msgs;
+
+ while (err->text != NULL) {
+ if (err->code == code) {
+ return err->code_name;
+ }
+ err++;
+ }
+
+ return NULL;
+}
diff --git a/src/libzscanner/error.h b/src/libzscanner/error.h
new file mode 100644
index 0000000..c547127
--- /dev/null
+++ b/src/libzscanner/error.h
@@ -0,0 +1,111 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief Error codes and handling.
+ *
+ * \addtogroup zone_scanner
+ * @{
+ */
+
+#pragma once
+
+enum err_codes {
+ ZS_OK = 0,
+ ZS_EINVAL = -1000,
+ ZS_ENOMEM,
+ ZS_FILE_OPEN,
+ ZS_FILE_INVALID,
+ ZS_DOS_NEWLINE,
+ ZS_UNCOVERED_STATE,
+ ZS_UNCLOSED_MULTILINE,
+ ZS_LEFT_PARENTHESIS,
+ ZS_RIGHT_PARENTHESIS,
+ ZS_UNSUPPORTED_TYPE,
+ ZS_BAD_PREVIOUS_OWNER,
+ ZS_BAD_DNAME_CHAR,
+ ZS_BAD_OWNER,
+ ZS_LABEL_OVERFLOW,
+ ZS_DNAME_OVERFLOW,
+ ZS_BAD_NUMBER,
+ ZS_NUMBER64_OVERFLOW,
+ ZS_NUMBER32_OVERFLOW,
+ ZS_NUMBER16_OVERFLOW,
+ ZS_NUMBER8_OVERFLOW,
+ ZS_FLOAT_OVERFLOW,
+ ZS_RDATA_OVERFLOW,
+ ZS_ITEM_OVERFLOW,
+ ZS_BAD_ADDRESS_CHAR,
+ ZS_BAD_IPV4,
+ ZS_BAD_IPV6,
+ ZS_BAD_GATEWAY,
+ ZS_BAD_GATEWAY_KEY,
+ ZS_BAD_APL,
+ ZS_BAD_RDATA,
+ ZS_BAD_HEX_RDATA,
+ ZS_BAD_HEX_CHAR,
+ ZS_BAD_BASE64_CHAR,
+ ZS_BAD_BASE32HEX_CHAR,
+ ZS_BAD_REST,
+ ZS_BAD_TIMESTAMP_CHAR,
+ ZS_BAD_TIMESTAMP_LENGTH,
+ ZS_BAD_TIMESTAMP,
+ ZS_BAD_DATE,
+ ZS_BAD_TIME,
+ ZS_BAD_TIME_UNIT,
+ ZS_BAD_BITMAP,
+ ZS_TEXT_OVERFLOW,
+ ZS_BAD_TEXT_CHAR,
+ ZS_BAD_TEXT,
+ ZS_BAD_DIRECTIVE,
+ ZS_BAD_TTL,
+ ZS_BAD_ORIGIN,
+ ZS_BAD_INCLUDE_FILENAME,
+ ZS_BAD_INCLUDE_ORIGIN,
+ ZS_UNPROCESSED_INCLUDE,
+ ZS_UNOPENED_INCLUDE,
+ ZS_BAD_RDATA_LENGTH,
+ ZS_CANNOT_TEXT_DATA,
+ ZS_BAD_LOC_DATA,
+ ZS_UNKNOWN_BLOCK,
+ ZS_BAD_ALGORITHM,
+ ZS_BAD_CERT_TYPE,
+ ZS_BAD_EUI_LENGTH,
+ ZS_BAD_L64_LENGTH,
+ ZS_BAD_CHAR_COLON,
+ ZS_BAD_CHAR_DASH
+};
+
+/*!
+ * \brief Returns error message for the given error code.
+ *
+ * \param code Error code.
+ *
+ * \return String containing the error message.
+ */
+const char* zs_strerror(const int code);
+
+/*!
+ * \brief Returns error code name of the given error code.
+ *
+ * \param code Error code.
+ *
+ * \return String containing the error code name.
+ */
+const char* zs_errorname(const int code);
+
+/*! @} */
diff --git a/src/libzscanner/functions.c b/src/libzscanner/functions.c
new file mode 100644
index 0000000..d9a1477
--- /dev/null
+++ b/src/libzscanner/functions.c
@@ -0,0 +1,821 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "libzscanner/error.h"
+#include "libzscanner/functions.h"
+
+const uint8_t digit_to_num[] = {
+ ['0'] = 0, ['1'] = 1, ['2'] = 2, ['3'] = 3, ['4'] = 4,
+ ['5'] = 5, ['6'] = 6, ['7'] = 7, ['8'] = 8, ['9'] = 9,
+};
+
+/*
+ * Hex transformation:
+ * 1 2
+ * 12345678 12345678
+ * in: AAAA BBBB
+ * out: AAAABBBB
+ */
+
+const uint8_t first_hex_to_num[] = {
+ ['0'] = ( 0 * 16), ['6'] = ( 6 * 16), ['C'] = (12 * 16), ['b'] = (11 * 16),
+ ['1'] = ( 1 * 16), ['7'] = ( 7 * 16), ['D'] = (13 * 16), ['c'] = (12 * 16),
+ ['2'] = ( 2 * 16), ['8'] = ( 8 * 16), ['E'] = (14 * 16), ['d'] = (13 * 16),
+ ['3'] = ( 3 * 16), ['9'] = ( 9 * 16), ['F'] = (15 * 16), ['e'] = (14 * 16),
+ ['4'] = ( 4 * 16), ['A'] = (10 * 16), ['a'] = (10 * 16), ['f'] = (15 * 16),
+ ['5'] = ( 5 * 16), ['B'] = (11 * 16),
+};
+
+const uint8_t second_hex_to_num[] = {
+ ['0'] = 0, ['4'] = 4, ['8'] = 8, ['C'] = 12, ['a'] = 10, ['d'] = 13,
+ ['1'] = 1, ['5'] = 5, ['9'] = 9, ['D'] = 13, ['b'] = 11, ['e'] = 14,
+ ['2'] = 2, ['6'] = 6, ['A'] = 10, ['E'] = 14, ['c'] = 12, ['f'] = 15,
+ ['3'] = 3, ['7'] = 7, ['B'] = 11, ['F'] = 15,
+};
+
+/*
+ * Base64 transformation:
+ * 1 2 3 4
+ * 12345678 12345678 12345678 12345678
+ * in: 00AAAAAA 00BBBBBB 00CCCCCC 00DDDDDD
+ * out: AAAAAABB BBBBCCCC CCDDDDDD
+ */
+
+// 0x3F = 00111111
+const uint8_t first_base64_to_num[] = {
+ ['A'] = (( 0 & 0x3F) << 2), ['g'] = ((32 & 0x3F) << 2),
+ ['B'] = (( 1 & 0x3F) << 2), ['h'] = ((33 & 0x3F) << 2),
+ ['C'] = (( 2 & 0x3F) << 2), ['i'] = ((34 & 0x3F) << 2),
+ ['D'] = (( 3 & 0x3F) << 2), ['j'] = ((35 & 0x3F) << 2),
+ ['E'] = (( 4 & 0x3F) << 2), ['k'] = ((36 & 0x3F) << 2),
+ ['F'] = (( 5 & 0x3F) << 2), ['l'] = ((37 & 0x3F) << 2),
+ ['G'] = (( 6 & 0x3F) << 2), ['m'] = ((38 & 0x3F) << 2),
+ ['H'] = (( 7 & 0x3F) << 2), ['n'] = ((39 & 0x3F) << 2),
+ ['I'] = (( 8 & 0x3F) << 2), ['o'] = ((40 & 0x3F) << 2),
+ ['J'] = (( 9 & 0x3F) << 2), ['p'] = ((41 & 0x3F) << 2),
+ ['K'] = ((10 & 0x3F) << 2), ['q'] = ((42 & 0x3F) << 2),
+ ['L'] = ((11 & 0x3F) << 2), ['r'] = ((43 & 0x3F) << 2),
+ ['M'] = ((12 & 0x3F) << 2), ['s'] = ((44 & 0x3F) << 2),
+ ['N'] = ((13 & 0x3F) << 2), ['t'] = ((45 & 0x3F) << 2),
+ ['O'] = ((14 & 0x3F) << 2), ['u'] = ((46 & 0x3F) << 2),
+ ['P'] = ((15 & 0x3F) << 2), ['v'] = ((47 & 0x3F) << 2),
+ ['Q'] = ((16 & 0x3F) << 2), ['w'] = ((48 & 0x3F) << 2),
+ ['R'] = ((17 & 0x3F) << 2), ['x'] = ((49 & 0x3F) << 2),
+ ['S'] = ((18 & 0x3F) << 2), ['y'] = ((50 & 0x3F) << 2),
+ ['T'] = ((19 & 0x3F) << 2), ['z'] = ((51 & 0x3F) << 2),
+ ['U'] = ((20 & 0x3F) << 2), ['0'] = ((52 & 0x3F) << 2),
+ ['V'] = ((21 & 0x3F) << 2), ['1'] = ((53 & 0x3F) << 2),
+ ['W'] = ((22 & 0x3F) << 2), ['2'] = ((54 & 0x3F) << 2),
+ ['X'] = ((23 & 0x3F) << 2), ['3'] = ((55 & 0x3F) << 2),
+ ['Y'] = ((24 & 0x3F) << 2), ['4'] = ((56 & 0x3F) << 2),
+ ['Z'] = ((25 & 0x3F) << 2), ['5'] = ((57 & 0x3F) << 2),
+ ['a'] = ((26 & 0x3F) << 2), ['6'] = ((58 & 0x3F) << 2),
+ ['b'] = ((27 & 0x3F) << 2), ['7'] = ((59 & 0x3F) << 2),
+ ['c'] = ((28 & 0x3F) << 2), ['8'] = ((60 & 0x3F) << 2),
+ ['d'] = ((29 & 0x3F) << 2), ['9'] = ((61 & 0x3F) << 2),
+ ['e'] = ((30 & 0x3F) << 2), ['+'] = ((62 & 0x3F) << 2),
+ ['f'] = ((31 & 0x3F) << 2), ['/'] = ((63 & 0x3F) << 2),
+};
+
+// 0x30 = 00110000
+const uint8_t second_left_base64_to_num[] = {
+ ['A'] = (( 0 & 0x30) >> 4), ['g'] = ((32 & 0x30) >> 4),
+ ['B'] = (( 1 & 0x30) >> 4), ['h'] = ((33 & 0x30) >> 4),
+ ['C'] = (( 2 & 0x30) >> 4), ['i'] = ((34 & 0x30) >> 4),
+ ['D'] = (( 3 & 0x30) >> 4), ['j'] = ((35 & 0x30) >> 4),
+ ['E'] = (( 4 & 0x30) >> 4), ['k'] = ((36 & 0x30) >> 4),
+ ['F'] = (( 5 & 0x30) >> 4), ['l'] = ((37 & 0x30) >> 4),
+ ['G'] = (( 6 & 0x30) >> 4), ['m'] = ((38 & 0x30) >> 4),
+ ['H'] = (( 7 & 0x30) >> 4), ['n'] = ((39 & 0x30) >> 4),
+ ['I'] = (( 8 & 0x30) >> 4), ['o'] = ((40 & 0x30) >> 4),
+ ['J'] = (( 9 & 0x30) >> 4), ['p'] = ((41 & 0x30) >> 4),
+ ['K'] = ((10 & 0x30) >> 4), ['q'] = ((42 & 0x30) >> 4),
+ ['L'] = ((11 & 0x30) >> 4), ['r'] = ((43 & 0x30) >> 4),
+ ['M'] = ((12 & 0x30) >> 4), ['s'] = ((44 & 0x30) >> 4),
+ ['N'] = ((13 & 0x30) >> 4), ['t'] = ((45 & 0x30) >> 4),
+ ['O'] = ((14 & 0x30) >> 4), ['u'] = ((46 & 0x30) >> 4),
+ ['P'] = ((15 & 0x30) >> 4), ['v'] = ((47 & 0x30) >> 4),
+ ['Q'] = ((16 & 0x30) >> 4), ['w'] = ((48 & 0x30) >> 4),
+ ['R'] = ((17 & 0x30) >> 4), ['x'] = ((49 & 0x30) >> 4),
+ ['S'] = ((18 & 0x30) >> 4), ['y'] = ((50 & 0x30) >> 4),
+ ['T'] = ((19 & 0x30) >> 4), ['z'] = ((51 & 0x30) >> 4),
+ ['U'] = ((20 & 0x30) >> 4), ['0'] = ((52 & 0x30) >> 4),
+ ['V'] = ((21 & 0x30) >> 4), ['1'] = ((53 & 0x30) >> 4),
+ ['W'] = ((22 & 0x30) >> 4), ['2'] = ((54 & 0x30) >> 4),
+ ['X'] = ((23 & 0x30) >> 4), ['3'] = ((55 & 0x30) >> 4),
+ ['Y'] = ((24 & 0x30) >> 4), ['4'] = ((56 & 0x30) >> 4),
+ ['Z'] = ((25 & 0x30) >> 4), ['5'] = ((57 & 0x30) >> 4),
+ ['a'] = ((26 & 0x30) >> 4), ['6'] = ((58 & 0x30) >> 4),
+ ['b'] = ((27 & 0x30) >> 4), ['7'] = ((59 & 0x30) >> 4),
+ ['c'] = ((28 & 0x30) >> 4), ['8'] = ((60 & 0x30) >> 4),
+ ['d'] = ((29 & 0x30) >> 4), ['9'] = ((61 & 0x30) >> 4),
+ ['e'] = ((30 & 0x30) >> 4), ['+'] = ((62 & 0x30) >> 4),
+ ['f'] = ((31 & 0x30) >> 4), ['/'] = ((63 & 0x30) >> 4),
+};
+
+// 0x0F = 00001111
+const uint8_t second_right_base64_to_num[] = {
+ ['A'] = (( 0 & 0x0F) << 4), ['g'] = ((32 & 0x0F) << 4),
+ ['B'] = (( 1 & 0x0F) << 4), ['h'] = ((33 & 0x0F) << 4),
+ ['C'] = (( 2 & 0x0F) << 4), ['i'] = ((34 & 0x0F) << 4),
+ ['D'] = (( 3 & 0x0F) << 4), ['j'] = ((35 & 0x0F) << 4),
+ ['E'] = (( 4 & 0x0F) << 4), ['k'] = ((36 & 0x0F) << 4),
+ ['F'] = (( 5 & 0x0F) << 4), ['l'] = ((37 & 0x0F) << 4),
+ ['G'] = (( 6 & 0x0F) << 4), ['m'] = ((38 & 0x0F) << 4),
+ ['H'] = (( 7 & 0x0F) << 4), ['n'] = ((39 & 0x0F) << 4),
+ ['I'] = (( 8 & 0x0F) << 4), ['o'] = ((40 & 0x0F) << 4),
+ ['J'] = (( 9 & 0x0F) << 4), ['p'] = ((41 & 0x0F) << 4),
+ ['K'] = ((10 & 0x0F) << 4), ['q'] = ((42 & 0x0F) << 4),
+ ['L'] = ((11 & 0x0F) << 4), ['r'] = ((43 & 0x0F) << 4),
+ ['M'] = ((12 & 0x0F) << 4), ['s'] = ((44 & 0x0F) << 4),
+ ['N'] = ((13 & 0x0F) << 4), ['t'] = ((45 & 0x0F) << 4),
+ ['O'] = ((14 & 0x0F) << 4), ['u'] = ((46 & 0x0F) << 4),
+ ['P'] = ((15 & 0x0F) << 4), ['v'] = ((47 & 0x0F) << 4),
+ ['Q'] = ((16 & 0x0F) << 4), ['w'] = ((48 & 0x0F) << 4),
+ ['R'] = ((17 & 0x0F) << 4), ['x'] = ((49 & 0x0F) << 4),
+ ['S'] = ((18 & 0x0F) << 4), ['y'] = ((50 & 0x0F) << 4),
+ ['T'] = ((19 & 0x0F) << 4), ['z'] = ((51 & 0x0F) << 4),
+ ['U'] = ((20 & 0x0F) << 4), ['0'] = ((52 & 0x0F) << 4),
+ ['V'] = ((21 & 0x0F) << 4), ['1'] = ((53 & 0x0F) << 4),
+ ['W'] = ((22 & 0x0F) << 4), ['2'] = ((54 & 0x0F) << 4),
+ ['X'] = ((23 & 0x0F) << 4), ['3'] = ((55 & 0x0F) << 4),
+ ['Y'] = ((24 & 0x0F) << 4), ['4'] = ((56 & 0x0F) << 4),
+ ['Z'] = ((25 & 0x0F) << 4), ['5'] = ((57 & 0x0F) << 4),
+ ['a'] = ((26 & 0x0F) << 4), ['6'] = ((58 & 0x0F) << 4),
+ ['b'] = ((27 & 0x0F) << 4), ['7'] = ((59 & 0x0F) << 4),
+ ['c'] = ((28 & 0x0F) << 4), ['8'] = ((60 & 0x0F) << 4),
+ ['d'] = ((29 & 0x0F) << 4), ['9'] = ((61 & 0x0F) << 4),
+ ['e'] = ((30 & 0x0F) << 4), ['+'] = ((62 & 0x0F) << 4),
+ ['f'] = ((31 & 0x0F) << 4), ['/'] = ((63 & 0x0F) << 4),
+};
+
+// 0x3C = 00111100
+const uint8_t third_left_base64_to_num[] = {
+ ['A'] = (( 0 & 0x3C) >> 2), ['g'] = ((32 & 0x3C) >> 2),
+ ['B'] = (( 1 & 0x3C) >> 2), ['h'] = ((33 & 0x3C) >> 2),
+ ['C'] = (( 2 & 0x3C) >> 2), ['i'] = ((34 & 0x3C) >> 2),
+ ['D'] = (( 3 & 0x3C) >> 2), ['j'] = ((35 & 0x3C) >> 2),
+ ['E'] = (( 4 & 0x3C) >> 2), ['k'] = ((36 & 0x3C) >> 2),
+ ['F'] = (( 5 & 0x3C) >> 2), ['l'] = ((37 & 0x3C) >> 2),
+ ['G'] = (( 6 & 0x3C) >> 2), ['m'] = ((38 & 0x3C) >> 2),
+ ['H'] = (( 7 & 0x3C) >> 2), ['n'] = ((39 & 0x3C) >> 2),
+ ['I'] = (( 8 & 0x3C) >> 2), ['o'] = ((40 & 0x3C) >> 2),
+ ['J'] = (( 9 & 0x3C) >> 2), ['p'] = ((41 & 0x3C) >> 2),
+ ['K'] = ((10 & 0x3C) >> 2), ['q'] = ((42 & 0x3C) >> 2),
+ ['L'] = ((11 & 0x3C) >> 2), ['r'] = ((43 & 0x3C) >> 2),
+ ['M'] = ((12 & 0x3C) >> 2), ['s'] = ((44 & 0x3C) >> 2),
+ ['N'] = ((13 & 0x3C) >> 2), ['t'] = ((45 & 0x3C) >> 2),
+ ['O'] = ((14 & 0x3C) >> 2), ['u'] = ((46 & 0x3C) >> 2),
+ ['P'] = ((15 & 0x3C) >> 2), ['v'] = ((47 & 0x3C) >> 2),
+ ['Q'] = ((16 & 0x3C) >> 2), ['w'] = ((48 & 0x3C) >> 2),
+ ['R'] = ((17 & 0x3C) >> 2), ['x'] = ((49 & 0x3C) >> 2),
+ ['S'] = ((18 & 0x3C) >> 2), ['y'] = ((50 & 0x3C) >> 2),
+ ['T'] = ((19 & 0x3C) >> 2), ['z'] = ((51 & 0x3C) >> 2),
+ ['U'] = ((20 & 0x3C) >> 2), ['0'] = ((52 & 0x3C) >> 2),
+ ['V'] = ((21 & 0x3C) >> 2), ['1'] = ((53 & 0x3C) >> 2),
+ ['W'] = ((22 & 0x3C) >> 2), ['2'] = ((54 & 0x3C) >> 2),
+ ['X'] = ((23 & 0x3C) >> 2), ['3'] = ((55 & 0x3C) >> 2),
+ ['Y'] = ((24 & 0x3C) >> 2), ['4'] = ((56 & 0x3C) >> 2),
+ ['Z'] = ((25 & 0x3C) >> 2), ['5'] = ((57 & 0x3C) >> 2),
+ ['a'] = ((26 & 0x3C) >> 2), ['6'] = ((58 & 0x3C) >> 2),
+ ['b'] = ((27 & 0x3C) >> 2), ['7'] = ((59 & 0x3C) >> 2),
+ ['c'] = ((28 & 0x3C) >> 2), ['8'] = ((60 & 0x3C) >> 2),
+ ['d'] = ((29 & 0x3C) >> 2), ['9'] = ((61 & 0x3C) >> 2),
+ ['e'] = ((30 & 0x3C) >> 2), ['+'] = ((62 & 0x3C) >> 2),
+ ['f'] = ((31 & 0x3C) >> 2), ['/'] = ((63 & 0x3C) >> 2),
+};
+
+// 0x03 = 00000011
+const uint8_t third_right_base64_to_num[] = {
+ ['A'] = (( 0 & 0x03) << 6), ['g'] = ((32 & 0x03) << 6),
+ ['B'] = (( 1 & 0x03) << 6), ['h'] = ((33 & 0x03) << 6),
+ ['C'] = (( 2 & 0x03) << 6), ['i'] = ((34 & 0x03) << 6),
+ ['D'] = (( 3 & 0x03) << 6), ['j'] = ((35 & 0x03) << 6),
+ ['E'] = (( 4 & 0x03) << 6), ['k'] = ((36 & 0x03) << 6),
+ ['F'] = (( 5 & 0x03) << 6), ['l'] = ((37 & 0x03) << 6),
+ ['G'] = (( 6 & 0x03) << 6), ['m'] = ((38 & 0x03) << 6),
+ ['H'] = (( 7 & 0x03) << 6), ['n'] = ((39 & 0x03) << 6),
+ ['I'] = (( 8 & 0x03) << 6), ['o'] = ((40 & 0x03) << 6),
+ ['J'] = (( 9 & 0x03) << 6), ['p'] = ((41 & 0x03) << 6),
+ ['K'] = ((10 & 0x03) << 6), ['q'] = ((42 & 0x03) << 6),
+ ['L'] = ((11 & 0x03) << 6), ['r'] = ((43 & 0x03) << 6),
+ ['M'] = ((12 & 0x03) << 6), ['s'] = ((44 & 0x03) << 6),
+ ['N'] = ((13 & 0x03) << 6), ['t'] = ((45 & 0x03) << 6),
+ ['O'] = ((14 & 0x03) << 6), ['u'] = ((46 & 0x03) << 6),
+ ['P'] = ((15 & 0x03) << 6), ['v'] = ((47 & 0x03) << 6),
+ ['Q'] = ((16 & 0x03) << 6), ['w'] = ((48 & 0x03) << 6),
+ ['R'] = ((17 & 0x03) << 6), ['x'] = ((49 & 0x03) << 6),
+ ['S'] = ((18 & 0x03) << 6), ['y'] = ((50 & 0x03) << 6),
+ ['T'] = ((19 & 0x03) << 6), ['z'] = ((51 & 0x03) << 6),
+ ['U'] = ((20 & 0x03) << 6), ['0'] = ((52 & 0x03) << 6),
+ ['V'] = ((21 & 0x03) << 6), ['1'] = ((53 & 0x03) << 6),
+ ['W'] = ((22 & 0x03) << 6), ['2'] = ((54 & 0x03) << 6),
+ ['X'] = ((23 & 0x03) << 6), ['3'] = ((55 & 0x03) << 6),
+ ['Y'] = ((24 & 0x03) << 6), ['4'] = ((56 & 0x03) << 6),
+ ['Z'] = ((25 & 0x03) << 6), ['5'] = ((57 & 0x03) << 6),
+ ['a'] = ((26 & 0x03) << 6), ['6'] = ((58 & 0x03) << 6),
+ ['b'] = ((27 & 0x03) << 6), ['7'] = ((59 & 0x03) << 6),
+ ['c'] = ((28 & 0x03) << 6), ['8'] = ((60 & 0x03) << 6),
+ ['d'] = ((29 & 0x03) << 6), ['9'] = ((61 & 0x03) << 6),
+ ['e'] = ((30 & 0x03) << 6), ['+'] = ((62 & 0x03) << 6),
+ ['f'] = ((31 & 0x03) << 6), ['/'] = ((63 & 0x03) << 6),
+};
+
+// 0x3F = 00111111
+const uint8_t fourth_base64_to_num[] = {
+ ['A'] = (( 0 & 0x3F) << 0), ['g'] = ((32 & 0x3F) << 0),
+ ['B'] = (( 1 & 0x3F) << 0), ['h'] = ((33 & 0x3F) << 0),
+ ['C'] = (( 2 & 0x3F) << 0), ['i'] = ((34 & 0x3F) << 0),
+ ['D'] = (( 3 & 0x3F) << 0), ['j'] = ((35 & 0x3F) << 0),
+ ['E'] = (( 4 & 0x3F) << 0), ['k'] = ((36 & 0x3F) << 0),
+ ['F'] = (( 5 & 0x3F) << 0), ['l'] = ((37 & 0x3F) << 0),
+ ['G'] = (( 6 & 0x3F) << 0), ['m'] = ((38 & 0x3F) << 0),
+ ['H'] = (( 7 & 0x3F) << 0), ['n'] = ((39 & 0x3F) << 0),
+ ['I'] = (( 8 & 0x3F) << 0), ['o'] = ((40 & 0x3F) << 0),
+ ['J'] = (( 9 & 0x3F) << 0), ['p'] = ((41 & 0x3F) << 0),
+ ['K'] = ((10 & 0x3F) << 0), ['q'] = ((42 & 0x3F) << 0),
+ ['L'] = ((11 & 0x3F) << 0), ['r'] = ((43 & 0x3F) << 0),
+ ['M'] = ((12 & 0x3F) << 0), ['s'] = ((44 & 0x3F) << 0),
+ ['N'] = ((13 & 0x3F) << 0), ['t'] = ((45 & 0x3F) << 0),
+ ['O'] = ((14 & 0x3F) << 0), ['u'] = ((46 & 0x3F) << 0),
+ ['P'] = ((15 & 0x3F) << 0), ['v'] = ((47 & 0x3F) << 0),
+ ['Q'] = ((16 & 0x3F) << 0), ['w'] = ((48 & 0x3F) << 0),
+ ['R'] = ((17 & 0x3F) << 0), ['x'] = ((49 & 0x3F) << 0),
+ ['S'] = ((18 & 0x3F) << 0), ['y'] = ((50 & 0x3F) << 0),
+ ['T'] = ((19 & 0x3F) << 0), ['z'] = ((51 & 0x3F) << 0),
+ ['U'] = ((20 & 0x3F) << 0), ['0'] = ((52 & 0x3F) << 0),
+ ['V'] = ((21 & 0x3F) << 0), ['1'] = ((53 & 0x3F) << 0),
+ ['W'] = ((22 & 0x3F) << 0), ['2'] = ((54 & 0x3F) << 0),
+ ['X'] = ((23 & 0x3F) << 0), ['3'] = ((55 & 0x3F) << 0),
+ ['Y'] = ((24 & 0x3F) << 0), ['4'] = ((56 & 0x3F) << 0),
+ ['Z'] = ((25 & 0x3F) << 0), ['5'] = ((57 & 0x3F) << 0),
+ ['a'] = ((26 & 0x3F) << 0), ['6'] = ((58 & 0x3F) << 0),
+ ['b'] = ((27 & 0x3F) << 0), ['7'] = ((59 & 0x3F) << 0),
+ ['c'] = ((28 & 0x3F) << 0), ['8'] = ((60 & 0x3F) << 0),
+ ['d'] = ((29 & 0x3F) << 0), ['9'] = ((61 & 0x3F) << 0),
+ ['e'] = ((30 & 0x3F) << 0), ['+'] = ((62 & 0x3F) << 0),
+ ['f'] = ((31 & 0x3F) << 0), ['/'] = ((63 & 0x3F) << 0),
+};
+
+/*
+ * Base32hex transformation (with lower-case):
+ * 1 2 3 4 5 6 7 8
+ * 12345678 12345678 12345678 12345678 12345678 12345678 12345678 12345678
+ * in: 000AAAAA 000BBBBB 000CCCCC 000DDDDD 000EEEEE 000FFFFF 000GGGGG 000HHHHH
+ * out AAAAABBB BBCCCCCD DDDDEEEE EFFFFFGG GGGHHHHH
+ */
+
+// 0x1F = 00011111
+const uint8_t first_base32hex_to_num[] = {
+ ['0'] = (( 0 & 0x1F) << 3), ['R'] = ((27 & 0x1F) << 3),
+ ['1'] = (( 1 & 0x1F) << 3), ['S'] = ((28 & 0x1F) << 3),
+ ['2'] = (( 2 & 0x1F) << 3), ['T'] = ((29 & 0x1F) << 3),
+ ['3'] = (( 3 & 0x1F) << 3), ['U'] = ((30 & 0x1F) << 3),
+ ['4'] = (( 4 & 0x1F) << 3), ['V'] = ((31 & 0x1F) << 3),
+ ['5'] = (( 5 & 0x1F) << 3), ['a'] = ((10 & 0x1F) << 3),
+ ['6'] = (( 6 & 0x1F) << 3), ['b'] = ((11 & 0x1F) << 3),
+ ['7'] = (( 7 & 0x1F) << 3), ['c'] = ((12 & 0x1F) << 3),
+ ['8'] = (( 8 & 0x1F) << 3), ['d'] = ((13 & 0x1F) << 3),
+ ['9'] = (( 9 & 0x1F) << 3), ['e'] = ((14 & 0x1F) << 3),
+ ['A'] = ((10 & 0x1F) << 3), ['f'] = ((15 & 0x1F) << 3),
+ ['B'] = ((11 & 0x1F) << 3), ['g'] = ((16 & 0x1F) << 3),
+ ['C'] = ((12 & 0x1F) << 3), ['h'] = ((17 & 0x1F) << 3),
+ ['D'] = ((13 & 0x1F) << 3), ['i'] = ((18 & 0x1F) << 3),
+ ['E'] = ((14 & 0x1F) << 3), ['j'] = ((19 & 0x1F) << 3),
+ ['F'] = ((15 & 0x1F) << 3), ['k'] = ((20 & 0x1F) << 3),
+ ['G'] = ((16 & 0x1F) << 3), ['l'] = ((21 & 0x1F) << 3),
+ ['H'] = ((17 & 0x1F) << 3), ['m'] = ((22 & 0x1F) << 3),
+ ['I'] = ((18 & 0x1F) << 3), ['n'] = ((23 & 0x1F) << 3),
+ ['J'] = ((19 & 0x1F) << 3), ['o'] = ((24 & 0x1F) << 3),
+ ['K'] = ((20 & 0x1F) << 3), ['p'] = ((25 & 0x1F) << 3),
+ ['L'] = ((21 & 0x1F) << 3), ['q'] = ((26 & 0x1F) << 3),
+ ['M'] = ((22 & 0x1F) << 3), ['r'] = ((27 & 0x1F) << 3),
+ ['N'] = ((23 & 0x1F) << 3), ['s'] = ((28 & 0x1F) << 3),
+ ['O'] = ((24 & 0x1F) << 3), ['t'] = ((29 & 0x1F) << 3),
+ ['P'] = ((25 & 0x1F) << 3), ['u'] = ((30 & 0x1F) << 3),
+ ['Q'] = ((26 & 0x1F) << 3), ['v'] = ((31 & 0x1F) << 3),
+};
+
+// 0x1C = 00011100
+const uint8_t second_left_base32hex_to_num[] = {
+ ['0'] = (( 0 & 0x1C) >> 2), ['R'] = ((27 & 0x1C) >> 2),
+ ['1'] = (( 1 & 0x1C) >> 2), ['S'] = ((28 & 0x1C) >> 2),
+ ['2'] = (( 2 & 0x1C) >> 2), ['T'] = ((29 & 0x1C) >> 2),
+ ['3'] = (( 3 & 0x1C) >> 2), ['U'] = ((30 & 0x1C) >> 2),
+ ['4'] = (( 4 & 0x1C) >> 2), ['V'] = ((31 & 0x1C) >> 2),
+ ['5'] = (( 5 & 0x1C) >> 2), ['a'] = ((10 & 0x1C) >> 2),
+ ['6'] = (( 6 & 0x1C) >> 2), ['b'] = ((11 & 0x1C) >> 2),
+ ['7'] = (( 7 & 0x1C) >> 2), ['c'] = ((12 & 0x1C) >> 2),
+ ['8'] = (( 8 & 0x1C) >> 2), ['d'] = ((13 & 0x1C) >> 2),
+ ['9'] = (( 9 & 0x1C) >> 2), ['e'] = ((14 & 0x1C) >> 2),
+ ['A'] = ((10 & 0x1C) >> 2), ['f'] = ((15 & 0x1C) >> 2),
+ ['B'] = ((11 & 0x1C) >> 2), ['g'] = ((16 & 0x1C) >> 2),
+ ['C'] = ((12 & 0x1C) >> 2), ['h'] = ((17 & 0x1C) >> 2),
+ ['D'] = ((13 & 0x1C) >> 2), ['i'] = ((18 & 0x1C) >> 2),
+ ['E'] = ((14 & 0x1C) >> 2), ['j'] = ((19 & 0x1C) >> 2),
+ ['F'] = ((15 & 0x1C) >> 2), ['k'] = ((20 & 0x1C) >> 2),
+ ['G'] = ((16 & 0x1C) >> 2), ['l'] = ((21 & 0x1C) >> 2),
+ ['H'] = ((17 & 0x1C) >> 2), ['m'] = ((22 & 0x1C) >> 2),
+ ['I'] = ((18 & 0x1C) >> 2), ['n'] = ((23 & 0x1C) >> 2),
+ ['J'] = ((19 & 0x1C) >> 2), ['o'] = ((24 & 0x1C) >> 2),
+ ['K'] = ((20 & 0x1C) >> 2), ['p'] = ((25 & 0x1C) >> 2),
+ ['L'] = ((21 & 0x1C) >> 2), ['q'] = ((26 & 0x1C) >> 2),
+ ['M'] = ((22 & 0x1C) >> 2), ['r'] = ((27 & 0x1C) >> 2),
+ ['N'] = ((23 & 0x1C) >> 2), ['s'] = ((28 & 0x1C) >> 2),
+ ['O'] = ((24 & 0x1C) >> 2), ['t'] = ((29 & 0x1C) >> 2),
+ ['P'] = ((25 & 0x1C) >> 2), ['u'] = ((30 & 0x1C) >> 2),
+ ['Q'] = ((26 & 0x1C) >> 2), ['v'] = ((31 & 0x1C) >> 2),
+};
+
+// 0x03 = 00000011
+const uint8_t second_right_base32hex_to_num[] = {
+ ['0'] = (( 0 & 0x03) << 6), ['R'] = ((27 & 0x03) << 6),
+ ['1'] = (( 1 & 0x03) << 6), ['S'] = ((28 & 0x03) << 6),
+ ['2'] = (( 2 & 0x03) << 6), ['T'] = ((29 & 0x03) << 6),
+ ['3'] = (( 3 & 0x03) << 6), ['U'] = ((30 & 0x03) << 6),
+ ['4'] = (( 4 & 0x03) << 6), ['V'] = ((31 & 0x03) << 6),
+ ['5'] = (( 5 & 0x03) << 6), ['a'] = ((10 & 0x03) << 6),
+ ['6'] = (( 6 & 0x03) << 6), ['b'] = ((11 & 0x03) << 6),
+ ['7'] = (( 7 & 0x03) << 6), ['c'] = ((12 & 0x03) << 6),
+ ['8'] = (( 8 & 0x03) << 6), ['d'] = ((13 & 0x03) << 6),
+ ['9'] = (( 9 & 0x03) << 6), ['e'] = ((14 & 0x03) << 6),
+ ['A'] = ((10 & 0x03) << 6), ['f'] = ((15 & 0x03) << 6),
+ ['B'] = ((11 & 0x03) << 6), ['g'] = ((16 & 0x03) << 6),
+ ['C'] = ((12 & 0x03) << 6), ['h'] = ((17 & 0x03) << 6),
+ ['D'] = ((13 & 0x03) << 6), ['i'] = ((18 & 0x03) << 6),
+ ['E'] = ((14 & 0x03) << 6), ['j'] = ((19 & 0x03) << 6),
+ ['F'] = ((15 & 0x03) << 6), ['k'] = ((20 & 0x03) << 6),
+ ['G'] = ((16 & 0x03) << 6), ['l'] = ((21 & 0x03) << 6),
+ ['H'] = ((17 & 0x03) << 6), ['m'] = ((22 & 0x03) << 6),
+ ['I'] = ((18 & 0x03) << 6), ['n'] = ((23 & 0x03) << 6),
+ ['J'] = ((19 & 0x03) << 6), ['o'] = ((24 & 0x03) << 6),
+ ['K'] = ((20 & 0x03) << 6), ['p'] = ((25 & 0x03) << 6),
+ ['L'] = ((21 & 0x03) << 6), ['q'] = ((26 & 0x03) << 6),
+ ['M'] = ((22 & 0x03) << 6), ['r'] = ((27 & 0x03) << 6),
+ ['N'] = ((23 & 0x03) << 6), ['s'] = ((28 & 0x03) << 6),
+ ['O'] = ((24 & 0x03) << 6), ['t'] = ((29 & 0x03) << 6),
+ ['P'] = ((25 & 0x03) << 6), ['u'] = ((30 & 0x03) << 6),
+ ['Q'] = ((26 & 0x03) << 6), ['v'] = ((31 & 0x03) << 6),
+};
+
+// 0x1F = 00011111
+const uint8_t third_base32hex_to_num[] = {
+ ['0'] = (( 0 & 0x1F) << 1), ['R'] = ((27 & 0x1F) << 1),
+ ['1'] = (( 1 & 0x1F) << 1), ['S'] = ((28 & 0x1F) << 1),
+ ['2'] = (( 2 & 0x1F) << 1), ['T'] = ((29 & 0x1F) << 1),
+ ['3'] = (( 3 & 0x1F) << 1), ['U'] = ((30 & 0x1F) << 1),
+ ['4'] = (( 4 & 0x1F) << 1), ['V'] = ((31 & 0x1F) << 1),
+ ['5'] = (( 5 & 0x1F) << 1), ['a'] = ((10 & 0x1F) << 1),
+ ['6'] = (( 6 & 0x1F) << 1), ['b'] = ((11 & 0x1F) << 1),
+ ['7'] = (( 7 & 0x1F) << 1), ['c'] = ((12 & 0x1F) << 1),
+ ['8'] = (( 8 & 0x1F) << 1), ['d'] = ((13 & 0x1F) << 1),
+ ['9'] = (( 9 & 0x1F) << 1), ['e'] = ((14 & 0x1F) << 1),
+ ['A'] = ((10 & 0x1F) << 1), ['f'] = ((15 & 0x1F) << 1),
+ ['B'] = ((11 & 0x1F) << 1), ['g'] = ((16 & 0x1F) << 1),
+ ['C'] = ((12 & 0x1F) << 1), ['h'] = ((17 & 0x1F) << 1),
+ ['D'] = ((13 & 0x1F) << 1), ['i'] = ((18 & 0x1F) << 1),
+ ['E'] = ((14 & 0x1F) << 1), ['j'] = ((19 & 0x1F) << 1),
+ ['F'] = ((15 & 0x1F) << 1), ['k'] = ((20 & 0x1F) << 1),
+ ['G'] = ((16 & 0x1F) << 1), ['l'] = ((21 & 0x1F) << 1),
+ ['H'] = ((17 & 0x1F) << 1), ['m'] = ((22 & 0x1F) << 1),
+ ['I'] = ((18 & 0x1F) << 1), ['n'] = ((23 & 0x1F) << 1),
+ ['J'] = ((19 & 0x1F) << 1), ['o'] = ((24 & 0x1F) << 1),
+ ['K'] = ((20 & 0x1F) << 1), ['p'] = ((25 & 0x1F) << 1),
+ ['L'] = ((21 & 0x1F) << 1), ['q'] = ((26 & 0x1F) << 1),
+ ['M'] = ((22 & 0x1F) << 1), ['r'] = ((27 & 0x1F) << 1),
+ ['N'] = ((23 & 0x1F) << 1), ['s'] = ((28 & 0x1F) << 1),
+ ['O'] = ((24 & 0x1F) << 1), ['t'] = ((29 & 0x1F) << 1),
+ ['P'] = ((25 & 0x1F) << 1), ['u'] = ((30 & 0x1F) << 1),
+ ['Q'] = ((26 & 0x1F) << 1), ['v'] = ((31 & 0x1F) << 1),
+};
+
+// 0x10 = 00010000
+const uint8_t fourth_left_base32hex_to_num[] = {
+ ['0'] = (( 0 & 0x10) >> 4), ['R'] = ((27 & 0x10) >> 4),
+ ['1'] = (( 1 & 0x10) >> 4), ['S'] = ((28 & 0x10) >> 4),
+ ['2'] = (( 2 & 0x10) >> 4), ['T'] = ((29 & 0x10) >> 4),
+ ['3'] = (( 3 & 0x10) >> 4), ['U'] = ((30 & 0x10) >> 4),
+ ['4'] = (( 4 & 0x10) >> 4), ['V'] = ((31 & 0x10) >> 4),
+ ['5'] = (( 5 & 0x10) >> 4), ['a'] = ((10 & 0x10) >> 4),
+ ['6'] = (( 6 & 0x10) >> 4), ['b'] = ((11 & 0x10) >> 4),
+ ['7'] = (( 7 & 0x10) >> 4), ['c'] = ((12 & 0x10) >> 4),
+ ['8'] = (( 8 & 0x10) >> 4), ['d'] = ((13 & 0x10) >> 4),
+ ['9'] = (( 9 & 0x10) >> 4), ['e'] = ((14 & 0x10) >> 4),
+ ['A'] = ((10 & 0x10) >> 4), ['f'] = ((15 & 0x10) >> 4),
+ ['B'] = ((11 & 0x10) >> 4), ['g'] = ((16 & 0x10) >> 4),
+ ['C'] = ((12 & 0x10) >> 4), ['h'] = ((17 & 0x10) >> 4),
+ ['D'] = ((13 & 0x10) >> 4), ['i'] = ((18 & 0x10) >> 4),
+ ['E'] = ((14 & 0x10) >> 4), ['j'] = ((19 & 0x10) >> 4),
+ ['F'] = ((15 & 0x10) >> 4), ['k'] = ((20 & 0x10) >> 4),
+ ['G'] = ((16 & 0x10) >> 4), ['l'] = ((21 & 0x10) >> 4),
+ ['H'] = ((17 & 0x10) >> 4), ['m'] = ((22 & 0x10) >> 4),
+ ['I'] = ((18 & 0x10) >> 4), ['n'] = ((23 & 0x10) >> 4),
+ ['J'] = ((19 & 0x10) >> 4), ['o'] = ((24 & 0x10) >> 4),
+ ['K'] = ((20 & 0x10) >> 4), ['p'] = ((25 & 0x10) >> 4),
+ ['L'] = ((21 & 0x10) >> 4), ['q'] = ((26 & 0x10) >> 4),
+ ['M'] = ((22 & 0x10) >> 4), ['r'] = ((27 & 0x10) >> 4),
+ ['N'] = ((23 & 0x10) >> 4), ['s'] = ((28 & 0x10) >> 4),
+ ['O'] = ((24 & 0x10) >> 4), ['t'] = ((29 & 0x10) >> 4),
+ ['P'] = ((25 & 0x10) >> 4), ['u'] = ((30 & 0x10) >> 4),
+ ['Q'] = ((26 & 0x10) >> 4), ['v'] = ((31 & 0x10) >> 4),
+};
+
+// 0x0F = 00001111
+const uint8_t fourth_right_base32hex_to_num[] = {
+ ['0'] = (( 0 & 0x0F) << 4), ['R'] = ((27 & 0x0F) << 4),
+ ['1'] = (( 1 & 0x0F) << 4), ['S'] = ((28 & 0x0F) << 4),
+ ['2'] = (( 2 & 0x0F) << 4), ['T'] = ((29 & 0x0F) << 4),
+ ['3'] = (( 3 & 0x0F) << 4), ['U'] = ((30 & 0x0F) << 4),
+ ['4'] = (( 4 & 0x0F) << 4), ['V'] = ((31 & 0x0F) << 4),
+ ['5'] = (( 5 & 0x0F) << 4), ['a'] = ((10 & 0x0F) << 4),
+ ['6'] = (( 6 & 0x0F) << 4), ['b'] = ((11 & 0x0F) << 4),
+ ['7'] = (( 7 & 0x0F) << 4), ['c'] = ((12 & 0x0F) << 4),
+ ['8'] = (( 8 & 0x0F) << 4), ['d'] = ((13 & 0x0F) << 4),
+ ['9'] = (( 9 & 0x0F) << 4), ['e'] = ((14 & 0x0F) << 4),
+ ['A'] = ((10 & 0x0F) << 4), ['f'] = ((15 & 0x0F) << 4),
+ ['B'] = ((11 & 0x0F) << 4), ['g'] = ((16 & 0x0F) << 4),
+ ['C'] = ((12 & 0x0F) << 4), ['h'] = ((17 & 0x0F) << 4),
+ ['D'] = ((13 & 0x0F) << 4), ['i'] = ((18 & 0x0F) << 4),
+ ['E'] = ((14 & 0x0F) << 4), ['j'] = ((19 & 0x0F) << 4),
+ ['F'] = ((15 & 0x0F) << 4), ['k'] = ((20 & 0x0F) << 4),
+ ['G'] = ((16 & 0x0F) << 4), ['l'] = ((21 & 0x0F) << 4),
+ ['H'] = ((17 & 0x0F) << 4), ['m'] = ((22 & 0x0F) << 4),
+ ['I'] = ((18 & 0x0F) << 4), ['n'] = ((23 & 0x0F) << 4),
+ ['J'] = ((19 & 0x0F) << 4), ['o'] = ((24 & 0x0F) << 4),
+ ['K'] = ((20 & 0x0F) << 4), ['p'] = ((25 & 0x0F) << 4),
+ ['L'] = ((21 & 0x0F) << 4), ['q'] = ((26 & 0x0F) << 4),
+ ['M'] = ((22 & 0x0F) << 4), ['r'] = ((27 & 0x0F) << 4),
+ ['N'] = ((23 & 0x0F) << 4), ['s'] = ((28 & 0x0F) << 4),
+ ['O'] = ((24 & 0x0F) << 4), ['t'] = ((29 & 0x0F) << 4),
+ ['P'] = ((25 & 0x0F) << 4), ['u'] = ((30 & 0x0F) << 4),
+ ['Q'] = ((26 & 0x0F) << 4), ['v'] = ((31 & 0x0F) << 4),
+};
+
+// 0x1E = 00011110
+const uint8_t fifth_left_base32hex_to_num[] = {
+ ['0'] = (( 0 & 0x1E) >> 1), ['R'] = ((27 & 0x1E) >> 1),
+ ['1'] = (( 1 & 0x1E) >> 1), ['S'] = ((28 & 0x1E) >> 1),
+ ['2'] = (( 2 & 0x1E) >> 1), ['T'] = ((29 & 0x1E) >> 1),
+ ['3'] = (( 3 & 0x1E) >> 1), ['U'] = ((30 & 0x1E) >> 1),
+ ['4'] = (( 4 & 0x1E) >> 1), ['V'] = ((31 & 0x1E) >> 1),
+ ['5'] = (( 5 & 0x1E) >> 1), ['a'] = ((10 & 0x1E) >> 1),
+ ['6'] = (( 6 & 0x1E) >> 1), ['b'] = ((11 & 0x1E) >> 1),
+ ['7'] = (( 7 & 0x1E) >> 1), ['c'] = ((12 & 0x1E) >> 1),
+ ['8'] = (( 8 & 0x1E) >> 1), ['d'] = ((13 & 0x1E) >> 1),
+ ['9'] = (( 9 & 0x1E) >> 1), ['e'] = ((14 & 0x1E) >> 1),
+ ['A'] = ((10 & 0x1E) >> 1), ['f'] = ((15 & 0x1E) >> 1),
+ ['B'] = ((11 & 0x1E) >> 1), ['g'] = ((16 & 0x1E) >> 1),
+ ['C'] = ((12 & 0x1E) >> 1), ['h'] = ((17 & 0x1E) >> 1),
+ ['D'] = ((13 & 0x1E) >> 1), ['i'] = ((18 & 0x1E) >> 1),
+ ['E'] = ((14 & 0x1E) >> 1), ['j'] = ((19 & 0x1E) >> 1),
+ ['F'] = ((15 & 0x1E) >> 1), ['k'] = ((20 & 0x1E) >> 1),
+ ['G'] = ((16 & 0x1E) >> 1), ['l'] = ((21 & 0x1E) >> 1),
+ ['H'] = ((17 & 0x1E) >> 1), ['m'] = ((22 & 0x1E) >> 1),
+ ['I'] = ((18 & 0x1E) >> 1), ['n'] = ((23 & 0x1E) >> 1),
+ ['J'] = ((19 & 0x1E) >> 1), ['o'] = ((24 & 0x1E) >> 1),
+ ['K'] = ((20 & 0x1E) >> 1), ['p'] = ((25 & 0x1E) >> 1),
+ ['L'] = ((21 & 0x1E) >> 1), ['q'] = ((26 & 0x1E) >> 1),
+ ['M'] = ((22 & 0x1E) >> 1), ['r'] = ((27 & 0x1E) >> 1),
+ ['N'] = ((23 & 0x1E) >> 1), ['s'] = ((28 & 0x1E) >> 1),
+ ['O'] = ((24 & 0x1E) >> 1), ['t'] = ((29 & 0x1E) >> 1),
+ ['P'] = ((25 & 0x1E) >> 1), ['u'] = ((30 & 0x1E) >> 1),
+ ['Q'] = ((26 & 0x1E) >> 1), ['v'] = ((31 & 0x1E) >> 1),
+};
+
+// 0x01 = 00000001
+const uint8_t fifth_right_base32hex_to_num[] = {
+ ['0'] = (( 0 & 0x01) << 7), ['R'] = ((27 & 0x01) << 7),
+ ['1'] = (( 1 & 0x01) << 7), ['S'] = ((28 & 0x01) << 7),
+ ['2'] = (( 2 & 0x01) << 7), ['T'] = ((29 & 0x01) << 7),
+ ['3'] = (( 3 & 0x01) << 7), ['U'] = ((30 & 0x01) << 7),
+ ['4'] = (( 4 & 0x01) << 7), ['V'] = ((31 & 0x01) << 7),
+ ['5'] = (( 5 & 0x01) << 7), ['a'] = ((10 & 0x01) << 7),
+ ['6'] = (( 6 & 0x01) << 7), ['b'] = ((11 & 0x01) << 7),
+ ['7'] = (( 7 & 0x01) << 7), ['c'] = ((12 & 0x01) << 7),
+ ['8'] = (( 8 & 0x01) << 7), ['d'] = ((13 & 0x01) << 7),
+ ['9'] = (( 9 & 0x01) << 7), ['e'] = ((14 & 0x01) << 7),
+ ['A'] = ((10 & 0x01) << 7), ['f'] = ((15 & 0x01) << 7),
+ ['B'] = ((11 & 0x01) << 7), ['g'] = ((16 & 0x01) << 7),
+ ['C'] = ((12 & 0x01) << 7), ['h'] = ((17 & 0x01) << 7),
+ ['D'] = ((13 & 0x01) << 7), ['i'] = ((18 & 0x01) << 7),
+ ['E'] = ((14 & 0x01) << 7), ['j'] = ((19 & 0x01) << 7),
+ ['F'] = ((15 & 0x01) << 7), ['k'] = ((20 & 0x01) << 7),
+ ['G'] = ((16 & 0x01) << 7), ['l'] = ((21 & 0x01) << 7),
+ ['H'] = ((17 & 0x01) << 7), ['m'] = ((22 & 0x01) << 7),
+ ['I'] = ((18 & 0x01) << 7), ['n'] = ((23 & 0x01) << 7),
+ ['J'] = ((19 & 0x01) << 7), ['o'] = ((24 & 0x01) << 7),
+ ['K'] = ((20 & 0x01) << 7), ['p'] = ((25 & 0x01) << 7),
+ ['L'] = ((21 & 0x01) << 7), ['q'] = ((26 & 0x01) << 7),
+ ['M'] = ((22 & 0x01) << 7), ['r'] = ((27 & 0x01) << 7),
+ ['N'] = ((23 & 0x01) << 7), ['s'] = ((28 & 0x01) << 7),
+ ['O'] = ((24 & 0x01) << 7), ['t'] = ((29 & 0x01) << 7),
+ ['P'] = ((25 & 0x01) << 7), ['u'] = ((30 & 0x01) << 7),
+ ['Q'] = ((26 & 0x01) << 7), ['v'] = ((31 & 0x01) << 7),
+};
+
+// 0x1F = 00011111
+const uint8_t sixth_base32hex_to_num[] = {
+ ['0'] = (( 0 & 0x1F) << 2), ['R'] = ((27 & 0x1F) << 2),
+ ['1'] = (( 1 & 0x1F) << 2), ['S'] = ((28 & 0x1F) << 2),
+ ['2'] = (( 2 & 0x1F) << 2), ['T'] = ((29 & 0x1F) << 2),
+ ['3'] = (( 3 & 0x1F) << 2), ['U'] = ((30 & 0x1F) << 2),
+ ['4'] = (( 4 & 0x1F) << 2), ['V'] = ((31 & 0x1F) << 2),
+ ['5'] = (( 5 & 0x1F) << 2), ['a'] = ((10 & 0x1F) << 2),
+ ['6'] = (( 6 & 0x1F) << 2), ['b'] = ((11 & 0x1F) << 2),
+ ['7'] = (( 7 & 0x1F) << 2), ['c'] = ((12 & 0x1F) << 2),
+ ['8'] = (( 8 & 0x1F) << 2), ['d'] = ((13 & 0x1F) << 2),
+ ['9'] = (( 9 & 0x1F) << 2), ['e'] = ((14 & 0x1F) << 2),
+ ['A'] = ((10 & 0x1F) << 2), ['f'] = ((15 & 0x1F) << 2),
+ ['B'] = ((11 & 0x1F) << 2), ['g'] = ((16 & 0x1F) << 2),
+ ['C'] = ((12 & 0x1F) << 2), ['h'] = ((17 & 0x1F) << 2),
+ ['D'] = ((13 & 0x1F) << 2), ['i'] = ((18 & 0x1F) << 2),
+ ['E'] = ((14 & 0x1F) << 2), ['j'] = ((19 & 0x1F) << 2),
+ ['F'] = ((15 & 0x1F) << 2), ['k'] = ((20 & 0x1F) << 2),
+ ['G'] = ((16 & 0x1F) << 2), ['l'] = ((21 & 0x1F) << 2),
+ ['H'] = ((17 & 0x1F) << 2), ['m'] = ((22 & 0x1F) << 2),
+ ['I'] = ((18 & 0x1F) << 2), ['n'] = ((23 & 0x1F) << 2),
+ ['J'] = ((19 & 0x1F) << 2), ['o'] = ((24 & 0x1F) << 2),
+ ['K'] = ((20 & 0x1F) << 2), ['p'] = ((25 & 0x1F) << 2),
+ ['L'] = ((21 & 0x1F) << 2), ['q'] = ((26 & 0x1F) << 2),
+ ['M'] = ((22 & 0x1F) << 2), ['r'] = ((27 & 0x1F) << 2),
+ ['N'] = ((23 & 0x1F) << 2), ['s'] = ((28 & 0x1F) << 2),
+ ['O'] = ((24 & 0x1F) << 2), ['t'] = ((29 & 0x1F) << 2),
+ ['P'] = ((25 & 0x1F) << 2), ['u'] = ((30 & 0x1F) << 2),
+ ['Q'] = ((26 & 0x1F) << 2), ['v'] = ((31 & 0x1F) << 2),
+};
+
+// 0x18 = 00011000
+const uint8_t seventh_left_base32hex_to_num[] = {
+ ['0'] = (( 0 & 0x18) >> 3), ['R'] = ((27 & 0x18) >> 3),
+ ['1'] = (( 1 & 0x18) >> 3), ['S'] = ((28 & 0x18) >> 3),
+ ['2'] = (( 2 & 0x18) >> 3), ['T'] = ((29 & 0x18) >> 3),
+ ['3'] = (( 3 & 0x18) >> 3), ['U'] = ((30 & 0x18) >> 3),
+ ['4'] = (( 4 & 0x18) >> 3), ['V'] = ((31 & 0x18) >> 3),
+ ['5'] = (( 5 & 0x18) >> 3), ['a'] = ((10 & 0x18) >> 3),
+ ['6'] = (( 6 & 0x18) >> 3), ['b'] = ((11 & 0x18) >> 3),
+ ['7'] = (( 7 & 0x18) >> 3), ['c'] = ((12 & 0x18) >> 3),
+ ['8'] = (( 8 & 0x18) >> 3), ['d'] = ((13 & 0x18) >> 3),
+ ['9'] = (( 9 & 0x18) >> 3), ['e'] = ((14 & 0x18) >> 3),
+ ['A'] = ((10 & 0x18) >> 3), ['f'] = ((15 & 0x18) >> 3),
+ ['B'] = ((11 & 0x18) >> 3), ['g'] = ((16 & 0x18) >> 3),
+ ['C'] = ((12 & 0x18) >> 3), ['h'] = ((17 & 0x18) >> 3),
+ ['D'] = ((13 & 0x18) >> 3), ['i'] = ((18 & 0x18) >> 3),
+ ['E'] = ((14 & 0x18) >> 3), ['j'] = ((19 & 0x18) >> 3),
+ ['F'] = ((15 & 0x18) >> 3), ['k'] = ((20 & 0x18) >> 3),
+ ['G'] = ((16 & 0x18) >> 3), ['l'] = ((21 & 0x18) >> 3),
+ ['H'] = ((17 & 0x18) >> 3), ['m'] = ((22 & 0x18) >> 3),
+ ['I'] = ((18 & 0x18) >> 3), ['n'] = ((23 & 0x18) >> 3),
+ ['J'] = ((19 & 0x18) >> 3), ['o'] = ((24 & 0x18) >> 3),
+ ['K'] = ((20 & 0x18) >> 3), ['p'] = ((25 & 0x18) >> 3),
+ ['L'] = ((21 & 0x18) >> 3), ['q'] = ((26 & 0x18) >> 3),
+ ['M'] = ((22 & 0x18) >> 3), ['r'] = ((27 & 0x18) >> 3),
+ ['N'] = ((23 & 0x18) >> 3), ['s'] = ((28 & 0x18) >> 3),
+ ['O'] = ((24 & 0x18) >> 3), ['t'] = ((29 & 0x18) >> 3),
+ ['P'] = ((25 & 0x18) >> 3), ['u'] = ((30 & 0x18) >> 3),
+ ['Q'] = ((26 & 0x18) >> 3), ['v'] = ((31 & 0x18) >> 3),
+};
+
+// 0x07 = 00000111
+const uint8_t seventh_right_base32hex_to_num[] = {
+ ['0'] = (( 0 & 0x07) << 5), ['R'] = ((27 & 0x07) << 5),
+ ['1'] = (( 1 & 0x07) << 5), ['S'] = ((28 & 0x07) << 5),
+ ['2'] = (( 2 & 0x07) << 5), ['T'] = ((29 & 0x07) << 5),
+ ['3'] = (( 3 & 0x07) << 5), ['U'] = ((30 & 0x07) << 5),
+ ['4'] = (( 4 & 0x07) << 5), ['V'] = ((31 & 0x07) << 5),
+ ['5'] = (( 5 & 0x07) << 5), ['a'] = ((10 & 0x07) << 5),
+ ['6'] = (( 6 & 0x07) << 5), ['b'] = ((11 & 0x07) << 5),
+ ['7'] = (( 7 & 0x07) << 5), ['c'] = ((12 & 0x07) << 5),
+ ['8'] = (( 8 & 0x07) << 5), ['d'] = ((13 & 0x07) << 5),
+ ['9'] = (( 9 & 0x07) << 5), ['e'] = ((14 & 0x07) << 5),
+ ['A'] = ((10 & 0x07) << 5), ['f'] = ((15 & 0x07) << 5),
+ ['B'] = ((11 & 0x07) << 5), ['g'] = ((16 & 0x07) << 5),
+ ['C'] = ((12 & 0x07) << 5), ['h'] = ((17 & 0x07) << 5),
+ ['D'] = ((13 & 0x07) << 5), ['i'] = ((18 & 0x07) << 5),
+ ['E'] = ((14 & 0x07) << 5), ['j'] = ((19 & 0x07) << 5),
+ ['F'] = ((15 & 0x07) << 5), ['k'] = ((20 & 0x07) << 5),
+ ['G'] = ((16 & 0x07) << 5), ['l'] = ((21 & 0x07) << 5),
+ ['H'] = ((17 & 0x07) << 5), ['m'] = ((22 & 0x07) << 5),
+ ['I'] = ((18 & 0x07) << 5), ['n'] = ((23 & 0x07) << 5),
+ ['J'] = ((19 & 0x07) << 5), ['o'] = ((24 & 0x07) << 5),
+ ['K'] = ((20 & 0x07) << 5), ['p'] = ((25 & 0x07) << 5),
+ ['L'] = ((21 & 0x07) << 5), ['q'] = ((26 & 0x07) << 5),
+ ['M'] = ((22 & 0x07) << 5), ['r'] = ((27 & 0x07) << 5),
+ ['N'] = ((23 & 0x07) << 5), ['s'] = ((28 & 0x07) << 5),
+ ['O'] = ((24 & 0x07) << 5), ['t'] = ((29 & 0x07) << 5),
+ ['P'] = ((25 & 0x07) << 5), ['u'] = ((30 & 0x07) << 5),
+ ['Q'] = ((26 & 0x07) << 5), ['v'] = ((31 & 0x07) << 5),
+};
+
+// 0x1F = 00011111
+const uint8_t eighth_base32hex_to_num[] = {
+ ['0'] = (( 0 & 0x1F) << 0), ['R'] = ((27 & 0x1F) << 0),
+ ['1'] = (( 1 & 0x1F) << 0), ['S'] = ((28 & 0x1F) << 0),
+ ['2'] = (( 2 & 0x1F) << 0), ['T'] = ((29 & 0x1F) << 0),
+ ['3'] = (( 3 & 0x1F) << 0), ['U'] = ((30 & 0x1F) << 0),
+ ['4'] = (( 4 & 0x1F) << 0), ['V'] = ((31 & 0x1F) << 0),
+ ['5'] = (( 5 & 0x1F) << 0), ['a'] = ((10 & 0x1F) << 0),
+ ['6'] = (( 6 & 0x1F) << 0), ['b'] = ((11 & 0x1F) << 0),
+ ['7'] = (( 7 & 0x1F) << 0), ['c'] = ((12 & 0x1F) << 0),
+ ['8'] = (( 8 & 0x1F) << 0), ['d'] = ((13 & 0x1F) << 0),
+ ['9'] = (( 9 & 0x1F) << 0), ['e'] = ((14 & 0x1F) << 0),
+ ['A'] = ((10 & 0x1F) << 0), ['f'] = ((15 & 0x1F) << 0),
+ ['B'] = ((11 & 0x1F) << 0), ['g'] = ((16 & 0x1F) << 0),
+ ['C'] = ((12 & 0x1F) << 0), ['h'] = ((17 & 0x1F) << 0),
+ ['D'] = ((13 & 0x1F) << 0), ['i'] = ((18 & 0x1F) << 0),
+ ['E'] = ((14 & 0x1F) << 0), ['j'] = ((19 & 0x1F) << 0),
+ ['F'] = ((15 & 0x1F) << 0), ['k'] = ((20 & 0x1F) << 0),
+ ['G'] = ((16 & 0x1F) << 0), ['l'] = ((21 & 0x1F) << 0),
+ ['H'] = ((17 & 0x1F) << 0), ['m'] = ((22 & 0x1F) << 0),
+ ['I'] = ((18 & 0x1F) << 0), ['n'] = ((23 & 0x1F) << 0),
+ ['J'] = ((19 & 0x1F) << 0), ['o'] = ((24 & 0x1F) << 0),
+ ['K'] = ((20 & 0x1F) << 0), ['p'] = ((25 & 0x1F) << 0),
+ ['L'] = ((21 & 0x1F) << 0), ['q'] = ((26 & 0x1F) << 0),
+ ['M'] = ((22 & 0x1F) << 0), ['r'] = ((27 & 0x1F) << 0),
+ ['N'] = ((23 & 0x1F) << 0), ['s'] = ((28 & 0x1F) << 0),
+ ['O'] = ((24 & 0x1F) << 0), ['t'] = ((29 & 0x1F) << 0),
+ ['P'] = ((25 & 0x1F) << 0), ['u'] = ((30 & 0x1F) << 0),
+ ['Q'] = ((26 & 0x1F) << 0), ['v'] = ((31 & 0x1F) << 0),
+};
+
+// Without leap day 29. 2.
+static const uint8_t days_in_months[] = {
+ [ 1] = 31, [ 2] = 28, [ 3] = 31, [ 4] = 30, [ 5] = 31, [ 6] = 30,
+ [ 7] = 31, [ 8] = 31, [ 9] = 30, [10] = 31, [11] = 30, [12] = 31,
+};
+
+// Without leap day 29. 2.
+static const uint16_t days_across_months[] = {
+ [ 1] = 0, [ 2] = 31, [ 3] = 59, [ 4] = 90, [ 5] = 120, [ 6] = 151,
+ [ 7] = 181, [ 8] = 212, [ 9] = 243, [10] = 273, [11] = 304, [12] = 334,
+};
+
+// 0 ~ 1970 ... 135 ~ 2105
+static const uint8_t is_leap_year[] = {
+ [ 1] = 0, [ 2] = 1, [ 3] = 0, [ 4] = 0, [ 5] = 0,
+ [ 6] = 1, [ 7] = 0, [ 8] = 0, [ 9] = 0, [ 10] = 1,
+ [ 11] = 0, [ 12] = 0, [ 13] = 0, [ 14] = 1, [ 15] = 0,
+ [ 16] = 0, [ 17] = 0, [ 18] = 1, [ 19] = 0, [ 20] = 0,
+ [ 21] = 0, [ 22] = 1, [ 23] = 0, [ 24] = 0, [ 25] = 0,
+ [ 26] = 1, [ 27] = 0, [ 28] = 0, [ 29] = 0, [ 30] = 1,
+ [ 31] = 0, [ 32] = 0, [ 33] = 0, [ 34] = 1, [ 35] = 0,
+ [ 36] = 0, [ 37] = 0, [ 38] = 1, [ 39] = 0, [ 40] = 0,
+ [ 41] = 0, [ 42] = 1, [ 43] = 0, [ 44] = 0, [ 45] = 0,
+ [ 46] = 1, [ 47] = 0, [ 48] = 0, [ 49] = 0, [ 50] = 1,
+ [ 51] = 0, [ 52] = 0, [ 53] = 0, [ 54] = 1, [ 55] = 0,
+ [ 56] = 0, [ 57] = 0, [ 58] = 1, [ 59] = 0, [ 60] = 0,
+ [ 61] = 0, [ 62] = 1, [ 63] = 0, [ 64] = 0, [ 65] = 0,
+ [ 66] = 1, [ 67] = 0, [ 68] = 0, [ 69] = 0, [ 70] = 1,
+ [ 71] = 0, [ 72] = 0, [ 73] = 0, [ 74] = 1, [ 75] = 0,
+ [ 76] = 0, [ 77] = 0, [ 78] = 1, [ 79] = 0, [ 80] = 0,
+ [ 81] = 0, [ 82] = 1, [ 83] = 0, [ 84] = 0, [ 85] = 0,
+ [ 86] = 1, [ 87] = 0, [ 88] = 0, [ 89] = 0, [ 90] = 1,
+ [ 91] = 0, [ 92] = 0, [ 93] = 0, [ 94] = 1, [ 95] = 0,
+ [ 96] = 0, [ 97] = 0, [ 98] = 1, [ 99] = 0, [100] = 0,
+ [101] = 0, [102] = 1, [103] = 0, [104] = 0, [105] = 0,
+ [106] = 1, [107] = 0, [108] = 0, [109] = 0, [110] = 1,
+ [111] = 0, [112] = 0, [113] = 0, [114] = 1, [115] = 0,
+ [116] = 0, [117] = 0, [118] = 1, [119] = 0, [120] = 0,
+ [121] = 0, [122] = 1, [123] = 0, [124] = 0, [125] = 0,
+ [126] = 1, [127] = 0, [128] = 0, [129] = 0, [130] = 0,
+ [131] = 0, [132] = 0, [133] = 0, [134] = 1, [135] = 0,
+};
+
+// 0 ~ 1970 ... 135 ~ 2105
+static const uint16_t days_across_years[] = {
+ [ 1] = 365, [ 2] = 730, [ 3] = 1096, [ 4] = 1461, [ 5] = 1826,
+ [ 6] = 2191, [ 7] = 2557, [ 8] = 2922, [ 9] = 3287, [ 10] = 3652,
+ [ 11] = 4018, [ 12] = 4383, [ 13] = 4748, [ 14] = 5113, [ 15] = 5479,
+ [ 16] = 5844, [ 17] = 6209, [ 18] = 6574, [ 19] = 6940, [ 20] = 7305,
+ [ 21] = 7670, [ 22] = 8035, [ 23] = 8401, [ 24] = 8766, [ 25] = 9131,
+ [ 26] = 9496, [ 27] = 9862, [ 28] = 10227, [ 29] = 10592, [ 30] = 10957,
+ [ 31] = 11323, [ 32] = 11688, [ 33] = 12053, [ 34] = 12418, [ 35] = 12784,
+ [ 36] = 13149, [ 37] = 13514, [ 38] = 13879, [ 39] = 14245, [ 40] = 14610,
+ [ 41] = 14975, [ 42] = 15340, [ 43] = 15706, [ 44] = 16071, [ 45] = 16436,
+ [ 46] = 16801, [ 47] = 17167, [ 48] = 17532, [ 49] = 17897, [ 50] = 18262,
+ [ 51] = 18628, [ 52] = 18993, [ 53] = 19358, [ 54] = 19723, [ 55] = 20089,
+ [ 56] = 20454, [ 57] = 20819, [ 58] = 21184, [ 59] = 21550, [ 60] = 21915,
+ [ 61] = 22280, [ 62] = 22645, [ 63] = 23011, [ 64] = 23376, [ 65] = 23741,
+ [ 66] = 24106, [ 67] = 24472, [ 68] = 24837, [ 69] = 25202, [ 70] = 25567,
+ [ 71] = 25933, [ 72] = 26298, [ 73] = 26663, [ 74] = 27028, [ 75] = 27394,
+ [ 76] = 27759, [ 77] = 28124, [ 78] = 28489, [ 79] = 28855, [ 80] = 29220,
+ [ 81] = 29585, [ 82] = 29950, [ 83] = 30316, [ 84] = 30681, [ 85] = 31046,
+ [ 86] = 31411, [ 87] = 31777, [ 88] = 32142, [ 89] = 32507, [ 90] = 32872,
+ [ 91] = 33238, [ 92] = 33603, [ 93] = 33968, [ 94] = 34333, [ 95] = 34699,
+ [ 96] = 35064, [ 97] = 35429, [ 98] = 35794, [ 99] = 36160, [100] = 36525,
+ [101] = 36890, [102] = 37255, [103] = 37621, [104] = 37986, [105] = 38351,
+ [106] = 38716, [107] = 39082, [108] = 39447, [109] = 39812, [110] = 40177,
+ [111] = 40543, [112] = 40908, [113] = 41273, [114] = 41638, [115] = 42004,
+ [116] = 42369, [117] = 42734, [118] = 43099, [119] = 43465, [120] = 43830,
+ [121] = 44195, [122] = 44560, [123] = 44926, [124] = 45291, [125] = 45656,
+ [126] = 46021, [127] = 46387, [128] = 46752, [129] = 47117, [130] = 47482,
+ [131] = 47847, [132] = 48212, [133] = 48577, [134] = 48942, [135] = 49308,
+};
+
+int date_to_timestamp(uint8_t *buff, uint32_t *timestamp)
+{
+ uint32_t year, month, day, hour, minute, second;
+ uint32_t leap_day = 0;
+
+ year = 1000 * (buff[ 0] - '0') + 100 * (buff[ 1] - '0') +
+ 10 * (buff[ 2] - '0') + (buff[ 3] - '0');
+ month = 10 * (buff[ 4] - '0') + (buff[ 5] - '0');
+ day = 10 * (buff[ 6] - '0') + (buff[ 7] - '0');
+ hour = 10 * (buff[ 8] - '0') + (buff[ 9] - '0');
+ minute = 10 * (buff[10] - '0') + (buff[11] - '0');
+ second = 10 * (buff[12] - '0') + (buff[13] - '0');
+
+ if (year < 1970 || year > 2105 || month < 1 || month > 12 || day < 1) {
+ return ZS_BAD_DATE;
+ } else {
+ year -= 1970;
+ }
+
+ if (is_leap_year[year]) {
+ if (month > 2) {
+ leap_day = 1; // Add one day in case of leap year.
+ } else if (month == 2 &&
+ day > (uint32_t)(days_in_months[month] + 1)) {
+ return ZS_BAD_DATE;
+ }
+ } else if (day > days_in_months[month]){
+ return ZS_BAD_DATE;
+ }
+
+ if (hour > 23 || minute > 59 || second > 59) {
+ return ZS_BAD_TIME;
+ }
+
+ *timestamp = hour * 3600 + minute * 60 + second +
+ (days_across_years[year] +
+ days_across_months[month] +
+ day - 1 + leap_day) * 86400;
+
+ return ZS_OK;
+}
+
+void wire_dname_to_str(const uint8_t *data,
+ const uint32_t data_len,
+ char *text)
+{
+ uint32_t i = 0, text_len = 0;
+
+ if (data == NULL || data_len == 0 || text == NULL) {
+ return;
+ }
+
+ uint8_t label_len = data[0];
+
+ // Loop over data characters.
+ for (i = 1; i < data_len; i++) {
+ // Replace label length with dot.
+ if (label_len == 0) {
+ label_len = data[i];
+ text[text_len++] = '.';
+ continue;
+ }
+
+ // Just in case use \123 notation.
+ text[text_len++] = '\\';
+ text[text_len++] = (data[i] / 100) + '0';
+ text[text_len++] = (data[i] / 10) % 10 + '0';
+ text[text_len++] = (data[i] ) % 10 + '0';
+
+ label_len--;
+ }
+
+ // Add trailing dot for root domain.
+ if (data_len == 1 && label_len == 0) {
+ text[text_len++] = '.';
+ }
+
+ // Ending text string.
+ text[text_len] = 0;
+}
+
+uint8_t loc64to8(uint64_t number)
+{
+ uint8_t exponent = 0;
+
+ while (number > 9) {
+ number /= 10;
+ exponent++;
+ }
+ // First 4 bits are mantisa, second 4 bits are exponent.
+ return ((uint8_t)number << 4) + (exponent & 15);
+}
diff --git a/src/libzscanner/functions.h b/src/libzscanner/functions.h
new file mode 100644
index 0000000..ba1bc16
--- /dev/null
+++ b/src/libzscanner/functions.h
@@ -0,0 +1,110 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief Zone scanner auxiliary functions.
+ *
+ * \addtogroup zone_scanner
+ * @{
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+/*! \brief Transforms digit char to number. */
+extern const uint8_t digit_to_num[];
+
+/*! \brief Transforms first hex char to the part of the total number. */
+extern const uint8_t first_hex_to_num[];
+/*! \brief Transforms second hex char to the part of the total number. */
+extern const uint8_t second_hex_to_num[];
+
+/*! \brief Transforms first Base64 char. */
+extern const uint8_t first_base64_to_num[];
+/*! \brief Transforms left part of the second Base64 char. */
+extern const uint8_t second_left_base64_to_num[];
+/*! \brief Transforms left part of the second Base64 char. */
+extern const uint8_t second_right_base64_to_num[];
+/*! \brief Transforms left part of the third Base64 char. */
+extern const uint8_t third_left_base64_to_num[];
+/*! \brief Transforms left part of the third Base64 char. */
+extern const uint8_t third_right_base64_to_num[];
+/*! \brief Transforms fourth Base64 char. */
+extern const uint8_t fourth_base64_to_num[];
+
+/*! \brief Transforms first Base32hex char. */
+extern const uint8_t first_base32hex_to_num[];
+/*! \brief Transforms left part of the second Base32hex char. */
+extern const uint8_t second_left_base32hex_to_num[];
+/*! \brief Transforms right part of the second Base32hex char. */
+extern const uint8_t second_right_base32hex_to_num[];
+/*! \brief Transforms third Base32hex char. */
+extern const uint8_t third_base32hex_to_num[];
+/*! \brief Transforms left part of the fourth Base32hex char. */
+extern const uint8_t fourth_left_base32hex_to_num[];
+/*! \brief Transforms right part of the fourth Base32hex char. */
+extern const uint8_t fourth_right_base32hex_to_num[];
+/*! \brief Transforms left part of the fifth Base32hex char. */
+extern const uint8_t fifth_left_base32hex_to_num[];
+/*! \brief Transforms right part of the fifth Base32hex char. */
+extern const uint8_t fifth_right_base32hex_to_num[];
+/*! \brief Transforms sixth Base32hex char. */
+extern const uint8_t sixth_base32hex_to_num[];
+/*! \brief Transforms left part of the seventh Base32hex char. */
+extern const uint8_t seventh_left_base32hex_to_num[];
+/*! \brief Transforms right part of the seventh Base32hex char. */
+extern const uint8_t seventh_right_base32hex_to_num[];
+/*! \brief Transforms eighth Base32hex char. */
+extern const uint8_t eighth_base32hex_to_num[];
+
+/*!
+ * \brief Converts YYYYMMDDHHMMSS time string to unsigned 32-bit timestamp.
+ *
+ * \param buff Buffer containing time string.
+ * \param timestamp Computed timestamp.
+ *
+ * \retval KNOT_EOK if success.
+ * \retval error_code if error.
+ */
+int date_to_timestamp(uint8_t *buff, uint32_t *timestamp);
+
+/*!
+ * \brief Converts wire-format dname to text dname.
+ *
+ * \param data Buffer containg wire-format dname.
+ * \param data_len Length of the buffer.
+ * \param text Text output.
+ */
+void wire_dname_to_str(const uint8_t *data,
+ const uint32_t data_len,
+ char *text);
+
+/*!
+ * \brief Converts unsigned integer to mantisa*10^(exponent).
+ *
+ * Given number is encoded as two 4-bit numbers. First part is mantisa [0-9],
+ * second part is decimal exponent [0-15]. Result is concatenation of these
+ * two blocks.
+ *
+ * \param number Number to convert.
+ *
+ * \retval number encoded number.
+ */
+uint8_t loc64to8(uint64_t number);
+
+/*! @} */
diff --git a/src/libzscanner/scanner.c.g2 b/src/libzscanner/scanner.c.g2
new file mode 100644
index 0000000..ad1d774
--- /dev/null
+++ b/src/libzscanner/scanner.c.g2
@@ -0,0 +1,85519 @@
+
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libgen.h>
+#include <math.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "libzscanner/scanner.h"
+#include "libzscanner/functions.h"
+#include "libknot/descriptor.h"
+
+/*! \brief Maximal length of rdata item. */
+#define MAX_ITEM_LENGTH 255
+
+/*! \brief Latitude value for equator (2^31). */
+#define LOC_LAT_ZERO (uint32_t)2147483648
+/*! \brief Longitude value for meridian (2^31). */
+#define LOC_LONG_ZERO (uint32_t)2147483648
+/*! \brief Zero level altitude value. */
+#define LOC_ALT_ZERO (uint32_t)10000000
+
+/*! \brief Shorthand for setting warning data. */
+#define WARN(err_code) { s->error.code = err_code; }
+/*! \brief Shorthand for setting error data. */
+#define ERR(err_code) { WARN(err_code); s->error.fatal = true; }
+/*! \brief Shorthand for error reset. */
+#define NOERR { WARN(ZS_OK); s->error.fatal = false; }
+
+/*!
+ * \brief Writes record type number to r_data.
+ *
+ * \param type Type number.
+ * \param rdata_tail Position where to write type number to.
+ */
+static inline void type_num(const uint16_t type, uint8_t **rdata_tail)
+{
+ *((uint16_t *)*rdata_tail) = htons(type);
+ *rdata_tail += 2;
+}
+
+/*!
+ * \brief Sets bit to bitmap window.
+ *
+ * \param type Type number.
+ * \param s Scanner context.
+ */
+static inline void window_add_bit(const uint16_t type, zs_scanner_t *s) {
+ uint8_t win = type / 256;
+ uint8_t bit_pos = type % 256;
+ uint8_t byte_pos = bit_pos / 8;
+
+ ((s->windows[win]).bitmap)[byte_pos] |= 128 >> (bit_pos % 8);
+
+ if ((s->windows[win]).length < byte_pos + 1) {
+ (s->windows[win]).length = byte_pos + 1;
+ }
+
+ if (s->last_window < win) {
+ s->last_window = win;
+ }
+}
+
+// Include scanner file (in Ragel).
+
+
+
+
+
+
+__attribute__((visibility("default")))
+int zs_init(
+ zs_scanner_t *s,
+ const char *origin,
+ const uint16_t rclass,
+ const uint32_t ttl)
+{
+ if (s == NULL) {
+ return -1;
+ }
+
+ memset(s, 0, sizeof(*s));
+
+ // Nonzero initial scanner state.
+ s->cs = 1127;
+
+ // Reset the file descriptor.
+ s->file.descriptor = -1;
+
+ // Use the root zone as origin if not specified.
+ if (origin == NULL || strlen(origin) == 0) {
+ origin = ".";
+ }
+ size_t origin_len = strlen(origin);
+
+ // Prepare a zone settings header.
+ const char *format;
+ if (origin[origin_len - 1] != '.') {
+ format = "$ORIGIN %s.\n";
+ } else {
+ format = "$ORIGIN %s\n";
+ }
+
+ char settings[1024];
+ int ret = snprintf(settings, sizeof(settings), format, origin);
+ if (ret <= 0 || ret >= sizeof(settings)) {
+ ERR(ZS_ENOMEM);
+ return -1;
+ }
+
+ // Parse the settings to set up the scanner origin.
+ if (zs_set_input_string(s, settings, ret) != 0 ||
+ zs_parse_all(s) != 0) {
+ return -1;
+ }
+
+ // Set scanner defaults.
+ s->path = strdup(".");
+ if (s->path == NULL) {
+ ERR(ZS_ENOMEM);
+ return -1;
+ }
+ s->default_class = rclass;
+ s->default_ttl = ttl;
+ s->line_counter = 1;
+
+ s->state = ZS_STATE_NONE;
+ s->process.automatic = false;
+
+ return 0;
+}
+
+static void input_deinit(
+ zs_scanner_t *s,
+ bool keep_filename)
+{
+ // Deinit the file input.
+ if (s->file.descriptor != -1) {
+ // Unmap the file content.
+ if (s->input.start != NULL) {
+ if (s->input.mmaped) {
+ munmap((void *)s->input.start,
+ s->input.end - s->input.start);
+ } else {
+ free((void *)s->input.start);
+ }
+ }
+
+ // Close the opened file.
+ close(s->file.descriptor);
+ s->file.descriptor = -1;
+ }
+
+ // Keep file name for possible trailing error report.
+ if (!keep_filename) {
+ free(s->file.name);
+ s->file.name = NULL;
+ }
+
+ // Unset the input limits.
+ s->input.start = NULL;
+ s->input.current = NULL;
+ s->input.end = NULL;
+ s->input.eof = false;
+}
+
+__attribute__((visibility("default")))
+void zs_deinit(
+ zs_scanner_t *s)
+{
+ if (s == NULL) {
+ return;
+ }
+
+ input_deinit(s, false);
+ free(s->path);
+}
+
+static int set_input_string(
+ zs_scanner_t *s,
+ const char *input,
+ size_t size,
+ bool final_block)
+{
+ if (s == NULL) {
+ return -1;
+ }
+
+ if (input == NULL) {
+ ERR(ZS_EINVAL);
+ return -1;
+ }
+
+ // Deinit possibly opened file.
+ input_deinit(s, final_block);
+
+ // Set the scanner input limits.
+ s->input.start = input;
+ s->input.current = input;
+ s->input.end = input + size;
+ s->input.eof = final_block;
+
+ return 0;
+}
+
+static char *read_file_to_buf(
+ int fd,
+ size_t *bufsize)
+{
+ size_t bufs = 0, newbufs = 8192;
+ char *buf = malloc(bufs + newbufs);
+ int ret = 0;
+
+ while (buf != NULL && (ret = read(fd, buf + bufs, newbufs)) == newbufs) {
+ bufs += newbufs;
+ newbufs = bufs;
+ char *newbuf = realloc(buf, bufs + newbufs);
+ if (newbuf == NULL) {
+ free(buf);
+ }
+ buf = newbuf;
+ }
+ if (ret < 0) {
+ free(buf);
+ return NULL;
+ }
+
+ *bufsize = bufs + ret;
+ return buf;
+}
+
+__attribute__((visibility("default")))
+int zs_set_input_string(
+ zs_scanner_t *s,
+ const char *input,
+ size_t size)
+{
+ s->state = ZS_STATE_NONE;
+
+ return set_input_string(s, input, size, false);
+}
+
+__attribute__((visibility("default")))
+int zs_set_input_file(
+ zs_scanner_t *s,
+ const char *file_name)
+{
+ if (s == NULL) {
+ return -1;
+ }
+
+ if (file_name == NULL) {
+ ERR(ZS_EINVAL);
+ return -1;
+ }
+
+ // Deinit possibly opened file.
+ input_deinit(s, false);
+
+ // Try to open the file.
+ s->file.descriptor = open(file_name, O_RDONLY);
+ if (s->file.descriptor == -1) {
+ ERR(ZS_FILE_OPEN);
+ return -1;
+ }
+
+ char *start = NULL;
+ size_t size = 0;
+
+ // Check the input.
+ struct stat file_stat;
+ if (fstat(s->file.descriptor, &file_stat) == -1) {
+ ERR(ZS_FILE_INVALID);
+ input_deinit(s, false);
+ return -1;
+ } else if (S_ISCHR(file_stat.st_mode) ||
+ S_ISBLK(file_stat.st_mode) ||
+ S_ISFIFO(file_stat.st_mode)) {
+ // Workaround if cannot mmap, read to memory.
+ start = read_file_to_buf(s->file.descriptor, &size);
+ if (start == NULL) {
+ ERR(ZS_FILE_INVALID);
+ input_deinit(s, false);
+ return -1;
+ }
+ } else if (!S_ISREG(file_stat.st_mode)) { // Require regular file.
+ ERR(ZS_FILE_INVALID);
+ input_deinit(s, false);
+ return -1;
+ } else if (file_stat.st_size > 0) { // Mmap non-emtpy file.
+ start = mmap(0, file_stat.st_size, PROT_READ, MAP_SHARED,
+ s->file.descriptor, 0);
+ if (start == MAP_FAILED) {
+ ERR(ZS_FILE_INVALID);
+ input_deinit(s, false);
+ return -1;
+ }
+
+ size = file_stat.st_size;
+ s->input.mmaped = true;
+
+ // Try to set the mapped memory advise to sequential.
+ (void)madvise(start, size, MADV_SEQUENTIAL);
+ }
+
+ // Set the scanner input limits.
+ s->input.start = start;
+ s->input.current = start;
+ s->input.end = start + size;
+
+ // Get absolute path of the zone file if possible.
+ char *full_name = realpath(file_name, NULL);
+ if (full_name != NULL) {
+ free(s->path);
+ s->path = strdup(dirname(full_name));
+ free(full_name);
+ if (s->path == NULL) {
+ ERR(ZS_ENOMEM);
+ input_deinit(s, false);
+ return -1;
+ }
+ }
+
+ s->file.name = strdup(file_name);
+ if (s->file.name == NULL) {
+ ERR(ZS_ENOMEM);
+ input_deinit(s, false);
+ return -1;
+ }
+
+ s->state = ZS_STATE_NONE;
+
+ return 0;
+}
+
+__attribute__((visibility("default")))
+int zs_set_processing(
+ zs_scanner_t *s,
+ void (*process_record)(zs_scanner_t *),
+ void (*process_error)(zs_scanner_t *),
+ void *data)
+{
+ if (s == NULL) {
+ return -1;
+ }
+
+ s->process.record = process_record;
+ s->process.error = process_error;
+ s->process.data = data;
+
+ return 0;
+}
+
+typedef enum {
+ WRAP_NONE, // Initial state.
+ WRAP_DETECTED, // Input block end is a first '\' in rdata.
+ WRAP_PROCESS // Parsing of auxiliary block = "\".
+} wrap_t;
+
+static void parse(
+ zs_scanner_t *s,
+ wrap_t *wrap)
+{
+ // Restore scanner input limits (Ragel internals).
+ const char *p = s->input.current;
+ const char *pe = s->input.end;
+ const char *eof = s->input.eof ? pe : NULL;
+
+ // Restore state variables (Ragel internals).
+ int cs = s->cs;
+ int top = s->top;
+ int stack[ZS_RAGEL_STACK_SIZE];
+ memcpy(stack, s->stack, sizeof(stack));
+
+ // Next 2 variables are for better performance.
+ // Restoring r_data pointer to next free space.
+ uint8_t *rdata_tail = s->r_data + s->r_data_tail;
+ // Initialization of the last r_data byte.
+ uint8_t *rdata_stop = s->r_data + ZS_MAX_RDATA_LENGTH - 1;
+
+ // Write scanner body (in C).
+
+ {
+ short _widec;
+ if ( p == pe )
+ goto _test_eof;
+ goto _resume;
+
+_again:
+ switch ( cs ) {
+ case 1127: goto st1127;
+ case 0: goto st0;
+ case 1: goto st1;
+ case 2: goto st2;
+ case 3: goto st3;
+ case 4: goto st4;
+ case 5: goto st5;
+ case 6: goto st6;
+ case 7: goto st7;
+ case 8: goto st8;
+ case 9: goto st9;
+ case 10: goto st10;
+ case 11: goto st11;
+ case 12: goto st12;
+ case 13: goto st13;
+ case 1128: goto st1128;
+ case 14: goto st14;
+ case 15: goto st15;
+ case 16: goto st16;
+ case 17: goto st17;
+ case 18: goto st18;
+ case 19: goto st19;
+ case 20: goto st20;
+ case 21: goto st21;
+ case 22: goto st22;
+ case 23: goto st23;
+ case 24: goto st24;
+ case 25: goto st25;
+ case 26: goto st26;
+ case 27: goto st27;
+ case 28: goto st28;
+ case 29: goto st29;
+ case 30: goto st30;
+ case 31: goto st31;
+ case 32: goto st32;
+ case 33: goto st33;
+ case 34: goto st34;
+ case 35: goto st35;
+ case 36: goto st36;
+ case 37: goto st37;
+ case 38: goto st38;
+ case 39: goto st39;
+ case 40: goto st40;
+ case 41: goto st41;
+ case 42: goto st42;
+ case 43: goto st43;
+ case 44: goto st44;
+ case 45: goto st45;
+ case 46: goto st46;
+ case 47: goto st47;
+ case 48: goto st48;
+ case 49: goto st49;
+ case 50: goto st50;
+ case 51: goto st51;
+ case 52: goto st52;
+ case 53: goto st53;
+ case 54: goto st54;
+ case 55: goto st55;
+ case 56: goto st56;
+ case 57: goto st57;
+ case 58: goto st58;
+ case 59: goto st59;
+ case 60: goto st60;
+ case 61: goto st61;
+ case 62: goto st62;
+ case 63: goto st63;
+ case 64: goto st64;
+ case 65: goto st65;
+ case 66: goto st66;
+ case 67: goto st67;
+ case 68: goto st68;
+ case 69: goto st69;
+ case 70: goto st70;
+ case 71: goto st71;
+ case 72: goto st72;
+ case 73: goto st73;
+ case 74: goto st74;
+ case 75: goto st75;
+ case 76: goto st76;
+ case 77: goto st77;
+ case 78: goto st78;
+ case 79: goto st79;
+ case 80: goto st80;
+ case 81: goto st81;
+ case 82: goto st82;
+ case 83: goto st83;
+ case 84: goto st84;
+ case 85: goto st85;
+ case 86: goto st86;
+ case 87: goto st87;
+ case 88: goto st88;
+ case 89: goto st89;
+ case 90: goto st90;
+ case 91: goto st91;
+ case 92: goto st92;
+ case 93: goto st93;
+ case 94: goto st94;
+ case 95: goto st95;
+ case 96: goto st96;
+ case 97: goto st97;
+ case 98: goto st98;
+ case 99: goto st99;
+ case 100: goto st100;
+ case 101: goto st101;
+ case 102: goto st102;
+ case 103: goto st103;
+ case 104: goto st104;
+ case 105: goto st105;
+ case 106: goto st106;
+ case 107: goto st107;
+ case 108: goto st108;
+ case 109: goto st109;
+ case 110: goto st110;
+ case 111: goto st111;
+ case 112: goto st112;
+ case 113: goto st113;
+ case 114: goto st114;
+ case 115: goto st115;
+ case 116: goto st116;
+ case 117: goto st117;
+ case 118: goto st118;
+ case 119: goto st119;
+ case 120: goto st120;
+ case 121: goto st121;
+ case 122: goto st122;
+ case 123: goto st123;
+ case 124: goto st124;
+ case 125: goto st125;
+ case 126: goto st126;
+ case 127: goto st127;
+ case 128: goto st128;
+ case 129: goto st129;
+ case 130: goto st130;
+ case 131: goto st131;
+ case 132: goto st132;
+ case 133: goto st133;
+ case 134: goto st134;
+ case 135: goto st135;
+ case 136: goto st136;
+ case 137: goto st137;
+ case 138: goto st138;
+ case 139: goto st139;
+ case 140: goto st140;
+ case 141: goto st141;
+ case 1129: goto st1129;
+ case 142: goto st142;
+ case 143: goto st143;
+ case 144: goto st144;
+ case 145: goto st145;
+ case 146: goto st146;
+ case 147: goto st147;
+ case 148: goto st148;
+ case 149: goto st149;
+ case 150: goto st150;
+ case 151: goto st151;
+ case 1130: goto st1130;
+ case 152: goto st152;
+ case 153: goto st153;
+ case 154: goto st154;
+ case 155: goto st155;
+ case 156: goto st156;
+ case 157: goto st157;
+ case 158: goto st158;
+ case 159: goto st159;
+ case 1131: goto st1131;
+ case 160: goto st160;
+ case 161: goto st161;
+ case 162: goto st162;
+ case 1132: goto st1132;
+ case 163: goto st163;
+ case 164: goto st164;
+ case 165: goto st165;
+ case 166: goto st166;
+ case 167: goto st167;
+ case 168: goto st168;
+ case 169: goto st169;
+ case 170: goto st170;
+ case 171: goto st171;
+ case 172: goto st172;
+ case 173: goto st173;
+ case 1133: goto st1133;
+ case 174: goto st174;
+ case 175: goto st175;
+ case 176: goto st176;
+ case 177: goto st177;
+ case 1134: goto st1134;
+ case 178: goto st178;
+ case 179: goto st179;
+ case 180: goto st180;
+ case 181: goto st181;
+ case 182: goto st182;
+ case 183: goto st183;
+ case 184: goto st184;
+ case 185: goto st185;
+ case 186: goto st186;
+ case 187: goto st187;
+ case 188: goto st188;
+ case 189: goto st189;
+ case 190: goto st190;
+ case 191: goto st191;
+ case 192: goto st192;
+ case 193: goto st193;
+ case 1135: goto st1135;
+ case 194: goto st194;
+ case 195: goto st195;
+ case 196: goto st196;
+ case 197: goto st197;
+ case 198: goto st198;
+ case 199: goto st199;
+ case 200: goto st200;
+ case 201: goto st201;
+ case 202: goto st202;
+ case 203: goto st203;
+ case 204: goto st204;
+ case 205: goto st205;
+ case 206: goto st206;
+ case 207: goto st207;
+ case 208: goto st208;
+ case 209: goto st209;
+ case 1136: goto st1136;
+ case 210: goto st210;
+ case 211: goto st211;
+ case 212: goto st212;
+ case 213: goto st213;
+ case 214: goto st214;
+ case 215: goto st215;
+ case 216: goto st216;
+ case 217: goto st217;
+ case 218: goto st218;
+ case 219: goto st219;
+ case 220: goto st220;
+ case 221: goto st221;
+ case 222: goto st222;
+ case 223: goto st223;
+ case 224: goto st224;
+ case 225: goto st225;
+ case 226: goto st226;
+ case 227: goto st227;
+ case 228: goto st228;
+ case 229: goto st229;
+ case 230: goto st230;
+ case 231: goto st231;
+ case 232: goto st232;
+ case 233: goto st233;
+ case 234: goto st234;
+ case 235: goto st235;
+ case 236: goto st236;
+ case 237: goto st237;
+ case 238: goto st238;
+ case 239: goto st239;
+ case 240: goto st240;
+ case 241: goto st241;
+ case 242: goto st242;
+ case 243: goto st243;
+ case 244: goto st244;
+ case 245: goto st245;
+ case 246: goto st246;
+ case 247: goto st247;
+ case 248: goto st248;
+ case 249: goto st249;
+ case 250: goto st250;
+ case 251: goto st251;
+ case 252: goto st252;
+ case 253: goto st253;
+ case 254: goto st254;
+ case 255: goto st255;
+ case 256: goto st256;
+ case 257: goto st257;
+ case 258: goto st258;
+ case 259: goto st259;
+ case 260: goto st260;
+ case 261: goto st261;
+ case 262: goto st262;
+ case 263: goto st263;
+ case 264: goto st264;
+ case 265: goto st265;
+ case 266: goto st266;
+ case 267: goto st267;
+ case 268: goto st268;
+ case 269: goto st269;
+ case 1137: goto st1137;
+ case 270: goto st270;
+ case 271: goto st271;
+ case 1138: goto st1138;
+ case 272: goto st272;
+ case 273: goto st273;
+ case 274: goto st274;
+ case 275: goto st275;
+ case 276: goto st276;
+ case 277: goto st277;
+ case 278: goto st278;
+ case 279: goto st279;
+ case 280: goto st280;
+ case 1139: goto st1139;
+ case 1140: goto st1140;
+ case 281: goto st281;
+ case 282: goto st282;
+ case 283: goto st283;
+ case 284: goto st284;
+ case 285: goto st285;
+ case 286: goto st286;
+ case 287: goto st287;
+ case 288: goto st288;
+ case 289: goto st289;
+ case 290: goto st290;
+ case 291: goto st291;
+ case 292: goto st292;
+ case 293: goto st293;
+ case 294: goto st294;
+ case 1141: goto st1141;
+ case 295: goto st295;
+ case 296: goto st296;
+ case 297: goto st297;
+ case 298: goto st298;
+ case 299: goto st299;
+ case 300: goto st300;
+ case 301: goto st301;
+ case 302: goto st302;
+ case 303: goto st303;
+ case 304: goto st304;
+ case 1142: goto st1142;
+ case 305: goto st305;
+ case 306: goto st306;
+ case 307: goto st307;
+ case 308: goto st308;
+ case 309: goto st309;
+ case 310: goto st310;
+ case 311: goto st311;
+ case 312: goto st312;
+ case 313: goto st313;
+ case 314: goto st314;
+ case 315: goto st315;
+ case 316: goto st316;
+ case 317: goto st317;
+ case 318: goto st318;
+ case 1143: goto st1143;
+ case 319: goto st319;
+ case 320: goto st320;
+ case 321: goto st321;
+ case 322: goto st322;
+ case 323: goto st323;
+ case 324: goto st324;
+ case 325: goto st325;
+ case 1144: goto st1144;
+ case 326: goto st326;
+ case 327: goto st327;
+ case 328: goto st328;
+ case 329: goto st329;
+ case 330: goto st330;
+ case 331: goto st331;
+ case 332: goto st332;
+ case 333: goto st333;
+ case 334: goto st334;
+ case 1145: goto st1145;
+ case 1146: goto st1146;
+ case 1147: goto st1147;
+ case 335: goto st335;
+ case 336: goto st336;
+ case 337: goto st337;
+ case 338: goto st338;
+ case 339: goto st339;
+ case 340: goto st340;
+ case 341: goto st341;
+ case 342: goto st342;
+ case 1148: goto st1148;
+ case 1149: goto st1149;
+ case 343: goto st343;
+ case 344: goto st344;
+ case 345: goto st345;
+ case 1150: goto st1150;
+ case 346: goto st346;
+ case 347: goto st347;
+ case 348: goto st348;
+ case 349: goto st349;
+ case 350: goto st350;
+ case 351: goto st351;
+ case 352: goto st352;
+ case 353: goto st353;
+ case 354: goto st354;
+ case 355: goto st355;
+ case 356: goto st356;
+ case 357: goto st357;
+ case 358: goto st358;
+ case 359: goto st359;
+ case 360: goto st360;
+ case 361: goto st361;
+ case 362: goto st362;
+ case 363: goto st363;
+ case 364: goto st364;
+ case 365: goto st365;
+ case 366: goto st366;
+ case 367: goto st367;
+ case 368: goto st368;
+ case 369: goto st369;
+ case 370: goto st370;
+ case 371: goto st371;
+ case 372: goto st372;
+ case 373: goto st373;
+ case 374: goto st374;
+ case 375: goto st375;
+ case 376: goto st376;
+ case 377: goto st377;
+ case 378: goto st378;
+ case 379: goto st379;
+ case 380: goto st380;
+ case 381: goto st381;
+ case 382: goto st382;
+ case 383: goto st383;
+ case 384: goto st384;
+ case 385: goto st385;
+ case 386: goto st386;
+ case 387: goto st387;
+ case 388: goto st388;
+ case 389: goto st389;
+ case 390: goto st390;
+ case 391: goto st391;
+ case 392: goto st392;
+ case 393: goto st393;
+ case 394: goto st394;
+ case 395: goto st395;
+ case 396: goto st396;
+ case 397: goto st397;
+ case 398: goto st398;
+ case 399: goto st399;
+ case 400: goto st400;
+ case 401: goto st401;
+ case 402: goto st402;
+ case 403: goto st403;
+ case 404: goto st404;
+ case 405: goto st405;
+ case 406: goto st406;
+ case 407: goto st407;
+ case 408: goto st408;
+ case 409: goto st409;
+ case 410: goto st410;
+ case 411: goto st411;
+ case 412: goto st412;
+ case 413: goto st413;
+ case 414: goto st414;
+ case 415: goto st415;
+ case 416: goto st416;
+ case 417: goto st417;
+ case 418: goto st418;
+ case 419: goto st419;
+ case 420: goto st420;
+ case 421: goto st421;
+ case 422: goto st422;
+ case 423: goto st423;
+ case 424: goto st424;
+ case 425: goto st425;
+ case 426: goto st426;
+ case 427: goto st427;
+ case 428: goto st428;
+ case 429: goto st429;
+ case 430: goto st430;
+ case 431: goto st431;
+ case 432: goto st432;
+ case 433: goto st433;
+ case 434: goto st434;
+ case 435: goto st435;
+ case 436: goto st436;
+ case 437: goto st437;
+ case 438: goto st438;
+ case 439: goto st439;
+ case 440: goto st440;
+ case 441: goto st441;
+ case 442: goto st442;
+ case 443: goto st443;
+ case 444: goto st444;
+ case 445: goto st445;
+ case 446: goto st446;
+ case 447: goto st447;
+ case 448: goto st448;
+ case 449: goto st449;
+ case 450: goto st450;
+ case 451: goto st451;
+ case 452: goto st452;
+ case 453: goto st453;
+ case 454: goto st454;
+ case 455: goto st455;
+ case 456: goto st456;
+ case 457: goto st457;
+ case 458: goto st458;
+ case 459: goto st459;
+ case 460: goto st460;
+ case 461: goto st461;
+ case 462: goto st462;
+ case 463: goto st463;
+ case 464: goto st464;
+ case 465: goto st465;
+ case 466: goto st466;
+ case 467: goto st467;
+ case 468: goto st468;
+ case 469: goto st469;
+ case 470: goto st470;
+ case 471: goto st471;
+ case 472: goto st472;
+ case 473: goto st473;
+ case 474: goto st474;
+ case 1151: goto st1151;
+ case 1152: goto st1152;
+ case 1153: goto st1153;
+ case 475: goto st475;
+ case 476: goto st476;
+ case 477: goto st477;
+ case 478: goto st478;
+ case 479: goto st479;
+ case 1154: goto st1154;
+ case 480: goto st480;
+ case 481: goto st481;
+ case 482: goto st482;
+ case 483: goto st483;
+ case 1155: goto st1155;
+ case 1156: goto st1156;
+ case 1157: goto st1157;
+ case 484: goto st484;
+ case 485: goto st485;
+ case 1158: goto st1158;
+ case 486: goto st486;
+ case 487: goto st487;
+ case 488: goto st488;
+ case 1159: goto st1159;
+ case 489: goto st489;
+ case 490: goto st490;
+ case 491: goto st491;
+ case 492: goto st492;
+ case 493: goto st493;
+ case 494: goto st494;
+ case 495: goto st495;
+ case 496: goto st496;
+ case 497: goto st497;
+ case 498: goto st498;
+ case 499: goto st499;
+ case 500: goto st500;
+ case 501: goto st501;
+ case 502: goto st502;
+ case 503: goto st503;
+ case 504: goto st504;
+ case 505: goto st505;
+ case 506: goto st506;
+ case 507: goto st507;
+ case 508: goto st508;
+ case 509: goto st509;
+ case 510: goto st510;
+ case 511: goto st511;
+ case 512: goto st512;
+ case 513: goto st513;
+ case 514: goto st514;
+ case 515: goto st515;
+ case 516: goto st516;
+ case 517: goto st517;
+ case 518: goto st518;
+ case 519: goto st519;
+ case 520: goto st520;
+ case 521: goto st521;
+ case 522: goto st522;
+ case 523: goto st523;
+ case 524: goto st524;
+ case 525: goto st525;
+ case 526: goto st526;
+ case 527: goto st527;
+ case 528: goto st528;
+ case 529: goto st529;
+ case 530: goto st530;
+ case 531: goto st531;
+ case 532: goto st532;
+ case 533: goto st533;
+ case 534: goto st534;
+ case 535: goto st535;
+ case 536: goto st536;
+ case 537: goto st537;
+ case 538: goto st538;
+ case 539: goto st539;
+ case 540: goto st540;
+ case 541: goto st541;
+ case 542: goto st542;
+ case 543: goto st543;
+ case 544: goto st544;
+ case 545: goto st545;
+ case 546: goto st546;
+ case 547: goto st547;
+ case 548: goto st548;
+ case 549: goto st549;
+ case 550: goto st550;
+ case 551: goto st551;
+ case 552: goto st552;
+ case 553: goto st553;
+ case 554: goto st554;
+ case 555: goto st555;
+ case 556: goto st556;
+ case 557: goto st557;
+ case 558: goto st558;
+ case 559: goto st559;
+ case 560: goto st560;
+ case 561: goto st561;
+ case 562: goto st562;
+ case 563: goto st563;
+ case 564: goto st564;
+ case 565: goto st565;
+ case 566: goto st566;
+ case 567: goto st567;
+ case 568: goto st568;
+ case 569: goto st569;
+ case 570: goto st570;
+ case 571: goto st571;
+ case 572: goto st572;
+ case 573: goto st573;
+ case 574: goto st574;
+ case 575: goto st575;
+ case 576: goto st576;
+ case 577: goto st577;
+ case 578: goto st578;
+ case 579: goto st579;
+ case 580: goto st580;
+ case 581: goto st581;
+ case 582: goto st582;
+ case 583: goto st583;
+ case 584: goto st584;
+ case 585: goto st585;
+ case 586: goto st586;
+ case 587: goto st587;
+ case 588: goto st588;
+ case 589: goto st589;
+ case 590: goto st590;
+ case 591: goto st591;
+ case 592: goto st592;
+ case 1160: goto st1160;
+ case 593: goto st593;
+ case 594: goto st594;
+ case 595: goto st595;
+ case 596: goto st596;
+ case 597: goto st597;
+ case 598: goto st598;
+ case 599: goto st599;
+ case 600: goto st600;
+ case 601: goto st601;
+ case 602: goto st602;
+ case 603: goto st603;
+ case 604: goto st604;
+ case 605: goto st605;
+ case 606: goto st606;
+ case 607: goto st607;
+ case 608: goto st608;
+ case 609: goto st609;
+ case 610: goto st610;
+ case 611: goto st611;
+ case 612: goto st612;
+ case 613: goto st613;
+ case 614: goto st614;
+ case 615: goto st615;
+ case 616: goto st616;
+ case 617: goto st617;
+ case 618: goto st618;
+ case 619: goto st619;
+ case 620: goto st620;
+ case 621: goto st621;
+ case 622: goto st622;
+ case 623: goto st623;
+ case 624: goto st624;
+ case 625: goto st625;
+ case 626: goto st626;
+ case 627: goto st627;
+ case 628: goto st628;
+ case 629: goto st629;
+ case 630: goto st630;
+ case 631: goto st631;
+ case 632: goto st632;
+ case 633: goto st633;
+ case 1161: goto st1161;
+ case 634: goto st634;
+ case 635: goto st635;
+ case 1162: goto st1162;
+ case 636: goto st636;
+ case 637: goto st637;
+ case 638: goto st638;
+ case 639: goto st639;
+ case 640: goto st640;
+ case 641: goto st641;
+ case 642: goto st642;
+ case 643: goto st643;
+ case 644: goto st644;
+ case 645: goto st645;
+ case 646: goto st646;
+ case 647: goto st647;
+ case 648: goto st648;
+ case 649: goto st649;
+ case 1163: goto st1163;
+ case 650: goto st650;
+ case 651: goto st651;
+ case 652: goto st652;
+ case 653: goto st653;
+ case 654: goto st654;
+ case 655: goto st655;
+ case 656: goto st656;
+ case 657: goto st657;
+ case 658: goto st658;
+ case 659: goto st659;
+ case 660: goto st660;
+ case 661: goto st661;
+ case 662: goto st662;
+ case 663: goto st663;
+ case 664: goto st664;
+ case 665: goto st665;
+ case 666: goto st666;
+ case 667: goto st667;
+ case 668: goto st668;
+ case 669: goto st669;
+ case 670: goto st670;
+ case 671: goto st671;
+ case 1164: goto st1164;
+ case 672: goto st672;
+ case 673: goto st673;
+ case 674: goto st674;
+ case 675: goto st675;
+ case 676: goto st676;
+ case 1165: goto st1165;
+ case 677: goto st677;
+ case 678: goto st678;
+ case 679: goto st679;
+ case 680: goto st680;
+ case 681: goto st681;
+ case 1166: goto st1166;
+ case 682: goto st682;
+ case 683: goto st683;
+ case 684: goto st684;
+ case 685: goto st685;
+ case 686: goto st686;
+ case 1167: goto st1167;
+ case 1168: goto st1168;
+ case 1169: goto st1169;
+ case 687: goto st687;
+ case 688: goto st688;
+ case 1170: goto st1170;
+ case 689: goto st689;
+ case 690: goto st690;
+ case 691: goto st691;
+ case 692: goto st692;
+ case 693: goto st693;
+ case 694: goto st694;
+ case 695: goto st695;
+ case 696: goto st696;
+ case 697: goto st697;
+ case 698: goto st698;
+ case 699: goto st699;
+ case 700: goto st700;
+ case 701: goto st701;
+ case 702: goto st702;
+ case 703: goto st703;
+ case 704: goto st704;
+ case 705: goto st705;
+ case 706: goto st706;
+ case 707: goto st707;
+ case 708: goto st708;
+ case 709: goto st709;
+ case 710: goto st710;
+ case 711: goto st711;
+ case 712: goto st712;
+ case 713: goto st713;
+ case 714: goto st714;
+ case 715: goto st715;
+ case 1171: goto st1171;
+ case 1172: goto st1172;
+ case 1173: goto st1173;
+ case 716: goto st716;
+ case 717: goto st717;
+ case 718: goto st718;
+ case 1174: goto st1174;
+ case 1175: goto st1175;
+ case 719: goto st719;
+ case 720: goto st720;
+ case 721: goto st721;
+ case 722: goto st722;
+ case 1176: goto st1176;
+ case 1177: goto st1177;
+ case 723: goto st723;
+ case 724: goto st724;
+ case 725: goto st725;
+ case 726: goto st726;
+ case 1178: goto st1178;
+ case 1179: goto st1179;
+ case 727: goto st727;
+ case 728: goto st728;
+ case 729: goto st729;
+ case 730: goto st730;
+ case 731: goto st731;
+ case 732: goto st732;
+ case 733: goto st733;
+ case 734: goto st734;
+ case 735: goto st735;
+ case 736: goto st736;
+ case 737: goto st737;
+ case 738: goto st738;
+ case 739: goto st739;
+ case 740: goto st740;
+ case 741: goto st741;
+ case 742: goto st742;
+ case 743: goto st743;
+ case 744: goto st744;
+ case 745: goto st745;
+ case 746: goto st746;
+ case 747: goto st747;
+ case 748: goto st748;
+ case 749: goto st749;
+ case 750: goto st750;
+ case 751: goto st751;
+ case 1180: goto st1180;
+ case 752: goto st752;
+ case 753: goto st753;
+ case 754: goto st754;
+ case 755: goto st755;
+ case 756: goto st756;
+ case 757: goto st757;
+ case 758: goto st758;
+ case 759: goto st759;
+ case 760: goto st760;
+ case 761: goto st761;
+ case 762: goto st762;
+ case 763: goto st763;
+ case 764: goto st764;
+ case 765: goto st765;
+ case 766: goto st766;
+ case 1181: goto st1181;
+ case 767: goto st767;
+ case 768: goto st768;
+ case 769: goto st769;
+ case 770: goto st770;
+ case 771: goto st771;
+ case 772: goto st772;
+ case 773: goto st773;
+ case 774: goto st774;
+ case 775: goto st775;
+ case 776: goto st776;
+ case 777: goto st777;
+ case 778: goto st778;
+ case 779: goto st779;
+ case 1182: goto st1182;
+ case 780: goto st780;
+ case 781: goto st781;
+ case 782: goto st782;
+ case 783: goto st783;
+ case 784: goto st784;
+ case 785: goto st785;
+ case 786: goto st786;
+ case 787: goto st787;
+ case 788: goto st788;
+ case 789: goto st789;
+ case 790: goto st790;
+ case 1183: goto st1183;
+ case 1184: goto st1184;
+ case 791: goto st791;
+ case 792: goto st792;
+ case 793: goto st793;
+ case 1185: goto st1185;
+ case 794: goto st794;
+ case 795: goto st795;
+ case 796: goto st796;
+ case 797: goto st797;
+ case 798: goto st798;
+ case 799: goto st799;
+ case 800: goto st800;
+ case 801: goto st801;
+ case 802: goto st802;
+ case 803: goto st803;
+ case 1186: goto st1186;
+ case 1187: goto st1187;
+ case 1188: goto st1188;
+ case 804: goto st804;
+ case 805: goto st805;
+ case 806: goto st806;
+ case 807: goto st807;
+ case 808: goto st808;
+ case 809: goto st809;
+ case 810: goto st810;
+ case 811: goto st811;
+ case 812: goto st812;
+ case 813: goto st813;
+ case 814: goto st814;
+ case 1189: goto st1189;
+ case 1190: goto st1190;
+ case 1191: goto st1191;
+ case 815: goto st815;
+ case 816: goto st816;
+ case 817: goto st817;
+ case 818: goto st818;
+ case 819: goto st819;
+ case 820: goto st820;
+ case 821: goto st821;
+ case 822: goto st822;
+ case 823: goto st823;
+ case 824: goto st824;
+ case 825: goto st825;
+ case 826: goto st826;
+ case 1192: goto st1192;
+ case 827: goto st827;
+ case 828: goto st828;
+ case 829: goto st829;
+ case 1193: goto st1193;
+ case 1194: goto st1194;
+ case 830: goto st830;
+ case 1195: goto st1195;
+ case 1196: goto st1196;
+ case 831: goto st831;
+ case 1197: goto st1197;
+ case 1198: goto st1198;
+ case 832: goto st832;
+ case 833: goto st833;
+ case 834: goto st834;
+ case 835: goto st835;
+ case 836: goto st836;
+ case 837: goto st837;
+ case 838: goto st838;
+ case 839: goto st839;
+ case 840: goto st840;
+ case 841: goto st841;
+ case 842: goto st842;
+ case 843: goto st843;
+ case 844: goto st844;
+ case 845: goto st845;
+ case 846: goto st846;
+ case 847: goto st847;
+ case 848: goto st848;
+ case 849: goto st849;
+ case 850: goto st850;
+ case 851: goto st851;
+ case 852: goto st852;
+ case 853: goto st853;
+ case 854: goto st854;
+ case 855: goto st855;
+ case 856: goto st856;
+ case 857: goto st857;
+ case 858: goto st858;
+ case 859: goto st859;
+ case 860: goto st860;
+ case 861: goto st861;
+ case 862: goto st862;
+ case 863: goto st863;
+ case 864: goto st864;
+ case 865: goto st865;
+ case 866: goto st866;
+ case 867: goto st867;
+ case 868: goto st868;
+ case 869: goto st869;
+ case 870: goto st870;
+ case 871: goto st871;
+ case 872: goto st872;
+ case 873: goto st873;
+ case 1199: goto st1199;
+ case 874: goto st874;
+ case 875: goto st875;
+ case 876: goto st876;
+ case 877: goto st877;
+ case 878: goto st878;
+ case 879: goto st879;
+ case 880: goto st880;
+ case 881: goto st881;
+ case 882: goto st882;
+ case 883: goto st883;
+ case 884: goto st884;
+ case 885: goto st885;
+ case 886: goto st886;
+ case 887: goto st887;
+ case 888: goto st888;
+ case 889: goto st889;
+ case 890: goto st890;
+ case 891: goto st891;
+ case 892: goto st892;
+ case 893: goto st893;
+ case 894: goto st894;
+ case 895: goto st895;
+ case 896: goto st896;
+ case 897: goto st897;
+ case 898: goto st898;
+ case 899: goto st899;
+ case 900: goto st900;
+ case 901: goto st901;
+ case 902: goto st902;
+ case 903: goto st903;
+ case 904: goto st904;
+ case 905: goto st905;
+ case 906: goto st906;
+ case 907: goto st907;
+ case 908: goto st908;
+ case 909: goto st909;
+ case 910: goto st910;
+ case 911: goto st911;
+ case 912: goto st912;
+ case 913: goto st913;
+ case 914: goto st914;
+ case 915: goto st915;
+ case 916: goto st916;
+ case 917: goto st917;
+ case 918: goto st918;
+ case 919: goto st919;
+ case 920: goto st920;
+ case 921: goto st921;
+ case 922: goto st922;
+ case 923: goto st923;
+ case 924: goto st924;
+ case 925: goto st925;
+ case 926: goto st926;
+ case 927: goto st927;
+ case 928: goto st928;
+ case 929: goto st929;
+ case 930: goto st930;
+ case 931: goto st931;
+ case 932: goto st932;
+ case 933: goto st933;
+ case 934: goto st934;
+ case 935: goto st935;
+ case 936: goto st936;
+ case 937: goto st937;
+ case 938: goto st938;
+ case 939: goto st939;
+ case 940: goto st940;
+ case 941: goto st941;
+ case 942: goto st942;
+ case 943: goto st943;
+ case 944: goto st944;
+ case 945: goto st945;
+ case 946: goto st946;
+ case 947: goto st947;
+ case 948: goto st948;
+ case 949: goto st949;
+ case 950: goto st950;
+ case 951: goto st951;
+ case 952: goto st952;
+ case 953: goto st953;
+ case 954: goto st954;
+ case 955: goto st955;
+ case 956: goto st956;
+ case 957: goto st957;
+ case 958: goto st958;
+ case 959: goto st959;
+ case 960: goto st960;
+ case 961: goto st961;
+ case 962: goto st962;
+ case 963: goto st963;
+ case 964: goto st964;
+ case 965: goto st965;
+ case 966: goto st966;
+ case 967: goto st967;
+ case 968: goto st968;
+ case 969: goto st969;
+ case 970: goto st970;
+ case 971: goto st971;
+ case 972: goto st972;
+ case 973: goto st973;
+ case 974: goto st974;
+ case 975: goto st975;
+ case 976: goto st976;
+ case 977: goto st977;
+ case 978: goto st978;
+ case 979: goto st979;
+ case 980: goto st980;
+ case 981: goto st981;
+ case 982: goto st982;
+ case 983: goto st983;
+ case 984: goto st984;
+ case 985: goto st985;
+ case 986: goto st986;
+ case 987: goto st987;
+ case 988: goto st988;
+ case 989: goto st989;
+ case 990: goto st990;
+ case 991: goto st991;
+ case 992: goto st992;
+ case 993: goto st993;
+ case 994: goto st994;
+ case 995: goto st995;
+ case 996: goto st996;
+ case 997: goto st997;
+ case 998: goto st998;
+ case 999: goto st999;
+ case 1000: goto st1000;
+ case 1001: goto st1001;
+ case 1002: goto st1002;
+ case 1003: goto st1003;
+ case 1004: goto st1004;
+ case 1005: goto st1005;
+ case 1006: goto st1006;
+ case 1007: goto st1007;
+ case 1008: goto st1008;
+ case 1009: goto st1009;
+ case 1010: goto st1010;
+ case 1011: goto st1011;
+ case 1012: goto st1012;
+ case 1200: goto st1200;
+ case 1013: goto st1013;
+ case 1014: goto st1014;
+ case 1015: goto st1015;
+ case 1016: goto st1016;
+ case 1017: goto st1017;
+ case 1018: goto st1018;
+ case 1019: goto st1019;
+ case 1020: goto st1020;
+ case 1201: goto st1201;
+ case 1021: goto st1021;
+ case 1022: goto st1022;
+ case 1023: goto st1023;
+ case 1024: goto st1024;
+ case 1025: goto st1025;
+ case 1202: goto st1202;
+ case 1026: goto st1026;
+ case 1027: goto st1027;
+ case 1028: goto st1028;
+ case 1029: goto st1029;
+ case 1030: goto st1030;
+ case 1031: goto st1031;
+ case 1032: goto st1032;
+ case 1033: goto st1033;
+ case 1034: goto st1034;
+ case 1035: goto st1035;
+ case 1036: goto st1036;
+ case 1037: goto st1037;
+ case 1038: goto st1038;
+ case 1039: goto st1039;
+ case 1040: goto st1040;
+ case 1041: goto st1041;
+ case 1042: goto st1042;
+ case 1043: goto st1043;
+ case 1203: goto st1203;
+ case 1044: goto st1044;
+ case 1045: goto st1045;
+ case 1046: goto st1046;
+ case 1047: goto st1047;
+ case 1048: goto st1048;
+ case 1049: goto st1049;
+ case 1050: goto st1050;
+ case 1051: goto st1051;
+ case 1052: goto st1052;
+ case 1053: goto st1053;
+ case 1054: goto st1054;
+ case 1055: goto st1055;
+ case 1056: goto st1056;
+ case 1057: goto st1057;
+ case 1058: goto st1058;
+ case 1059: goto st1059;
+ case 1060: goto st1060;
+ case 1061: goto st1061;
+ case 1062: goto st1062;
+ case 1204: goto st1204;
+ case 1063: goto st1063;
+ case 1064: goto st1064;
+ case 1065: goto st1065;
+ case 1066: goto st1066;
+ case 1067: goto st1067;
+ case 1068: goto st1068;
+ case 1069: goto st1069;
+ case 1070: goto st1070;
+ case 1071: goto st1071;
+ case 1072: goto st1072;
+ case 1073: goto st1073;
+ case 1074: goto st1074;
+ case 1075: goto st1075;
+ case 1076: goto st1076;
+ case 1077: goto st1077;
+ case 1205: goto st1205;
+ case 1206: goto st1206;
+ case 1207: goto st1207;
+ case 1078: goto st1078;
+ case 1079: goto st1079;
+ case 1080: goto st1080;
+ case 1081: goto st1081;
+ case 1082: goto st1082;
+ case 1083: goto st1083;
+ case 1084: goto st1084;
+ case 1208: goto st1208;
+ case 1085: goto st1085;
+ case 1086: goto st1086;
+ case 1087: goto st1087;
+ case 1088: goto st1088;
+ case 1089: goto st1089;
+ case 1090: goto st1090;
+ case 1091: goto st1091;
+ case 1092: goto st1092;
+ case 1093: goto st1093;
+ case 1094: goto st1094;
+ case 1095: goto st1095;
+ case 1096: goto st1096;
+ case 1097: goto st1097;
+ case 1209: goto st1209;
+ case 1098: goto st1098;
+ case 1099: goto st1099;
+ case 1100: goto st1100;
+ case 1101: goto st1101;
+ case 1102: goto st1102;
+ case 1103: goto st1103;
+ case 1104: goto st1104;
+ case 1210: goto st1210;
+ case 1105: goto st1105;
+ case 1106: goto st1106;
+ case 1107: goto st1107;
+ case 1108: goto st1108;
+ case 1109: goto st1109;
+ case 1110: goto st1110;
+ case 1211: goto st1211;
+ case 1111: goto st1111;
+ case 1112: goto st1112;
+ case 1113: goto st1113;
+ case 1114: goto st1114;
+ case 1115: goto st1115;
+ case 1116: goto st1116;
+ case 1212: goto st1212;
+ case 1117: goto st1117;
+ case 1118: goto st1118;
+ case 1119: goto st1119;
+ case 1120: goto st1120;
+ case 1121: goto st1121;
+ case 1122: goto st1122;
+ case 1123: goto st1123;
+ case 1124: goto st1124;
+ case 1213: goto st1213;
+ case 1125: goto st1125;
+ case 1126: goto st1126;
+ default: break;
+ }
+
+ if ( ++p == pe )
+ goto _test_eof;
+_resume:
+ switch ( cs )
+ {
+tr20:
+ {
+ s->line_counter++;
+ }
+ goto st1127;
+tr83:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1127; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1127; goto _out;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1127;
+tr89:
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1127; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1127; goto _out;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1127;
+tr92:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1127; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1127; goto _out;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1127;
+tr666:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1127;
+tr760:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1127; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1127; goto _out;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1127;
+tr878:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1127; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1127; goto _out;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ goto st1127;
+tr882:
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1127; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1127; goto _out;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ goto st1127;
+tr3618:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1127;
+tr3678:
+ {
+ NOERR;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1127;
+st1127:
+ if ( ++p == pe )
+ goto _test_eof1127;
+case 1127:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3613;
+ case 32: goto tr3613;
+ case 36: goto st152;
+ case 40: goto tr3615;
+ case 41: goto tr3616;
+ case 42: goto tr3617;
+ case 92: goto tr3617;
+ case 95: goto tr3617;
+ case 778: goto tr3618;
+ case 827: goto tr3619;
+ case 1034: goto tr3620;
+ case 1083: goto tr3621;
+ }
+ if ( _widec < 64 ) {
+ if ( 45 <= _widec && _widec <= 57 )
+ goto tr3617;
+ } else if ( _widec > 90 ) {
+ if ( 97 <= _widec && _widec <= 122 )
+ goto tr3617;
+ } else
+ goto tr3617;
+ goto tr3612;
+tr0:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr24:
+ {
+ WARN(ZS_BAD_TIME_UNIT);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr36:
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr57:
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr71:
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr79:
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr85:
+ {
+ WARN(ZS_BAD_REST);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr114:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr139:
+ {
+ WARN(ZS_BAD_TIME_UNIT);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr145:
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr583:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr585:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr667:
+ {
+ ERR(ZS_BAD_DIRECTIVE);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr678:
+ {
+ s->r_owner_length = 0;
+ WARN(ZS_BAD_OWNER);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr692:
+ {
+ s->r_owner_length = 0;
+ WARN(ZS_BAD_OWNER);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_TIME_UNIT);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr720:
+ {
+ s->r_owner_length = 0;
+ WARN(ZS_BAD_OWNER);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr735:
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr773:
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; {goto st268;}
+ }
+ {
+ ERR(ZS_BAD_DIRECTIVE);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr783:
+ {
+ s->r_owner_length = 0;
+ WARN(ZS_BAD_OWNER);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr789:
+ {
+ s->r_owner_length = 0;
+ WARN(ZS_BAD_OWNER);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_TIME_UNIT);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr802:
+ {
+ s->r_owner_length = 0;
+ WARN(ZS_BAD_OWNER);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr816:
+ {
+ s->r_owner_length = 0;
+ WARN(ZS_BAD_OWNER);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr908:
+ {
+ s->r_owner_length = 0;
+ WARN(ZS_BAD_OWNER);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr919:
+ {
+ WARN(ZS_BAD_DNAME_CHAR);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr932:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_DNAME_CHAR);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr940:
+ {
+ WARN(ZS_BAD_TEXT_CHAR);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_TEXT);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr946:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_TEXT_CHAR);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_TEXT);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr957:
+ {
+ WARN(ZS_BAD_TEXT);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr964:
+ {
+ ERR(ZS_BAD_TTL);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr970:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ {
+ ERR(ZS_BAD_TTL);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr972:
+ {
+ WARN(ZS_BAD_TIME_UNIT);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; {goto st268;}
+ }
+ {
+ ERR(ZS_BAD_TTL);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr984:
+ {
+ WARN(ZS_BAD_REST);
+ p--; {goto st268;}
+ }
+ {
+ ERR(ZS_BAD_TTL);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr993:
+ {
+ WARN(ZS_BAD_TIME_UNIT);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ {
+ ERR(ZS_BAD_TTL);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr1008:
+ {
+ ERR(ZS_BAD_ORIGIN);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr1020:
+ {
+ WARN(ZS_BAD_REST);
+ p--; {goto st268;}
+ }
+ {
+ ERR(ZS_BAD_ORIGIN);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr1036:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ {
+ ERR(ZS_BAD_ORIGIN);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr1050:
+ {
+ ERR(ZS_BAD_INCLUDE_FILENAME);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr1051:
+ {
+ ERR(ZS_BAD_INCLUDE_FILENAME);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr1058:
+ {
+ ERR(ZS_BAD_INCLUDE_ORIGIN);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr1068:
+ {
+ ERR(ZS_BAD_INCLUDE_ORIGIN);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr1085:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ {
+ ERR(ZS_BAD_INCLUDE_ORIGIN);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr1102:
+ {
+ WARN(ZS_BAD_BASE64_CHAR);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr1118:
+ {
+ WARN(ZS_BAD_BITMAP);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr1611:
+ {
+ WARN(ZS_BAD_HEX_RDATA);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr1617:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_HEX_RDATA);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr1625:
+ {
+ WARN(ZS_BAD_HEX_CHAR);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_HEX_RDATA);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_HEX_RDATA);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr1687:
+ {
+ WARN(ZS_BAD_ALGORITHM);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr1809:
+ {
+ WARN(ZS_BAD_CERT_TYPE);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr1862:
+ {
+ WARN(ZS_BAD_ADDRESS_CHAR);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr1885:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr1904:
+ {
+ WARN(ZS_BAD_TIME_UNIT);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr2070:
+ {
+ s->long_string = false;
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr2093:
+ {
+ WARN(ZS_BAD_LOC_DATA);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr2496:
+ {
+ WARN(ZS_BAD_APL);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr2511:
+ {
+ WARN(ZS_BAD_ADDRESS_CHAR);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_APL);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr2556:
+ {
+ WARN(ZS_BAD_HEX_CHAR);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr2627:
+ {
+ WARN(ZS_BAD_GATEWAY);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr2642:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_GATEWAY);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr2656:
+ {
+ WARN(ZS_BAD_GATEWAY);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_GATEWAY_KEY);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr2679:
+ {
+ WARN(ZS_BAD_GATEWAY_KEY);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr2703:
+ {
+ WARN(ZS_BAD_ADDRESS_CHAR);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_GATEWAY);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr2710:
+ {
+ WARN(ZS_BAD_ADDRESS_CHAR);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_GATEWAY);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_GATEWAY_KEY);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr2829:
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr2883:
+ {
+ WARN(ZS_BAD_TIMESTAMP_CHAR);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr3262:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr3363:
+ {
+ WARN(ZS_BAD_BASE32HEX_CHAR);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr3530:
+ {
+ WARN(ZS_BAD_HEX_CHAR);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_CHAR_COLON);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr3536:
+ {
+ WARN(ZS_BAD_CHAR_COLON);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_HEX_CHAR);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr3542:
+ {
+ WARN(ZS_BAD_CHAR_DASH);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_HEX_CHAR);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr3612:
+ {
+ s->r_owner_length = 0;
+ WARN(ZS_BAD_OWNER);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr3634:
+ {
+ s->r_owner_length = 0;
+ WARN(ZS_BAD_OWNER);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr3655:
+ {
+ s->r_owner_length = 0;
+ WARN(ZS_BAD_OWNER);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr3672:
+ {
+ s->r_owner_length = 0;
+ WARN(ZS_BAD_OWNER);
+ p--; {goto st268;}
+ }
+ {
+ ERR(ZS_BAD_DIRECTIVE);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; {goto st268;}
+ }
+ goto st0;
+tr3696:
+ {
+ s->r_owner_length = 0;
+ WARN(ZS_BAD_OWNER);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; {goto st268;}
+ }
+ goto st0;
+st0:
+cs = 0;
+ goto _out;
+tr2:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1;
+tr3:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1;
+tr3613:
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st1;
+tr3615:
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st1;
+tr3616:
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st1;
+tr3682:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st1;
+tr3683:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st1;
+tr3673:
+ {
+ NOERR;
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st1;
+tr3675:
+ {
+ NOERR;
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st1;
+tr3676:
+ {
+ NOERR;
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st1;
+st1:
+ if ( ++p == pe )
+ goto _test_eof1;
+case 1:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st1;
+ case 32: goto st1;
+ case 40: goto tr2;
+ case 41: goto tr3;
+ case 65: goto tr5;
+ case 67: goto tr6;
+ case 68: goto tr7;
+ case 69: goto tr8;
+ case 72: goto tr9;
+ case 73: goto tr10;
+ case 75: goto tr11;
+ case 76: goto tr12;
+ case 77: goto tr13;
+ case 78: goto tr14;
+ case 80: goto tr15;
+ case 82: goto tr16;
+ case 83: goto tr17;
+ case 84: goto tr18;
+ case 85: goto tr19;
+ case 97: goto tr5;
+ case 99: goto tr6;
+ case 100: goto tr7;
+ case 101: goto tr8;
+ case 104: goto tr9;
+ case 105: goto tr10;
+ case 107: goto tr11;
+ case 108: goto tr12;
+ case 109: goto tr13;
+ case 110: goto tr14;
+ case 112: goto tr15;
+ case 114: goto tr16;
+ case 115: goto tr17;
+ case 116: goto tr18;
+ case 117: goto tr19;
+ case 778: goto tr20;
+ case 827: goto tr21;
+ case 1034: goto tr22;
+ case 1083: goto tr23;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr4;
+ goto tr0;
+tr4:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st2;
+tr28:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st2;
+st2:
+ if ( ++p == pe )
+ goto _test_eof2;
+case 2:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr25;
+ case 32: goto tr25;
+ case 40: goto tr26;
+ case 41: goto tr27;
+ case 68: goto tr29;
+ case 72: goto tr30;
+ case 77: goto tr31;
+ case 83: goto st166;
+ case 87: goto tr33;
+ case 100: goto tr29;
+ case 104: goto tr30;
+ case 109: goto tr31;
+ case 115: goto st166;
+ case 119: goto tr33;
+ case 1034: goto tr34;
+ case 1083: goto tr35;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr28;
+ goto tr24;
+tr38:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st3;
+tr39:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st3;
+tr55:
+ {
+ s->line_counter++;
+ }
+ goto st3;
+tr25:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st3;
+tr26:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st3;
+tr27:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st3;
+tr34:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st3;
+tr719:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st3;
+tr712:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st3;
+tr713:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st3;
+tr714:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st3;
+tr716:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st3;
+st3:
+ if ( ++p == pe )
+ goto _test_eof3;
+case 3:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st3;
+ case 32: goto st3;
+ case 40: goto tr38;
+ case 41: goto tr39;
+ case 65: goto tr40;
+ case 67: goto tr41;
+ case 68: goto tr42;
+ case 69: goto tr43;
+ case 72: goto tr44;
+ case 73: goto tr45;
+ case 75: goto tr46;
+ case 76: goto tr47;
+ case 77: goto tr48;
+ case 78: goto tr49;
+ case 80: goto tr50;
+ case 82: goto tr51;
+ case 83: goto tr52;
+ case 84: goto tr53;
+ case 85: goto tr54;
+ case 97: goto tr40;
+ case 99: goto tr41;
+ case 100: goto tr42;
+ case 101: goto tr43;
+ case 104: goto tr44;
+ case 105: goto tr45;
+ case 107: goto tr46;
+ case 108: goto tr47;
+ case 109: goto tr48;
+ case 110: goto tr49;
+ case 112: goto tr50;
+ case 114: goto tr51;
+ case 115: goto tr52;
+ case 116: goto tr53;
+ case 117: goto tr54;
+ case 1034: goto tr55;
+ case 1083: goto tr56;
+ }
+ goto tr36;
+tr5:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st4;
+tr40:
+ {
+ s->r_class = s->default_class;
+ }
+ goto st4;
+tr622:
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st4;
+st4:
+ if ( ++p == pe )
+ goto _test_eof4;
+case 4:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr58;
+ case 32: goto tr58;
+ case 40: goto tr59;
+ case 41: goto tr60;
+ case 65: goto st230;
+ case 70: goto st233;
+ case 80: goto st237;
+ case 97: goto st230;
+ case 102: goto st233;
+ case 112: goto st237;
+ case 2058: goto tr64;
+ case 2107: goto tr65;
+ case 2314: goto tr66;
+ case 2363: goto tr66;
+ case 2570: goto tr67;
+ case 2619: goto tr68;
+ }
+ goto tr57;
+tr72:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr73:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr75:
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr58:
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr59:
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr60:
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr64:
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr96:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr156:
+ { s->r_type = KNOT_RRTYPE_CAA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr157:
+ { s->r_type = KNOT_RRTYPE_CAA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr158:
+ { s->r_type = KNOT_RRTYPE_CAA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr159:
+ { s->r_type = KNOT_RRTYPE_CAA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr178:
+ { s->r_type = KNOT_RRTYPE_CDNSKEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr179:
+ { s->r_type = KNOT_RRTYPE_CDNSKEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr180:
+ { s->r_type = KNOT_RRTYPE_CDNSKEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr181:
+ { s->r_type = KNOT_RRTYPE_CDNSKEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr186:
+ { s->r_type = KNOT_RRTYPE_CDS; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr187:
+ { s->r_type = KNOT_RRTYPE_CDS; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr188:
+ { s->r_type = KNOT_RRTYPE_CDS; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr189:
+ { s->r_type = KNOT_RRTYPE_CDS; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr196:
+ { s->r_type = KNOT_RRTYPE_CERT; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr197:
+ { s->r_type = KNOT_RRTYPE_CERT; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr198:
+ { s->r_type = KNOT_RRTYPE_CERT; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr199:
+ { s->r_type = KNOT_RRTYPE_CERT; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr207:
+ { s->r_type = KNOT_RRTYPE_CNAME; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr208:
+ { s->r_type = KNOT_RRTYPE_CNAME; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr209:
+ { s->r_type = KNOT_RRTYPE_CNAME; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr210:
+ { s->r_type = KNOT_RRTYPE_CNAME; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr221:
+ { s->r_type = KNOT_RRTYPE_DHCID; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr222:
+ { s->r_type = KNOT_RRTYPE_DHCID; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr223:
+ { s->r_type = KNOT_RRTYPE_DHCID; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr224:
+ { s->r_type = KNOT_RRTYPE_DHCID; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr233:
+ { s->r_type = KNOT_RRTYPE_DNAME; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr234:
+ { s->r_type = KNOT_RRTYPE_DNAME; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr235:
+ { s->r_type = KNOT_RRTYPE_DNAME; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr236:
+ { s->r_type = KNOT_RRTYPE_DNAME; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr244:
+ { s->r_type = KNOT_RRTYPE_DNSKEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr245:
+ { s->r_type = KNOT_RRTYPE_DNSKEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr246:
+ { s->r_type = KNOT_RRTYPE_DNSKEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr247:
+ { s->r_type = KNOT_RRTYPE_DNSKEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr252:
+ { s->r_type = KNOT_RRTYPE_DS; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr253:
+ { s->r_type = KNOT_RRTYPE_DS; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr254:
+ { s->r_type = KNOT_RRTYPE_DS; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr255:
+ { s->r_type = KNOT_RRTYPE_DS; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr265:
+ { s->r_type = KNOT_RRTYPE_EUI48; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr266:
+ { s->r_type = KNOT_RRTYPE_EUI48; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr267:
+ { s->r_type = KNOT_RRTYPE_EUI48; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr268:
+ { s->r_type = KNOT_RRTYPE_EUI48; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr274:
+ { s->r_type = KNOT_RRTYPE_EUI64; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr275:
+ { s->r_type = KNOT_RRTYPE_EUI64; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr276:
+ { s->r_type = KNOT_RRTYPE_EUI64; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr277:
+ { s->r_type = KNOT_RRTYPE_EUI64; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr286:
+ { s->r_type = KNOT_RRTYPE_HINFO; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr287:
+ { s->r_type = KNOT_RRTYPE_HINFO; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr288:
+ { s->r_type = KNOT_RRTYPE_HINFO; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr289:
+ { s->r_type = KNOT_RRTYPE_HINFO; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr327:
+ { s->r_type = KNOT_RRTYPE_IPSECKEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr328:
+ { s->r_type = KNOT_RRTYPE_IPSECKEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr329:
+ { s->r_type = KNOT_RRTYPE_IPSECKEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr330:
+ { s->r_type = KNOT_RRTYPE_IPSECKEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr338:
+ { s->r_type = KNOT_RRTYPE_KEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr339:
+ { s->r_type = KNOT_RRTYPE_KEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr340:
+ { s->r_type = KNOT_RRTYPE_KEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr341:
+ { s->r_type = KNOT_RRTYPE_KEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr346:
+ { s->r_type = KNOT_RRTYPE_KX; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr347:
+ { s->r_type = KNOT_RRTYPE_KX; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr348:
+ { s->r_type = KNOT_RRTYPE_KX; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr349:
+ { s->r_type = KNOT_RRTYPE_KX; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr359:
+ { s->r_type = KNOT_RRTYPE_L32; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr360:
+ { s->r_type = KNOT_RRTYPE_L32; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr361:
+ { s->r_type = KNOT_RRTYPE_L32; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr362:
+ { s->r_type = KNOT_RRTYPE_L32; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr368:
+ { s->r_type = KNOT_RRTYPE_L64; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr369:
+ { s->r_type = KNOT_RRTYPE_L64; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr370:
+ { s->r_type = KNOT_RRTYPE_L64; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr371:
+ { s->r_type = KNOT_RRTYPE_L64; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr377:
+ { s->r_type = KNOT_RRTYPE_LOC; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr378:
+ { s->r_type = KNOT_RRTYPE_LOC; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr379:
+ { s->r_type = KNOT_RRTYPE_LOC; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr380:
+ { s->r_type = KNOT_RRTYPE_LOC; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr385:
+ { s->r_type = KNOT_RRTYPE_LP; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr386:
+ { s->r_type = KNOT_RRTYPE_LP; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr387:
+ { s->r_type = KNOT_RRTYPE_LP; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr388:
+ { s->r_type = KNOT_RRTYPE_LP; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr398:
+ { s->r_type = KNOT_RRTYPE_MINFO; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr399:
+ { s->r_type = KNOT_RRTYPE_MINFO; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr400:
+ { s->r_type = KNOT_RRTYPE_MINFO; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr401:
+ { s->r_type = KNOT_RRTYPE_MINFO; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr406:
+ { s->r_type = KNOT_RRTYPE_MX; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr407:
+ { s->r_type = KNOT_RRTYPE_MX; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr408:
+ { s->r_type = KNOT_RRTYPE_MX; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr409:
+ { s->r_type = KNOT_RRTYPE_MX; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr420:
+ { s->r_type = KNOT_RRTYPE_NAPTR; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr421:
+ { s->r_type = KNOT_RRTYPE_NAPTR; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr422:
+ { s->r_type = KNOT_RRTYPE_NAPTR; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr423:
+ { s->r_type = KNOT_RRTYPE_NAPTR; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr429:
+ { s->r_type = KNOT_RRTYPE_NID; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr430:
+ { s->r_type = KNOT_RRTYPE_NID; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr431:
+ { s->r_type = KNOT_RRTYPE_NID; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr432:
+ { s->r_type = KNOT_RRTYPE_NID; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr437:
+ { s->r_type = KNOT_RRTYPE_NS; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr438:
+ { s->r_type = KNOT_RRTYPE_NS; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr439:
+ { s->r_type = KNOT_RRTYPE_NS; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr441:
+ { s->r_type = KNOT_RRTYPE_NS; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr447:
+ { s->r_type = KNOT_RRTYPE_NSEC; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr448:
+ { s->r_type = KNOT_RRTYPE_NSEC; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr449:
+ { s->r_type = KNOT_RRTYPE_NSEC; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr451:
+ { s->r_type = KNOT_RRTYPE_NSEC; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr456:
+ { s->r_type = KNOT_RRTYPE_NSEC3; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr457:
+ { s->r_type = KNOT_RRTYPE_NSEC3; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr458:
+ { s->r_type = KNOT_RRTYPE_NSEC3; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr460:
+ { s->r_type = KNOT_RRTYPE_NSEC3; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr469:
+ { s->r_type = KNOT_RRTYPE_NSEC3PARAM; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr470:
+ { s->r_type = KNOT_RRTYPE_NSEC3PARAM; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr471:
+ { s->r_type = KNOT_RRTYPE_NSEC3PARAM; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr472:
+ { s->r_type = KNOT_RRTYPE_NSEC3PARAM; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr479:
+ { s->r_type = KNOT_RRTYPE_PTR; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr480:
+ { s->r_type = KNOT_RRTYPE_PTR; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr481:
+ { s->r_type = KNOT_RRTYPE_PTR; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr482:
+ { s->r_type = KNOT_RRTYPE_PTR; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr490:
+ { s->r_type = KNOT_RRTYPE_RP; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr491:
+ { s->r_type = KNOT_RRTYPE_RP; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr492:
+ { s->r_type = KNOT_RRTYPE_RP; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr493:
+ { s->r_type = KNOT_RRTYPE_RP; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr501:
+ { s->r_type = KNOT_RRTYPE_RRSIG; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr502:
+ { s->r_type = KNOT_RRTYPE_RRSIG; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr503:
+ { s->r_type = KNOT_RRTYPE_RRSIG; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr504:
+ { s->r_type = KNOT_RRTYPE_RRSIG; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr509:
+ { s->r_type = KNOT_RRTYPE_RT; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr510:
+ { s->r_type = KNOT_RRTYPE_RT; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr511:
+ { s->r_type = KNOT_RRTYPE_RT; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr512:
+ { s->r_type = KNOT_RRTYPE_RT; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr522:
+ { s->r_type = KNOT_RRTYPE_SOA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr523:
+ { s->r_type = KNOT_RRTYPE_SOA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr524:
+ { s->r_type = KNOT_RRTYPE_SOA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr525:
+ { s->r_type = KNOT_RRTYPE_SOA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr531:
+ { s->r_type = KNOT_RRTYPE_SPF; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr532:
+ { s->r_type = KNOT_RRTYPE_SPF; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr533:
+ { s->r_type = KNOT_RRTYPE_SPF; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr534:
+ { s->r_type = KNOT_RRTYPE_SPF; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr540:
+ { s->r_type = KNOT_RRTYPE_SRV; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr541:
+ { s->r_type = KNOT_RRTYPE_SRV; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr542:
+ { s->r_type = KNOT_RRTYPE_SRV; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr543:
+ { s->r_type = KNOT_RRTYPE_SRV; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr551:
+ { s->r_type = KNOT_RRTYPE_SSHFP; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr552:
+ { s->r_type = KNOT_RRTYPE_SSHFP; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr553:
+ { s->r_type = KNOT_RRTYPE_SSHFP; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr554:
+ { s->r_type = KNOT_RRTYPE_SSHFP; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr564:
+ { s->r_type = KNOT_RRTYPE_TLSA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr565:
+ { s->r_type = KNOT_RRTYPE_TLSA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr566:
+ { s->r_type = KNOT_RRTYPE_TLSA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr567:
+ { s->r_type = KNOT_RRTYPE_TLSA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr573:
+ { s->r_type = KNOT_RRTYPE_TXT; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr574:
+ { s->r_type = KNOT_RRTYPE_TXT; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr575:
+ { s->r_type = KNOT_RRTYPE_TXT; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr576:
+ { s->r_type = KNOT_RRTYPE_TXT; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr586:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ s->r_type = (uint16_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr587:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ s->r_type = (uint16_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr588:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ s->r_type = (uint16_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr590:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ s->r_type = (uint16_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr597:
+ { s->r_type = KNOT_RRTYPE_URI; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr598:
+ { s->r_type = KNOT_RRTYPE_URI; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr599:
+ { s->r_type = KNOT_RRTYPE_URI; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr600:
+ { s->r_type = KNOT_RRTYPE_URI; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr845:
+ { s->r_type = KNOT_RRTYPE_AAAA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr846:
+ { s->r_type = KNOT_RRTYPE_AAAA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr847:
+ { s->r_type = KNOT_RRTYPE_AAAA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr848:
+ { s->r_type = KNOT_RRTYPE_AAAA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr856:
+ { s->r_type = KNOT_RRTYPE_AFSDB; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr857:
+ { s->r_type = KNOT_RRTYPE_AFSDB; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr858:
+ { s->r_type = KNOT_RRTYPE_AFSDB; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr859:
+ { s->r_type = KNOT_RRTYPE_AFSDB; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+tr865:
+ { s->r_type = KNOT_RRTYPE_APL; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st5;
+tr866:
+ { s->r_type = KNOT_RRTYPE_APL; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st5;
+tr867:
+ { s->r_type = KNOT_RRTYPE_APL; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st5;
+tr868:
+ { s->r_type = KNOT_RRTYPE_APL; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st5;
+st5:
+ if ( ++p == pe )
+ goto _test_eof5;
+case 5:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st5;
+ case 32: goto st5;
+ case 40: goto tr72;
+ case 41: goto tr73;
+ case 92: goto tr74;
+ case 2058: goto tr75;
+ case 2107: goto tr76;
+ case 2314: goto tr69;
+ case 2363: goto tr69;
+ case 2570: goto tr77;
+ case 2619: goto tr78;
+ }
+ if ( _widec < 11 ) {
+ if ( _widec <= 8 )
+ goto tr69;
+ } else if ( _widec > 58 ) {
+ if ( 60 <= _widec )
+ goto tr69;
+ } else
+ goto tr69;
+ goto tr71;
+tr66:
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr69:
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr93:
+ {
+ if (*wrap == WRAP_NONE) {
+ p--;
+ }
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr94:
+ {
+ switch (s->r_type) {
+ // Next types must not have empty rdata.
+ case KNOT_RRTYPE_A:
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ case KNOT_RRTYPE_SOA:
+ case KNOT_RRTYPE_HINFO:
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ case KNOT_RRTYPE_RP:
+ case KNOT_RRTYPE_AAAA:
+ case KNOT_RRTYPE_LOC:
+ case KNOT_RRTYPE_SRV:
+ case KNOT_RRTYPE_NAPTR:
+ case KNOT_RRTYPE_CERT:
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_SSHFP:
+ case KNOT_RRTYPE_IPSECKEY:
+ case KNOT_RRTYPE_RRSIG:
+ case KNOT_RRTYPE_NSEC:
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_DHCID:
+ case KNOT_RRTYPE_NSEC3:
+ case KNOT_RRTYPE_NSEC3PARAM:
+ case KNOT_RRTYPE_TLSA:
+ case KNOT_RRTYPE_CDS:
+ case KNOT_RRTYPE_CDNSKEY:
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L32:
+ case KNOT_RRTYPE_L64:
+ case KNOT_RRTYPE_LP:
+ case KNOT_RRTYPE_EUI48:
+ case KNOT_RRTYPE_EUI64:
+ case KNOT_RRTYPE_URI:
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st468;}
+ // Next types can have empty rdata.
+ case KNOT_RRTYPE_APL:
+ default:
+ {stack[top++] = 6;goto st477;}
+ }
+ }
+ goto st6;
+tr161:
+ { s->r_type = KNOT_RRTYPE_CAA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr183:
+ { s->r_type = KNOT_RRTYPE_CDNSKEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr191:
+ { s->r_type = KNOT_RRTYPE_CDS; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr201:
+ { s->r_type = KNOT_RRTYPE_CERT; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr212:
+ { s->r_type = KNOT_RRTYPE_CNAME; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr226:
+ { s->r_type = KNOT_RRTYPE_DHCID; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr238:
+ { s->r_type = KNOT_RRTYPE_DNAME; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr249:
+ { s->r_type = KNOT_RRTYPE_DNSKEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr257:
+ { s->r_type = KNOT_RRTYPE_DS; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr270:
+ { s->r_type = KNOT_RRTYPE_EUI48; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr279:
+ { s->r_type = KNOT_RRTYPE_EUI64; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr291:
+ { s->r_type = KNOT_RRTYPE_HINFO; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr332:
+ { s->r_type = KNOT_RRTYPE_IPSECKEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr343:
+ { s->r_type = KNOT_RRTYPE_KEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr351:
+ { s->r_type = KNOT_RRTYPE_KX; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr364:
+ { s->r_type = KNOT_RRTYPE_L32; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr373:
+ { s->r_type = KNOT_RRTYPE_L64; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr382:
+ { s->r_type = KNOT_RRTYPE_LOC; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr390:
+ { s->r_type = KNOT_RRTYPE_LP; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr403:
+ { s->r_type = KNOT_RRTYPE_MINFO; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr411:
+ { s->r_type = KNOT_RRTYPE_MX; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr425:
+ { s->r_type = KNOT_RRTYPE_NAPTR; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr434:
+ { s->r_type = KNOT_RRTYPE_NID; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr443:
+ { s->r_type = KNOT_RRTYPE_NS; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr453:
+ { s->r_type = KNOT_RRTYPE_NSEC; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr462:
+ { s->r_type = KNOT_RRTYPE_NSEC3; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr474:
+ { s->r_type = KNOT_RRTYPE_NSEC3PARAM; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr484:
+ { s->r_type = KNOT_RRTYPE_PTR; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr495:
+ { s->r_type = KNOT_RRTYPE_RP; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr506:
+ { s->r_type = KNOT_RRTYPE_RRSIG; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr514:
+ { s->r_type = KNOT_RRTYPE_RT; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr527:
+ { s->r_type = KNOT_RRTYPE_SOA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr536:
+ { s->r_type = KNOT_RRTYPE_SPF; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr545:
+ { s->r_type = KNOT_RRTYPE_SRV; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr556:
+ { s->r_type = KNOT_RRTYPE_SSHFP; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr569:
+ { s->r_type = KNOT_RRTYPE_TLSA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr578:
+ { s->r_type = KNOT_RRTYPE_TXT; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr592:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ s->r_type = (uint16_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr602:
+ { s->r_type = KNOT_RRTYPE_URI; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr850:
+ { s->r_type = KNOT_RRTYPE_AAAA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr861:
+ { s->r_type = KNOT_RRTYPE_AFSDB; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+tr870:
+ { s->r_type = KNOT_RRTYPE_APL; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 6;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 6;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 6;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 6;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 6;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 6;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 6;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 6;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 6;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 6;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 6;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 6;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 6;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 6;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 6;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 6;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 6;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 6;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 6;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 6;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 6;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 6;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 6;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 6;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 6;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 6;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 6;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 6;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 6;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st6;
+st6:
+ if ( ++p == pe )
+ goto _test_eof6;
+case 6:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr80;
+ case 32: goto tr80;
+ case 40: goto tr81;
+ case 41: goto tr82;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr83;
+ case 1083: goto tr84;
+ }
+ goto tr79;
+tr87:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st7;
+tr88:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st7;
+tr80:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st7;
+tr81:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st7;
+tr82:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st7;
+st7:
+ if ( ++p == pe )
+ goto _test_eof7;
+case 7:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st7;
+ case 32: goto st7;
+ case 40: goto tr87;
+ case 41: goto tr88;
+ case 778: goto tr89;
+ case 827: goto tr90;
+ case 1034: goto tr89;
+ case 1083: goto tr90;
+ }
+ goto tr85;
+tr90:
+ {
+ s->buffer_length = 0;
+ }
+ goto st8;
+tr84:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st8;
+tr91:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st8;
+tr761:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st8;
+tr765:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st8;
+st8:
+ if ( ++p == pe )
+ goto _test_eof8;
+case 8:
+ if ( (*p) == 10 )
+ goto tr92;
+ goto tr91;
+tr74:
+ {
+ if (pe - p == 1) {
+ *wrap = WRAP_DETECTED;
+ }
+ }
+ goto st9;
+st9:
+ if ( ++p == pe )
+ goto _test_eof9;
+case 9:
+ if ( (*p) == 35 )
+ goto tr94;
+ goto tr93;
+tr76:
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr65:
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr95:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st10;
+tr160:
+ { s->r_type = KNOT_RRTYPE_CAA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr182:
+ { s->r_type = KNOT_RRTYPE_CDNSKEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr190:
+ { s->r_type = KNOT_RRTYPE_CDS; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr200:
+ { s->r_type = KNOT_RRTYPE_CERT; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr211:
+ { s->r_type = KNOT_RRTYPE_CNAME; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr225:
+ { s->r_type = KNOT_RRTYPE_DHCID; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr237:
+ { s->r_type = KNOT_RRTYPE_DNAME; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr248:
+ { s->r_type = KNOT_RRTYPE_DNSKEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr256:
+ { s->r_type = KNOT_RRTYPE_DS; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr269:
+ { s->r_type = KNOT_RRTYPE_EUI48; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr278:
+ { s->r_type = KNOT_RRTYPE_EUI64; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr290:
+ { s->r_type = KNOT_RRTYPE_HINFO; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr331:
+ { s->r_type = KNOT_RRTYPE_IPSECKEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr342:
+ { s->r_type = KNOT_RRTYPE_KEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr350:
+ { s->r_type = KNOT_RRTYPE_KX; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr363:
+ { s->r_type = KNOT_RRTYPE_L32; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr372:
+ { s->r_type = KNOT_RRTYPE_L64; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr381:
+ { s->r_type = KNOT_RRTYPE_LOC; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr389:
+ { s->r_type = KNOT_RRTYPE_LP; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr402:
+ { s->r_type = KNOT_RRTYPE_MINFO; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr410:
+ { s->r_type = KNOT_RRTYPE_MX; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr424:
+ { s->r_type = KNOT_RRTYPE_NAPTR; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr433:
+ { s->r_type = KNOT_RRTYPE_NID; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr442:
+ { s->r_type = KNOT_RRTYPE_NS; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr452:
+ { s->r_type = KNOT_RRTYPE_NSEC; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr461:
+ { s->r_type = KNOT_RRTYPE_NSEC3; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr473:
+ { s->r_type = KNOT_RRTYPE_NSEC3PARAM; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr483:
+ { s->r_type = KNOT_RRTYPE_PTR; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr494:
+ { s->r_type = KNOT_RRTYPE_RP; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr505:
+ { s->r_type = KNOT_RRTYPE_RRSIG; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr513:
+ { s->r_type = KNOT_RRTYPE_RT; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr526:
+ { s->r_type = KNOT_RRTYPE_SOA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr535:
+ { s->r_type = KNOT_RRTYPE_SPF; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr544:
+ { s->r_type = KNOT_RRTYPE_SRV; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr555:
+ { s->r_type = KNOT_RRTYPE_SSHFP; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr568:
+ { s->r_type = KNOT_RRTYPE_TLSA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr577:
+ { s->r_type = KNOT_RRTYPE_TXT; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr591:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ s->r_type = (uint16_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr601:
+ { s->r_type = KNOT_RRTYPE_URI; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr849:
+ { s->r_type = KNOT_RRTYPE_AAAA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr860:
+ { s->r_type = KNOT_RRTYPE_AFSDB; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+tr869:
+ { s->r_type = KNOT_RRTYPE_APL; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st10;
+st10:
+ if ( ++p == pe )
+ goto _test_eof10;
+case 10:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr96;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr95;
+ goto tr71;
+tr67:
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr77:
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr162:
+ { s->r_type = KNOT_RRTYPE_CAA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr184:
+ { s->r_type = KNOT_RRTYPE_CDNSKEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr192:
+ { s->r_type = KNOT_RRTYPE_CDS; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr202:
+ { s->r_type = KNOT_RRTYPE_CERT; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr213:
+ { s->r_type = KNOT_RRTYPE_CNAME; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr227:
+ { s->r_type = KNOT_RRTYPE_DHCID; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr239:
+ { s->r_type = KNOT_RRTYPE_DNAME; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr250:
+ { s->r_type = KNOT_RRTYPE_DNSKEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr258:
+ { s->r_type = KNOT_RRTYPE_DS; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr271:
+ { s->r_type = KNOT_RRTYPE_EUI48; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr280:
+ { s->r_type = KNOT_RRTYPE_EUI64; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr292:
+ { s->r_type = KNOT_RRTYPE_HINFO; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr333:
+ { s->r_type = KNOT_RRTYPE_IPSECKEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr344:
+ { s->r_type = KNOT_RRTYPE_KEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr352:
+ { s->r_type = KNOT_RRTYPE_KX; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr365:
+ { s->r_type = KNOT_RRTYPE_L32; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr374:
+ { s->r_type = KNOT_RRTYPE_L64; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr383:
+ { s->r_type = KNOT_RRTYPE_LOC; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr391:
+ { s->r_type = KNOT_RRTYPE_LP; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr404:
+ { s->r_type = KNOT_RRTYPE_MINFO; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr412:
+ { s->r_type = KNOT_RRTYPE_MX; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr426:
+ { s->r_type = KNOT_RRTYPE_NAPTR; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr435:
+ { s->r_type = KNOT_RRTYPE_NID; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr444:
+ { s->r_type = KNOT_RRTYPE_NS; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr454:
+ { s->r_type = KNOT_RRTYPE_NSEC; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr463:
+ { s->r_type = KNOT_RRTYPE_NSEC3; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr475:
+ { s->r_type = KNOT_RRTYPE_NSEC3PARAM; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr485:
+ { s->r_type = KNOT_RRTYPE_PTR; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr496:
+ { s->r_type = KNOT_RRTYPE_RP; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr507:
+ { s->r_type = KNOT_RRTYPE_RRSIG; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr515:
+ { s->r_type = KNOT_RRTYPE_RT; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr528:
+ { s->r_type = KNOT_RRTYPE_SOA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr537:
+ { s->r_type = KNOT_RRTYPE_SPF; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr546:
+ { s->r_type = KNOT_RRTYPE_SRV; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr557:
+ { s->r_type = KNOT_RRTYPE_SSHFP; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr570:
+ { s->r_type = KNOT_RRTYPE_TLSA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr579:
+ { s->r_type = KNOT_RRTYPE_TXT; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr593:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ s->r_type = (uint16_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr603:
+ { s->r_type = KNOT_RRTYPE_URI; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr851:
+ { s->r_type = KNOT_RRTYPE_AAAA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr862:
+ { s->r_type = KNOT_RRTYPE_AFSDB; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+tr871:
+ { s->r_type = KNOT_RRTYPE_APL; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 11;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 11;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 11;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 11;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 11;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 11;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 11;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 11;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 11;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 11;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 11;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 11;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 11;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 11;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 11;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 11;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 11;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 11;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 11;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 11;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 11;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 11;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 11;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 11;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 11;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 11;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 11;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 11;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 11;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st11;
+st11:
+ if ( ++p == pe )
+ goto _test_eof11;
+case 11:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr97;
+ case 32: goto tr97;
+ case 40: goto tr98;
+ case 41: goto tr99;
+ case 92: goto tr74;
+ case 1802: goto tr83;
+ case 1851: goto tr84;
+ case 2058: goto tr83;
+ case 2107: goto tr100;
+ case 2314: goto tr101;
+ case 2363: goto tr102;
+ case 2570: goto tr83;
+ case 2619: goto tr103;
+ }
+ if ( _widec < 11 ) {
+ if ( _widec <= 8 )
+ goto tr69;
+ } else if ( _widec > 58 ) {
+ if ( 60 <= _widec )
+ goto tr69;
+ } else
+ goto tr69;
+ goto tr79;
+tr105:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st12;
+tr106:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st12;
+tr97:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st12;
+tr98:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st12;
+tr99:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st12;
+st12:
+ if ( ++p == pe )
+ goto _test_eof12;
+case 12:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st12;
+ case 32: goto st12;
+ case 40: goto tr105;
+ case 41: goto tr106;
+ case 92: goto tr74;
+ case 1802: goto tr89;
+ case 1851: goto tr90;
+ case 2058: goto tr89;
+ case 2107: goto tr107;
+ case 2314: goto tr108;
+ case 2363: goto tr109;
+ case 2570: goto tr89;
+ case 2619: goto tr110;
+ }
+ if ( _widec < 11 ) {
+ if ( _widec <= 8 )
+ goto tr69;
+ } else if ( _widec > 58 ) {
+ if ( 60 <= _widec )
+ goto tr69;
+ } else
+ goto tr69;
+ goto tr79;
+tr107:
+ {
+ s->buffer_length = 0;
+ }
+ goto st13;
+tr111:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st13;
+tr100:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st13;
+tr167:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st13;
+tr171:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st13;
+tr740:
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st13;
+st13:
+ if ( ++p == pe )
+ goto _test_eof13;
+case 13:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 778: goto tr92;
+ case 1034: goto tr112;
+ }
+ if ( _widec > 895 ) {
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr111;
+ } else if ( _widec >= 640 )
+ goto tr91;
+ goto tr79;
+tr112:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1128; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1128; goto _out;}
+ }
+ }
+ goto st1128;
+tr748:
+ {
+ s->line_counter++;
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1128; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1128; goto _out;}
+ }
+ }
+ goto st1128;
+tr739:
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1128; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1128; goto _out;}
+ }
+ }
+ goto st1128;
+st1128:
+ if ( ++p == pe )
+ goto _test_eof1128;
+case 1128:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr3622;
+ case 32: goto tr3622;
+ case 36: goto tr3623;
+ case 40: goto tr3624;
+ case 41: goto tr3625;
+ case 42: goto tr3626;
+ case 58: goto tr69;
+ case 92: goto tr3627;
+ case 95: goto tr3626;
+ case 1802: goto tr3618;
+ case 1851: goto tr3619;
+ case 2058: goto tr3628;
+ case 2107: goto tr3629;
+ case 2314: goto tr3630;
+ case 2363: goto tr3631;
+ case 2570: goto tr3632;
+ case 2619: goto tr3633;
+ }
+ if ( _widec < 60 ) {
+ if ( _widec < 11 ) {
+ if ( _widec <= 8 )
+ goto tr69;
+ } else if ( _widec > 44 ) {
+ if ( 45 <= _widec && _widec <= 57 )
+ goto tr3626;
+ } else
+ goto tr69;
+ } else if ( _widec > 63 ) {
+ if ( _widec < 91 ) {
+ if ( 64 <= _widec && _widec <= 90 )
+ goto tr3626;
+ } else if ( _widec > 96 ) {
+ if ( _widec > 122 ) {
+ if ( 123 <= _widec )
+ goto tr69;
+ } else if ( _widec >= 97 )
+ goto tr3626;
+ } else
+ goto tr69;
+ } else
+ goto tr69;
+ goto tr783;
+tr115:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st14;
+tr116:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st14;
+tr3622:
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st14;
+tr3624:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st14;
+tr3625:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st14;
+st14:
+ if ( ++p == pe )
+ goto _test_eof14;
+case 14:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st14;
+ case 32: goto st14;
+ case 40: goto tr115;
+ case 41: goto tr116;
+ case 58: goto tr69;
+ case 65: goto tr118;
+ case 67: goto tr119;
+ case 68: goto tr120;
+ case 69: goto tr121;
+ case 72: goto tr122;
+ case 73: goto tr123;
+ case 75: goto tr124;
+ case 76: goto tr125;
+ case 77: goto tr126;
+ case 78: goto tr127;
+ case 80: goto tr128;
+ case 82: goto tr129;
+ case 83: goto tr130;
+ case 84: goto tr131;
+ case 85: goto tr132;
+ case 92: goto tr74;
+ case 97: goto tr118;
+ case 99: goto tr119;
+ case 100: goto tr120;
+ case 101: goto tr121;
+ case 104: goto tr122;
+ case 105: goto tr123;
+ case 107: goto tr124;
+ case 108: goto tr125;
+ case 109: goto tr126;
+ case 110: goto tr127;
+ case 112: goto tr128;
+ case 114: goto tr129;
+ case 115: goto tr130;
+ case 116: goto tr131;
+ case 117: goto tr132;
+ case 1802: goto tr20;
+ case 1851: goto tr21;
+ case 2058: goto tr133;
+ case 2107: goto tr134;
+ case 2314: goto tr135;
+ case 2363: goto tr136;
+ case 2570: goto tr137;
+ case 2619: goto tr138;
+ }
+ if ( _widec < 11 ) {
+ if ( _widec <= 8 )
+ goto tr69;
+ } else if ( _widec > 47 ) {
+ if ( _widec > 57 ) {
+ if ( 60 <= _widec )
+ goto tr69;
+ } else if ( _widec >= 48 )
+ goto tr117;
+ } else
+ goto tr69;
+ goto tr114;
+tr117:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 15;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 15;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 15;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 15;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 15;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 15;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 15;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 15;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 15;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 15;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 15;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 15;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 15;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 15;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 15;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 15;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 15;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 15;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 15;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 15;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 15;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 15;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 15;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 15;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 15;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 15;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 15;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 15;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 15;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st15;
+st15:
+ if ( ++p == pe )
+ goto _test_eof15;
+case 15:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr140;
+ case 32: goto tr140;
+ case 40: goto tr141;
+ case 41: goto tr142;
+ case 68: goto tr29;
+ case 72: goto tr30;
+ case 77: goto tr31;
+ case 83: goto st166;
+ case 87: goto tr33;
+ case 100: goto tr29;
+ case 104: goto tr30;
+ case 109: goto tr31;
+ case 115: goto st166;
+ case 119: goto tr33;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr143;
+ case 1083: goto tr144;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr28;
+ goto tr139;
+tr147:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st16;
+tr148:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st16;
+tr140:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st16;
+tr141:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st16;
+tr142:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st16;
+st16:
+ if ( ++p == pe )
+ goto _test_eof16;
+case 16:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st16;
+ case 32: goto st16;
+ case 40: goto tr147;
+ case 41: goto tr148;
+ case 65: goto tr40;
+ case 67: goto tr41;
+ case 68: goto tr42;
+ case 69: goto tr43;
+ case 72: goto tr44;
+ case 73: goto tr45;
+ case 75: goto tr46;
+ case 76: goto tr47;
+ case 77: goto tr48;
+ case 78: goto tr49;
+ case 80: goto tr50;
+ case 82: goto tr51;
+ case 83: goto tr52;
+ case 84: goto tr53;
+ case 85: goto tr54;
+ case 97: goto tr40;
+ case 99: goto tr41;
+ case 100: goto tr42;
+ case 101: goto tr43;
+ case 104: goto tr44;
+ case 105: goto tr45;
+ case 107: goto tr46;
+ case 108: goto tr47;
+ case 109: goto tr48;
+ case 110: goto tr49;
+ case 112: goto tr50;
+ case 114: goto tr51;
+ case 115: goto tr52;
+ case 116: goto tr53;
+ case 117: goto tr54;
+ case 778: goto tr89;
+ case 827: goto tr90;
+ case 1034: goto tr149;
+ case 1083: goto tr150;
+ }
+ goto tr145;
+tr6:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st17;
+tr41:
+ {
+ s->r_class = s->default_class;
+ }
+ goto st17;
+tr623:
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st17;
+st17:
+ if ( ++p == pe )
+ goto _test_eof17;
+case 17:
+ switch( (*p) ) {
+ case 65: goto st18;
+ case 68: goto st22;
+ case 69: goto st29;
+ case 78: goto st32;
+ case 97: goto st18;
+ case 100: goto st22;
+ case 101: goto st29;
+ case 110: goto st32;
+ }
+ goto tr36;
+st18:
+ if ( ++p == pe )
+ goto _test_eof18;
+case 18:
+ switch( (*p) ) {
+ case 65: goto st19;
+ case 97: goto st19;
+ }
+ goto tr36;
+st19:
+ if ( ++p == pe )
+ goto _test_eof19;
+case 19:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr156;
+ case 32: goto tr156;
+ case 40: goto tr157;
+ case 41: goto tr158;
+ case 2058: goto tr159;
+ case 2107: goto tr160;
+ case 2314: goto tr161;
+ case 2363: goto tr161;
+ case 2570: goto tr162;
+ case 2619: goto tr163;
+ }
+ goto tr57;
+tr68:
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr78:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr163:
+ { s->r_type = KNOT_RRTYPE_CAA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr185:
+ { s->r_type = KNOT_RRTYPE_CDNSKEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr193:
+ { s->r_type = KNOT_RRTYPE_CDS; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr203:
+ { s->r_type = KNOT_RRTYPE_CERT; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr214:
+ { s->r_type = KNOT_RRTYPE_CNAME; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr228:
+ { s->r_type = KNOT_RRTYPE_DHCID; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr240:
+ { s->r_type = KNOT_RRTYPE_DNAME; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr251:
+ { s->r_type = KNOT_RRTYPE_DNSKEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr259:
+ { s->r_type = KNOT_RRTYPE_DS; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr272:
+ { s->r_type = KNOT_RRTYPE_EUI48; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr281:
+ { s->r_type = KNOT_RRTYPE_EUI64; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr293:
+ { s->r_type = KNOT_RRTYPE_HINFO; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr334:
+ { s->r_type = KNOT_RRTYPE_IPSECKEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr345:
+ { s->r_type = KNOT_RRTYPE_KEY; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr353:
+ { s->r_type = KNOT_RRTYPE_KX; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr366:
+ { s->r_type = KNOT_RRTYPE_L32; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr375:
+ { s->r_type = KNOT_RRTYPE_L64; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr384:
+ { s->r_type = KNOT_RRTYPE_LOC; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr392:
+ { s->r_type = KNOT_RRTYPE_LP; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr405:
+ { s->r_type = KNOT_RRTYPE_MINFO; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr413:
+ { s->r_type = KNOT_RRTYPE_MX; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr427:
+ { s->r_type = KNOT_RRTYPE_NAPTR; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr436:
+ { s->r_type = KNOT_RRTYPE_NID; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr445:
+ { s->r_type = KNOT_RRTYPE_NS; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr455:
+ { s->r_type = KNOT_RRTYPE_NSEC; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr464:
+ { s->r_type = KNOT_RRTYPE_NSEC3; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr476:
+ { s->r_type = KNOT_RRTYPE_NSEC3PARAM; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr486:
+ { s->r_type = KNOT_RRTYPE_PTR; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr497:
+ { s->r_type = KNOT_RRTYPE_RP; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr508:
+ { s->r_type = KNOT_RRTYPE_RRSIG; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr516:
+ { s->r_type = KNOT_RRTYPE_RT; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr529:
+ { s->r_type = KNOT_RRTYPE_SOA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr538:
+ { s->r_type = KNOT_RRTYPE_SPF; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr547:
+ { s->r_type = KNOT_RRTYPE_SRV; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr558:
+ { s->r_type = KNOT_RRTYPE_SSHFP; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr571:
+ { s->r_type = KNOT_RRTYPE_TLSA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr580:
+ { s->r_type = KNOT_RRTYPE_TXT; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr594:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ s->r_type = (uint16_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr604:
+ { s->r_type = KNOT_RRTYPE_URI; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr852:
+ { s->r_type = KNOT_RRTYPE_AAAA; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr863:
+ { s->r_type = KNOT_RRTYPE_AFSDB; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+tr872:
+ { s->r_type = KNOT_RRTYPE_APL; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 20;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 20;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 20;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 20;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 20;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 20;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 20;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 20;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 20;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 20;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 20;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 20;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 20;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 20;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 20;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 20;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 20;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 20;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 20;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 20;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 20;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 20;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 20;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 20;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 20;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 20;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 20;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 20;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 20;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st20;
+st20:
+ if ( ++p == pe )
+ goto _test_eof20;
+case 20:
+ _widec = (*p);
+ if ( (*p) < 11 ) {
+ if ( (*p) > 9 ) {
+ if ( 10 <= (*p) && (*p) <= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 58 ) {
+ if ( (*p) > 59 ) {
+ if ( 60 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 777: goto tr80;
+ case 778: goto tr83;
+ case 800: goto tr80;
+ case 808: goto tr81;
+ case 809: goto tr82;
+ case 827: goto tr84;
+ case 1033: goto tr164;
+ case 1034: goto tr83;
+ case 1056: goto tr164;
+ case 1064: goto tr165;
+ case 1065: goto tr166;
+ case 1083: goto tr167;
+ }
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr95;
+ goto tr79;
+tr168:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st21;
+tr164:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st21;
+tr165:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st21;
+tr166:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st21;
+tr169:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st21;
+tr170:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st21;
+st21:
+ if ( ++p == pe )
+ goto _test_eof21;
+case 21:
+ _widec = (*p);
+ if ( (*p) < 11 ) {
+ if ( (*p) > 9 ) {
+ if ( 10 <= (*p) && (*p) <= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 58 ) {
+ if ( (*p) > 59 ) {
+ if ( 60 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 777: goto st7;
+ case 778: goto tr89;
+ case 800: goto st7;
+ case 808: goto tr87;
+ case 809: goto tr88;
+ case 827: goto tr90;
+ case 1033: goto tr168;
+ case 1034: goto tr89;
+ case 1056: goto tr168;
+ case 1064: goto tr169;
+ case 1065: goto tr170;
+ case 1083: goto tr171;
+ }
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr95;
+ goto tr79;
+st22:
+ if ( ++p == pe )
+ goto _test_eof22;
+case 22:
+ switch( (*p) ) {
+ case 78: goto st23;
+ case 83: goto st28;
+ case 110: goto st23;
+ case 115: goto st28;
+ }
+ goto tr36;
+st23:
+ if ( ++p == pe )
+ goto _test_eof23;
+case 23:
+ switch( (*p) ) {
+ case 83: goto st24;
+ case 115: goto st24;
+ }
+ goto tr36;
+st24:
+ if ( ++p == pe )
+ goto _test_eof24;
+case 24:
+ switch( (*p) ) {
+ case 75: goto st25;
+ case 107: goto st25;
+ }
+ goto tr36;
+st25:
+ if ( ++p == pe )
+ goto _test_eof25;
+case 25:
+ switch( (*p) ) {
+ case 69: goto st26;
+ case 101: goto st26;
+ }
+ goto tr36;
+st26:
+ if ( ++p == pe )
+ goto _test_eof26;
+case 26:
+ switch( (*p) ) {
+ case 89: goto st27;
+ case 121: goto st27;
+ }
+ goto tr36;
+st27:
+ if ( ++p == pe )
+ goto _test_eof27;
+case 27:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr178;
+ case 32: goto tr178;
+ case 40: goto tr179;
+ case 41: goto tr180;
+ case 2058: goto tr181;
+ case 2107: goto tr182;
+ case 2314: goto tr183;
+ case 2363: goto tr183;
+ case 2570: goto tr184;
+ case 2619: goto tr185;
+ }
+ goto tr57;
+st28:
+ if ( ++p == pe )
+ goto _test_eof28;
+case 28:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr186;
+ case 32: goto tr186;
+ case 40: goto tr187;
+ case 41: goto tr188;
+ case 2058: goto tr189;
+ case 2107: goto tr190;
+ case 2314: goto tr191;
+ case 2363: goto tr191;
+ case 2570: goto tr192;
+ case 2619: goto tr193;
+ }
+ goto tr57;
+st29:
+ if ( ++p == pe )
+ goto _test_eof29;
+case 29:
+ switch( (*p) ) {
+ case 82: goto st30;
+ case 114: goto st30;
+ }
+ goto tr36;
+st30:
+ if ( ++p == pe )
+ goto _test_eof30;
+case 30:
+ switch( (*p) ) {
+ case 84: goto st31;
+ case 116: goto st31;
+ }
+ goto tr36;
+st31:
+ if ( ++p == pe )
+ goto _test_eof31;
+case 31:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr196;
+ case 32: goto tr196;
+ case 40: goto tr197;
+ case 41: goto tr198;
+ case 2058: goto tr199;
+ case 2107: goto tr200;
+ case 2314: goto tr201;
+ case 2363: goto tr201;
+ case 2570: goto tr202;
+ case 2619: goto tr203;
+ }
+ goto tr57;
+st32:
+ if ( ++p == pe )
+ goto _test_eof32;
+case 32:
+ switch( (*p) ) {
+ case 65: goto st33;
+ case 97: goto st33;
+ }
+ goto tr36;
+st33:
+ if ( ++p == pe )
+ goto _test_eof33;
+case 33:
+ switch( (*p) ) {
+ case 77: goto st34;
+ case 109: goto st34;
+ }
+ goto tr36;
+st34:
+ if ( ++p == pe )
+ goto _test_eof34;
+case 34:
+ switch( (*p) ) {
+ case 69: goto st35;
+ case 101: goto st35;
+ }
+ goto tr36;
+st35:
+ if ( ++p == pe )
+ goto _test_eof35;
+case 35:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr207;
+ case 32: goto tr207;
+ case 40: goto tr208;
+ case 41: goto tr209;
+ case 2058: goto tr210;
+ case 2107: goto tr211;
+ case 2314: goto tr212;
+ case 2363: goto tr212;
+ case 2570: goto tr213;
+ case 2619: goto tr214;
+ }
+ goto tr57;
+tr7:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st36;
+tr42:
+ {
+ s->r_class = s->default_class;
+ }
+ goto st36;
+tr624:
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st36;
+st36:
+ if ( ++p == pe )
+ goto _test_eof36;
+case 36:
+ switch( (*p) ) {
+ case 72: goto st37;
+ case 78: goto st41;
+ case 83: goto st49;
+ case 104: goto st37;
+ case 110: goto st41;
+ case 115: goto st49;
+ }
+ goto tr36;
+st37:
+ if ( ++p == pe )
+ goto _test_eof37;
+case 37:
+ switch( (*p) ) {
+ case 67: goto st38;
+ case 99: goto st38;
+ }
+ goto tr36;
+st38:
+ if ( ++p == pe )
+ goto _test_eof38;
+case 38:
+ switch( (*p) ) {
+ case 73: goto st39;
+ case 105: goto st39;
+ }
+ goto tr36;
+st39:
+ if ( ++p == pe )
+ goto _test_eof39;
+case 39:
+ switch( (*p) ) {
+ case 68: goto st40;
+ case 100: goto st40;
+ }
+ goto tr36;
+st40:
+ if ( ++p == pe )
+ goto _test_eof40;
+case 40:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr221;
+ case 32: goto tr221;
+ case 40: goto tr222;
+ case 41: goto tr223;
+ case 2058: goto tr224;
+ case 2107: goto tr225;
+ case 2314: goto tr226;
+ case 2363: goto tr226;
+ case 2570: goto tr227;
+ case 2619: goto tr228;
+ }
+ goto tr57;
+st41:
+ if ( ++p == pe )
+ goto _test_eof41;
+case 41:
+ switch( (*p) ) {
+ case 65: goto st42;
+ case 83: goto st45;
+ case 97: goto st42;
+ case 115: goto st45;
+ }
+ goto tr36;
+st42:
+ if ( ++p == pe )
+ goto _test_eof42;
+case 42:
+ switch( (*p) ) {
+ case 77: goto st43;
+ case 109: goto st43;
+ }
+ goto tr36;
+st43:
+ if ( ++p == pe )
+ goto _test_eof43;
+case 43:
+ switch( (*p) ) {
+ case 69: goto st44;
+ case 101: goto st44;
+ }
+ goto tr36;
+st44:
+ if ( ++p == pe )
+ goto _test_eof44;
+case 44:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr233;
+ case 32: goto tr233;
+ case 40: goto tr234;
+ case 41: goto tr235;
+ case 2058: goto tr236;
+ case 2107: goto tr237;
+ case 2314: goto tr238;
+ case 2363: goto tr238;
+ case 2570: goto tr239;
+ case 2619: goto tr240;
+ }
+ goto tr57;
+st45:
+ if ( ++p == pe )
+ goto _test_eof45;
+case 45:
+ switch( (*p) ) {
+ case 75: goto st46;
+ case 107: goto st46;
+ }
+ goto tr36;
+st46:
+ if ( ++p == pe )
+ goto _test_eof46;
+case 46:
+ switch( (*p) ) {
+ case 69: goto st47;
+ case 101: goto st47;
+ }
+ goto tr36;
+st47:
+ if ( ++p == pe )
+ goto _test_eof47;
+case 47:
+ switch( (*p) ) {
+ case 89: goto st48;
+ case 121: goto st48;
+ }
+ goto tr36;
+st48:
+ if ( ++p == pe )
+ goto _test_eof48;
+case 48:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr244;
+ case 32: goto tr244;
+ case 40: goto tr245;
+ case 41: goto tr246;
+ case 2058: goto tr247;
+ case 2107: goto tr248;
+ case 2314: goto tr249;
+ case 2363: goto tr249;
+ case 2570: goto tr250;
+ case 2619: goto tr251;
+ }
+ goto tr57;
+st49:
+ if ( ++p == pe )
+ goto _test_eof49;
+case 49:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr252;
+ case 32: goto tr252;
+ case 40: goto tr253;
+ case 41: goto tr254;
+ case 2058: goto tr255;
+ case 2107: goto tr256;
+ case 2314: goto tr257;
+ case 2363: goto tr257;
+ case 2570: goto tr258;
+ case 2619: goto tr259;
+ }
+ goto tr57;
+tr8:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st50;
+tr43:
+ {
+ s->r_class = s->default_class;
+ }
+ goto st50;
+tr625:
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st50;
+st50:
+ if ( ++p == pe )
+ goto _test_eof50;
+case 50:
+ switch( (*p) ) {
+ case 85: goto st51;
+ case 117: goto st51;
+ }
+ goto tr36;
+st51:
+ if ( ++p == pe )
+ goto _test_eof51;
+case 51:
+ switch( (*p) ) {
+ case 73: goto st52;
+ case 105: goto st52;
+ }
+ goto tr36;
+st52:
+ if ( ++p == pe )
+ goto _test_eof52;
+case 52:
+ switch( (*p) ) {
+ case 52: goto st53;
+ case 54: goto st55;
+ }
+ goto tr36;
+st53:
+ if ( ++p == pe )
+ goto _test_eof53;
+case 53:
+ if ( (*p) == 56 )
+ goto st54;
+ goto tr36;
+st54:
+ if ( ++p == pe )
+ goto _test_eof54;
+case 54:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr265;
+ case 32: goto tr265;
+ case 40: goto tr266;
+ case 41: goto tr267;
+ case 2058: goto tr268;
+ case 2107: goto tr269;
+ case 2314: goto tr270;
+ case 2363: goto tr270;
+ case 2570: goto tr271;
+ case 2619: goto tr272;
+ }
+ goto tr57;
+st55:
+ if ( ++p == pe )
+ goto _test_eof55;
+case 55:
+ if ( (*p) == 52 )
+ goto st56;
+ goto tr36;
+st56:
+ if ( ++p == pe )
+ goto _test_eof56;
+case 56:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr274;
+ case 32: goto tr274;
+ case 40: goto tr275;
+ case 41: goto tr276;
+ case 2058: goto tr277;
+ case 2107: goto tr278;
+ case 2314: goto tr279;
+ case 2363: goto tr279;
+ case 2570: goto tr280;
+ case 2619: goto tr281;
+ }
+ goto tr57;
+tr9:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st57;
+tr44:
+ {
+ s->r_class = s->default_class;
+ }
+ goto st57;
+tr626:
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st57;
+st57:
+ if ( ++p == pe )
+ goto _test_eof57;
+case 57:
+ switch( (*p) ) {
+ case 73: goto st58;
+ case 105: goto st58;
+ }
+ goto tr36;
+st58:
+ if ( ++p == pe )
+ goto _test_eof58;
+case 58:
+ switch( (*p) ) {
+ case 78: goto st59;
+ case 110: goto st59;
+ }
+ goto tr36;
+st59:
+ if ( ++p == pe )
+ goto _test_eof59;
+case 59:
+ switch( (*p) ) {
+ case 70: goto st60;
+ case 102: goto st60;
+ }
+ goto tr36;
+st60:
+ if ( ++p == pe )
+ goto _test_eof60;
+case 60:
+ switch( (*p) ) {
+ case 79: goto st61;
+ case 111: goto st61;
+ }
+ goto tr36;
+st61:
+ if ( ++p == pe )
+ goto _test_eof61;
+case 61:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr286;
+ case 32: goto tr286;
+ case 40: goto tr287;
+ case 41: goto tr288;
+ case 2058: goto tr289;
+ case 2107: goto tr290;
+ case 2314: goto tr291;
+ case 2363: goto tr291;
+ case 2570: goto tr292;
+ case 2619: goto tr293;
+ }
+ goto tr57;
+tr45:
+ {
+ s->r_class = s->default_class;
+ }
+ goto st62;
+st62:
+ if ( ++p == pe )
+ goto _test_eof62;
+case 62:
+ switch( (*p) ) {
+ case 78: goto st63;
+ case 80: goto st66;
+ case 110: goto st63;
+ case 112: goto st66;
+ }
+ goto tr36;
+st63:
+ if ( ++p == pe )
+ goto _test_eof63;
+case 63:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr296;
+ case 32: goto tr296;
+ case 40: goto tr297;
+ case 41: goto tr298;
+ case 1034: goto tr299;
+ case 1083: goto tr300;
+ }
+ goto tr36;
+tr302:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st64;
+tr303:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st64;
+tr319:
+ {
+ s->line_counter++;
+ }
+ goto st64;
+tr639:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st64;
+tr640:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st64;
+tr641:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st64;
+tr648:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st64;
+tr606:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st64;
+tr296:
+ {
+ s->r_class = KNOT_CLASS_IN;
+ }
+ goto st64;
+tr297:
+ {
+ s->r_class = KNOT_CLASS_IN;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st64;
+tr298:
+ {
+ s->r_class = KNOT_CLASS_IN;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st64;
+tr299:
+ {
+ s->r_class = KNOT_CLASS_IN;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st64;
+tr657:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st64;
+tr658:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st64;
+tr659:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st64;
+tr661:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st64;
+st64:
+ if ( ++p == pe )
+ goto _test_eof64;
+case 64:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st64;
+ case 32: goto st64;
+ case 40: goto tr302;
+ case 41: goto tr303;
+ case 65: goto st4;
+ case 67: goto st17;
+ case 68: goto st36;
+ case 69: goto st50;
+ case 72: goto st57;
+ case 73: goto st65;
+ case 75: goto st73;
+ case 76: goto st77;
+ case 77: goto st85;
+ case 78: goto st91;
+ case 80: goto st107;
+ case 82: goto st110;
+ case 83: goto st117;
+ case 84: goto st128;
+ case 85: goto st138;
+ case 97: goto st4;
+ case 99: goto st17;
+ case 100: goto st36;
+ case 101: goto st50;
+ case 104: goto st57;
+ case 105: goto st65;
+ case 107: goto st73;
+ case 108: goto st77;
+ case 109: goto st85;
+ case 110: goto st91;
+ case 112: goto st107;
+ case 114: goto st110;
+ case 115: goto st117;
+ case 116: goto st128;
+ case 117: goto st138;
+ case 1034: goto tr319;
+ case 1083: goto tr320;
+ }
+ goto tr36;
+tr627:
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st65;
+st65:
+ if ( ++p == pe )
+ goto _test_eof65;
+case 65:
+ switch( (*p) ) {
+ case 80: goto st66;
+ case 112: goto st66;
+ }
+ goto tr36;
+st66:
+ if ( ++p == pe )
+ goto _test_eof66;
+case 66:
+ switch( (*p) ) {
+ case 83: goto st67;
+ case 115: goto st67;
+ }
+ goto tr36;
+st67:
+ if ( ++p == pe )
+ goto _test_eof67;
+case 67:
+ switch( (*p) ) {
+ case 69: goto st68;
+ case 101: goto st68;
+ }
+ goto tr36;
+st68:
+ if ( ++p == pe )
+ goto _test_eof68;
+case 68:
+ switch( (*p) ) {
+ case 67: goto st69;
+ case 99: goto st69;
+ }
+ goto tr36;
+st69:
+ if ( ++p == pe )
+ goto _test_eof69;
+case 69:
+ switch( (*p) ) {
+ case 75: goto st70;
+ case 107: goto st70;
+ }
+ goto tr36;
+st70:
+ if ( ++p == pe )
+ goto _test_eof70;
+case 70:
+ switch( (*p) ) {
+ case 69: goto st71;
+ case 101: goto st71;
+ }
+ goto tr36;
+st71:
+ if ( ++p == pe )
+ goto _test_eof71;
+case 71:
+ switch( (*p) ) {
+ case 89: goto st72;
+ case 121: goto st72;
+ }
+ goto tr36;
+st72:
+ if ( ++p == pe )
+ goto _test_eof72;
+case 72:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr327;
+ case 32: goto tr327;
+ case 40: goto tr328;
+ case 41: goto tr329;
+ case 2058: goto tr330;
+ case 2107: goto tr331;
+ case 2314: goto tr332;
+ case 2363: goto tr332;
+ case 2570: goto tr333;
+ case 2619: goto tr334;
+ }
+ goto tr57;
+tr11:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st73;
+tr46:
+ {
+ s->r_class = s->default_class;
+ }
+ goto st73;
+tr628:
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st73;
+st73:
+ if ( ++p == pe )
+ goto _test_eof73;
+case 73:
+ switch( (*p) ) {
+ case 69: goto st74;
+ case 88: goto st76;
+ case 101: goto st74;
+ case 120: goto st76;
+ }
+ goto tr36;
+st74:
+ if ( ++p == pe )
+ goto _test_eof74;
+case 74:
+ switch( (*p) ) {
+ case 89: goto st75;
+ case 121: goto st75;
+ }
+ goto tr36;
+st75:
+ if ( ++p == pe )
+ goto _test_eof75;
+case 75:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr338;
+ case 32: goto tr338;
+ case 40: goto tr339;
+ case 41: goto tr340;
+ case 2058: goto tr341;
+ case 2107: goto tr342;
+ case 2314: goto tr343;
+ case 2363: goto tr343;
+ case 2570: goto tr344;
+ case 2619: goto tr345;
+ }
+ goto tr57;
+st76:
+ if ( ++p == pe )
+ goto _test_eof76;
+case 76:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr346;
+ case 32: goto tr346;
+ case 40: goto tr347;
+ case 41: goto tr348;
+ case 2058: goto tr349;
+ case 2107: goto tr350;
+ case 2314: goto tr351;
+ case 2363: goto tr351;
+ case 2570: goto tr352;
+ case 2619: goto tr353;
+ }
+ goto tr57;
+tr12:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st77;
+tr47:
+ {
+ s->r_class = s->default_class;
+ }
+ goto st77;
+tr629:
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st77;
+st77:
+ if ( ++p == pe )
+ goto _test_eof77;
+case 77:
+ switch( (*p) ) {
+ case 51: goto st78;
+ case 54: goto st80;
+ case 79: goto st82;
+ case 80: goto st84;
+ case 111: goto st82;
+ case 112: goto st84;
+ }
+ goto tr36;
+st78:
+ if ( ++p == pe )
+ goto _test_eof78;
+case 78:
+ if ( (*p) == 50 )
+ goto st79;
+ goto tr36;
+st79:
+ if ( ++p == pe )
+ goto _test_eof79;
+case 79:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr359;
+ case 32: goto tr359;
+ case 40: goto tr360;
+ case 41: goto tr361;
+ case 2058: goto tr362;
+ case 2107: goto tr363;
+ case 2314: goto tr364;
+ case 2363: goto tr364;
+ case 2570: goto tr365;
+ case 2619: goto tr366;
+ }
+ goto tr57;
+st80:
+ if ( ++p == pe )
+ goto _test_eof80;
+case 80:
+ if ( (*p) == 52 )
+ goto st81;
+ goto tr36;
+st81:
+ if ( ++p == pe )
+ goto _test_eof81;
+case 81:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr368;
+ case 32: goto tr368;
+ case 40: goto tr369;
+ case 41: goto tr370;
+ case 2058: goto tr371;
+ case 2107: goto tr372;
+ case 2314: goto tr373;
+ case 2363: goto tr373;
+ case 2570: goto tr374;
+ case 2619: goto tr375;
+ }
+ goto tr57;
+st82:
+ if ( ++p == pe )
+ goto _test_eof82;
+case 82:
+ switch( (*p) ) {
+ case 67: goto st83;
+ case 99: goto st83;
+ }
+ goto tr36;
+st83:
+ if ( ++p == pe )
+ goto _test_eof83;
+case 83:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr377;
+ case 32: goto tr377;
+ case 40: goto tr378;
+ case 41: goto tr379;
+ case 2058: goto tr380;
+ case 2107: goto tr381;
+ case 2314: goto tr382;
+ case 2363: goto tr382;
+ case 2570: goto tr383;
+ case 2619: goto tr384;
+ }
+ goto tr57;
+st84:
+ if ( ++p == pe )
+ goto _test_eof84;
+case 84:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr385;
+ case 32: goto tr385;
+ case 40: goto tr386;
+ case 41: goto tr387;
+ case 2058: goto tr388;
+ case 2107: goto tr389;
+ case 2314: goto tr390;
+ case 2363: goto tr390;
+ case 2570: goto tr391;
+ case 2619: goto tr392;
+ }
+ goto tr57;
+tr13:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st85;
+tr48:
+ {
+ s->r_class = s->default_class;
+ }
+ goto st85;
+tr630:
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st85;
+st85:
+ if ( ++p == pe )
+ goto _test_eof85;
+case 85:
+ switch( (*p) ) {
+ case 73: goto st86;
+ case 88: goto st90;
+ case 105: goto st86;
+ case 120: goto st90;
+ }
+ goto tr36;
+st86:
+ if ( ++p == pe )
+ goto _test_eof86;
+case 86:
+ switch( (*p) ) {
+ case 78: goto st87;
+ case 110: goto st87;
+ }
+ goto tr36;
+st87:
+ if ( ++p == pe )
+ goto _test_eof87;
+case 87:
+ switch( (*p) ) {
+ case 70: goto st88;
+ case 102: goto st88;
+ }
+ goto tr36;
+st88:
+ if ( ++p == pe )
+ goto _test_eof88;
+case 88:
+ switch( (*p) ) {
+ case 79: goto st89;
+ case 111: goto st89;
+ }
+ goto tr36;
+st89:
+ if ( ++p == pe )
+ goto _test_eof89;
+case 89:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr398;
+ case 32: goto tr398;
+ case 40: goto tr399;
+ case 41: goto tr400;
+ case 2058: goto tr401;
+ case 2107: goto tr402;
+ case 2314: goto tr403;
+ case 2363: goto tr403;
+ case 2570: goto tr404;
+ case 2619: goto tr405;
+ }
+ goto tr57;
+st90:
+ if ( ++p == pe )
+ goto _test_eof90;
+case 90:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr406;
+ case 32: goto tr406;
+ case 40: goto tr407;
+ case 41: goto tr408;
+ case 2058: goto tr409;
+ case 2107: goto tr410;
+ case 2314: goto tr411;
+ case 2363: goto tr411;
+ case 2570: goto tr412;
+ case 2619: goto tr413;
+ }
+ goto tr57;
+tr14:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st91;
+tr49:
+ {
+ s->r_class = s->default_class;
+ }
+ goto st91;
+tr631:
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st91;
+st91:
+ if ( ++p == pe )
+ goto _test_eof91;
+case 91:
+ switch( (*p) ) {
+ case 65: goto st92;
+ case 73: goto st96;
+ case 83: goto st98;
+ case 97: goto st92;
+ case 105: goto st96;
+ case 115: goto st98;
+ }
+ goto tr36;
+st92:
+ if ( ++p == pe )
+ goto _test_eof92;
+case 92:
+ switch( (*p) ) {
+ case 80: goto st93;
+ case 112: goto st93;
+ }
+ goto tr36;
+st93:
+ if ( ++p == pe )
+ goto _test_eof93;
+case 93:
+ switch( (*p) ) {
+ case 84: goto st94;
+ case 116: goto st94;
+ }
+ goto tr36;
+st94:
+ if ( ++p == pe )
+ goto _test_eof94;
+case 94:
+ switch( (*p) ) {
+ case 82: goto st95;
+ case 114: goto st95;
+ }
+ goto tr36;
+st95:
+ if ( ++p == pe )
+ goto _test_eof95;
+case 95:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr420;
+ case 32: goto tr420;
+ case 40: goto tr421;
+ case 41: goto tr422;
+ case 2058: goto tr423;
+ case 2107: goto tr424;
+ case 2314: goto tr425;
+ case 2363: goto tr425;
+ case 2570: goto tr426;
+ case 2619: goto tr427;
+ }
+ goto tr57;
+st96:
+ if ( ++p == pe )
+ goto _test_eof96;
+case 96:
+ switch( (*p) ) {
+ case 68: goto st97;
+ case 100: goto st97;
+ }
+ goto tr36;
+st97:
+ if ( ++p == pe )
+ goto _test_eof97;
+case 97:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr429;
+ case 32: goto tr429;
+ case 40: goto tr430;
+ case 41: goto tr431;
+ case 2058: goto tr432;
+ case 2107: goto tr433;
+ case 2314: goto tr434;
+ case 2363: goto tr434;
+ case 2570: goto tr435;
+ case 2619: goto tr436;
+ }
+ goto tr57;
+st98:
+ if ( ++p == pe )
+ goto _test_eof98;
+case 98:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr437;
+ case 32: goto tr437;
+ case 40: goto tr438;
+ case 41: goto tr439;
+ case 69: goto st99;
+ case 101: goto st99;
+ case 2058: goto tr441;
+ case 2107: goto tr442;
+ case 2314: goto tr443;
+ case 2363: goto tr443;
+ case 2570: goto tr444;
+ case 2619: goto tr445;
+ }
+ goto tr57;
+st99:
+ if ( ++p == pe )
+ goto _test_eof99;
+case 99:
+ switch( (*p) ) {
+ case 67: goto st100;
+ case 99: goto st100;
+ }
+ goto tr36;
+st100:
+ if ( ++p == pe )
+ goto _test_eof100;
+case 100:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr447;
+ case 32: goto tr447;
+ case 40: goto tr448;
+ case 41: goto tr449;
+ case 51: goto st101;
+ case 2058: goto tr451;
+ case 2107: goto tr452;
+ case 2314: goto tr453;
+ case 2363: goto tr453;
+ case 2570: goto tr454;
+ case 2619: goto tr455;
+ }
+ goto tr57;
+st101:
+ if ( ++p == pe )
+ goto _test_eof101;
+case 101:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr456;
+ case 32: goto tr456;
+ case 40: goto tr457;
+ case 41: goto tr458;
+ case 80: goto st102;
+ case 112: goto st102;
+ case 2058: goto tr460;
+ case 2107: goto tr461;
+ case 2314: goto tr462;
+ case 2363: goto tr462;
+ case 2570: goto tr463;
+ case 2619: goto tr464;
+ }
+ goto tr57;
+st102:
+ if ( ++p == pe )
+ goto _test_eof102;
+case 102:
+ switch( (*p) ) {
+ case 65: goto st103;
+ case 97: goto st103;
+ }
+ goto tr36;
+st103:
+ if ( ++p == pe )
+ goto _test_eof103;
+case 103:
+ switch( (*p) ) {
+ case 82: goto st104;
+ case 114: goto st104;
+ }
+ goto tr36;
+st104:
+ if ( ++p == pe )
+ goto _test_eof104;
+case 104:
+ switch( (*p) ) {
+ case 65: goto st105;
+ case 97: goto st105;
+ }
+ goto tr36;
+st105:
+ if ( ++p == pe )
+ goto _test_eof105;
+case 105:
+ switch( (*p) ) {
+ case 77: goto st106;
+ case 109: goto st106;
+ }
+ goto tr36;
+st106:
+ if ( ++p == pe )
+ goto _test_eof106;
+case 106:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr469;
+ case 32: goto tr469;
+ case 40: goto tr470;
+ case 41: goto tr471;
+ case 2058: goto tr472;
+ case 2107: goto tr473;
+ case 2314: goto tr474;
+ case 2363: goto tr474;
+ case 2570: goto tr475;
+ case 2619: goto tr476;
+ }
+ goto tr57;
+tr15:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st107;
+tr50:
+ {
+ s->r_class = s->default_class;
+ }
+ goto st107;
+tr632:
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st107;
+st107:
+ if ( ++p == pe )
+ goto _test_eof107;
+case 107:
+ switch( (*p) ) {
+ case 84: goto st108;
+ case 116: goto st108;
+ }
+ goto tr36;
+st108:
+ if ( ++p == pe )
+ goto _test_eof108;
+case 108:
+ switch( (*p) ) {
+ case 82: goto st109;
+ case 114: goto st109;
+ }
+ goto tr36;
+st109:
+ if ( ++p == pe )
+ goto _test_eof109;
+case 109:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr479;
+ case 32: goto tr479;
+ case 40: goto tr480;
+ case 41: goto tr481;
+ case 2058: goto tr482;
+ case 2107: goto tr483;
+ case 2314: goto tr484;
+ case 2363: goto tr484;
+ case 2570: goto tr485;
+ case 2619: goto tr486;
+ }
+ goto tr57;
+tr16:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st110;
+tr51:
+ {
+ s->r_class = s->default_class;
+ }
+ goto st110;
+tr633:
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st110;
+st110:
+ if ( ++p == pe )
+ goto _test_eof110;
+case 110:
+ switch( (*p) ) {
+ case 80: goto st111;
+ case 82: goto st112;
+ case 84: goto st116;
+ case 112: goto st111;
+ case 114: goto st112;
+ case 116: goto st116;
+ }
+ goto tr36;
+st111:
+ if ( ++p == pe )
+ goto _test_eof111;
+case 111:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr490;
+ case 32: goto tr490;
+ case 40: goto tr491;
+ case 41: goto tr492;
+ case 2058: goto tr493;
+ case 2107: goto tr494;
+ case 2314: goto tr495;
+ case 2363: goto tr495;
+ case 2570: goto tr496;
+ case 2619: goto tr497;
+ }
+ goto tr57;
+st112:
+ if ( ++p == pe )
+ goto _test_eof112;
+case 112:
+ switch( (*p) ) {
+ case 83: goto st113;
+ case 115: goto st113;
+ }
+ goto tr36;
+st113:
+ if ( ++p == pe )
+ goto _test_eof113;
+case 113:
+ switch( (*p) ) {
+ case 73: goto st114;
+ case 105: goto st114;
+ }
+ goto tr36;
+st114:
+ if ( ++p == pe )
+ goto _test_eof114;
+case 114:
+ switch( (*p) ) {
+ case 71: goto st115;
+ case 103: goto st115;
+ }
+ goto tr36;
+st115:
+ if ( ++p == pe )
+ goto _test_eof115;
+case 115:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr501;
+ case 32: goto tr501;
+ case 40: goto tr502;
+ case 41: goto tr503;
+ case 2058: goto tr504;
+ case 2107: goto tr505;
+ case 2314: goto tr506;
+ case 2363: goto tr506;
+ case 2570: goto tr507;
+ case 2619: goto tr508;
+ }
+ goto tr57;
+st116:
+ if ( ++p == pe )
+ goto _test_eof116;
+case 116:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr509;
+ case 32: goto tr509;
+ case 40: goto tr510;
+ case 41: goto tr511;
+ case 2058: goto tr512;
+ case 2107: goto tr513;
+ case 2314: goto tr514;
+ case 2363: goto tr514;
+ case 2570: goto tr515;
+ case 2619: goto tr516;
+ }
+ goto tr57;
+tr17:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st117;
+tr52:
+ {
+ s->r_class = s->default_class;
+ }
+ goto st117;
+tr634:
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st117;
+st117:
+ if ( ++p == pe )
+ goto _test_eof117;
+case 117:
+ switch( (*p) ) {
+ case 79: goto st118;
+ case 80: goto st120;
+ case 82: goto st122;
+ case 83: goto st124;
+ case 111: goto st118;
+ case 112: goto st120;
+ case 114: goto st122;
+ case 115: goto st124;
+ }
+ goto tr36;
+st118:
+ if ( ++p == pe )
+ goto _test_eof118;
+case 118:
+ switch( (*p) ) {
+ case 65: goto st119;
+ case 97: goto st119;
+ }
+ goto tr36;
+st119:
+ if ( ++p == pe )
+ goto _test_eof119;
+case 119:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr522;
+ case 32: goto tr522;
+ case 40: goto tr523;
+ case 41: goto tr524;
+ case 2058: goto tr525;
+ case 2107: goto tr526;
+ case 2314: goto tr527;
+ case 2363: goto tr527;
+ case 2570: goto tr528;
+ case 2619: goto tr529;
+ }
+ goto tr57;
+st120:
+ if ( ++p == pe )
+ goto _test_eof120;
+case 120:
+ switch( (*p) ) {
+ case 70: goto st121;
+ case 102: goto st121;
+ }
+ goto tr36;
+st121:
+ if ( ++p == pe )
+ goto _test_eof121;
+case 121:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr531;
+ case 32: goto tr531;
+ case 40: goto tr532;
+ case 41: goto tr533;
+ case 2058: goto tr534;
+ case 2107: goto tr535;
+ case 2314: goto tr536;
+ case 2363: goto tr536;
+ case 2570: goto tr537;
+ case 2619: goto tr538;
+ }
+ goto tr57;
+st122:
+ if ( ++p == pe )
+ goto _test_eof122;
+case 122:
+ switch( (*p) ) {
+ case 86: goto st123;
+ case 118: goto st123;
+ }
+ goto tr36;
+st123:
+ if ( ++p == pe )
+ goto _test_eof123;
+case 123:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr540;
+ case 32: goto tr540;
+ case 40: goto tr541;
+ case 41: goto tr542;
+ case 2058: goto tr543;
+ case 2107: goto tr544;
+ case 2314: goto tr545;
+ case 2363: goto tr545;
+ case 2570: goto tr546;
+ case 2619: goto tr547;
+ }
+ goto tr57;
+st124:
+ if ( ++p == pe )
+ goto _test_eof124;
+case 124:
+ switch( (*p) ) {
+ case 72: goto st125;
+ case 104: goto st125;
+ }
+ goto tr36;
+st125:
+ if ( ++p == pe )
+ goto _test_eof125;
+case 125:
+ switch( (*p) ) {
+ case 70: goto st126;
+ case 102: goto st126;
+ }
+ goto tr36;
+st126:
+ if ( ++p == pe )
+ goto _test_eof126;
+case 126:
+ switch( (*p) ) {
+ case 80: goto st127;
+ case 112: goto st127;
+ }
+ goto tr36;
+st127:
+ if ( ++p == pe )
+ goto _test_eof127;
+case 127:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr551;
+ case 32: goto tr551;
+ case 40: goto tr552;
+ case 41: goto tr553;
+ case 2058: goto tr554;
+ case 2107: goto tr555;
+ case 2314: goto tr556;
+ case 2363: goto tr556;
+ case 2570: goto tr557;
+ case 2619: goto tr558;
+ }
+ goto tr57;
+tr18:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st128;
+tr53:
+ {
+ s->r_class = s->default_class;
+ }
+ goto st128;
+tr635:
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st128;
+st128:
+ if ( ++p == pe )
+ goto _test_eof128;
+case 128:
+ switch( (*p) ) {
+ case 76: goto st129;
+ case 88: goto st132;
+ case 89: goto st134;
+ case 108: goto st129;
+ case 120: goto st132;
+ case 121: goto st134;
+ }
+ goto tr36;
+st129:
+ if ( ++p == pe )
+ goto _test_eof129;
+case 129:
+ switch( (*p) ) {
+ case 83: goto st130;
+ case 115: goto st130;
+ }
+ goto tr36;
+st130:
+ if ( ++p == pe )
+ goto _test_eof130;
+case 130:
+ switch( (*p) ) {
+ case 65: goto st131;
+ case 97: goto st131;
+ }
+ goto tr36;
+st131:
+ if ( ++p == pe )
+ goto _test_eof131;
+case 131:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr564;
+ case 32: goto tr564;
+ case 40: goto tr565;
+ case 41: goto tr566;
+ case 2058: goto tr567;
+ case 2107: goto tr568;
+ case 2314: goto tr569;
+ case 2363: goto tr569;
+ case 2570: goto tr570;
+ case 2619: goto tr571;
+ }
+ goto tr57;
+st132:
+ if ( ++p == pe )
+ goto _test_eof132;
+case 132:
+ switch( (*p) ) {
+ case 84: goto st133;
+ case 116: goto st133;
+ }
+ goto tr36;
+st133:
+ if ( ++p == pe )
+ goto _test_eof133;
+case 133:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr573;
+ case 32: goto tr573;
+ case 40: goto tr574;
+ case 41: goto tr575;
+ case 2058: goto tr576;
+ case 2107: goto tr577;
+ case 2314: goto tr578;
+ case 2363: goto tr578;
+ case 2570: goto tr579;
+ case 2619: goto tr580;
+ }
+ goto tr57;
+st134:
+ if ( ++p == pe )
+ goto _test_eof134;
+case 134:
+ switch( (*p) ) {
+ case 80: goto st135;
+ case 112: goto st135;
+ }
+ goto tr36;
+st135:
+ if ( ++p == pe )
+ goto _test_eof135;
+case 135:
+ switch( (*p) ) {
+ case 69: goto st136;
+ case 101: goto st136;
+ }
+ goto tr36;
+st136:
+ if ( ++p == pe )
+ goto _test_eof136;
+case 136:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr584;
+ goto tr583;
+tr584:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st137;
+tr589:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st137;
+st137:
+ if ( ++p == pe )
+ goto _test_eof137;
+case 137:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr586;
+ case 32: goto tr586;
+ case 40: goto tr587;
+ case 41: goto tr588;
+ case 2058: goto tr590;
+ case 2107: goto tr591;
+ case 2314: goto tr592;
+ case 2363: goto tr592;
+ case 2570: goto tr593;
+ case 2619: goto tr594;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr589;
+ goto tr585;
+tr19:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st138;
+tr54:
+ {
+ s->r_class = s->default_class;
+ }
+ goto st138;
+tr636:
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st138;
+st138:
+ if ( ++p == pe )
+ goto _test_eof138;
+case 138:
+ switch( (*p) ) {
+ case 82: goto st139;
+ case 114: goto st139;
+ }
+ goto tr36;
+st139:
+ if ( ++p == pe )
+ goto _test_eof139;
+case 139:
+ switch( (*p) ) {
+ case 73: goto st140;
+ case 105: goto st140;
+ }
+ goto tr36;
+st140:
+ if ( ++p == pe )
+ goto _test_eof140;
+case 140:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr597;
+ case 32: goto tr597;
+ case 40: goto tr598;
+ case 41: goto tr599;
+ case 2058: goto tr600;
+ case 2107: goto tr601;
+ case 2314: goto tr602;
+ case 2363: goto tr602;
+ case 2570: goto tr603;
+ case 2619: goto tr604;
+ }
+ goto tr57;
+tr320:
+ {
+ s->buffer_length = 0;
+ }
+ goto st141;
+tr649:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st141;
+tr605:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st141;
+tr300:
+ {
+ s->r_class = KNOT_CLASS_IN;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st141;
+tr662:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st141;
+st141:
+ if ( ++p == pe )
+ goto _test_eof141;
+case 141:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr606;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr605;
+ goto tr36;
+tr914:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1129; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1129; goto _out;}
+ }
+ }
+ goto st1129;
+tr143:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1129; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1129; goto _out;}
+ }
+ }
+ goto st1129;
+tr149:
+ {
+ s->line_counter++;
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1129; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1129; goto _out;}
+ }
+ }
+ goto st1129;
+st1129:
+ if ( ++p == pe )
+ goto _test_eof1129;
+case 1129:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3635;
+ case 32: goto tr3635;
+ case 36: goto st152;
+ case 40: goto tr3636;
+ case 41: goto tr3637;
+ case 42: goto tr3617;
+ case 65: goto tr3638;
+ case 67: goto tr3639;
+ case 68: goto tr3640;
+ case 69: goto tr3641;
+ case 72: goto tr3642;
+ case 73: goto tr3643;
+ case 75: goto tr3644;
+ case 76: goto tr3645;
+ case 77: goto tr3646;
+ case 78: goto tr3647;
+ case 80: goto tr3648;
+ case 82: goto tr3649;
+ case 83: goto tr3650;
+ case 84: goto tr3651;
+ case 85: goto tr3652;
+ case 92: goto tr3617;
+ case 95: goto tr3617;
+ case 97: goto tr3638;
+ case 99: goto tr3639;
+ case 100: goto tr3640;
+ case 101: goto tr3641;
+ case 104: goto tr3642;
+ case 105: goto tr3643;
+ case 107: goto tr3644;
+ case 108: goto tr3645;
+ case 109: goto tr3646;
+ case 110: goto tr3647;
+ case 112: goto tr3648;
+ case 114: goto tr3649;
+ case 115: goto tr3650;
+ case 116: goto tr3651;
+ case 117: goto tr3652;
+ case 778: goto tr3618;
+ case 827: goto tr3619;
+ case 1034: goto tr3653;
+ case 1083: goto tr3654;
+ }
+ if ( _widec < 64 ) {
+ if ( 45 <= _widec && _widec <= 57 )
+ goto tr3617;
+ } else if ( _widec > 90 ) {
+ if ( 98 <= _widec && _widec <= 122 )
+ goto tr3617;
+ } else
+ goto tr3617;
+ goto tr3634;
+tr608:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st142;
+tr609:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st142;
+tr3635:
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st142;
+tr3636:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st142;
+tr3637:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st142;
+st142:
+ if ( ++p == pe )
+ goto _test_eof142;
+case 142:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st142;
+ case 32: goto st142;
+ case 40: goto tr608;
+ case 41: goto tr609;
+ case 65: goto tr5;
+ case 67: goto tr6;
+ case 68: goto tr7;
+ case 69: goto tr8;
+ case 72: goto tr9;
+ case 73: goto tr10;
+ case 75: goto tr11;
+ case 76: goto tr12;
+ case 77: goto tr13;
+ case 78: goto tr14;
+ case 80: goto tr15;
+ case 82: goto tr16;
+ case 83: goto tr17;
+ case 84: goto tr18;
+ case 85: goto tr19;
+ case 97: goto tr5;
+ case 99: goto tr6;
+ case 100: goto tr7;
+ case 101: goto tr8;
+ case 104: goto tr9;
+ case 105: goto tr10;
+ case 107: goto tr11;
+ case 108: goto tr12;
+ case 109: goto tr13;
+ case 110: goto tr14;
+ case 112: goto tr15;
+ case 114: goto tr16;
+ case 115: goto tr17;
+ case 116: goto tr18;
+ case 117: goto tr19;
+ case 778: goto tr20;
+ case 827: goto tr21;
+ case 1034: goto tr610;
+ case 1083: goto tr611;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr4;
+ goto tr0;
+tr10:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ goto st143;
+st143:
+ if ( ++p == pe )
+ goto _test_eof143;
+case 143:
+ switch( (*p) ) {
+ case 78: goto st144;
+ case 80: goto st66;
+ case 110: goto st144;
+ case 112: goto st66;
+ }
+ goto tr36;
+st144:
+ if ( ++p == pe )
+ goto _test_eof144;
+case 144:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr613;
+ case 32: goto tr613;
+ case 40: goto tr614;
+ case 41: goto tr615;
+ case 1034: goto tr616;
+ case 1083: goto tr617;
+ }
+ goto tr36;
+tr619:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st145;
+tr620:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st145;
+tr637:
+ {
+ s->line_counter++;
+ }
+ goto st145;
+tr664:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st145;
+tr613:
+ {
+ s->r_class = KNOT_CLASS_IN;
+ }
+ goto st145;
+tr614:
+ {
+ s->r_class = KNOT_CLASS_IN;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st145;
+tr615:
+ {
+ s->r_class = KNOT_CLASS_IN;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st145;
+tr616:
+ {
+ s->r_class = KNOT_CLASS_IN;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st145;
+st145:
+ if ( ++p == pe )
+ goto _test_eof145;
+case 145:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st145;
+ case 32: goto st145;
+ case 40: goto tr619;
+ case 41: goto tr620;
+ case 65: goto tr622;
+ case 67: goto tr623;
+ case 68: goto tr624;
+ case 69: goto tr625;
+ case 72: goto tr626;
+ case 73: goto tr627;
+ case 75: goto tr628;
+ case 76: goto tr629;
+ case 77: goto tr630;
+ case 78: goto tr631;
+ case 80: goto tr632;
+ case 82: goto tr633;
+ case 83: goto tr634;
+ case 84: goto tr635;
+ case 85: goto tr636;
+ case 97: goto tr622;
+ case 99: goto tr623;
+ case 100: goto tr624;
+ case 101: goto tr625;
+ case 104: goto tr626;
+ case 105: goto tr627;
+ case 107: goto tr628;
+ case 108: goto tr629;
+ case 109: goto tr630;
+ case 110: goto tr631;
+ case 112: goto tr632;
+ case 114: goto tr633;
+ case 115: goto tr634;
+ case 116: goto tr635;
+ case 117: goto tr636;
+ case 1034: goto tr637;
+ case 1083: goto tr638;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr621;
+ goto tr583;
+tr621:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st146;
+tr642:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st146;
+st146:
+ if ( ++p == pe )
+ goto _test_eof146;
+case 146:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr639;
+ case 32: goto tr639;
+ case 40: goto tr640;
+ case 41: goto tr641;
+ case 68: goto tr643;
+ case 72: goto tr644;
+ case 77: goto tr645;
+ case 83: goto st147;
+ case 87: goto tr647;
+ case 100: goto tr643;
+ case 104: goto tr644;
+ case 109: goto tr645;
+ case 115: goto st147;
+ case 119: goto tr647;
+ case 1034: goto tr648;
+ case 1083: goto tr649;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr642;
+ goto tr24;
+tr643:
+ { if (s->number64 <= (UINT32_MAX / 86400)) {
+ s->number64 *= 86400;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st147;
+tr644:
+ { if (s->number64 <= (UINT32_MAX / 3600)) {
+ s->number64 *= 3600;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st147;
+tr645:
+ { if (s->number64 <= (UINT32_MAX / 60)) {
+ s->number64 *= 60;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st147;
+tr647:
+ { if (s->number64 <= (UINT32_MAX / 604800)) {
+ s->number64 *= 604800;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st147;
+st147:
+ if ( ++p == pe )
+ goto _test_eof147;
+case 147:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr639;
+ case 32: goto tr639;
+ case 40: goto tr640;
+ case 41: goto tr641;
+ case 1034: goto tr648;
+ case 1083: goto tr649;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr650;
+ goto tr24;
+tr651:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st148;
+tr650:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st148;
+tr660:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st148;
+st148:
+ if ( ++p == pe )
+ goto _test_eof148;
+case 148:
+ switch( (*p) ) {
+ case 68: goto tr652;
+ case 72: goto tr653;
+ case 77: goto tr654;
+ case 83: goto st149;
+ case 87: goto tr656;
+ case 100: goto tr652;
+ case 104: goto tr653;
+ case 109: goto tr654;
+ case 115: goto st149;
+ case 119: goto tr656;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr651;
+ goto tr24;
+tr652:
+ { if (s->number64 <= (UINT32_MAX / 86400)) {
+ s->number64 *= 86400;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st149;
+tr653:
+ { if (s->number64 <= (UINT32_MAX / 3600)) {
+ s->number64 *= 3600;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st149;
+tr654:
+ { if (s->number64 <= (UINT32_MAX / 60)) {
+ s->number64 *= 60;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st149;
+tr656:
+ { if (s->number64 <= (UINT32_MAX / 604800)) {
+ s->number64 *= 604800;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st149;
+st149:
+ if ( ++p == pe )
+ goto _test_eof149;
+case 149:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr657;
+ case 32: goto tr657;
+ case 40: goto tr658;
+ case 41: goto tr659;
+ case 1034: goto tr661;
+ case 1083: goto tr662;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr660;
+ goto tr24;
+tr638:
+ {
+ s->buffer_length = 0;
+ }
+ goto st150;
+tr663:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st150;
+tr617:
+ {
+ s->r_class = KNOT_CLASS_IN;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st150;
+st150:
+ if ( ++p == pe )
+ goto _test_eof150;
+case 150:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr664;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr663;
+ goto tr36;
+tr21:
+ {
+ s->buffer_length = 0;
+ }
+ goto st151;
+tr3619:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st151;
+tr665:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st151;
+tr3679:
+ {
+ NOERR;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st151;
+st151:
+ if ( ++p == pe )
+ goto _test_eof151;
+case 151:
+ if ( (*p) == 10 )
+ goto tr666;
+ goto tr665;
+tr610:
+ {
+ s->line_counter++;
+ }
+ goto st1130;
+tr912:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1130;
+tr801:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1130; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1130; goto _out;}
+ }
+ }
+ goto st1130;
+tr798:
+ {
+ s->line_counter++;
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1130; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1130; goto _out;}
+ }
+ }
+ goto st1130;
+tr793:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1130; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1130; goto _out;}
+ }
+ }
+ goto st1130;
+tr3653:
+ {
+ s->line_counter++;
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st1130;
+st1130:
+ if ( ++p == pe )
+ goto _test_eof1130;
+case 1130:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3635;
+ case 32: goto tr3635;
+ case 36: goto st152;
+ case 40: goto tr3636;
+ case 41: goto tr3637;
+ case 42: goto tr3617;
+ case 65: goto tr3657;
+ case 67: goto tr3658;
+ case 68: goto tr3659;
+ case 69: goto tr3660;
+ case 72: goto tr3661;
+ case 73: goto tr3662;
+ case 75: goto tr3663;
+ case 76: goto tr3664;
+ case 77: goto tr3665;
+ case 78: goto tr3666;
+ case 80: goto tr3667;
+ case 82: goto tr3668;
+ case 83: goto tr3669;
+ case 84: goto tr3670;
+ case 85: goto tr3671;
+ case 92: goto tr3617;
+ case 95: goto tr3617;
+ case 97: goto tr3657;
+ case 99: goto tr3658;
+ case 100: goto tr3659;
+ case 101: goto tr3660;
+ case 104: goto tr3661;
+ case 105: goto tr3662;
+ case 107: goto tr3663;
+ case 108: goto tr3664;
+ case 109: goto tr3665;
+ case 110: goto tr3666;
+ case 112: goto tr3667;
+ case 114: goto tr3668;
+ case 115: goto tr3669;
+ case 116: goto tr3670;
+ case 117: goto tr3671;
+ case 778: goto tr3618;
+ case 827: goto tr3619;
+ case 1034: goto tr3653;
+ case 1083: goto tr3654;
+ }
+ if ( _widec < 48 ) {
+ if ( 45 <= _widec && _widec <= 47 )
+ goto tr3617;
+ } else if ( _widec > 57 ) {
+ if ( _widec > 90 ) {
+ if ( 98 <= _widec && _widec <= 122 )
+ goto tr3617;
+ } else if ( _widec >= 64 )
+ goto tr3617;
+ } else
+ goto tr3656;
+ goto tr3655;
+tr3674:
+ {
+ NOERR;
+ }
+ goto st152;
+st152:
+ if ( ++p == pe )
+ goto _test_eof152;
+case 152:
+ switch( (*p) ) {
+ case 73: goto tr668;
+ case 79: goto tr669;
+ case 84: goto tr670;
+ case 105: goto tr668;
+ case 111: goto tr669;
+ case 116: goto tr670;
+ }
+ goto tr667;
+tr668:
+ {
+ ERR(ZS_OK);
+ }
+ goto st153;
+st153:
+ if ( ++p == pe )
+ goto _test_eof153;
+case 153:
+ switch( (*p) ) {
+ case 78: goto st154;
+ case 110: goto st154;
+ }
+ goto tr667;
+st154:
+ if ( ++p == pe )
+ goto _test_eof154;
+case 154:
+ switch( (*p) ) {
+ case 67: goto st155;
+ case 99: goto st155;
+ }
+ goto tr667;
+st155:
+ if ( ++p == pe )
+ goto _test_eof155;
+case 155:
+ switch( (*p) ) {
+ case 76: goto st156;
+ case 108: goto st156;
+ }
+ goto tr667;
+st156:
+ if ( ++p == pe )
+ goto _test_eof156;
+case 156:
+ switch( (*p) ) {
+ case 85: goto st157;
+ case 117: goto st157;
+ }
+ goto tr667;
+st157:
+ if ( ++p == pe )
+ goto _test_eof157;
+case 157:
+ switch( (*p) ) {
+ case 68: goto st158;
+ case 100: goto st158;
+ }
+ goto tr667;
+st158:
+ if ( ++p == pe )
+ goto _test_eof158;
+case 158:
+ switch( (*p) ) {
+ case 69: goto st159;
+ case 101: goto st159;
+ }
+ goto tr667;
+st159:
+ if ( ++p == pe )
+ goto _test_eof159;
+case 159:
+ switch( (*p) ) {
+ case 32: goto tr677;
+ case 59: goto tr677;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr677;
+ } else if ( (*p) >= 9 )
+ goto tr677;
+ goto tr667;
+tr677:
+ { p--; {stack[top++] = 1131;goto st312;} }
+ goto st1131;
+tr779:
+ { p--; {stack[top++] = 1131;goto st300;} }
+ goto st1131;
+tr782:
+ { p--; {stack[top++] = 1131;goto st291;} }
+ goto st1131;
+st1131:
+ if ( ++p == pe )
+ goto _test_eof1131;
+case 1131:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3673;
+ case 32: goto tr3673;
+ case 36: goto tr3674;
+ case 40: goto tr3675;
+ case 41: goto tr3676;
+ case 42: goto tr3677;
+ case 92: goto tr3677;
+ case 95: goto tr3677;
+ case 778: goto tr3678;
+ case 827: goto tr3679;
+ case 1034: goto tr3680;
+ case 1083: goto tr3681;
+ }
+ if ( _widec < 64 ) {
+ if ( 45 <= _widec && _widec <= 57 )
+ goto tr3677;
+ } else if ( _widec > 90 ) {
+ if ( 97 <= _widec && _widec <= 122 )
+ goto tr3677;
+ } else
+ goto tr3677;
+ goto tr3672;
+tr3617:
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 160;goto st270;} }
+ goto st160;
+tr3677:
+ {
+ NOERR;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 160;goto st270;} }
+ goto st160;
+st160:
+ if ( ++p == pe )
+ goto _test_eof160;
+case 160:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr679;
+ case 32: goto tr679;
+ case 40: goto tr680;
+ case 41: goto tr681;
+ case 1034: goto tr682;
+ case 1083: goto tr683;
+ }
+ goto tr678;
+tr685:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st161;
+tr686:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st161;
+tr687:
+ {
+ s->line_counter++;
+ }
+ goto st161;
+tr691:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st161;
+tr679:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ goto st161;
+tr680:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st161;
+tr681:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st161;
+tr682:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st161;
+st161:
+ if ( ++p == pe )
+ goto _test_eof161;
+case 161:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st161;
+ case 32: goto st161;
+ case 40: goto tr685;
+ case 41: goto tr686;
+ case 65: goto tr5;
+ case 67: goto tr6;
+ case 68: goto tr7;
+ case 69: goto tr8;
+ case 72: goto tr9;
+ case 73: goto tr10;
+ case 75: goto tr11;
+ case 76: goto tr12;
+ case 77: goto tr13;
+ case 78: goto tr14;
+ case 80: goto tr15;
+ case 82: goto tr16;
+ case 83: goto tr17;
+ case 84: goto tr18;
+ case 85: goto tr19;
+ case 97: goto tr5;
+ case 99: goto tr6;
+ case 100: goto tr7;
+ case 101: goto tr8;
+ case 104: goto tr9;
+ case 105: goto tr10;
+ case 107: goto tr11;
+ case 108: goto tr12;
+ case 109: goto tr13;
+ case 110: goto tr14;
+ case 112: goto tr15;
+ case 114: goto tr16;
+ case 115: goto tr17;
+ case 116: goto tr18;
+ case 117: goto tr19;
+ case 1034: goto tr687;
+ case 1083: goto tr688;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr4;
+ goto tr583;
+tr688:
+ {
+ s->buffer_length = 0;
+ }
+ goto st162;
+tr689:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st162;
+tr683:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st162;
+st162:
+ if ( ++p == pe )
+ goto _test_eof162;
+case 162:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr691;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr689;
+ goto st0;
+tr22:
+ {
+ s->line_counter++;
+ }
+ goto st1132;
+tr910:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1132;
+tr756:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1132; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1132; goto _out;}
+ }
+ }
+ goto st1132;
+tr753:
+ {
+ s->line_counter++;
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1132; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1132; goto _out;}
+ }
+ }
+ goto st1132;
+tr787:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1132; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1132; goto _out;}
+ }
+ }
+ goto st1132;
+tr824:
+ {
+ s->line_counter++;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1132; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1132; goto _out;}
+ }
+ }
+ goto st1132;
+tr827:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1132; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1132; goto _out;}
+ }
+ }
+ goto st1132;
+tr3620:
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st1132;
+tr3684:
+ {
+ s->line_counter++;
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st1132;
+tr3680:
+ {
+ NOERR;
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st1132;
+tr3689:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1132; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1132; goto _out;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ goto st1132;
+tr3713:
+ {
+ s->line_counter++;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1132; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1132; goto _out;}
+ }
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ goto st1132;
+st1132:
+ if ( ++p == pe )
+ goto _test_eof1132;
+case 1132:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3613;
+ case 32: goto tr3613;
+ case 36: goto st152;
+ case 40: goto tr3682;
+ case 41: goto tr3683;
+ case 42: goto tr3617;
+ case 65: goto tr3657;
+ case 67: goto tr3658;
+ case 68: goto tr3659;
+ case 69: goto tr3660;
+ case 72: goto tr3661;
+ case 73: goto tr3662;
+ case 75: goto tr3663;
+ case 76: goto tr3664;
+ case 77: goto tr3665;
+ case 78: goto tr3666;
+ case 80: goto tr3667;
+ case 82: goto tr3668;
+ case 83: goto tr3669;
+ case 84: goto tr3670;
+ case 85: goto tr3671;
+ case 92: goto tr3617;
+ case 95: goto tr3617;
+ case 97: goto tr3657;
+ case 99: goto tr3658;
+ case 100: goto tr3659;
+ case 101: goto tr3660;
+ case 104: goto tr3661;
+ case 105: goto tr3662;
+ case 107: goto tr3663;
+ case 108: goto tr3664;
+ case 109: goto tr3665;
+ case 110: goto tr3666;
+ case 112: goto tr3667;
+ case 114: goto tr3668;
+ case 115: goto tr3669;
+ case 116: goto tr3670;
+ case 117: goto tr3671;
+ case 778: goto tr3618;
+ case 827: goto tr3619;
+ case 1034: goto tr3684;
+ case 1083: goto tr3685;
+ }
+ if ( _widec < 48 ) {
+ if ( 45 <= _widec && _widec <= 47 )
+ goto tr3617;
+ } else if ( _widec > 57 ) {
+ if ( _widec > 90 ) {
+ if ( 98 <= _widec && _widec <= 122 )
+ goto tr3617;
+ } else if ( _widec >= 64 )
+ goto tr3617;
+ } else
+ goto tr3656;
+ goto tr3655;
+tr3656:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 163;goto st270;} }
+ goto st163;
+st163:
+ if ( ++p == pe )
+ goto _test_eof163;
+case 163:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr693;
+ case 32: goto tr693;
+ case 40: goto tr694;
+ case 41: goto tr695;
+ case 68: goto tr29;
+ case 72: goto tr30;
+ case 77: goto tr31;
+ case 83: goto st166;
+ case 87: goto tr33;
+ case 100: goto tr29;
+ case 104: goto tr30;
+ case 109: goto tr31;
+ case 115: goto st166;
+ case 119: goto tr33;
+ case 1034: goto tr696;
+ case 1083: goto tr697;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr28;
+ goto tr692;
+tr699:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st164;
+tr700:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st164;
+tr701:
+ {
+ s->line_counter++;
+ }
+ goto st164;
+tr704:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st164;
+tr693:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st164;
+tr694:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st164;
+tr695:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st164;
+tr696:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st164;
+st164:
+ if ( ++p == pe )
+ goto _test_eof164;
+case 164:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st164;
+ case 32: goto st164;
+ case 40: goto tr699;
+ case 41: goto tr700;
+ case 65: goto tr5;
+ case 67: goto tr6;
+ case 68: goto tr7;
+ case 69: goto tr8;
+ case 72: goto tr9;
+ case 73: goto tr10;
+ case 75: goto tr11;
+ case 76: goto tr12;
+ case 77: goto tr13;
+ case 78: goto tr14;
+ case 80: goto tr15;
+ case 82: goto tr16;
+ case 83: goto tr17;
+ case 84: goto tr18;
+ case 85: goto tr19;
+ case 97: goto tr5;
+ case 99: goto tr6;
+ case 100: goto tr7;
+ case 101: goto tr8;
+ case 104: goto tr9;
+ case 105: goto tr10;
+ case 107: goto tr11;
+ case 108: goto tr12;
+ case 109: goto tr13;
+ case 110: goto tr14;
+ case 112: goto tr15;
+ case 114: goto tr16;
+ case 115: goto tr17;
+ case 116: goto tr18;
+ case 117: goto tr19;
+ case 1034: goto tr701;
+ case 1083: goto tr702;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr4;
+ goto tr583;
+tr702:
+ {
+ s->buffer_length = 0;
+ }
+ goto st165;
+tr703:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st165;
+tr697:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st165;
+st165:
+ if ( ++p == pe )
+ goto _test_eof165;
+case 165:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr704;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr703;
+ goto tr36;
+tr29:
+ { if (s->number64 <= (UINT32_MAX / 86400)) {
+ s->number64 *= 86400;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st166;
+tr30:
+ { if (s->number64 <= (UINT32_MAX / 3600)) {
+ s->number64 *= 3600;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st166;
+tr31:
+ { if (s->number64 <= (UINT32_MAX / 60)) {
+ s->number64 *= 60;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st166;
+tr33:
+ { if (s->number64 <= (UINT32_MAX / 604800)) {
+ s->number64 *= 604800;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st166;
+st166:
+ if ( ++p == pe )
+ goto _test_eof166;
+case 166:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr25;
+ case 32: goto tr25;
+ case 40: goto tr26;
+ case 41: goto tr27;
+ case 1034: goto tr34;
+ case 1083: goto tr35;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr705;
+ goto tr24;
+tr706:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st167;
+tr705:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st167;
+tr715:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st167;
+st167:
+ if ( ++p == pe )
+ goto _test_eof167;
+case 167:
+ switch( (*p) ) {
+ case 68: goto tr707;
+ case 72: goto tr708;
+ case 77: goto tr709;
+ case 83: goto st168;
+ case 87: goto tr711;
+ case 100: goto tr707;
+ case 104: goto tr708;
+ case 109: goto tr709;
+ case 115: goto st168;
+ case 119: goto tr711;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr706;
+ goto tr24;
+tr707:
+ { if (s->number64 <= (UINT32_MAX / 86400)) {
+ s->number64 *= 86400;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st168;
+tr708:
+ { if (s->number64 <= (UINT32_MAX / 3600)) {
+ s->number64 *= 3600;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st168;
+tr709:
+ { if (s->number64 <= (UINT32_MAX / 60)) {
+ s->number64 *= 60;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st168;
+tr711:
+ { if (s->number64 <= (UINT32_MAX / 604800)) {
+ s->number64 *= 604800;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st168;
+st168:
+ if ( ++p == pe )
+ goto _test_eof168;
+case 168:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr712;
+ case 32: goto tr712;
+ case 40: goto tr713;
+ case 41: goto tr714;
+ case 1034: goto tr716;
+ case 1083: goto tr717;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr715;
+ goto tr24;
+tr56:
+ {
+ s->buffer_length = 0;
+ }
+ goto st169;
+tr35:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st169;
+tr718:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st169;
+tr717:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st169;
+st169:
+ if ( ++p == pe )
+ goto _test_eof169;
+case 169:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr719;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr718;
+ goto tr36;
+tr3638:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 170;goto st270;} }
+ goto st170;
+tr3657:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 170;goto st270;} }
+ goto st170;
+st170:
+ if ( ++p == pe )
+ goto _test_eof170;
+case 170:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr721;
+ case 32: goto tr721;
+ case 40: goto tr722;
+ case 41: goto tr723;
+ case 65: goto st230;
+ case 70: goto st233;
+ case 80: goto st237;
+ case 97: goto st230;
+ case 102: goto st233;
+ case 112: goto st237;
+ case 2058: goto tr724;
+ case 2107: goto tr725;
+ case 2314: goto tr66;
+ case 2363: goto tr66;
+ case 2570: goto tr726;
+ case 2619: goto tr727;
+ }
+ goto tr720;
+tr729:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st171;
+tr730:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st171;
+tr731:
+ {
+ s->line_counter++;
+ }
+ goto st171;
+tr896:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st171;
+tr721:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st171;
+tr722:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st171;
+tr723:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st171;
+tr724:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ s->line_counter++;
+ }
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st171;
+st171:
+ if ( ++p == pe )
+ goto _test_eof171;
+case 171:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st171;
+ case 32: goto st171;
+ case 40: goto tr729;
+ case 41: goto tr730;
+ case 58: goto tr69;
+ case 65: goto tr118;
+ case 67: goto tr119;
+ case 68: goto tr120;
+ case 69: goto tr121;
+ case 72: goto tr122;
+ case 73: goto tr123;
+ case 75: goto tr124;
+ case 76: goto tr125;
+ case 77: goto tr126;
+ case 78: goto tr127;
+ case 80: goto tr128;
+ case 82: goto tr129;
+ case 83: goto tr130;
+ case 84: goto tr131;
+ case 85: goto tr132;
+ case 92: goto tr74;
+ case 97: goto tr118;
+ case 99: goto tr119;
+ case 100: goto tr120;
+ case 101: goto tr121;
+ case 104: goto tr122;
+ case 105: goto tr123;
+ case 107: goto tr124;
+ case 108: goto tr125;
+ case 109: goto tr126;
+ case 110: goto tr127;
+ case 112: goto tr128;
+ case 114: goto tr129;
+ case 115: goto tr130;
+ case 116: goto tr131;
+ case 117: goto tr132;
+ case 2058: goto tr731;
+ case 2107: goto tr732;
+ case 2314: goto tr69;
+ case 2363: goto tr69;
+ case 2570: goto tr733;
+ case 2619: goto tr734;
+ }
+ if ( _widec < 11 ) {
+ if ( _widec <= 8 )
+ goto tr69;
+ } else if ( _widec > 47 ) {
+ if ( _widec > 57 ) {
+ if ( 60 <= _widec )
+ goto tr69;
+ } else if ( _widec >= 48 )
+ goto tr117;
+ } else
+ goto tr69;
+ goto tr585;
+tr118:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 172;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 172;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 172;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 172;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 172;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 172;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 172;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 172;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 172;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 172;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 172;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 172;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 172;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 172;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 172;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 172;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 172;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 172;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 172;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 172;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 172;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 172;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 172;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 172;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 172;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 172;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 172;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 172;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 172;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st172;
+st172:
+ if ( ++p == pe )
+ goto _test_eof172;
+case 172:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr736;
+ case 32: goto tr736;
+ case 40: goto tr737;
+ case 41: goto tr738;
+ case 65: goto st230;
+ case 70: goto st233;
+ case 80: goto st237;
+ case 97: goto st230;
+ case 102: goto st233;
+ case 112: goto st237;
+ case 1802: goto tr83;
+ case 1851: goto tr84;
+ case 2058: goto tr739;
+ case 2107: goto tr740;
+ case 2314: goto tr741;
+ case 2363: goto tr742;
+ case 2570: goto tr743;
+ case 2619: goto tr744;
+ }
+ goto tr735;
+tr746:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st173;
+tr747:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st173;
+tr736:
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st173;
+tr737:
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st173;
+tr738:
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st173;
+st173:
+ if ( ++p == pe )
+ goto _test_eof173;
+case 173:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st173;
+ case 32: goto st173;
+ case 40: goto tr746;
+ case 41: goto tr747;
+ case 92: goto tr74;
+ case 1802: goto tr89;
+ case 1851: goto tr90;
+ case 2058: goto tr748;
+ case 2107: goto tr107;
+ case 2314: goto tr108;
+ case 2363: goto tr109;
+ case 2570: goto tr749;
+ case 2619: goto tr110;
+ }
+ if ( _widec < 11 ) {
+ if ( _widec <= 8 )
+ goto tr69;
+ } else if ( _widec > 58 ) {
+ if ( 60 <= _widec )
+ goto tr69;
+ } else
+ goto tr69;
+ goto tr79;
+tr101:
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 1133;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 1133;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 1133;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 1133;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 1133;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 1133;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 1133;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 1133;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 1133;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 1133;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 1133;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 1133;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 1133;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 1133;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 1133;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 1133;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 1133;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 1133;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 1133;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 1133;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 1133;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 1133;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 1133;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 1133;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 1133;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 1133;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 1133;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 1133;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 1133;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1133; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1133; goto _out;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1133;
+tr108:
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 1133;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 1133;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 1133;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 1133;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 1133;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 1133;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 1133;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 1133;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 1133;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 1133;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 1133;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 1133;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 1133;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 1133;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 1133;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 1133;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 1133;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 1133;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 1133;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 1133;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 1133;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 1133;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 1133;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 1133;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 1133;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 1133;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 1133;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 1133;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 1133;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1133; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1133; goto _out;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1133;
+tr135:
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 1133;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 1133;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 1133;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 1133;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 1133;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 1133;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 1133;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 1133;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 1133;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 1133;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 1133;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 1133;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 1133;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 1133;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 1133;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 1133;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 1133;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 1133;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 1133;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 1133;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 1133;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 1133;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 1133;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 1133;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 1133;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 1133;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 1133;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 1133;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 1133;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1133;
+tr741:
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 1133;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 1133;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 1133;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 1133;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 1133;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 1133;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 1133;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 1133;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 1133;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 1133;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 1133;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 1133;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 1133;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 1133;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 1133;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 1133;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 1133;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 1133;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 1133;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 1133;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 1133;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 1133;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 1133;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 1133;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 1133;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 1133;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 1133;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 1133;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 1133;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1133; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1133; goto _out;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1133;
+tr3630:
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 1133;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 1133;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 1133;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 1133;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 1133;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 1133;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 1133;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 1133;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 1133;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 1133;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 1133;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 1133;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 1133;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 1133;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 1133;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 1133;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 1133;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 1133;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 1133;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 1133;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 1133;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 1133;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 1133;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 1133;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 1133;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 1133;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 1133;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 1133;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 1133;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1133;
+st1133:
+ if ( ++p == pe )
+ goto _test_eof1133;
+case 1133:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3686;
+ case 32: goto tr3686;
+ case 36: goto st152;
+ case 40: goto tr3687;
+ case 41: goto tr3688;
+ case 42: goto tr3617;
+ case 92: goto tr3617;
+ case 95: goto tr3617;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr3689;
+ case 1083: goto tr3690;
+ }
+ if ( _widec < 64 ) {
+ if ( 45 <= _widec && _widec <= 57 )
+ goto tr3617;
+ } else if ( _widec > 90 ) {
+ if ( 97 <= _widec && _widec <= 122 )
+ goto tr3617;
+ } else
+ goto tr3617;
+ goto tr783;
+tr751:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st174;
+tr752:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st174;
+tr821:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st174;
+tr822:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st174;
+tr823:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st174;
+tr784:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st174;
+tr785:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st174;
+tr786:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st174;
+tr3686:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ goto st174;
+tr3687:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ goto st174;
+tr3688:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ goto st174;
+st174:
+ if ( ++p == pe )
+ goto _test_eof174;
+case 174:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st174;
+ case 32: goto st174;
+ case 40: goto tr751;
+ case 41: goto tr752;
+ case 65: goto tr5;
+ case 67: goto tr6;
+ case 68: goto tr7;
+ case 69: goto tr8;
+ case 72: goto tr9;
+ case 73: goto tr10;
+ case 75: goto tr11;
+ case 76: goto tr12;
+ case 77: goto tr13;
+ case 78: goto tr14;
+ case 80: goto tr15;
+ case 82: goto tr16;
+ case 83: goto tr17;
+ case 84: goto tr18;
+ case 85: goto tr19;
+ case 97: goto tr5;
+ case 99: goto tr6;
+ case 100: goto tr7;
+ case 101: goto tr8;
+ case 104: goto tr9;
+ case 105: goto tr10;
+ case 107: goto tr11;
+ case 108: goto tr12;
+ case 109: goto tr13;
+ case 110: goto tr14;
+ case 112: goto tr15;
+ case 114: goto tr16;
+ case 115: goto tr17;
+ case 116: goto tr18;
+ case 117: goto tr19;
+ case 778: goto tr89;
+ case 827: goto tr90;
+ case 1034: goto tr753;
+ case 1083: goto tr754;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr4;
+ goto tr0;
+tr754:
+ {
+ s->buffer_length = 0;
+ }
+ goto st175;
+tr755:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st175;
+tr825:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st175;
+tr830:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st175;
+tr834:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st175;
+tr788:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st175;
+tr3690:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ goto st175;
+st175:
+ if ( ++p == pe )
+ goto _test_eof175;
+case 175:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 778: goto tr92;
+ case 1034: goto tr756;
+ }
+ if ( _widec > 895 ) {
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr755;
+ } else if ( _widec >= 640 )
+ goto tr91;
+ goto tr85;
+tr102:
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 176;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 176;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 176;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 176;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 176;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 176;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 176;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 176;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 176;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 176;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 176;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 176;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 176;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 176;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 176;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 176;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 176;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 176;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 176;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 176;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 176;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 176;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 176;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 176;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 176;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 176;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 176;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 176;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 176;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st176;
+tr109:
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 176;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 176;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 176;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 176;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 176;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 176;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 176;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 176;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 176;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 176;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 176;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 176;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 176;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 176;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 176;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 176;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 176;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 176;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 176;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 176;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 176;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 176;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 176;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 176;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 176;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 176;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 176;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 176;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 176;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st176;
+tr742:
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 176;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 176;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 176;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 176;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 176;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 176;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 176;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 176;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 176;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 176;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 176;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 176;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 176;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 176;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 176;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 176;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 176;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 176;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 176;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 176;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 176;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 176;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 176;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 176;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 176;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 176;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 176;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 176;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 176;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st176;
+st176:
+ if ( ++p == pe )
+ goto _test_eof176;
+case 176:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr757;
+ case 32: goto tr757;
+ case 40: goto tr758;
+ case 41: goto tr759;
+ case 778: goto tr760;
+ case 827: goto tr761;
+ case 1034: goto tr760;
+ case 1083: goto tr761;
+ }
+ if ( _widec < 11 ) {
+ if ( _widec <= 8 )
+ goto tr91;
+ } else if ( _widec > 58 ) {
+ if ( 60 <= _widec )
+ goto tr91;
+ } else
+ goto tr91;
+ goto tr79;
+tr762:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st177;
+tr757:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st177;
+tr758:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st177;
+tr759:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st177;
+tr763:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st177;
+tr764:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st177;
+st177:
+ if ( ++p == pe )
+ goto _test_eof177;
+case 177:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr762;
+ case 32: goto tr762;
+ case 40: goto tr763;
+ case 41: goto tr764;
+ case 778: goto tr92;
+ case 827: goto tr765;
+ case 1034: goto tr92;
+ case 1083: goto tr765;
+ }
+ if ( _widec < 11 ) {
+ if ( _widec <= 8 )
+ goto tr91;
+ } else if ( _widec > 58 ) {
+ if ( 60 <= _widec )
+ goto tr91;
+ } else
+ goto tr91;
+ goto tr85;
+tr743:
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 1134;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 1134;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 1134;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 1134;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 1134;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 1134;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 1134;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 1134;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 1134;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 1134;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 1134;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 1134;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 1134;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 1134;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 1134;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 1134;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 1134;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 1134;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 1134;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 1134;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 1134;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 1134;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 1134;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 1134;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 1134;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 1134;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 1134;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 1134;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 1134;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1134; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1134; goto _out;}
+ }
+ }
+ goto st1134;
+tr749:
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 1134;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 1134;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 1134;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 1134;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 1134;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 1134;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 1134;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 1134;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 1134;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 1134;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 1134;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 1134;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 1134;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 1134;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 1134;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 1134;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 1134;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 1134;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 1134;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 1134;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 1134;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 1134;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 1134;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 1134;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 1134;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 1134;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 1134;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 1134;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 1134;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1134; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1134; goto _out;}
+ }
+ }
+ goto st1134;
+st1134:
+ if ( ++p == pe )
+ goto _test_eof1134;
+case 1134:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr3691;
+ case 32: goto tr3691;
+ case 36: goto tr3623;
+ case 40: goto tr3692;
+ case 41: goto tr3693;
+ case 42: goto tr3626;
+ case 58: goto tr69;
+ case 92: goto tr3627;
+ case 95: goto tr3626;
+ case 1802: goto tr83;
+ case 1851: goto tr84;
+ case 2058: goto tr3689;
+ case 2107: goto tr3694;
+ case 2314: goto tr101;
+ case 2363: goto tr102;
+ case 2570: goto tr3689;
+ case 2619: goto tr3695;
+ }
+ if ( _widec < 60 ) {
+ if ( _widec < 11 ) {
+ if ( _widec <= 8 )
+ goto tr69;
+ } else if ( _widec > 44 ) {
+ if ( 45 <= _widec && _widec <= 57 )
+ goto tr3626;
+ } else
+ goto tr69;
+ } else if ( _widec > 63 ) {
+ if ( _widec < 91 ) {
+ if ( 64 <= _widec && _widec <= 90 )
+ goto tr3626;
+ } else if ( _widec > 96 ) {
+ if ( _widec > 122 ) {
+ if ( 123 <= _widec )
+ goto tr69;
+ } else if ( _widec >= 97 )
+ goto tr3626;
+ } else
+ goto tr69;
+ } else
+ goto tr69;
+ goto tr783;
+tr767:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st178;
+tr768:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st178;
+tr897:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st178;
+tr898:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st178;
+tr899:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st178;
+tr3691:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ goto st178;
+tr3692:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ goto st178;
+tr3693:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ goto st178;
+st178:
+ if ( ++p == pe )
+ goto _test_eof178;
+case 178:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st178;
+ case 32: goto st178;
+ case 40: goto tr767;
+ case 41: goto tr768;
+ case 58: goto tr69;
+ case 65: goto tr118;
+ case 67: goto tr119;
+ case 68: goto tr120;
+ case 69: goto tr121;
+ case 72: goto tr122;
+ case 73: goto tr123;
+ case 75: goto tr124;
+ case 76: goto tr125;
+ case 77: goto tr126;
+ case 78: goto tr127;
+ case 80: goto tr128;
+ case 82: goto tr129;
+ case 83: goto tr130;
+ case 84: goto tr131;
+ case 85: goto tr132;
+ case 92: goto tr74;
+ case 97: goto tr118;
+ case 99: goto tr119;
+ case 100: goto tr120;
+ case 101: goto tr121;
+ case 104: goto tr122;
+ case 105: goto tr123;
+ case 107: goto tr124;
+ case 108: goto tr125;
+ case 109: goto tr126;
+ case 110: goto tr127;
+ case 112: goto tr128;
+ case 114: goto tr129;
+ case 115: goto tr130;
+ case 116: goto tr131;
+ case 117: goto tr132;
+ case 1802: goto tr89;
+ case 1851: goto tr90;
+ case 2058: goto tr753;
+ case 2107: goto tr769;
+ case 2314: goto tr108;
+ case 2363: goto tr109;
+ case 2570: goto tr753;
+ case 2619: goto tr770;
+ }
+ if ( _widec < 11 ) {
+ if ( _widec <= 8 )
+ goto tr69;
+ } else if ( _widec > 47 ) {
+ if ( _widec > 57 ) {
+ if ( 60 <= _widec )
+ goto tr69;
+ } else if ( _widec >= 48 )
+ goto tr117;
+ } else
+ goto tr69;
+ goto tr114;
+tr119:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 179;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 179;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 179;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 179;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 179;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 179;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 179;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 179;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 179;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 179;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 179;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 179;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 179;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 179;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 179;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 179;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 179;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 179;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 179;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 179;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 179;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 179;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 179;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 179;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 179;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 179;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 179;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 179;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 179;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st179;
+st179:
+ if ( ++p == pe )
+ goto _test_eof179;
+case 179:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr80;
+ case 32: goto tr80;
+ case 40: goto tr81;
+ case 41: goto tr82;
+ case 65: goto st18;
+ case 68: goto st22;
+ case 69: goto st29;
+ case 78: goto st32;
+ case 97: goto st18;
+ case 100: goto st22;
+ case 101: goto st29;
+ case 110: goto st32;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr83;
+ case 1083: goto tr84;
+ }
+ goto tr735;
+tr120:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 180;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 180;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 180;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 180;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 180;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 180;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 180;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 180;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 180;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 180;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 180;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 180;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 180;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 180;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 180;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 180;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 180;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 180;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 180;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 180;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 180;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 180;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 180;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 180;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 180;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 180;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 180;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 180;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 180;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st180;
+st180:
+ if ( ++p == pe )
+ goto _test_eof180;
+case 180:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr80;
+ case 32: goto tr80;
+ case 40: goto tr81;
+ case 41: goto tr82;
+ case 72: goto st37;
+ case 78: goto st41;
+ case 83: goto st49;
+ case 104: goto st37;
+ case 110: goto st41;
+ case 115: goto st49;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr83;
+ case 1083: goto tr84;
+ }
+ goto tr735;
+tr121:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 181;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 181;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 181;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 181;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 181;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 181;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 181;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 181;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 181;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 181;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 181;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 181;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 181;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 181;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 181;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 181;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 181;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 181;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 181;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 181;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 181;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 181;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 181;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 181;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 181;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 181;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 181;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 181;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 181;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st181;
+st181:
+ if ( ++p == pe )
+ goto _test_eof181;
+case 181:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr80;
+ case 32: goto tr80;
+ case 40: goto tr81;
+ case 41: goto tr82;
+ case 85: goto st51;
+ case 117: goto st51;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr83;
+ case 1083: goto tr84;
+ }
+ goto tr735;
+tr122:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 182;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 182;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 182;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 182;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 182;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 182;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 182;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 182;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 182;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 182;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 182;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 182;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 182;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 182;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 182;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 182;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 182;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 182;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 182;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 182;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 182;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 182;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 182;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 182;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 182;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 182;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 182;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 182;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 182;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st182;
+st182:
+ if ( ++p == pe )
+ goto _test_eof182;
+case 182:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr80;
+ case 32: goto tr80;
+ case 40: goto tr81;
+ case 41: goto tr82;
+ case 73: goto st58;
+ case 105: goto st58;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr83;
+ case 1083: goto tr84;
+ }
+ goto tr735;
+tr123:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 183;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 183;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 183;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 183;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 183;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 183;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 183;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 183;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 183;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 183;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 183;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 183;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 183;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 183;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 183;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 183;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 183;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 183;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 183;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 183;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 183;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 183;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 183;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 183;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 183;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 183;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 183;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 183;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 183;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st183;
+st183:
+ if ( ++p == pe )
+ goto _test_eof183;
+case 183:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr80;
+ case 32: goto tr80;
+ case 40: goto tr81;
+ case 41: goto tr82;
+ case 78: goto st144;
+ case 80: goto st66;
+ case 110: goto st144;
+ case 112: goto st66;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr83;
+ case 1083: goto tr84;
+ }
+ goto tr735;
+tr124:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 184;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 184;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 184;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 184;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 184;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 184;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 184;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 184;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 184;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 184;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 184;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 184;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 184;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 184;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 184;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 184;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 184;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 184;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 184;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 184;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 184;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 184;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 184;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 184;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 184;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 184;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 184;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 184;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 184;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st184;
+st184:
+ if ( ++p == pe )
+ goto _test_eof184;
+case 184:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr80;
+ case 32: goto tr80;
+ case 40: goto tr81;
+ case 41: goto tr82;
+ case 69: goto st74;
+ case 88: goto st76;
+ case 101: goto st74;
+ case 120: goto st76;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr83;
+ case 1083: goto tr84;
+ }
+ goto tr735;
+tr125:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 185;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 185;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 185;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 185;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 185;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 185;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 185;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 185;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 185;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 185;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 185;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 185;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 185;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 185;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 185;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 185;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 185;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 185;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 185;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 185;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 185;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 185;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 185;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 185;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 185;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 185;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 185;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 185;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 185;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st185;
+st185:
+ if ( ++p == pe )
+ goto _test_eof185;
+case 185:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr80;
+ case 32: goto tr80;
+ case 40: goto tr81;
+ case 41: goto tr82;
+ case 51: goto st78;
+ case 54: goto st80;
+ case 79: goto st82;
+ case 80: goto st84;
+ case 111: goto st82;
+ case 112: goto st84;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr83;
+ case 1083: goto tr84;
+ }
+ goto tr735;
+tr126:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 186;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 186;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 186;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 186;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 186;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 186;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 186;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 186;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 186;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 186;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 186;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 186;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 186;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 186;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 186;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 186;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 186;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 186;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 186;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 186;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 186;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 186;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 186;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 186;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 186;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 186;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 186;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 186;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 186;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st186;
+st186:
+ if ( ++p == pe )
+ goto _test_eof186;
+case 186:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr80;
+ case 32: goto tr80;
+ case 40: goto tr81;
+ case 41: goto tr82;
+ case 73: goto st86;
+ case 88: goto st90;
+ case 105: goto st86;
+ case 120: goto st90;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr83;
+ case 1083: goto tr84;
+ }
+ goto tr735;
+tr127:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 187;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 187;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 187;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 187;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 187;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 187;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 187;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 187;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 187;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 187;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 187;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 187;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 187;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 187;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 187;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 187;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 187;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 187;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 187;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 187;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 187;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 187;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 187;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 187;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 187;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 187;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 187;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 187;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 187;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st187;
+st187:
+ if ( ++p == pe )
+ goto _test_eof187;
+case 187:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr80;
+ case 32: goto tr80;
+ case 40: goto tr81;
+ case 41: goto tr82;
+ case 65: goto st92;
+ case 73: goto st96;
+ case 83: goto st98;
+ case 97: goto st92;
+ case 105: goto st96;
+ case 115: goto st98;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr83;
+ case 1083: goto tr84;
+ }
+ goto tr735;
+tr128:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 188;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 188;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 188;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 188;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 188;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 188;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 188;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 188;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 188;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 188;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 188;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 188;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 188;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 188;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 188;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 188;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 188;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 188;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 188;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 188;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 188;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 188;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 188;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 188;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 188;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 188;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 188;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 188;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 188;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st188;
+st188:
+ if ( ++p == pe )
+ goto _test_eof188;
+case 188:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr80;
+ case 32: goto tr80;
+ case 40: goto tr81;
+ case 41: goto tr82;
+ case 84: goto st108;
+ case 116: goto st108;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr83;
+ case 1083: goto tr84;
+ }
+ goto tr735;
+tr129:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 189;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 189;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 189;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 189;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 189;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 189;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 189;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 189;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 189;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 189;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 189;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 189;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 189;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 189;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 189;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 189;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 189;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 189;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 189;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 189;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 189;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 189;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 189;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 189;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 189;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 189;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 189;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 189;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 189;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st189;
+st189:
+ if ( ++p == pe )
+ goto _test_eof189;
+case 189:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr80;
+ case 32: goto tr80;
+ case 40: goto tr81;
+ case 41: goto tr82;
+ case 80: goto st111;
+ case 82: goto st112;
+ case 84: goto st116;
+ case 112: goto st111;
+ case 114: goto st112;
+ case 116: goto st116;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr83;
+ case 1083: goto tr84;
+ }
+ goto tr735;
+tr130:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 190;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 190;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 190;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 190;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 190;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 190;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 190;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 190;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 190;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 190;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 190;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 190;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 190;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 190;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 190;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 190;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 190;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 190;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 190;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 190;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 190;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 190;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 190;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 190;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 190;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 190;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 190;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 190;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 190;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st190;
+st190:
+ if ( ++p == pe )
+ goto _test_eof190;
+case 190:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr80;
+ case 32: goto tr80;
+ case 40: goto tr81;
+ case 41: goto tr82;
+ case 79: goto st118;
+ case 80: goto st120;
+ case 82: goto st122;
+ case 83: goto st124;
+ case 111: goto st118;
+ case 112: goto st120;
+ case 114: goto st122;
+ case 115: goto st124;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr83;
+ case 1083: goto tr84;
+ }
+ goto tr735;
+tr131:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 191;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 191;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 191;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 191;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 191;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 191;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 191;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 191;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 191;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 191;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 191;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 191;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 191;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 191;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 191;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 191;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 191;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 191;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 191;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 191;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 191;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 191;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 191;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 191;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 191;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 191;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 191;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 191;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 191;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st191;
+st191:
+ if ( ++p == pe )
+ goto _test_eof191;
+case 191:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr80;
+ case 32: goto tr80;
+ case 40: goto tr81;
+ case 41: goto tr82;
+ case 76: goto st129;
+ case 88: goto st132;
+ case 89: goto st134;
+ case 108: goto st129;
+ case 120: goto st132;
+ case 121: goto st134;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr83;
+ case 1083: goto tr84;
+ }
+ goto tr735;
+tr132:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 192;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 192;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 192;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 192;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 192;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 192;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 192;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 192;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 192;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 192;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 192;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 192;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 192;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 192;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 192;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 192;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 192;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 192;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 192;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 192;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 192;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 192;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 192;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 192;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 192;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 192;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 192;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 192;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 192;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st192;
+st192:
+ if ( ++p == pe )
+ goto _test_eof192;
+case 192:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr80;
+ case 32: goto tr80;
+ case 40: goto tr81;
+ case 41: goto tr82;
+ case 82: goto st139;
+ case 114: goto st139;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr83;
+ case 1083: goto tr84;
+ }
+ goto tr735;
+tr769:
+ {
+ s->buffer_length = 0;
+ }
+ goto st193;
+tr771:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st193;
+tr900:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st193;
+tr838:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st193;
+tr842:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st193;
+tr807:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st193;
+tr3694:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ goto st193;
+st193:
+ if ( ++p == pe )
+ goto _test_eof193;
+case 193:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 778: goto tr92;
+ case 1034: goto tr772;
+ }
+ if ( _widec > 895 ) {
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr771;
+ } else if ( _widec >= 640 )
+ goto tr91;
+ goto tr79;
+tr133:
+ {
+ s->line_counter++;
+ }
+ goto st1135;
+tr874:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1135;
+tr772:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1135; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1135; goto _out;}
+ }
+ }
+ goto st1135;
+tr813:
+ {
+ s->line_counter++;
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1135; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1135; goto _out;}
+ }
+ }
+ goto st1135;
+tr806:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ s->line_counter++;
+ }
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1135; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1135; goto _out;}
+ }
+ }
+ goto st1135;
+tr3628:
+ {
+ s->line_counter++;
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st1135;
+st1135:
+ if ( ++p == pe )
+ goto _test_eof1135;
+case 1135:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr3622;
+ case 32: goto tr3622;
+ case 36: goto tr3623;
+ case 40: goto tr3624;
+ case 41: goto tr3625;
+ case 42: goto tr3626;
+ case 58: goto tr69;
+ case 65: goto tr3698;
+ case 67: goto tr3699;
+ case 68: goto tr3700;
+ case 69: goto tr3701;
+ case 72: goto tr3702;
+ case 73: goto tr3703;
+ case 75: goto tr3704;
+ case 76: goto tr3705;
+ case 77: goto tr3706;
+ case 78: goto tr3707;
+ case 80: goto tr3708;
+ case 82: goto tr3709;
+ case 83: goto tr3710;
+ case 84: goto tr3711;
+ case 85: goto tr3712;
+ case 92: goto tr3627;
+ case 95: goto tr3626;
+ case 97: goto tr3698;
+ case 99: goto tr3699;
+ case 100: goto tr3700;
+ case 101: goto tr3701;
+ case 104: goto tr3702;
+ case 105: goto tr3703;
+ case 107: goto tr3704;
+ case 108: goto tr3705;
+ case 109: goto tr3706;
+ case 110: goto tr3707;
+ case 112: goto tr3708;
+ case 114: goto tr3709;
+ case 115: goto tr3710;
+ case 116: goto tr3711;
+ case 117: goto tr3712;
+ case 1802: goto tr3618;
+ case 1851: goto tr3619;
+ case 2058: goto tr3628;
+ case 2107: goto tr3629;
+ case 2314: goto tr3630;
+ case 2363: goto tr3631;
+ case 2570: goto tr3632;
+ case 2619: goto tr3633;
+ }
+ if ( _widec < 60 ) {
+ if ( _widec < 11 ) {
+ if ( _widec <= 8 )
+ goto tr69;
+ } else if ( _widec > 44 ) {
+ if ( _widec > 47 ) {
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3697;
+ } else if ( _widec >= 45 )
+ goto tr3626;
+ } else
+ goto tr69;
+ } else if ( _widec > 63 ) {
+ if ( _widec < 91 ) {
+ if ( 64 <= _widec && _widec <= 90 )
+ goto tr3626;
+ } else if ( _widec > 96 ) {
+ if ( _widec > 122 ) {
+ if ( 123 <= _widec )
+ goto tr69;
+ } else if ( _widec >= 98 )
+ goto tr3626;
+ } else
+ goto tr69;
+ } else
+ goto tr69;
+ goto tr3696;
+tr3623:
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 194;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 194;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 194;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 194;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 194;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 194;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 194;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 194;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 194;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 194;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 194;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 194;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 194;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 194;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 194;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 194;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 194;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 194;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 194;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 194;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 194;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 194;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 194;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 194;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 194;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 194;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 194;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 194;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 194;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st194;
+st194:
+ if ( ++p == pe )
+ goto _test_eof194;
+case 194:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr80;
+ case 32: goto tr80;
+ case 40: goto tr81;
+ case 41: goto tr82;
+ case 73: goto tr668;
+ case 79: goto tr669;
+ case 84: goto tr670;
+ case 105: goto tr668;
+ case 111: goto tr669;
+ case 116: goto tr670;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr83;
+ case 1083: goto tr84;
+ }
+ goto tr773;
+tr669:
+ {
+ ERR(ZS_OK);
+ }
+ goto st195;
+st195:
+ if ( ++p == pe )
+ goto _test_eof195;
+case 195:
+ switch( (*p) ) {
+ case 82: goto st196;
+ case 114: goto st196;
+ }
+ goto tr667;
+st196:
+ if ( ++p == pe )
+ goto _test_eof196;
+case 196:
+ switch( (*p) ) {
+ case 73: goto st197;
+ case 105: goto st197;
+ }
+ goto tr667;
+st197:
+ if ( ++p == pe )
+ goto _test_eof197;
+case 197:
+ switch( (*p) ) {
+ case 71: goto st198;
+ case 103: goto st198;
+ }
+ goto tr667;
+st198:
+ if ( ++p == pe )
+ goto _test_eof198;
+case 198:
+ switch( (*p) ) {
+ case 73: goto st199;
+ case 105: goto st199;
+ }
+ goto tr667;
+st199:
+ if ( ++p == pe )
+ goto _test_eof199;
+case 199:
+ switch( (*p) ) {
+ case 78: goto st200;
+ case 110: goto st200;
+ }
+ goto tr667;
+st200:
+ if ( ++p == pe )
+ goto _test_eof200;
+case 200:
+ switch( (*p) ) {
+ case 32: goto tr779;
+ case 59: goto tr779;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr779;
+ } else if ( (*p) >= 9 )
+ goto tr779;
+ goto tr667;
+tr670:
+ {
+ ERR(ZS_OK);
+ }
+ goto st201;
+st201:
+ if ( ++p == pe )
+ goto _test_eof201;
+case 201:
+ switch( (*p) ) {
+ case 84: goto st202;
+ case 116: goto st202;
+ }
+ goto tr667;
+st202:
+ if ( ++p == pe )
+ goto _test_eof202;
+case 202:
+ switch( (*p) ) {
+ case 76: goto st203;
+ case 108: goto st203;
+ }
+ goto tr667;
+st203:
+ if ( ++p == pe )
+ goto _test_eof203;
+case 203:
+ switch( (*p) ) {
+ case 32: goto tr782;
+ case 59: goto tr782;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr782;
+ } else if ( (*p) >= 9 )
+ goto tr782;
+ goto tr667;
+tr3626:
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 204;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 204;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 204;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 204;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 204;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 204;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 204;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 204;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 204;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 204;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 204;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 204;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 204;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 204;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 204;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 204;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 204;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 204;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 204;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 204;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 204;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 204;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 204;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 204;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 204;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 204;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 204;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 204;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 204;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 204;goto st270;} }
+ goto st204;
+st204:
+ if ( ++p == pe )
+ goto _test_eof204;
+case 204:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr784;
+ case 32: goto tr784;
+ case 40: goto tr785;
+ case 41: goto tr786;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr787;
+ case 1083: goto tr788;
+ }
+ goto tr783;
+tr3697:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 205;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 205;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 205;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 205;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 205;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 205;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 205;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 205;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 205;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 205;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 205;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 205;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 205;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 205;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 205;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 205;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 205;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 205;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 205;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 205;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 205;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 205;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 205;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 205;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 205;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 205;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 205;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 205;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 205;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 205;goto st270;} }
+ goto st205;
+st205:
+ if ( ++p == pe )
+ goto _test_eof205;
+case 205:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr790;
+ case 32: goto tr790;
+ case 40: goto tr791;
+ case 41: goto tr792;
+ case 68: goto tr29;
+ case 72: goto tr30;
+ case 77: goto tr31;
+ case 83: goto st166;
+ case 87: goto tr33;
+ case 100: goto tr29;
+ case 104: goto tr30;
+ case 109: goto tr31;
+ case 115: goto st166;
+ case 119: goto tr33;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr793;
+ case 1083: goto tr794;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr28;
+ goto tr789;
+tr796:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st206;
+tr797:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st206;
+tr790:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st206;
+tr791:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st206;
+tr792:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st206;
+st206:
+ if ( ++p == pe )
+ goto _test_eof206;
+case 206:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st206;
+ case 32: goto st206;
+ case 40: goto tr796;
+ case 41: goto tr797;
+ case 65: goto tr5;
+ case 67: goto tr6;
+ case 68: goto tr7;
+ case 69: goto tr8;
+ case 72: goto tr9;
+ case 73: goto tr10;
+ case 75: goto tr11;
+ case 76: goto tr12;
+ case 77: goto tr13;
+ case 78: goto tr14;
+ case 80: goto tr15;
+ case 82: goto tr16;
+ case 83: goto tr17;
+ case 84: goto tr18;
+ case 85: goto tr19;
+ case 97: goto tr5;
+ case 99: goto tr6;
+ case 100: goto tr7;
+ case 101: goto tr8;
+ case 104: goto tr9;
+ case 105: goto tr10;
+ case 107: goto tr11;
+ case 108: goto tr12;
+ case 109: goto tr13;
+ case 110: goto tr14;
+ case 112: goto tr15;
+ case 114: goto tr16;
+ case 115: goto tr17;
+ case 116: goto tr18;
+ case 117: goto tr19;
+ case 778: goto tr89;
+ case 827: goto tr90;
+ case 1034: goto tr798;
+ case 1083: goto tr799;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr4;
+ goto tr0;
+tr799:
+ {
+ s->buffer_length = 0;
+ }
+ goto st207;
+tr800:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st207;
+tr794:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st207;
+st207:
+ if ( ++p == pe )
+ goto _test_eof207;
+case 207:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 778: goto tr92;
+ case 1034: goto tr801;
+ }
+ if ( _widec > 895 ) {
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr800;
+ } else if ( _widec >= 640 )
+ goto tr91;
+ goto tr145;
+tr3698:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 208;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 208;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 208;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 208;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 208;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 208;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 208;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 208;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 208;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 208;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 208;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 208;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 208;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 208;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 208;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 208;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 208;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 208;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 208;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 208;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 208;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 208;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 208;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 208;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 208;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 208;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 208;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 208;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 208;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 208;goto st270;} }
+ goto st208;
+st208:
+ if ( ++p == pe )
+ goto _test_eof208;
+case 208:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr803;
+ case 32: goto tr803;
+ case 40: goto tr804;
+ case 41: goto tr805;
+ case 65: goto st230;
+ case 70: goto st233;
+ case 80: goto st237;
+ case 97: goto st230;
+ case 102: goto st233;
+ case 112: goto st237;
+ case 1802: goto tr83;
+ case 1851: goto tr84;
+ case 2058: goto tr806;
+ case 2107: goto tr807;
+ case 2314: goto tr741;
+ case 2363: goto tr742;
+ case 2570: goto tr808;
+ case 2619: goto tr809;
+ }
+ goto tr802;
+tr811:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st209;
+tr812:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st209;
+tr803:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st209;
+tr804:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st209;
+tr805:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st209;
+st209:
+ if ( ++p == pe )
+ goto _test_eof209;
+case 209:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st209;
+ case 32: goto st209;
+ case 40: goto tr811;
+ case 41: goto tr812;
+ case 58: goto tr69;
+ case 65: goto tr118;
+ case 67: goto tr119;
+ case 68: goto tr120;
+ case 69: goto tr121;
+ case 72: goto tr122;
+ case 73: goto tr123;
+ case 75: goto tr124;
+ case 76: goto tr125;
+ case 77: goto tr126;
+ case 78: goto tr127;
+ case 80: goto tr128;
+ case 82: goto tr129;
+ case 83: goto tr130;
+ case 84: goto tr131;
+ case 85: goto tr132;
+ case 92: goto tr74;
+ case 97: goto tr118;
+ case 99: goto tr119;
+ case 100: goto tr120;
+ case 101: goto tr121;
+ case 104: goto tr122;
+ case 105: goto tr123;
+ case 107: goto tr124;
+ case 108: goto tr125;
+ case 109: goto tr126;
+ case 110: goto tr127;
+ case 112: goto tr128;
+ case 114: goto tr129;
+ case 115: goto tr130;
+ case 116: goto tr131;
+ case 117: goto tr132;
+ case 1802: goto tr89;
+ case 1851: goto tr90;
+ case 2058: goto tr813;
+ case 2107: goto tr769;
+ case 2314: goto tr108;
+ case 2363: goto tr109;
+ case 2570: goto tr814;
+ case 2619: goto tr770;
+ }
+ if ( _widec < 11 ) {
+ if ( _widec <= 8 )
+ goto tr69;
+ } else if ( _widec > 47 ) {
+ if ( _widec > 57 ) {
+ if ( 60 <= _widec )
+ goto tr69;
+ } else if ( _widec >= 48 )
+ goto tr117;
+ } else
+ goto tr69;
+ goto tr114;
+tr137:
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 1136;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 1136;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 1136;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 1136;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 1136;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 1136;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 1136;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 1136;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 1136;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 1136;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 1136;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 1136;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 1136;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 1136;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 1136;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 1136;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 1136;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 1136;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 1136;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 1136;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 1136;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 1136;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 1136;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 1136;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 1136;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 1136;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 1136;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 1136;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 1136;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st1136;
+tr814:
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 1136;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 1136;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 1136;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 1136;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 1136;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 1136;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 1136;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 1136;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 1136;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 1136;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 1136;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 1136;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 1136;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 1136;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 1136;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 1136;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 1136;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 1136;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 1136;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 1136;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 1136;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 1136;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 1136;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 1136;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 1136;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 1136;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 1136;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 1136;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 1136;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1136; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1136; goto _out;}
+ }
+ }
+ goto st1136;
+tr808:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ s->line_counter++;
+ }
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 1136;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 1136;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 1136;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 1136;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 1136;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 1136;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 1136;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 1136;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 1136;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 1136;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 1136;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 1136;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 1136;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 1136;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 1136;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 1136;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 1136;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 1136;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 1136;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 1136;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 1136;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 1136;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 1136;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 1136;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 1136;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 1136;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 1136;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 1136;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 1136;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; cs = 1136; goto _out;}
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; cs = 1136; goto _out;}
+ }
+ }
+ goto st1136;
+tr3632:
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 1136;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 1136;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 1136;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 1136;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 1136;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 1136;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 1136;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 1136;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 1136;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 1136;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 1136;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 1136;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 1136;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 1136;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 1136;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 1136;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 1136;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 1136;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 1136;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 1136;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 1136;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 1136;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 1136;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 1136;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 1136;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 1136;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 1136;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 1136;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 1136;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st1136;
+st1136:
+ if ( ++p == pe )
+ goto _test_eof1136;
+case 1136:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr3691;
+ case 32: goto tr3691;
+ case 36: goto tr3623;
+ case 40: goto tr3692;
+ case 41: goto tr3693;
+ case 42: goto tr3626;
+ case 58: goto tr69;
+ case 65: goto tr3698;
+ case 67: goto tr3699;
+ case 68: goto tr3700;
+ case 69: goto tr3701;
+ case 72: goto tr3702;
+ case 73: goto tr3703;
+ case 75: goto tr3704;
+ case 76: goto tr3705;
+ case 77: goto tr3706;
+ case 78: goto tr3707;
+ case 80: goto tr3708;
+ case 82: goto tr3709;
+ case 83: goto tr3710;
+ case 84: goto tr3711;
+ case 85: goto tr3712;
+ case 92: goto tr3627;
+ case 95: goto tr3626;
+ case 97: goto tr3698;
+ case 99: goto tr3699;
+ case 100: goto tr3700;
+ case 101: goto tr3701;
+ case 104: goto tr3702;
+ case 105: goto tr3703;
+ case 107: goto tr3704;
+ case 108: goto tr3705;
+ case 109: goto tr3706;
+ case 110: goto tr3707;
+ case 112: goto tr3708;
+ case 114: goto tr3709;
+ case 115: goto tr3710;
+ case 116: goto tr3711;
+ case 117: goto tr3712;
+ case 1802: goto tr83;
+ case 1851: goto tr84;
+ case 2058: goto tr3713;
+ case 2107: goto tr3694;
+ case 2314: goto tr101;
+ case 2363: goto tr102;
+ case 2570: goto tr3713;
+ case 2619: goto tr3695;
+ }
+ if ( _widec < 60 ) {
+ if ( _widec < 11 ) {
+ if ( _widec <= 8 )
+ goto tr69;
+ } else if ( _widec > 44 ) {
+ if ( _widec > 47 ) {
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3697;
+ } else if ( _widec >= 45 )
+ goto tr3626;
+ } else
+ goto tr69;
+ } else if ( _widec > 63 ) {
+ if ( _widec < 91 ) {
+ if ( 64 <= _widec && _widec <= 90 )
+ goto tr3626;
+ } else if ( _widec > 96 ) {
+ if ( _widec > 122 ) {
+ if ( 123 <= _widec )
+ goto tr69;
+ } else if ( _widec >= 98 )
+ goto tr3626;
+ } else
+ goto tr69;
+ } else
+ goto tr69;
+ goto tr3696;
+tr3699:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 210;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 210;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 210;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 210;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 210;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 210;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 210;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 210;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 210;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 210;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 210;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 210;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 210;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 210;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 210;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 210;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 210;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 210;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 210;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 210;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 210;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 210;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 210;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 210;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 210;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 210;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 210;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 210;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 210;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 210;goto st270;} }
+ goto st210;
+st210:
+ if ( ++p == pe )
+ goto _test_eof210;
+case 210:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr784;
+ case 32: goto tr784;
+ case 40: goto tr785;
+ case 41: goto tr786;
+ case 65: goto st18;
+ case 68: goto st22;
+ case 69: goto st29;
+ case 78: goto st32;
+ case 97: goto st18;
+ case 100: goto st22;
+ case 101: goto st29;
+ case 110: goto st32;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr787;
+ case 1083: goto tr788;
+ }
+ goto tr802;
+tr3700:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 211;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 211;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 211;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 211;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 211;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 211;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 211;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 211;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 211;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 211;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 211;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 211;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 211;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 211;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 211;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 211;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 211;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 211;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 211;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 211;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 211;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 211;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 211;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 211;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 211;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 211;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 211;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 211;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 211;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 211;goto st270;} }
+ goto st211;
+st211:
+ if ( ++p == pe )
+ goto _test_eof211;
+case 211:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr784;
+ case 32: goto tr784;
+ case 40: goto tr785;
+ case 41: goto tr786;
+ case 72: goto st37;
+ case 78: goto st41;
+ case 83: goto st49;
+ case 104: goto st37;
+ case 110: goto st41;
+ case 115: goto st49;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr787;
+ case 1083: goto tr788;
+ }
+ goto tr802;
+tr3701:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 212;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 212;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 212;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 212;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 212;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 212;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 212;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 212;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 212;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 212;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 212;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 212;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 212;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 212;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 212;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 212;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 212;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 212;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 212;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 212;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 212;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 212;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 212;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 212;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 212;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 212;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 212;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 212;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 212;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 212;goto st270;} }
+ goto st212;
+st212:
+ if ( ++p == pe )
+ goto _test_eof212;
+case 212:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr784;
+ case 32: goto tr784;
+ case 40: goto tr785;
+ case 41: goto tr786;
+ case 85: goto st51;
+ case 117: goto st51;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr787;
+ case 1083: goto tr788;
+ }
+ goto tr802;
+tr3702:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 213;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 213;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 213;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 213;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 213;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 213;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 213;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 213;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 213;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 213;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 213;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 213;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 213;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 213;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 213;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 213;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 213;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 213;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 213;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 213;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 213;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 213;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 213;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 213;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 213;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 213;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 213;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 213;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 213;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 213;goto st270;} }
+ goto st213;
+st213:
+ if ( ++p == pe )
+ goto _test_eof213;
+case 213:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr784;
+ case 32: goto tr784;
+ case 40: goto tr785;
+ case 41: goto tr786;
+ case 73: goto st58;
+ case 105: goto st58;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr787;
+ case 1083: goto tr788;
+ }
+ goto tr802;
+tr3703:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 214;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 214;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 214;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 214;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 214;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 214;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 214;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 214;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 214;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 214;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 214;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 214;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 214;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 214;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 214;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 214;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 214;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 214;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 214;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 214;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 214;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 214;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 214;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 214;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 214;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 214;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 214;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 214;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 214;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 214;goto st270;} }
+ goto st214;
+st214:
+ if ( ++p == pe )
+ goto _test_eof214;
+case 214:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr784;
+ case 32: goto tr784;
+ case 40: goto tr785;
+ case 41: goto tr786;
+ case 78: goto st144;
+ case 80: goto st66;
+ case 110: goto st144;
+ case 112: goto st66;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr787;
+ case 1083: goto tr788;
+ }
+ goto tr802;
+tr3704:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 215;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 215;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 215;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 215;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 215;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 215;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 215;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 215;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 215;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 215;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 215;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 215;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 215;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 215;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 215;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 215;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 215;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 215;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 215;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 215;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 215;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 215;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 215;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 215;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 215;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 215;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 215;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 215;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 215;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 215;goto st270;} }
+ goto st215;
+st215:
+ if ( ++p == pe )
+ goto _test_eof215;
+case 215:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr784;
+ case 32: goto tr784;
+ case 40: goto tr785;
+ case 41: goto tr786;
+ case 69: goto st74;
+ case 88: goto st76;
+ case 101: goto st74;
+ case 120: goto st76;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr787;
+ case 1083: goto tr788;
+ }
+ goto tr802;
+tr3705:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 216;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 216;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 216;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 216;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 216;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 216;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 216;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 216;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 216;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 216;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 216;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 216;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 216;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 216;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 216;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 216;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 216;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 216;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 216;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 216;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 216;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 216;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 216;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 216;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 216;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 216;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 216;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 216;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 216;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 216;goto st270;} }
+ goto st216;
+st216:
+ if ( ++p == pe )
+ goto _test_eof216;
+case 216:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr784;
+ case 32: goto tr784;
+ case 40: goto tr785;
+ case 41: goto tr786;
+ case 51: goto st78;
+ case 54: goto st80;
+ case 79: goto st82;
+ case 80: goto st84;
+ case 111: goto st82;
+ case 112: goto st84;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr787;
+ case 1083: goto tr788;
+ }
+ goto tr802;
+tr3706:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 217;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 217;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 217;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 217;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 217;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 217;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 217;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 217;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 217;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 217;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 217;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 217;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 217;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 217;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 217;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 217;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 217;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 217;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 217;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 217;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 217;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 217;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 217;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 217;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 217;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 217;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 217;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 217;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 217;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 217;goto st270;} }
+ goto st217;
+st217:
+ if ( ++p == pe )
+ goto _test_eof217;
+case 217:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr784;
+ case 32: goto tr784;
+ case 40: goto tr785;
+ case 41: goto tr786;
+ case 73: goto st86;
+ case 88: goto st90;
+ case 105: goto st86;
+ case 120: goto st90;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr787;
+ case 1083: goto tr788;
+ }
+ goto tr802;
+tr3707:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 218;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 218;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 218;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 218;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 218;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 218;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 218;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 218;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 218;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 218;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 218;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 218;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 218;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 218;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 218;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 218;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 218;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 218;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 218;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 218;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 218;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 218;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 218;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 218;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 218;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 218;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 218;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 218;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 218;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 218;goto st270;} }
+ goto st218;
+st218:
+ if ( ++p == pe )
+ goto _test_eof218;
+case 218:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr784;
+ case 32: goto tr784;
+ case 40: goto tr785;
+ case 41: goto tr786;
+ case 65: goto st92;
+ case 73: goto st96;
+ case 83: goto st98;
+ case 97: goto st92;
+ case 105: goto st96;
+ case 115: goto st98;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr787;
+ case 1083: goto tr788;
+ }
+ goto tr802;
+tr3708:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 219;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 219;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 219;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 219;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 219;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 219;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 219;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 219;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 219;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 219;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 219;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 219;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 219;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 219;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 219;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 219;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 219;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 219;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 219;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 219;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 219;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 219;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 219;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 219;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 219;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 219;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 219;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 219;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 219;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 219;goto st270;} }
+ goto st219;
+st219:
+ if ( ++p == pe )
+ goto _test_eof219;
+case 219:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr784;
+ case 32: goto tr784;
+ case 40: goto tr785;
+ case 41: goto tr786;
+ case 84: goto st108;
+ case 116: goto st108;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr787;
+ case 1083: goto tr788;
+ }
+ goto tr802;
+tr3709:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 220;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 220;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 220;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 220;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 220;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 220;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 220;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 220;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 220;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 220;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 220;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 220;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 220;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 220;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 220;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 220;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 220;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 220;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 220;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 220;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 220;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 220;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 220;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 220;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 220;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 220;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 220;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 220;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 220;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 220;goto st270;} }
+ goto st220;
+st220:
+ if ( ++p == pe )
+ goto _test_eof220;
+case 220:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr784;
+ case 32: goto tr784;
+ case 40: goto tr785;
+ case 41: goto tr786;
+ case 80: goto st111;
+ case 82: goto st112;
+ case 84: goto st116;
+ case 112: goto st111;
+ case 114: goto st112;
+ case 116: goto st116;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr787;
+ case 1083: goto tr788;
+ }
+ goto tr802;
+tr3710:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 221;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 221;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 221;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 221;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 221;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 221;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 221;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 221;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 221;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 221;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 221;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 221;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 221;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 221;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 221;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 221;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 221;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 221;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 221;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 221;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 221;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 221;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 221;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 221;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 221;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 221;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 221;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 221;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 221;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 221;goto st270;} }
+ goto st221;
+st221:
+ if ( ++p == pe )
+ goto _test_eof221;
+case 221:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr784;
+ case 32: goto tr784;
+ case 40: goto tr785;
+ case 41: goto tr786;
+ case 79: goto st118;
+ case 80: goto st120;
+ case 82: goto st122;
+ case 83: goto st124;
+ case 111: goto st118;
+ case 112: goto st120;
+ case 114: goto st122;
+ case 115: goto st124;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr787;
+ case 1083: goto tr788;
+ }
+ goto tr802;
+tr3711:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 222;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 222;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 222;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 222;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 222;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 222;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 222;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 222;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 222;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 222;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 222;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 222;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 222;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 222;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 222;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 222;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 222;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 222;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 222;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 222;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 222;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 222;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 222;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 222;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 222;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 222;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 222;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 222;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 222;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 222;goto st270;} }
+ goto st222;
+st222:
+ if ( ++p == pe )
+ goto _test_eof222;
+case 222:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr784;
+ case 32: goto tr784;
+ case 40: goto tr785;
+ case 41: goto tr786;
+ case 76: goto st129;
+ case 88: goto st132;
+ case 89: goto st134;
+ case 108: goto st129;
+ case 120: goto st132;
+ case 121: goto st134;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr787;
+ case 1083: goto tr788;
+ }
+ goto tr802;
+tr3712:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 223;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 223;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 223;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 223;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 223;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 223;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 223;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 223;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 223;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 223;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 223;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 223;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 223;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 223;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 223;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 223;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 223;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 223;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 223;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 223;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 223;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 223;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 223;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 223;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 223;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 223;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 223;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 223;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 223;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 223;goto st270;} }
+ goto st223;
+st223:
+ if ( ++p == pe )
+ goto _test_eof223;
+case 223:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr784;
+ case 32: goto tr784;
+ case 40: goto tr785;
+ case 41: goto tr786;
+ case 82: goto st139;
+ case 114: goto st139;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr787;
+ case 1083: goto tr788;
+ }
+ goto tr802;
+tr3627:
+ {
+ if (pe - p == 1) {
+ *wrap = WRAP_DETECTED;
+ }
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 224;goto st270;} }
+ goto st224;
+st224:
+ if ( ++p == pe )
+ goto _test_eof224;
+case 224:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr815;
+ case 32: goto tr815;
+ case 35: goto tr94;
+ case 40: goto tr817;
+ case 41: goto tr818;
+ case 778: goto tr93;
+ case 827: goto tr93;
+ case 1034: goto tr819;
+ case 1083: goto tr820;
+ }
+ if ( _widec < 11 ) {
+ if ( _widec <= 8 )
+ goto tr93;
+ } else if ( _widec > 58 ) {
+ if ( 60 <= _widec )
+ goto tr93;
+ } else
+ goto tr93;
+ goto tr816;
+tr815:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ if (*wrap == WRAP_NONE) {
+ p--;
+ }
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 225;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 225;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 225;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 225;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 225;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 225;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 225;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 225;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 225;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 225;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 225;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 225;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 225;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 225;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 225;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 225;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 225;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 225;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 225;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 225;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 225;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 225;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 225;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 225;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 225;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 225;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 225;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 225;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 225;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st225;
+tr817:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ {
+ if (*wrap == WRAP_NONE) {
+ p--;
+ }
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 225;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 225;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 225;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 225;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 225;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 225;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 225;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 225;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 225;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 225;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 225;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 225;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 225;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 225;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 225;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 225;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 225;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 225;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 225;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 225;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 225;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 225;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 225;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 225;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 225;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 225;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 225;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 225;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 225;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st225;
+tr818:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ {
+ if (*wrap == WRAP_NONE) {
+ p--;
+ }
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 225;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 225;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 225;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 225;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 225;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 225;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 225;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 225;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 225;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 225;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 225;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 225;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 225;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 225;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 225;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 225;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 225;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 225;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 225;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 225;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 225;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 225;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 225;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 225;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 225;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 225;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 225;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 225;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 225;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st225;
+tr819:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ if (*wrap == WRAP_NONE) {
+ p--;
+ }
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 225;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 225;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 225;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 225;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 225;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 225;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 225;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 225;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 225;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 225;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 225;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 225;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 225;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 225;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 225;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 225;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 225;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 225;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 225;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 225;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 225;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 225;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 225;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 225;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 225;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 225;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 225;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 225;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 225;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st225;
+st225:
+ if ( ++p == pe )
+ goto _test_eof225;
+case 225:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr821;
+ case 32: goto tr821;
+ case 40: goto tr822;
+ case 41: goto tr823;
+ case 65: goto tr5;
+ case 67: goto tr6;
+ case 68: goto tr7;
+ case 69: goto tr8;
+ case 72: goto tr9;
+ case 73: goto tr10;
+ case 75: goto tr11;
+ case 76: goto tr12;
+ case 77: goto tr13;
+ case 78: goto tr14;
+ case 80: goto tr15;
+ case 82: goto tr16;
+ case 83: goto tr17;
+ case 84: goto tr18;
+ case 85: goto tr19;
+ case 97: goto tr5;
+ case 99: goto tr6;
+ case 100: goto tr7;
+ case 101: goto tr8;
+ case 104: goto tr9;
+ case 105: goto tr10;
+ case 107: goto tr11;
+ case 108: goto tr12;
+ case 109: goto tr13;
+ case 110: goto tr14;
+ case 112: goto tr15;
+ case 114: goto tr16;
+ case 115: goto tr17;
+ case 116: goto tr18;
+ case 117: goto tr19;
+ case 778: goto tr83;
+ case 827: goto tr84;
+ case 1034: goto tr824;
+ case 1083: goto tr825;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr4;
+ goto tr114;
+tr820:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ if (*wrap == WRAP_NONE) {
+ p--;
+ }
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 226;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 226;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 226;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 226;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 226;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 226;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 226;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 226;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 226;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 226;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 226;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 226;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 226;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 226;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 226;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 226;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 226;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 226;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 226;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 226;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 226;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 226;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 226;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 226;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 226;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 226;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 226;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 226;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 226;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st226;
+st226:
+ if ( ++p == pe )
+ goto _test_eof226;
+case 226:
+ _widec = (*p);
+ if ( (*p) < 11 ) {
+ if ( (*p) > 9 ) {
+ if ( 10 <= (*p) && (*p) <= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 58 ) {
+ if ( (*p) > 59 ) {
+ if ( 60 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 777: goto tr80;
+ case 778: goto tr83;
+ case 800: goto tr80;
+ case 808: goto tr81;
+ case 809: goto tr82;
+ case 827: goto tr84;
+ case 1033: goto tr826;
+ case 1034: goto tr827;
+ case 1056: goto tr826;
+ case 1064: goto tr828;
+ case 1065: goto tr829;
+ case 1083: goto tr830;
+ }
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr689;
+ goto tr79;
+tr831:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st227;
+tr826:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st227;
+tr828:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st227;
+tr829:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st227;
+tr832:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st227;
+tr833:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st227;
+st227:
+ if ( ++p == pe )
+ goto _test_eof227;
+case 227:
+ _widec = (*p);
+ if ( (*p) < 11 ) {
+ if ( (*p) > 9 ) {
+ if ( 10 <= (*p) && (*p) <= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 58 ) {
+ if ( (*p) > 59 ) {
+ if ( 60 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 777: goto st7;
+ case 778: goto tr89;
+ case 800: goto st7;
+ case 808: goto tr87;
+ case 809: goto tr88;
+ case 827: goto tr90;
+ case 1033: goto tr831;
+ case 1034: goto tr756;
+ case 1056: goto tr831;
+ case 1064: goto tr832;
+ case 1065: goto tr833;
+ case 1083: goto tr834;
+ }
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr689;
+ goto tr85;
+tr770:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 228;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 228;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 228;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 228;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 228;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 228;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 228;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 228;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 228;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 228;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 228;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 228;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 228;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 228;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 228;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 228;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 228;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 228;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 228;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 228;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 228;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 228;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 228;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 228;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 228;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 228;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 228;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 228;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 228;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st228;
+tr901:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 228;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 228;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 228;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 228;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 228;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 228;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 228;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 228;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 228;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 228;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 228;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 228;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 228;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 228;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 228;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 228;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 228;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 228;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 228;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 228;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 228;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 228;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 228;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 228;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 228;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 228;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 228;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 228;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 228;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st228;
+tr809:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 228;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 228;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 228;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 228;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 228;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 228;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 228;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 228;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 228;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 228;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 228;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 228;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 228;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 228;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 228;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 228;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 228;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 228;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 228;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 228;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 228;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 228;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 228;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 228;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 228;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 228;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 228;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 228;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 228;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st228;
+tr3695:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 228;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 228;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 228;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 228;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 228;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 228;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 228;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 228;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 228;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 228;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 228;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 228;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 228;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 228;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 228;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 228;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 228;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 228;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 228;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 228;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 228;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 228;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 228;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 228;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 228;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 228;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 228;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 228;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 228;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ goto st228;
+st228:
+ if ( ++p == pe )
+ goto _test_eof228;
+case 228:
+ _widec = (*p);
+ if ( (*p) < 11 ) {
+ if ( (*p) > 9 ) {
+ if ( 10 <= (*p) && (*p) <= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 58 ) {
+ if ( (*p) > 59 ) {
+ if ( 60 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 777: goto tr757;
+ case 778: goto tr760;
+ case 800: goto tr757;
+ case 808: goto tr758;
+ case 809: goto tr759;
+ case 827: goto tr761;
+ case 1033: goto tr835;
+ case 1034: goto tr827;
+ case 1056: goto tr835;
+ case 1064: goto tr836;
+ case 1065: goto tr837;
+ case 1083: goto tr838;
+ }
+ if ( _widec > 895 ) {
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr771;
+ } else if ( _widec >= 640 )
+ goto tr91;
+ goto tr79;
+tr839:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st229;
+tr835:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st229;
+tr836:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st229;
+tr837:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st229;
+tr840:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st229;
+tr841:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st229;
+st229:
+ if ( ++p == pe )
+ goto _test_eof229;
+case 229:
+ _widec = (*p);
+ if ( (*p) < 11 ) {
+ if ( (*p) > 9 ) {
+ if ( 10 <= (*p) && (*p) <= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 58 ) {
+ if ( (*p) > 59 ) {
+ if ( 60 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 777: goto tr762;
+ case 778: goto tr92;
+ case 800: goto tr762;
+ case 808: goto tr763;
+ case 809: goto tr764;
+ case 827: goto tr765;
+ case 1033: goto tr839;
+ case 1034: goto tr756;
+ case 1056: goto tr839;
+ case 1064: goto tr840;
+ case 1065: goto tr841;
+ case 1083: goto tr842;
+ }
+ if ( _widec > 895 ) {
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr771;
+ } else if ( _widec >= 640 )
+ goto tr91;
+ goto tr79;
+st230:
+ if ( ++p == pe )
+ goto _test_eof230;
+case 230:
+ switch( (*p) ) {
+ case 65: goto st231;
+ case 97: goto st231;
+ }
+ goto tr36;
+st231:
+ if ( ++p == pe )
+ goto _test_eof231;
+case 231:
+ switch( (*p) ) {
+ case 65: goto st232;
+ case 97: goto st232;
+ }
+ goto tr36;
+st232:
+ if ( ++p == pe )
+ goto _test_eof232;
+case 232:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr845;
+ case 32: goto tr845;
+ case 40: goto tr846;
+ case 41: goto tr847;
+ case 2058: goto tr848;
+ case 2107: goto tr849;
+ case 2314: goto tr850;
+ case 2363: goto tr850;
+ case 2570: goto tr851;
+ case 2619: goto tr852;
+ }
+ goto tr57;
+st233:
+ if ( ++p == pe )
+ goto _test_eof233;
+case 233:
+ switch( (*p) ) {
+ case 83: goto st234;
+ case 115: goto st234;
+ }
+ goto tr36;
+st234:
+ if ( ++p == pe )
+ goto _test_eof234;
+case 234:
+ switch( (*p) ) {
+ case 68: goto st235;
+ case 100: goto st235;
+ }
+ goto tr36;
+st235:
+ if ( ++p == pe )
+ goto _test_eof235;
+case 235:
+ switch( (*p) ) {
+ case 66: goto st236;
+ case 98: goto st236;
+ }
+ goto tr36;
+st236:
+ if ( ++p == pe )
+ goto _test_eof236;
+case 236:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr856;
+ case 32: goto tr856;
+ case 40: goto tr857;
+ case 41: goto tr858;
+ case 2058: goto tr859;
+ case 2107: goto tr860;
+ case 2314: goto tr861;
+ case 2363: goto tr861;
+ case 2570: goto tr862;
+ case 2619: goto tr863;
+ }
+ goto tr57;
+st237:
+ if ( ++p == pe )
+ goto _test_eof237;
+case 237:
+ switch( (*p) ) {
+ case 76: goto st238;
+ case 108: goto st238;
+ }
+ goto tr36;
+st238:
+ if ( ++p == pe )
+ goto _test_eof238;
+case 238:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr865;
+ case 32: goto tr865;
+ case 40: goto tr866;
+ case 41: goto tr867;
+ case 2058: goto tr868;
+ case 2107: goto tr869;
+ case 2314: goto tr870;
+ case 2363: goto tr870;
+ case 2570: goto tr871;
+ case 2619: goto tr872;
+ }
+ goto tr57;
+tr134:
+ {
+ s->buffer_length = 0;
+ }
+ goto st239;
+tr873:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st239;
+tr3629:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st239;
+st239:
+ if ( ++p == pe )
+ goto _test_eof239;
+case 239:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 778: goto tr666;
+ case 1034: goto tr874;
+ }
+ if ( _widec > 895 ) {
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr873;
+ } else if ( _widec >= 640 )
+ goto tr665;
+ goto tr79;
+tr3631:
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 240;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 240;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 240;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 240;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 240;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 240;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 240;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 240;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 240;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 240;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 240;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 240;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 240;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 240;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 240;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 240;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 240;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 240;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 240;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 240;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 240;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 240;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 240;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 240;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 240;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 240;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 240;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 240;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 240;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st240;
+tr136:
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 240;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 240;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 240;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 240;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 240;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 240;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 240;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 240;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 240;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 240;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 240;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 240;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 240;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 240;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 240;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 240;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 240;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 240;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 240;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 240;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 240;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 240;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 240;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 240;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 240;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 240;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 240;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 240;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 240;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st240;
+st240:
+ if ( ++p == pe )
+ goto _test_eof240;
+case 240:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr875;
+ case 32: goto tr875;
+ case 40: goto tr876;
+ case 41: goto tr877;
+ case 778: goto tr878;
+ case 827: goto tr761;
+ case 1034: goto tr878;
+ case 1083: goto tr761;
+ }
+ if ( _widec < 11 ) {
+ if ( _widec <= 8 )
+ goto tr665;
+ } else if ( _widec > 58 ) {
+ if ( 60 <= _widec )
+ goto tr665;
+ } else
+ goto tr665;
+ goto tr79;
+tr879:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st241;
+tr875:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st241;
+tr876:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st241;
+tr877:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st241;
+tr880:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st241;
+tr881:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st241;
+st241:
+ if ( ++p == pe )
+ goto _test_eof241;
+case 241:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr879;
+ case 32: goto tr879;
+ case 40: goto tr880;
+ case 41: goto tr881;
+ case 778: goto tr882;
+ case 827: goto tr765;
+ case 1034: goto tr882;
+ case 1083: goto tr765;
+ }
+ if ( _widec < 11 ) {
+ if ( _widec <= 8 )
+ goto tr665;
+ } else if ( _widec > 58 ) {
+ if ( 60 <= _widec )
+ goto tr665;
+ } else
+ goto tr665;
+ goto tr85;
+tr138:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 242;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 242;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 242;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 242;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 242;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 242;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 242;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 242;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 242;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 242;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 242;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 242;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 242;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 242;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 242;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 242;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 242;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 242;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 242;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 242;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 242;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 242;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 242;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 242;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 242;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 242;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 242;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 242;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 242;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st242;
+tr3633:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 242;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 242;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 242;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 242;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 242;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 242;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 242;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 242;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 242;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 242;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 242;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 242;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 242;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 242;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 242;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 242;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 242;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 242;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 242;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 242;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 242;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 242;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 242;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 242;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 242;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 242;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 242;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 242;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 242;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st242;
+st242:
+ if ( ++p == pe )
+ goto _test_eof242;
+case 242:
+ _widec = (*p);
+ if ( (*p) < 11 ) {
+ if ( (*p) > 9 ) {
+ if ( 10 <= (*p) && (*p) <= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 58 ) {
+ if ( (*p) > 59 ) {
+ if ( 60 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 777: goto tr875;
+ case 778: goto tr878;
+ case 800: goto tr875;
+ case 808: goto tr876;
+ case 809: goto tr877;
+ case 827: goto tr761;
+ case 1033: goto tr883;
+ case 1034: goto tr827;
+ case 1056: goto tr883;
+ case 1064: goto tr884;
+ case 1065: goto tr885;
+ case 1083: goto tr838;
+ }
+ if ( _widec > 895 ) {
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr873;
+ } else if ( _widec >= 640 )
+ goto tr665;
+ goto tr79;
+tr886:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st243;
+tr883:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st243;
+tr884:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st243;
+tr885:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st243;
+tr887:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st243;
+tr888:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st243;
+st243:
+ if ( ++p == pe )
+ goto _test_eof243;
+case 243:
+ _widec = (*p);
+ if ( (*p) < 11 ) {
+ if ( (*p) > 9 ) {
+ if ( 10 <= (*p) && (*p) <= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 58 ) {
+ if ( (*p) > 59 ) {
+ if ( 60 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 777: goto tr879;
+ case 778: goto tr882;
+ case 800: goto tr879;
+ case 808: goto tr880;
+ case 809: goto tr881;
+ case 827: goto tr765;
+ case 1033: goto tr886;
+ case 1034: goto tr756;
+ case 1056: goto tr886;
+ case 1064: goto tr887;
+ case 1065: goto tr888;
+ case 1083: goto tr842;
+ }
+ if ( _widec > 895 ) {
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr873;
+ } else if ( _widec >= 640 )
+ goto tr665;
+ goto tr79;
+tr110:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 244;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 244;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 244;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 244;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 244;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 244;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 244;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 244;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 244;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 244;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 244;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 244;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 244;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 244;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 244;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 244;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 244;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 244;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 244;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 244;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 244;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 244;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 244;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 244;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 244;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 244;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 244;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 244;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 244;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st244;
+tr103:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 244;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 244;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 244;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 244;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 244;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 244;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 244;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 244;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 244;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 244;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 244;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 244;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 244;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 244;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 244;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 244;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 244;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 244;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 244;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 244;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 244;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 244;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 244;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 244;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 244;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 244;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 244;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 244;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 244;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st244;
+tr744:
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 244;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 244;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 244;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 244;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 244;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 244;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 244;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 244;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 244;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 244;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 244;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 244;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 244;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 244;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 244;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 244;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 244;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 244;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 244;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 244;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 244;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 244;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 244;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 244;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 244;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 244;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 244;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 244;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 244;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st244;
+st244:
+ if ( ++p == pe )
+ goto _test_eof244;
+case 244:
+ _widec = (*p);
+ if ( (*p) < 11 ) {
+ if ( (*p) > 9 ) {
+ if ( 10 <= (*p) && (*p) <= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 58 ) {
+ if ( (*p) > 59 ) {
+ if ( 60 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 777: goto tr757;
+ case 778: goto tr760;
+ case 800: goto tr757;
+ case 808: goto tr758;
+ case 809: goto tr759;
+ case 827: goto tr761;
+ case 1033: goto tr889;
+ case 1034: goto tr760;
+ case 1056: goto tr889;
+ case 1064: goto tr890;
+ case 1065: goto tr891;
+ case 1083: goto tr167;
+ }
+ if ( _widec > 895 ) {
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr111;
+ } else if ( _widec >= 640 )
+ goto tr91;
+ goto tr79;
+tr892:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st245;
+tr889:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st245;
+tr890:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st245;
+tr891:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st245;
+tr893:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st245;
+tr894:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st245;
+st245:
+ if ( ++p == pe )
+ goto _test_eof245;
+case 245:
+ _widec = (*p);
+ if ( (*p) < 11 ) {
+ if ( (*p) > 9 ) {
+ if ( 10 <= (*p) && (*p) <= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 58 ) {
+ if ( (*p) > 59 ) {
+ if ( 60 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 777: goto tr762;
+ case 778: goto tr92;
+ case 800: goto tr762;
+ case 808: goto tr763;
+ case 809: goto tr764;
+ case 827: goto tr765;
+ case 1033: goto tr892;
+ case 1034: goto tr92;
+ case 1056: goto tr892;
+ case 1064: goto tr893;
+ case 1065: goto tr894;
+ case 1083: goto tr171;
+ }
+ if ( _widec > 895 ) {
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr111;
+ } else if ( _widec >= 640 )
+ goto tr91;
+ goto tr79;
+tr732:
+ {
+ s->buffer_length = 0;
+ }
+ goto st246;
+tr895:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st246;
+tr725:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ goto st246;
+st246:
+ if ( ++p == pe )
+ goto _test_eof246;
+case 246:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr896;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr895;
+ goto tr71;
+tr733:
+ {
+ s->line_counter++;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 247;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 247;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 247;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 247;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 247;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 247;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 247;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 247;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 247;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 247;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 247;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 247;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 247;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 247;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 247;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 247;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 247;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 247;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 247;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 247;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 247;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 247;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 247;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 247;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 247;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 247;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 247;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 247;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 247;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st247;
+tr726:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ s->line_counter++;
+ }
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 247;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 247;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 247;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 247;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 247;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 247;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 247;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 247;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 247;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 247;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 247;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 247;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 247;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 247;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 247;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 247;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 247;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 247;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 247;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 247;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 247;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 247;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 247;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 247;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 247;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 247;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 247;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 247;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 247;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st247;
+st247:
+ if ( ++p == pe )
+ goto _test_eof247;
+case 247:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr897;
+ case 32: goto tr897;
+ case 40: goto tr898;
+ case 41: goto tr899;
+ case 58: goto tr69;
+ case 65: goto tr118;
+ case 67: goto tr119;
+ case 68: goto tr120;
+ case 69: goto tr121;
+ case 72: goto tr122;
+ case 73: goto tr123;
+ case 75: goto tr124;
+ case 76: goto tr125;
+ case 77: goto tr126;
+ case 78: goto tr127;
+ case 80: goto tr128;
+ case 82: goto tr129;
+ case 83: goto tr130;
+ case 84: goto tr131;
+ case 85: goto tr132;
+ case 92: goto tr74;
+ case 97: goto tr118;
+ case 99: goto tr119;
+ case 100: goto tr120;
+ case 101: goto tr121;
+ case 104: goto tr122;
+ case 105: goto tr123;
+ case 107: goto tr124;
+ case 108: goto tr125;
+ case 109: goto tr126;
+ case 110: goto tr127;
+ case 112: goto tr128;
+ case 114: goto tr129;
+ case 115: goto tr130;
+ case 116: goto tr131;
+ case 117: goto tr132;
+ case 1802: goto tr83;
+ case 1851: goto tr84;
+ case 2058: goto tr824;
+ case 2107: goto tr900;
+ case 2314: goto tr101;
+ case 2363: goto tr102;
+ case 2570: goto tr824;
+ case 2619: goto tr901;
+ }
+ if ( _widec < 11 ) {
+ if ( _widec <= 8 )
+ goto tr69;
+ } else if ( _widec > 47 ) {
+ if ( _widec > 57 ) {
+ if ( 60 <= _widec )
+ goto tr69;
+ } else if ( _widec >= 48 )
+ goto tr117;
+ } else
+ goto tr69;
+ goto tr114;
+tr734:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 248;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 248;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 248;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 248;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 248;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 248;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 248;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 248;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 248;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 248;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 248;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 248;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 248;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 248;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 248;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 248;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 248;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 248;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 248;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 248;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 248;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 248;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 248;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 248;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 248;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 248;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 248;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 248;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 248;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st248;
+tr727:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ { s->r_type = KNOT_RRTYPE_A; }
+ {
+ rdata_tail = s->r_data;
+ }
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = 248;goto st632;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = 248;goto st634;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = 248;goto st636;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = 248;goto st668;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = 248;goto st673;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = 248;goto st678;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = 248;goto st683;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = 248;goto st687;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = 248;goto st689;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = 248;goto st744;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = 248;goto st755;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = 248;goto st772;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = 248;goto st783;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = 248;goto st794;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = 248;goto st807;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = 248;goto st817;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = 248;goto st856;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = 248;goto st1010;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = 248;goto st1013;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = 248;goto st1024;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = 248;goto st1026;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = 248;goto st1055;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = 248;goto st1068;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = 248;goto st1086;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = 248;goto st1081;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = 248;goto st1099;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = 248;goto st1105;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = 248;goto st1111;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = 248;goto st1119;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {goto st268;}
+ }
+ }
+ goto st248;
+st248:
+ if ( ++p == pe )
+ goto _test_eof248;
+case 248:
+ _widec = (*p);
+ if ( (*p) < 11 ) {
+ if ( (*p) > 9 ) {
+ if ( 10 <= (*p) && (*p) <= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 58 ) {
+ if ( (*p) > 59 ) {
+ if ( 60 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 777: goto tr80;
+ case 778: goto tr83;
+ case 800: goto tr80;
+ case 808: goto tr81;
+ case 809: goto tr82;
+ case 827: goto tr84;
+ case 1033: goto tr902;
+ case 1034: goto tr827;
+ case 1056: goto tr902;
+ case 1064: goto tr903;
+ case 1065: goto tr904;
+ case 1083: goto tr838;
+ }
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr895;
+ goto tr79;
+tr905:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st249;
+tr902:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st249;
+tr903:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st249;
+tr904:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st249;
+tr906:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st249;
+tr907:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st249;
+st249:
+ if ( ++p == pe )
+ goto _test_eof249;
+case 249:
+ _widec = (*p);
+ if ( (*p) < 11 ) {
+ if ( (*p) > 9 ) {
+ if ( 10 <= (*p) && (*p) <= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 58 ) {
+ if ( (*p) > 59 ) {
+ if ( 60 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 777: goto st7;
+ case 778: goto tr89;
+ case 800: goto st7;
+ case 808: goto tr87;
+ case 809: goto tr88;
+ case 827: goto tr90;
+ case 1033: goto tr905;
+ case 1034: goto tr756;
+ case 1056: goto tr905;
+ case 1064: goto tr906;
+ case 1065: goto tr907;
+ case 1083: goto tr842;
+ }
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr895;
+ goto tr79;
+tr3639:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 250;goto st270;} }
+ goto st250;
+tr3658:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 250;goto st270;} }
+ goto st250;
+st250:
+ if ( ++p == pe )
+ goto _test_eof250;
+case 250:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr679;
+ case 32: goto tr679;
+ case 40: goto tr680;
+ case 41: goto tr681;
+ case 65: goto st18;
+ case 68: goto st22;
+ case 69: goto st29;
+ case 78: goto st32;
+ case 97: goto st18;
+ case 100: goto st22;
+ case 101: goto st29;
+ case 110: goto st32;
+ case 1034: goto tr682;
+ case 1083: goto tr683;
+ }
+ goto tr908;
+tr3640:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 251;goto st270;} }
+ goto st251;
+tr3659:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 251;goto st270;} }
+ goto st251;
+st251:
+ if ( ++p == pe )
+ goto _test_eof251;
+case 251:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr679;
+ case 32: goto tr679;
+ case 40: goto tr680;
+ case 41: goto tr681;
+ case 72: goto st37;
+ case 78: goto st41;
+ case 83: goto st49;
+ case 104: goto st37;
+ case 110: goto st41;
+ case 115: goto st49;
+ case 1034: goto tr682;
+ case 1083: goto tr683;
+ }
+ goto tr908;
+tr3641:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 252;goto st270;} }
+ goto st252;
+tr3660:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 252;goto st270;} }
+ goto st252;
+st252:
+ if ( ++p == pe )
+ goto _test_eof252;
+case 252:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr679;
+ case 32: goto tr679;
+ case 40: goto tr680;
+ case 41: goto tr681;
+ case 85: goto st51;
+ case 117: goto st51;
+ case 1034: goto tr682;
+ case 1083: goto tr683;
+ }
+ goto tr908;
+tr3642:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 253;goto st270;} }
+ goto st253;
+tr3661:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 253;goto st270;} }
+ goto st253;
+st253:
+ if ( ++p == pe )
+ goto _test_eof253;
+case 253:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr679;
+ case 32: goto tr679;
+ case 40: goto tr680;
+ case 41: goto tr681;
+ case 73: goto st58;
+ case 105: goto st58;
+ case 1034: goto tr682;
+ case 1083: goto tr683;
+ }
+ goto tr908;
+tr3662:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 254;goto st270;} }
+ goto st254;
+st254:
+ if ( ++p == pe )
+ goto _test_eof254;
+case 254:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr679;
+ case 32: goto tr679;
+ case 40: goto tr680;
+ case 41: goto tr681;
+ case 78: goto st144;
+ case 80: goto st66;
+ case 110: goto st144;
+ case 112: goto st66;
+ case 1034: goto tr682;
+ case 1083: goto tr683;
+ }
+ goto tr908;
+tr3644:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 255;goto st270;} }
+ goto st255;
+tr3663:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 255;goto st270;} }
+ goto st255;
+st255:
+ if ( ++p == pe )
+ goto _test_eof255;
+case 255:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr679;
+ case 32: goto tr679;
+ case 40: goto tr680;
+ case 41: goto tr681;
+ case 69: goto st74;
+ case 88: goto st76;
+ case 101: goto st74;
+ case 120: goto st76;
+ case 1034: goto tr682;
+ case 1083: goto tr683;
+ }
+ goto tr908;
+tr3645:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 256;goto st270;} }
+ goto st256;
+tr3664:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 256;goto st270;} }
+ goto st256;
+st256:
+ if ( ++p == pe )
+ goto _test_eof256;
+case 256:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr679;
+ case 32: goto tr679;
+ case 40: goto tr680;
+ case 41: goto tr681;
+ case 51: goto st78;
+ case 54: goto st80;
+ case 79: goto st82;
+ case 80: goto st84;
+ case 111: goto st82;
+ case 112: goto st84;
+ case 1034: goto tr682;
+ case 1083: goto tr683;
+ }
+ goto tr908;
+tr3646:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 257;goto st270;} }
+ goto st257;
+tr3665:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 257;goto st270;} }
+ goto st257;
+st257:
+ if ( ++p == pe )
+ goto _test_eof257;
+case 257:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr679;
+ case 32: goto tr679;
+ case 40: goto tr680;
+ case 41: goto tr681;
+ case 73: goto st86;
+ case 88: goto st90;
+ case 105: goto st86;
+ case 120: goto st90;
+ case 1034: goto tr682;
+ case 1083: goto tr683;
+ }
+ goto tr908;
+tr3647:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 258;goto st270;} }
+ goto st258;
+tr3666:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 258;goto st270;} }
+ goto st258;
+st258:
+ if ( ++p == pe )
+ goto _test_eof258;
+case 258:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr679;
+ case 32: goto tr679;
+ case 40: goto tr680;
+ case 41: goto tr681;
+ case 65: goto st92;
+ case 73: goto st96;
+ case 83: goto st98;
+ case 97: goto st92;
+ case 105: goto st96;
+ case 115: goto st98;
+ case 1034: goto tr682;
+ case 1083: goto tr683;
+ }
+ goto tr908;
+tr3648:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 259;goto st270;} }
+ goto st259;
+tr3667:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 259;goto st270;} }
+ goto st259;
+st259:
+ if ( ++p == pe )
+ goto _test_eof259;
+case 259:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr679;
+ case 32: goto tr679;
+ case 40: goto tr680;
+ case 41: goto tr681;
+ case 84: goto st108;
+ case 116: goto st108;
+ case 1034: goto tr682;
+ case 1083: goto tr683;
+ }
+ goto tr908;
+tr3649:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 260;goto st270;} }
+ goto st260;
+tr3668:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 260;goto st270;} }
+ goto st260;
+st260:
+ if ( ++p == pe )
+ goto _test_eof260;
+case 260:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr679;
+ case 32: goto tr679;
+ case 40: goto tr680;
+ case 41: goto tr681;
+ case 80: goto st111;
+ case 82: goto st112;
+ case 84: goto st116;
+ case 112: goto st111;
+ case 114: goto st112;
+ case 116: goto st116;
+ case 1034: goto tr682;
+ case 1083: goto tr683;
+ }
+ goto tr908;
+tr3650:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 261;goto st270;} }
+ goto st261;
+tr3669:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 261;goto st270;} }
+ goto st261;
+st261:
+ if ( ++p == pe )
+ goto _test_eof261;
+case 261:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr679;
+ case 32: goto tr679;
+ case 40: goto tr680;
+ case 41: goto tr681;
+ case 79: goto st118;
+ case 80: goto st120;
+ case 82: goto st122;
+ case 83: goto st124;
+ case 111: goto st118;
+ case 112: goto st120;
+ case 114: goto st122;
+ case 115: goto st124;
+ case 1034: goto tr682;
+ case 1083: goto tr683;
+ }
+ goto tr908;
+tr3651:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 262;goto st270;} }
+ goto st262;
+tr3670:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 262;goto st270;} }
+ goto st262;
+st262:
+ if ( ++p == pe )
+ goto _test_eof262;
+case 262:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr679;
+ case 32: goto tr679;
+ case 40: goto tr680;
+ case 41: goto tr681;
+ case 76: goto st129;
+ case 88: goto st132;
+ case 89: goto st134;
+ case 108: goto st129;
+ case 120: goto st132;
+ case 121: goto st134;
+ case 1034: goto tr682;
+ case 1083: goto tr683;
+ }
+ goto tr908;
+tr3652:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 263;goto st270;} }
+ goto st263;
+tr3671:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 263;goto st270;} }
+ goto st263;
+st263:
+ if ( ++p == pe )
+ goto _test_eof263;
+case 263:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr679;
+ case 32: goto tr679;
+ case 40: goto tr680;
+ case 41: goto tr681;
+ case 82: goto st139;
+ case 114: goto st139;
+ case 1034: goto tr682;
+ case 1083: goto tr683;
+ }
+ goto tr908;
+tr23:
+ {
+ s->buffer_length = 0;
+ }
+ goto st264;
+tr909:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st264;
+tr3621:
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st264;
+tr3685:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st264;
+tr3681:
+ {
+ NOERR;
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st264;
+st264:
+ if ( ++p == pe )
+ goto _test_eof264;
+case 264:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 778: goto tr666;
+ case 1034: goto tr910;
+ }
+ if ( _widec > 895 ) {
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr909;
+ } else if ( _widec >= 640 )
+ goto tr665;
+ goto tr85;
+tr611:
+ {
+ s->buffer_length = 0;
+ }
+ goto st265;
+tr911:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st265;
+tr3654:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st265;
+st265:
+ if ( ++p == pe )
+ goto _test_eof265;
+case 265:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 778: goto tr666;
+ case 1034: goto tr912;
+ }
+ if ( _widec > 895 ) {
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr911;
+ } else if ( _widec >= 640 )
+ goto tr665;
+ goto tr145;
+tr3643:
+ {
+ s->r_class = s->default_class;
+ }
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ { p--; {stack[top++] = 266;goto st270;} }
+ goto st266;
+st266:
+ if ( ++p == pe )
+ goto _test_eof266;
+case 266:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr679;
+ case 32: goto tr679;
+ case 40: goto tr680;
+ case 41: goto tr681;
+ case 78: goto st63;
+ case 80: goto st66;
+ case 110: goto st63;
+ case 112: goto st66;
+ case 1034: goto tr682;
+ case 1083: goto tr683;
+ }
+ goto tr908;
+tr150:
+ {
+ s->buffer_length = 0;
+ }
+ goto st267;
+tr913:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st267;
+tr144:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st267;
+st267:
+ if ( ++p == pe )
+ goto _test_eof267;
+case 267:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 778: goto tr92;
+ case 1034: goto tr914;
+ }
+ if ( _widec > 895 ) {
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr913;
+ } else if ( _widec >= 640 )
+ goto tr91;
+ goto tr145;
+st268:
+ if ( ++p == pe )
+ goto _test_eof268;
+case 268:
+ if ( (*p) == 10 )
+ goto tr916;
+ goto tr915;
+tr915:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ if ((*p) == '\r') {
+ ERR(ZS_DOS_NEWLINE);
+ }
+
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st269;
+tr917:
+ {
+ if ((*p) == '\r') {
+ ERR(ZS_DOS_NEWLINE);
+ }
+
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st269;
+st269:
+ if ( ++p == pe )
+ goto _test_eof269;
+case 269:
+ if ( (*p) == 10 )
+ goto tr918;
+ goto tr917;
+tr916:
+ cs = 1137;
+ {
+ s->buffer_length = 0;
+ }
+ {
+ // Terminate the error context string.
+ s->buffer[s->buffer_length++] = 0;
+
+ // Error counter incrementation.
+ s->error.counter++;
+
+ // Initialize the fcall stack.
+ top = 0;
+
+ // Reset the multiline context.
+ s->multiline = false;
+
+ s->state = ZS_STATE_ERROR;
+
+ // Execute the error callback.
+ if (s->process.automatic) {
+ if (s->process.error != NULL) {
+ s->process.error(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; goto _out;}
+ }
+ }
+
+ // Stop the scanner if fatal error.
+ if (s->error.fatal) {
+ {p++; goto _out;}
+ }
+ {goto st1127;}
+ } else {
+ // Return if external processing.
+ p--; cs = 1127; {p++; goto _out;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto _again;
+tr918:
+ cs = 1137;
+ {
+ // Terminate the error context string.
+ s->buffer[s->buffer_length++] = 0;
+
+ // Error counter incrementation.
+ s->error.counter++;
+
+ // Initialize the fcall stack.
+ top = 0;
+
+ // Reset the multiline context.
+ s->multiline = false;
+
+ s->state = ZS_STATE_ERROR;
+
+ // Execute the error callback.
+ if (s->process.automatic) {
+ if (s->process.error != NULL) {
+ s->process.error(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; goto _out;}
+ }
+ }
+
+ // Stop the scanner if fatal error.
+ if (s->error.fatal) {
+ {p++; goto _out;}
+ }
+ {goto st1127;}
+ } else {
+ // Return if external processing.
+ p--; cs = 1127; {p++; goto _out;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto _again;
+st1137:
+ if ( ++p == pe )
+ goto _test_eof1137;
+case 1137:
+ goto st0;
+st270:
+ if ( ++p == pe )
+ goto _test_eof270;
+case 270:
+ switch( (*p) ) {
+ case 42: goto tr920;
+ case 46: goto tr921;
+ case 64: goto st278;
+ case 92: goto tr923;
+ case 95: goto tr920;
+ }
+ if ( (*p) < 65 ) {
+ if ( 45 <= (*p) && (*p) <= 57 )
+ goto tr920;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr920;
+ } else
+ goto tr920;
+ goto tr919;
+tr920:
+ {
+ s->item_length_position = 0;
+ s->dname_tmp_length = 0;
+ }
+ {
+ s->item_length = 0;
+ s->item_length_position = s->dname_tmp_length++;
+ }
+ {
+ // Check for maximum dname label length.
+ if (s->item_length < ZS_MAX_LABEL_LENGTH) {
+ (s->dname)[s->dname_tmp_length++] = (*p);
+ s->item_length++;
+ } else {
+ WARN(ZS_LABEL_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st271;
+tr925:
+ {
+ // Check for maximum dname label length.
+ if (s->item_length < ZS_MAX_LABEL_LENGTH) {
+ (s->dname)[s->dname_tmp_length++] = (*p);
+ s->item_length++;
+ } else {
+ WARN(ZS_LABEL_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st271;
+tr929:
+ {
+ s->item_length = 0;
+ s->item_length_position = s->dname_tmp_length++;
+ }
+ {
+ // Check for maximum dname label length.
+ if (s->item_length < ZS_MAX_LABEL_LENGTH) {
+ (s->dname)[s->dname_tmp_length++] = (*p);
+ s->item_length++;
+ } else {
+ WARN(ZS_LABEL_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st271;
+tr936:
+ {
+ s->dname_tmp_length++;
+ }
+ {
+ // Check for maximum dname label length.
+ if (s->item_length < ZS_MAX_LABEL_LENGTH) {
+ (s->dname)[s->dname_tmp_length++] = (*p);
+ s->item_length++;
+ } else {
+ WARN(ZS_LABEL_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st271;
+st271:
+ if ( ++p == pe )
+ goto _test_eof271;
+case 271:
+ switch( (*p) ) {
+ case 32: goto tr924;
+ case 42: goto tr925;
+ case 46: goto tr926;
+ case 59: goto tr924;
+ case 92: goto st273;
+ case 95: goto tr925;
+ }
+ if ( (*p) < 45 ) {
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr924;
+ } else if ( (*p) >= 9 )
+ goto tr924;
+ } else if ( (*p) > 57 ) {
+ if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr925;
+ } else if ( (*p) >= 65 )
+ goto tr925;
+ } else
+ goto tr925;
+ goto tr919;
+tr924:
+ {
+ // Check for maximum dname length overflow after each label.
+ // (at least the next label length must follow).
+ if (s->dname_tmp_length < ZS_MAX_DNAME_LENGTH) {
+ (s->dname)[s->item_length_position] =
+ (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_DNAME_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ // Check for (relative + origin) dname length overflow.
+ if (s->dname_tmp_length + s->zone_origin_length <= ZS_MAX_DNAME_LENGTH) {
+ memcpy(s->dname + s->dname_tmp_length,
+ s->zone_origin,
+ s->zone_origin_length);
+
+ s->dname_tmp_length += s->zone_origin_length;
+ } else {
+ WARN(ZS_DNAME_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1138;
+tr928:
+ {
+ // Enough room for the terminal label is guaranteed (_label_exit).
+ (s->dname)[s->dname_tmp_length++] = 0;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1138;
+tr935:
+ {
+ s->dname_tmp_length++;
+ }
+ {
+ // Check for maximum dname length overflow after each label.
+ // (at least the next label length must follow).
+ if (s->dname_tmp_length < ZS_MAX_DNAME_LENGTH) {
+ (s->dname)[s->item_length_position] =
+ (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_DNAME_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ // Check for (relative + origin) dname length overflow.
+ if (s->dname_tmp_length + s->zone_origin_length <= ZS_MAX_DNAME_LENGTH) {
+ memcpy(s->dname + s->dname_tmp_length,
+ s->zone_origin,
+ s->zone_origin_length);
+
+ s->dname_tmp_length += s->zone_origin_length;
+ } else {
+ WARN(ZS_DNAME_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1138;
+tr939:
+ {
+ // Copy already verified zone origin.
+ memcpy(s->dname,
+ s->zone_origin,
+ s->zone_origin_length);
+
+ s->dname_tmp_length = s->zone_origin_length;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1138;
+st1138:
+ if ( ++p == pe )
+ goto _test_eof1138;
+case 1138:
+ goto st0;
+tr926:
+ {
+ // Check for maximum dname length overflow after each label.
+ // (at least the next label length must follow).
+ if (s->dname_tmp_length < ZS_MAX_DNAME_LENGTH) {
+ (s->dname)[s->item_length_position] =
+ (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_DNAME_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st272;
+tr937:
+ {
+ s->dname_tmp_length++;
+ }
+ {
+ // Check for maximum dname length overflow after each label.
+ // (at least the next label length must follow).
+ if (s->dname_tmp_length < ZS_MAX_DNAME_LENGTH) {
+ (s->dname)[s->item_length_position] =
+ (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_DNAME_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st272;
+st272:
+ if ( ++p == pe )
+ goto _test_eof272;
+case 272:
+ switch( (*p) ) {
+ case 32: goto tr928;
+ case 42: goto tr929;
+ case 45: goto tr929;
+ case 59: goto tr928;
+ case 92: goto tr930;
+ case 95: goto tr929;
+ }
+ if ( (*p) < 47 ) {
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr928;
+ } else if ( (*p) >= 9 )
+ goto tr928;
+ } else if ( (*p) > 57 ) {
+ if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr929;
+ } else if ( (*p) >= 65 )
+ goto tr929;
+ } else
+ goto tr929;
+ goto tr919;
+tr923:
+ {
+ s->item_length_position = 0;
+ s->dname_tmp_length = 0;
+ }
+ {
+ s->item_length = 0;
+ s->item_length_position = s->dname_tmp_length++;
+ }
+ goto st273;
+tr930:
+ {
+ s->item_length = 0;
+ s->item_length_position = s->dname_tmp_length++;
+ }
+ goto st273;
+tr938:
+ {
+ s->dname_tmp_length++;
+ }
+ goto st273;
+st273:
+ if ( ++p == pe )
+ goto _test_eof273;
+case 273:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr931;
+ goto tr925;
+tr931:
+ {
+ if (s->item_length < ZS_MAX_LABEL_LENGTH) {
+ (s->dname)[s->dname_tmp_length] = 0;
+ s->item_length++;
+ } else {
+ WARN(ZS_LABEL_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ (s->dname)[s->dname_tmp_length] *= 10;
+ (s->dname)[s->dname_tmp_length] += digit_to_num[(uint8_t)(*p)];
+ }
+ goto st274;
+st274:
+ if ( ++p == pe )
+ goto _test_eof274;
+case 274:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr933;
+ goto tr932;
+tr933:
+ {
+ (s->dname)[s->dname_tmp_length] *= 10;
+ (s->dname)[s->dname_tmp_length] += digit_to_num[(uint8_t)(*p)];
+ }
+ goto st275;
+st275:
+ if ( ++p == pe )
+ goto _test_eof275;
+case 275:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr934;
+ goto tr932;
+tr934:
+ {
+ (s->dname)[s->dname_tmp_length] *= 10;
+ (s->dname)[s->dname_tmp_length] += digit_to_num[(uint8_t)(*p)];
+ }
+ goto st276;
+st276:
+ if ( ++p == pe )
+ goto _test_eof276;
+case 276:
+ switch( (*p) ) {
+ case 32: goto tr935;
+ case 42: goto tr936;
+ case 46: goto tr937;
+ case 59: goto tr935;
+ case 92: goto tr938;
+ case 95: goto tr936;
+ }
+ if ( (*p) < 45 ) {
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr935;
+ } else if ( (*p) >= 9 )
+ goto tr935;
+ } else if ( (*p) > 57 ) {
+ if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr936;
+ } else if ( (*p) >= 65 )
+ goto tr936;
+ } else
+ goto tr936;
+ goto tr932;
+tr921:
+ {
+ s->item_length_position = 0;
+ s->dname_tmp_length = 0;
+ }
+ goto st277;
+st277:
+ if ( ++p == pe )
+ goto _test_eof277;
+case 277:
+ switch( (*p) ) {
+ case 32: goto tr928;
+ case 59: goto tr928;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr928;
+ } else if ( (*p) >= 9 )
+ goto tr928;
+ goto tr919;
+st278:
+ if ( ++p == pe )
+ goto _test_eof278;
+case 278:
+ switch( (*p) ) {
+ case 32: goto tr939;
+ case 59: goto tr939;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr939;
+ } else if ( (*p) >= 9 )
+ goto tr939;
+ goto tr919;
+st279:
+ if ( ++p == pe )
+ goto _test_eof279;
+case 279:
+ switch( (*p) ) {
+ case 34: goto st285;
+ case 92: goto st281;
+ }
+ if ( (*p) > 58 ) {
+ if ( 60 <= (*p) && (*p) <= 126 )
+ goto tr941;
+ } else if ( (*p) >= 33 )
+ goto tr941;
+ goto tr940;
+tr941:
+ {
+ if (rdata_tail <= rdata_stop) {
+ // Split long string.
+ if (s->long_string &&
+ rdata_tail - s->item_length_location == 1 + MAX_ITEM_LENGTH) {
+ // _item_length_exit equivalent.
+ *(s->item_length_location) = MAX_ITEM_LENGTH;
+ // _item_length_init equivalent.
+ s->item_length_location = rdata_tail++;
+
+ if (rdata_tail > rdata_stop) {
+ WARN(ZS_TEXT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+
+ *(rdata_tail++) = (*p);
+ } else {
+ WARN(ZS_TEXT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st280;
+tr951:
+ {
+ rdata_tail++;
+ }
+ {
+ if (rdata_tail <= rdata_stop) {
+ // Split long string.
+ if (s->long_string &&
+ rdata_tail - s->item_length_location == 1 + MAX_ITEM_LENGTH) {
+ // _item_length_exit equivalent.
+ *(s->item_length_location) = MAX_ITEM_LENGTH;
+ // _item_length_init equivalent.
+ s->item_length_location = rdata_tail++;
+
+ if (rdata_tail > rdata_stop) {
+ WARN(ZS_TEXT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+
+ *(rdata_tail++) = (*p);
+ } else {
+ WARN(ZS_TEXT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st280;
+st280:
+ if ( ++p == pe )
+ goto _test_eof280;
+case 280:
+ switch( (*p) ) {
+ case 32: goto tr944;
+ case 33: goto tr941;
+ case 59: goto tr944;
+ case 92: goto st281;
+ }
+ if ( (*p) < 35 ) {
+ if ( 9 <= (*p) && (*p) <= 10 )
+ goto tr944;
+ } else if ( (*p) > 39 ) {
+ if ( (*p) > 41 ) {
+ if ( 42 <= (*p) && (*p) <= 126 )
+ goto tr941;
+ } else if ( (*p) >= 40 )
+ goto tr945;
+ } else
+ goto tr941;
+ goto tr940;
+tr944:
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1139;
+tr950:
+ {
+ rdata_tail++;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1139;
+st1139:
+ if ( ++p == pe )
+ goto _test_eof1139;
+case 1139:
+ goto st0;
+tr945:
+ {
+ if (rdata_tail <= rdata_stop) {
+ // Split long string.
+ if (s->long_string &&
+ rdata_tail - s->item_length_location == 1 + MAX_ITEM_LENGTH) {
+ // _item_length_exit equivalent.
+ *(s->item_length_location) = MAX_ITEM_LENGTH;
+ // _item_length_init equivalent.
+ s->item_length_location = rdata_tail++;
+
+ if (rdata_tail > rdata_stop) {
+ WARN(ZS_TEXT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+
+ *(rdata_tail++) = (*p);
+ } else {
+ WARN(ZS_TEXT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1140;
+tr952:
+ {
+ rdata_tail++;
+ }
+ {
+ if (rdata_tail <= rdata_stop) {
+ // Split long string.
+ if (s->long_string &&
+ rdata_tail - s->item_length_location == 1 + MAX_ITEM_LENGTH) {
+ // _item_length_exit equivalent.
+ *(s->item_length_location) = MAX_ITEM_LENGTH;
+ // _item_length_init equivalent.
+ s->item_length_location = rdata_tail++;
+
+ if (rdata_tail > rdata_stop) {
+ WARN(ZS_TEXT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+
+ *(rdata_tail++) = (*p);
+ } else {
+ WARN(ZS_TEXT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1140;
+st1140:
+ if ( ++p == pe )
+ goto _test_eof1140;
+case 1140:
+ switch( (*p) ) {
+ case 32: goto tr944;
+ case 33: goto tr941;
+ case 59: goto tr944;
+ case 92: goto st281;
+ }
+ if ( (*p) < 35 ) {
+ if ( 9 <= (*p) && (*p) <= 10 )
+ goto tr944;
+ } else if ( (*p) > 39 ) {
+ if ( (*p) > 41 ) {
+ if ( 42 <= (*p) && (*p) <= 126 )
+ goto tr941;
+ } else if ( (*p) >= 40 )
+ goto tr945;
+ } else
+ goto tr941;
+ goto tr940;
+tr953:
+ {
+ rdata_tail++;
+ }
+ goto st281;
+st281:
+ if ( ++p == pe )
+ goto _test_eof281;
+case 281:
+ if ( (*p) < 48 ) {
+ if ( 32 <= (*p) && (*p) <= 47 )
+ goto tr941;
+ } else if ( (*p) > 57 ) {
+ if ( 58 <= (*p) && (*p) <= 126 )
+ goto tr941;
+ } else
+ goto tr947;
+ goto tr946;
+tr947:
+ {
+ if (rdata_tail <= rdata_stop) {
+ // Split long string.
+ if (s->long_string &&
+ rdata_tail - s->item_length_location == 1 + MAX_ITEM_LENGTH) {
+ // _item_length_exit equivalent.
+ *(s->item_length_location) = MAX_ITEM_LENGTH;
+ // _item_length_init equivalent.
+ s->item_length_location = rdata_tail++;
+
+ if (rdata_tail > rdata_stop) {
+ WARN(ZS_TEXT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+
+ *rdata_tail = 0;
+ s->item_length++;
+ } else {
+ WARN(ZS_TEXT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if ((*rdata_tail < (UINT8_MAX / 10)) || // Dominant fast check.
+ ((*rdata_tail == (UINT8_MAX / 10)) && // Marginal case.
+ ((*p) <= (UINT8_MAX % 10) + '0')
+ )
+ ) {
+ *rdata_tail *= 10;
+ *rdata_tail += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st282;
+st282:
+ if ( ++p == pe )
+ goto _test_eof282;
+case 282:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr948;
+ goto tr946;
+tr948:
+ {
+ if ((*rdata_tail < (UINT8_MAX / 10)) || // Dominant fast check.
+ ((*rdata_tail == (UINT8_MAX / 10)) && // Marginal case.
+ ((*p) <= (UINT8_MAX % 10) + '0')
+ )
+ ) {
+ *rdata_tail *= 10;
+ *rdata_tail += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st283;
+st283:
+ if ( ++p == pe )
+ goto _test_eof283;
+case 283:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr949;
+ goto tr946;
+tr949:
+ {
+ if ((*rdata_tail < (UINT8_MAX / 10)) || // Dominant fast check.
+ ((*rdata_tail == (UINT8_MAX / 10)) && // Marginal case.
+ ((*p) <= (UINT8_MAX % 10) + '0')
+ )
+ ) {
+ *rdata_tail *= 10;
+ *rdata_tail += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st284;
+st284:
+ if ( ++p == pe )
+ goto _test_eof284;
+case 284:
+ switch( (*p) ) {
+ case 32: goto tr950;
+ case 33: goto tr951;
+ case 59: goto tr950;
+ case 92: goto tr953;
+ }
+ if ( (*p) < 35 ) {
+ if ( 9 <= (*p) && (*p) <= 10 )
+ goto tr950;
+ } else if ( (*p) > 39 ) {
+ if ( (*p) > 41 ) {
+ if ( 42 <= (*p) && (*p) <= 126 )
+ goto tr951;
+ } else if ( (*p) >= 40 )
+ goto tr952;
+ } else
+ goto tr951;
+ goto tr946;
+tr954:
+ {
+ if (rdata_tail <= rdata_stop) {
+ // Split long string.
+ if (s->long_string &&
+ rdata_tail - s->item_length_location == 1 + MAX_ITEM_LENGTH) {
+ // _item_length_exit equivalent.
+ *(s->item_length_location) = MAX_ITEM_LENGTH;
+ // _item_length_init equivalent.
+ s->item_length_location = rdata_tail++;
+
+ if (rdata_tail > rdata_stop) {
+ WARN(ZS_TEXT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+
+ *(rdata_tail++) = (*p);
+ } else {
+ WARN(ZS_TEXT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st285;
+tr961:
+ {
+ rdata_tail++;
+ }
+ {
+ if (rdata_tail <= rdata_stop) {
+ // Split long string.
+ if (s->long_string &&
+ rdata_tail - s->item_length_location == 1 + MAX_ITEM_LENGTH) {
+ // _item_length_exit equivalent.
+ *(s->item_length_location) = MAX_ITEM_LENGTH;
+ // _item_length_init equivalent.
+ s->item_length_location = rdata_tail++;
+
+ if (rdata_tail > rdata_stop) {
+ WARN(ZS_TEXT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+
+ *(rdata_tail++) = (*p);
+ } else {
+ WARN(ZS_TEXT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st285;
+st285:
+ if ( ++p == pe )
+ goto _test_eof285;
+case 285:
+ _widec = (*p);
+ if ( 10 <= (*p) && (*p) <= 10 ) {
+ _widec = (short)(128 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr954;
+ case 34: goto st286;
+ case 92: goto st287;
+ case 522: goto tr954;
+ }
+ if ( 32 <= _widec && _widec <= 126 )
+ goto tr954;
+ goto tr940;
+tr962:
+ {
+ rdata_tail++;
+ }
+ goto st286;
+st286:
+ if ( ++p == pe )
+ goto _test_eof286;
+case 286:
+ switch( (*p) ) {
+ case 32: goto tr944;
+ case 59: goto tr944;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr944;
+ } else if ( (*p) >= 9 )
+ goto tr944;
+ goto tr957;
+tr963:
+ {
+ rdata_tail++;
+ }
+ goto st287;
+st287:
+ if ( ++p == pe )
+ goto _test_eof287;
+case 287:
+ if ( (*p) < 48 ) {
+ if ( 32 <= (*p) && (*p) <= 47 )
+ goto tr954;
+ } else if ( (*p) > 57 ) {
+ if ( 58 <= (*p) && (*p) <= 126 )
+ goto tr954;
+ } else
+ goto tr958;
+ goto tr946;
+tr958:
+ {
+ if (rdata_tail <= rdata_stop) {
+ // Split long string.
+ if (s->long_string &&
+ rdata_tail - s->item_length_location == 1 + MAX_ITEM_LENGTH) {
+ // _item_length_exit equivalent.
+ *(s->item_length_location) = MAX_ITEM_LENGTH;
+ // _item_length_init equivalent.
+ s->item_length_location = rdata_tail++;
+
+ if (rdata_tail > rdata_stop) {
+ WARN(ZS_TEXT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+
+ *rdata_tail = 0;
+ s->item_length++;
+ } else {
+ WARN(ZS_TEXT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if ((*rdata_tail < (UINT8_MAX / 10)) || // Dominant fast check.
+ ((*rdata_tail == (UINT8_MAX / 10)) && // Marginal case.
+ ((*p) <= (UINT8_MAX % 10) + '0')
+ )
+ ) {
+ *rdata_tail *= 10;
+ *rdata_tail += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st288;
+st288:
+ if ( ++p == pe )
+ goto _test_eof288;
+case 288:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr959;
+ goto tr946;
+tr959:
+ {
+ if ((*rdata_tail < (UINT8_MAX / 10)) || // Dominant fast check.
+ ((*rdata_tail == (UINT8_MAX / 10)) && // Marginal case.
+ ((*p) <= (UINT8_MAX % 10) + '0')
+ )
+ ) {
+ *rdata_tail *= 10;
+ *rdata_tail += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st289;
+st289:
+ if ( ++p == pe )
+ goto _test_eof289;
+case 289:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr960;
+ goto tr946;
+tr960:
+ {
+ if ((*rdata_tail < (UINT8_MAX / 10)) || // Dominant fast check.
+ ((*rdata_tail == (UINT8_MAX / 10)) && // Marginal case.
+ ((*p) <= (UINT8_MAX % 10) + '0')
+ )
+ ) {
+ *rdata_tail *= 10;
+ *rdata_tail += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st290;
+st290:
+ if ( ++p == pe )
+ goto _test_eof290;
+case 290:
+ _widec = (*p);
+ if ( 10 <= (*p) && (*p) <= 10 ) {
+ _widec = (short)(128 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr961;
+ case 34: goto tr962;
+ case 92: goto tr963;
+ case 522: goto tr961;
+ }
+ if ( 32 <= _widec && _widec <= 126 )
+ goto tr961;
+ goto tr946;
+st291:
+ if ( ++p == pe )
+ goto _test_eof291;
+case 291:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st292;
+ case 32: goto st292;
+ case 40: goto tr966;
+ case 41: goto tr967;
+ case 1034: goto tr968;
+ case 1083: goto tr969;
+ }
+ goto tr964;
+tr966:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st292;
+tr967:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st292;
+tr968:
+ {
+ s->line_counter++;
+ }
+ goto st292;
+tr1007:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st292;
+st292:
+ if ( ++p == pe )
+ goto _test_eof292;
+case 292:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st292;
+ case 32: goto st292;
+ case 40: goto tr966;
+ case 41: goto tr967;
+ case 1034: goto tr968;
+ case 1083: goto tr969;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr971;
+ goto tr970;
+tr971:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st293;
+tr976:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st293;
+st293:
+ if ( ++p == pe )
+ goto _test_eof293;
+case 293:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr973;
+ case 32: goto tr973;
+ case 40: goto tr974;
+ case 41: goto tr975;
+ case 68: goto tr977;
+ case 72: goto tr978;
+ case 77: goto tr979;
+ case 83: goto st296;
+ case 87: goto tr981;
+ case 100: goto tr977;
+ case 104: goto tr978;
+ case 109: goto tr979;
+ case 115: goto st296;
+ case 119: goto tr981;
+ case 778: goto tr982;
+ case 827: goto tr983;
+ case 1034: goto tr982;
+ case 1083: goto tr983;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr976;
+ goto tr972;
+tr986:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st294;
+tr987:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st294;
+tr973:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st294;
+tr974:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st294;
+tr975:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st294;
+tr1000:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st294;
+tr1001:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st294;
+tr1002:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st294;
+st294:
+ if ( ++p == pe )
+ goto _test_eof294;
+case 294:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st294;
+ case 32: goto st294;
+ case 40: goto tr986;
+ case 41: goto tr987;
+ case 778: goto tr988;
+ case 827: goto tr989;
+ case 1034: goto tr988;
+ case 1083: goto tr989;
+ }
+ goto tr984;
+tr982:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->default_ttl = (uint32_t)(s->number64);
+ } else {
+ ERR(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1141;
+tr988:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->default_ttl = (uint32_t)(s->number64);
+ } else {
+ ERR(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1141;
+tr991:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->default_ttl = (uint32_t)(s->number64);
+ } else {
+ ERR(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1141;
+tr1004:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->default_ttl = (uint32_t)(s->number64);
+ } else {
+ ERR(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1141;
+st1141:
+ if ( ++p == pe )
+ goto _test_eof1141;
+case 1141:
+ goto st0;
+tr989:
+ {
+ s->buffer_length = 0;
+ }
+ goto st295;
+tr983:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st295;
+tr990:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st295;
+tr1005:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st295;
+st295:
+ if ( ++p == pe )
+ goto _test_eof295;
+case 295:
+ if ( (*p) == 10 )
+ goto tr991;
+ goto tr990;
+tr977:
+ { if (s->number64 <= (UINT32_MAX / 86400)) {
+ s->number64 *= 86400;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st296;
+tr978:
+ { if (s->number64 <= (UINT32_MAX / 3600)) {
+ s->number64 *= 3600;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st296;
+tr979:
+ { if (s->number64 <= (UINT32_MAX / 60)) {
+ s->number64 *= 60;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st296;
+tr981:
+ { if (s->number64 <= (UINT32_MAX / 604800)) {
+ s->number64 *= 604800;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st296;
+st296:
+ if ( ++p == pe )
+ goto _test_eof296;
+case 296:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr973;
+ case 32: goto tr973;
+ case 40: goto tr974;
+ case 41: goto tr975;
+ case 778: goto tr982;
+ case 827: goto tr983;
+ case 1034: goto tr982;
+ case 1083: goto tr983;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr992;
+ goto tr972;
+tr994:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st297;
+tr992:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st297;
+tr1003:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st297;
+st297:
+ if ( ++p == pe )
+ goto _test_eof297;
+case 297:
+ switch( (*p) ) {
+ case 68: goto tr995;
+ case 72: goto tr996;
+ case 77: goto tr997;
+ case 83: goto st298;
+ case 87: goto tr999;
+ case 100: goto tr995;
+ case 104: goto tr996;
+ case 109: goto tr997;
+ case 115: goto st298;
+ case 119: goto tr999;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr994;
+ goto tr993;
+tr995:
+ { if (s->number64 <= (UINT32_MAX / 86400)) {
+ s->number64 *= 86400;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st298;
+tr996:
+ { if (s->number64 <= (UINT32_MAX / 3600)) {
+ s->number64 *= 3600;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st298;
+tr997:
+ { if (s->number64 <= (UINT32_MAX / 60)) {
+ s->number64 *= 60;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st298;
+tr999:
+ { if (s->number64 <= (UINT32_MAX / 604800)) {
+ s->number64 *= 604800;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st298;
+st298:
+ if ( ++p == pe )
+ goto _test_eof298;
+case 298:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr1000;
+ case 32: goto tr1000;
+ case 40: goto tr1001;
+ case 41: goto tr1002;
+ case 778: goto tr1004;
+ case 827: goto tr1005;
+ case 1034: goto tr1004;
+ case 1083: goto tr1005;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr1003;
+ goto tr972;
+tr969:
+ {
+ s->buffer_length = 0;
+ }
+ goto st299;
+tr1006:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st299;
+st299:
+ if ( ++p == pe )
+ goto _test_eof299;
+case 299:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr1007;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr1006;
+ goto tr964;
+st300:
+ if ( ++p == pe )
+ goto _test_eof300;
+case 300:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st301;
+ case 32: goto st301;
+ case 40: goto tr1010;
+ case 41: goto tr1011;
+ case 1034: goto tr1012;
+ case 1083: goto tr1013;
+ }
+ goto tr1008;
+tr1010:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st301;
+tr1011:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st301;
+tr1012:
+ {
+ s->line_counter++;
+ }
+ goto st301;
+tr1043:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st301;
+st301:
+ if ( ++p == pe )
+ goto _test_eof301;
+case 301:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st301;
+ case 32: goto st301;
+ case 40: goto tr1010;
+ case 41: goto tr1011;
+ case 42: goto tr1014;
+ case 46: goto tr1015;
+ case 92: goto tr1016;
+ case 95: goto tr1014;
+ case 1034: goto tr1012;
+ case 1083: goto tr1013;
+ }
+ if ( _widec < 65 ) {
+ if ( 45 <= _widec && _widec <= 57 )
+ goto tr1014;
+ } else if ( _widec > 90 ) {
+ if ( 97 <= _widec && _widec <= 122 )
+ goto tr1014;
+ } else
+ goto tr1014;
+ goto tr1008;
+tr1017:
+ {
+ // Check for maximum dname label length.
+ if (s->item_length < ZS_MAX_LABEL_LENGTH) {
+ (s->dname)[s->dname_tmp_length++] = (*p);
+ s->item_length++;
+ } else {
+ WARN(ZS_LABEL_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st302;
+tr1024:
+ {
+ s->item_length = 0;
+ s->item_length_position = s->dname_tmp_length++;
+ }
+ {
+ // Check for maximum dname label length.
+ if (s->item_length < ZS_MAX_LABEL_LENGTH) {
+ (s->dname)[s->dname_tmp_length++] = (*p);
+ s->item_length++;
+ } else {
+ WARN(ZS_LABEL_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st302;
+tr1039:
+ {
+ s->dname_tmp_length++;
+ }
+ {
+ // Check for maximum dname label length.
+ if (s->item_length < ZS_MAX_LABEL_LENGTH) {
+ (s->dname)[s->dname_tmp_length++] = (*p);
+ s->item_length++;
+ } else {
+ WARN(ZS_LABEL_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st302;
+tr1014:
+ {
+ s->dname = s->zone_origin;
+ }
+ {
+ s->item_length_position = 0;
+ s->dname_tmp_length = 0;
+ }
+ {
+ s->item_length = 0;
+ s->item_length_position = s->dname_tmp_length++;
+ }
+ {
+ // Check for maximum dname label length.
+ if (s->item_length < ZS_MAX_LABEL_LENGTH) {
+ (s->dname)[s->dname_tmp_length++] = (*p);
+ s->item_length++;
+ } else {
+ WARN(ZS_LABEL_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st302;
+st302:
+ if ( ++p == pe )
+ goto _test_eof302;
+case 302:
+ switch( (*p) ) {
+ case 42: goto tr1017;
+ case 46: goto tr1018;
+ case 92: goto st306;
+ case 95: goto tr1017;
+ }
+ if ( (*p) < 65 ) {
+ if ( 45 <= (*p) && (*p) <= 57 )
+ goto tr1017;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr1017;
+ } else
+ goto tr1017;
+ goto tr1008;
+tr1018:
+ {
+ // Check for maximum dname length overflow after each label.
+ // (at least the next label length must follow).
+ if (s->dname_tmp_length < ZS_MAX_DNAME_LENGTH) {
+ (s->dname)[s->item_length_position] =
+ (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_DNAME_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st303;
+tr1040:
+ {
+ s->dname_tmp_length++;
+ }
+ {
+ // Check for maximum dname length overflow after each label.
+ // (at least the next label length must follow).
+ if (s->dname_tmp_length < ZS_MAX_DNAME_LENGTH) {
+ (s->dname)[s->item_length_position] =
+ (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_DNAME_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st303;
+st303:
+ if ( ++p == pe )
+ goto _test_eof303;
+case 303:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr1021;
+ case 32: goto tr1021;
+ case 40: goto tr1022;
+ case 41: goto tr1023;
+ case 42: goto tr1024;
+ case 45: goto tr1024;
+ case 92: goto tr1025;
+ case 95: goto tr1024;
+ case 778: goto tr1026;
+ case 827: goto tr1027;
+ case 1034: goto tr1026;
+ case 1083: goto tr1027;
+ }
+ if ( _widec < 65 ) {
+ if ( 47 <= _widec && _widec <= 57 )
+ goto tr1024;
+ } else if ( _widec > 90 ) {
+ if ( 97 <= _widec && _widec <= 122 )
+ goto tr1024;
+ } else
+ goto tr1024;
+ goto tr1020;
+tr1029:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st304;
+tr1030:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st304;
+tr1021:
+ {
+ // Enough room for the terminal label is guaranteed (_label_exit).
+ (s->dname)[s->dname_tmp_length++] = 0;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st304;
+tr1022:
+ {
+ // Enough room for the terminal label is guaranteed (_label_exit).
+ (s->dname)[s->dname_tmp_length++] = 0;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st304;
+tr1023:
+ {
+ // Enough room for the terminal label is guaranteed (_label_exit).
+ (s->dname)[s->dname_tmp_length++] = 0;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st304;
+st304:
+ if ( ++p == pe )
+ goto _test_eof304;
+case 304:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st304;
+ case 32: goto st304;
+ case 40: goto tr1029;
+ case 41: goto tr1030;
+ case 778: goto tr1031;
+ case 827: goto tr1032;
+ case 1034: goto tr1031;
+ case 1083: goto tr1032;
+ }
+ goto tr1020;
+tr1026:
+ {
+ // Enough room for the terminal label is guaranteed (_label_exit).
+ (s->dname)[s->dname_tmp_length++] = 0;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ s->zone_origin_length = s->dname_tmp_length;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1142;
+tr1031:
+ {
+ s->zone_origin_length = s->dname_tmp_length;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1142;
+tr1034:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->zone_origin_length = s->dname_tmp_length;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1142;
+st1142:
+ if ( ++p == pe )
+ goto _test_eof1142;
+case 1142:
+ goto st0;
+tr1032:
+ {
+ s->buffer_length = 0;
+ }
+ goto st305;
+tr1033:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st305;
+tr1027:
+ {
+ // Enough room for the terminal label is guaranteed (_label_exit).
+ (s->dname)[s->dname_tmp_length++] = 0;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st305;
+st305:
+ if ( ++p == pe )
+ goto _test_eof305;
+case 305:
+ if ( (*p) == 10 )
+ goto tr1034;
+ goto tr1033;
+tr1025:
+ {
+ s->item_length = 0;
+ s->item_length_position = s->dname_tmp_length++;
+ }
+ goto st306;
+tr1041:
+ {
+ s->dname_tmp_length++;
+ }
+ goto st306;
+tr1016:
+ {
+ s->dname = s->zone_origin;
+ }
+ {
+ s->item_length_position = 0;
+ s->dname_tmp_length = 0;
+ }
+ {
+ s->item_length = 0;
+ s->item_length_position = s->dname_tmp_length++;
+ }
+ goto st306;
+st306:
+ if ( ++p == pe )
+ goto _test_eof306;
+case 306:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr1035;
+ goto tr1017;
+tr1035:
+ {
+ if (s->item_length < ZS_MAX_LABEL_LENGTH) {
+ (s->dname)[s->dname_tmp_length] = 0;
+ s->item_length++;
+ } else {
+ WARN(ZS_LABEL_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ (s->dname)[s->dname_tmp_length] *= 10;
+ (s->dname)[s->dname_tmp_length] += digit_to_num[(uint8_t)(*p)];
+ }
+ goto st307;
+st307:
+ if ( ++p == pe )
+ goto _test_eof307;
+case 307:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr1037;
+ goto tr1036;
+tr1037:
+ {
+ (s->dname)[s->dname_tmp_length] *= 10;
+ (s->dname)[s->dname_tmp_length] += digit_to_num[(uint8_t)(*p)];
+ }
+ goto st308;
+st308:
+ if ( ++p == pe )
+ goto _test_eof308;
+case 308:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr1038;
+ goto tr1036;
+tr1038:
+ {
+ (s->dname)[s->dname_tmp_length] *= 10;
+ (s->dname)[s->dname_tmp_length] += digit_to_num[(uint8_t)(*p)];
+ }
+ goto st309;
+st309:
+ if ( ++p == pe )
+ goto _test_eof309;
+case 309:
+ switch( (*p) ) {
+ case 42: goto tr1039;
+ case 46: goto tr1040;
+ case 92: goto tr1041;
+ case 95: goto tr1039;
+ }
+ if ( (*p) < 65 ) {
+ if ( 45 <= (*p) && (*p) <= 57 )
+ goto tr1039;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr1039;
+ } else
+ goto tr1039;
+ goto tr1036;
+tr1015:
+ {
+ s->dname = s->zone_origin;
+ }
+ {
+ s->item_length_position = 0;
+ s->dname_tmp_length = 0;
+ }
+ goto st310;
+st310:
+ if ( ++p == pe )
+ goto _test_eof310;
+case 310:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr1021;
+ case 32: goto tr1021;
+ case 40: goto tr1022;
+ case 41: goto tr1023;
+ case 778: goto tr1026;
+ case 827: goto tr1027;
+ case 1034: goto tr1026;
+ case 1083: goto tr1027;
+ }
+ goto tr1020;
+tr1013:
+ {
+ s->buffer_length = 0;
+ }
+ goto st311;
+tr1042:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st311;
+st311:
+ if ( ++p == pe )
+ goto _test_eof311;
+case 311:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr1043;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr1042;
+ goto tr1008;
+st312:
+ if ( ++p == pe )
+ goto _test_eof312;
+case 312:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st313;
+ case 32: goto st313;
+ case 40: goto tr1045;
+ case 41: goto tr1046;
+ case 1034: goto tr1047;
+ case 1083: goto tr1048;
+ }
+ goto st0;
+tr1045:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st313;
+tr1046:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st313;
+tr1047:
+ {
+ s->line_counter++;
+ }
+ goto st313;
+tr1101:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st313;
+st313:
+ if ( ++p == pe )
+ goto _test_eof313;
+case 313:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st313;
+ case 32: goto st313;
+ case 40: goto tr1045;
+ case 41: goto tr1046;
+ case 1034: goto tr1047;
+ case 1083: goto tr1048;
+ }
+ if ( _widec < 11 ) {
+ if ( _widec <= 8 )
+ goto tr1049;
+ } else if ( _widec > 58 ) {
+ if ( 60 <= _widec )
+ goto tr1049;
+ } else
+ goto tr1049;
+ goto tr1050;
+tr1049:
+ {
+ rdata_tail = s->r_data;
+ }
+ { p--; {stack[top++] = 314;goto st279;} }
+ goto st314;
+st314:
+ if ( ++p == pe )
+ goto _test_eof314;
+case 314:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr1052;
+ case 32: goto tr1052;
+ case 40: goto tr1053;
+ case 41: goto tr1054;
+ case 778: goto tr1055;
+ case 827: goto tr1056;
+ case 1034: goto tr1055;
+ case 1083: goto tr1057;
+ }
+ goto tr1051;
+tr1060:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st315;
+tr1061:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st315;
+tr1052:
+ {
+ size_t len = rdata_tail - s->r_data;
+ if (len >= sizeof(s->include_filename)) {
+ ERR(ZS_BAD_INCLUDE_FILENAME);
+ p--; {goto st268;}
+ }
+
+ // Store zero terminated include filename.
+ memcpy(s->include_filename, s->r_data, len);
+ s->include_filename[len] = '\0';
+
+ // For detection whether origin is not present.
+ s->dname = NULL;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st315;
+tr1053:
+ {
+ size_t len = rdata_tail - s->r_data;
+ if (len >= sizeof(s->include_filename)) {
+ ERR(ZS_BAD_INCLUDE_FILENAME);
+ p--; {goto st268;}
+ }
+
+ // Store zero terminated include filename.
+ memcpy(s->include_filename, s->r_data, len);
+ s->include_filename[len] = '\0';
+
+ // For detection whether origin is not present.
+ s->dname = NULL;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st315;
+tr1054:
+ {
+ size_t len = rdata_tail - s->r_data;
+ if (len >= sizeof(s->include_filename)) {
+ ERR(ZS_BAD_INCLUDE_FILENAME);
+ p--; {goto st268;}
+ }
+
+ // Store zero terminated include filename.
+ memcpy(s->include_filename, s->r_data, len);
+ s->include_filename[len] = '\0';
+
+ // For detection whether origin is not present.
+ s->dname = NULL;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st315;
+st315:
+ if ( ++p == pe )
+ goto _test_eof315;
+case 315:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st315;
+ case 32: goto st315;
+ case 40: goto tr1060;
+ case 41: goto tr1061;
+ case 42: goto tr1062;
+ case 46: goto tr1063;
+ case 92: goto tr1064;
+ case 95: goto tr1062;
+ case 778: goto tr1065;
+ case 827: goto tr1066;
+ case 1034: goto tr1065;
+ case 1083: goto tr1067;
+ }
+ if ( _widec < 65 ) {
+ if ( 45 <= _widec && _widec <= 57 )
+ goto tr1062;
+ } else if ( _widec > 90 ) {
+ if ( 97 <= _widec && _widec <= 122 )
+ goto tr1062;
+ } else
+ goto tr1062;
+ goto tr1058;
+tr1069:
+ {
+ // Check for maximum dname label length.
+ if (s->item_length < ZS_MAX_LABEL_LENGTH) {
+ (s->dname)[s->dname_tmp_length++] = (*p);
+ s->item_length++;
+ } else {
+ WARN(ZS_LABEL_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st316;
+tr1075:
+ {
+ s->item_length = 0;
+ s->item_length_position = s->dname_tmp_length++;
+ }
+ {
+ // Check for maximum dname label length.
+ if (s->item_length < ZS_MAX_LABEL_LENGTH) {
+ (s->dname)[s->dname_tmp_length++] = (*p);
+ s->item_length++;
+ } else {
+ WARN(ZS_LABEL_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st316;
+tr1088:
+ {
+ s->dname_tmp_length++;
+ }
+ {
+ // Check for maximum dname label length.
+ if (s->item_length < ZS_MAX_LABEL_LENGTH) {
+ (s->dname)[s->dname_tmp_length++] = (*p);
+ s->item_length++;
+ } else {
+ WARN(ZS_LABEL_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st316;
+tr1062:
+ {
+ s->dname = s->r_data;
+ }
+ {
+ s->item_length_position = 0;
+ s->dname_tmp_length = 0;
+ }
+ {
+ s->item_length = 0;
+ s->item_length_position = s->dname_tmp_length++;
+ }
+ {
+ // Check for maximum dname label length.
+ if (s->item_length < ZS_MAX_LABEL_LENGTH) {
+ (s->dname)[s->dname_tmp_length++] = (*p);
+ s->item_length++;
+ } else {
+ WARN(ZS_LABEL_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st316;
+st316:
+ if ( ++p == pe )
+ goto _test_eof316;
+case 316:
+ switch( (*p) ) {
+ case 42: goto tr1069;
+ case 46: goto tr1070;
+ case 92: goto st320;
+ case 95: goto tr1069;
+ }
+ if ( (*p) < 65 ) {
+ if ( 45 <= (*p) && (*p) <= 57 )
+ goto tr1069;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr1069;
+ } else
+ goto tr1069;
+ goto tr1068;
+tr1070:
+ {
+ // Check for maximum dname length overflow after each label.
+ // (at least the next label length must follow).
+ if (s->dname_tmp_length < ZS_MAX_DNAME_LENGTH) {
+ (s->dname)[s->item_length_position] =
+ (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_DNAME_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st317;
+tr1089:
+ {
+ s->dname_tmp_length++;
+ }
+ {
+ // Check for maximum dname length overflow after each label.
+ // (at least the next label length must follow).
+ if (s->dname_tmp_length < ZS_MAX_DNAME_LENGTH) {
+ (s->dname)[s->item_length_position] =
+ (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_DNAME_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st317;
+st317:
+ if ( ++p == pe )
+ goto _test_eof317;
+case 317:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr1072;
+ case 32: goto tr1072;
+ case 40: goto tr1073;
+ case 41: goto tr1074;
+ case 42: goto tr1075;
+ case 45: goto tr1075;
+ case 92: goto tr1076;
+ case 95: goto tr1075;
+ case 778: goto tr1077;
+ case 827: goto tr1078;
+ case 1034: goto tr1077;
+ case 1083: goto tr1078;
+ }
+ if ( _widec < 65 ) {
+ if ( 47 <= _widec && _widec <= 57 )
+ goto tr1075;
+ } else if ( _widec > 90 ) {
+ if ( 97 <= _widec && _widec <= 122 )
+ goto tr1075;
+ } else
+ goto tr1075;
+ goto tr1058;
+tr1080:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st318;
+tr1081:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st318;
+tr1072:
+ {
+ // Enough room for the terminal label is guaranteed (_label_exit).
+ (s->dname)[s->dname_tmp_length++] = 0;
+ }
+ {
+ s->r_data_length = s->dname_tmp_length;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st318;
+tr1073:
+ {
+ // Enough room for the terminal label is guaranteed (_label_exit).
+ (s->dname)[s->dname_tmp_length++] = 0;
+ }
+ {
+ s->r_data_length = s->dname_tmp_length;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st318;
+tr1074:
+ {
+ // Enough room for the terminal label is guaranteed (_label_exit).
+ (s->dname)[s->dname_tmp_length++] = 0;
+ }
+ {
+ s->r_data_length = s->dname_tmp_length;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st318;
+st318:
+ if ( ++p == pe )
+ goto _test_eof318;
+case 318:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st318;
+ case 32: goto st318;
+ case 40: goto tr1080;
+ case 41: goto tr1081;
+ case 778: goto tr1065;
+ case 827: goto tr1066;
+ case 1034: goto tr1065;
+ case 1083: goto tr1066;
+ }
+ goto tr85;
+tr1055:
+ cs = 1143;
+ {
+ size_t len = rdata_tail - s->r_data;
+ if (len >= sizeof(s->include_filename)) {
+ ERR(ZS_BAD_INCLUDE_FILENAME);
+ p--; {goto st268;}
+ }
+
+ // Store zero terminated include filename.
+ memcpy(s->include_filename, s->r_data, len);
+ s->include_filename[len] = '\0';
+
+ // For detection whether origin is not present.
+ s->dname = NULL;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ // Extend relative file path.
+ if (s->include_filename[0] != '/') {
+ int ret = snprintf((char *)(s->buffer), sizeof(s->buffer),
+ "%s/%s", s->path, s->include_filename);
+ if (ret <= 0 || ret > sizeof(s->buffer)) {
+ ERR(ZS_BAD_INCLUDE_FILENAME);
+ p--; {goto st268;}
+ }
+ memcpy(s->include_filename, s->buffer, ret);
+ }
+
+ // Origin conversion from wire to text form in \DDD notation.
+ if (s->dname == NULL) { // Use current origin.
+ wire_dname_to_str(s->zone_origin,
+ s->zone_origin_length,
+ (char *)s->buffer);
+ } else { // Use specified origin.
+ wire_dname_to_str(s->r_data,
+ s->r_data_length,
+ (char *)s->buffer);
+ }
+
+ // Let the caller to solve the include.
+ if (s->process.automatic) {
+ // Create new scanner for included zone file.
+ zs_scanner_t *ss = malloc(sizeof(zs_scanner_t));
+ if (ss == NULL) {
+ ERR(ZS_UNPROCESSED_INCLUDE);
+ p--; {goto st268;}
+ }
+
+ // Parse included zone file.
+ if (zs_init(ss, (char *)s->buffer, s->default_class,
+ s->default_ttl) != 0 ||
+ zs_set_input_file(ss, (char *)(s->include_filename)) != 0 ||
+ zs_set_processing(ss, s->process.record, s->process.error,
+ s->process.data) != 0 ||
+ zs_parse_all(ss) != 0) {
+ // File internal errors are handled by error callback.
+ if (ss->error.counter > 0) {
+ s->error.counter += ss->error.counter;
+ ERR(ZS_UNPROCESSED_INCLUDE);
+ // General include file error.
+ } else {
+ ERR(ss->error.code);
+ }
+ zs_deinit(ss);
+ free(ss);
+ p--; {goto st268;}
+ }
+ zs_deinit(ss);
+ free(ss);
+ } else {
+ s->state = ZS_STATE_INCLUDE;
+ p--; cs = 1127; {p++; goto _out;}
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ {
+ s->line_counter++;
+ }
+ goto _again;
+tr1065:
+ cs = 1143;
+ {
+ // Extend relative file path.
+ if (s->include_filename[0] != '/') {
+ int ret = snprintf((char *)(s->buffer), sizeof(s->buffer),
+ "%s/%s", s->path, s->include_filename);
+ if (ret <= 0 || ret > sizeof(s->buffer)) {
+ ERR(ZS_BAD_INCLUDE_FILENAME);
+ p--; {goto st268;}
+ }
+ memcpy(s->include_filename, s->buffer, ret);
+ }
+
+ // Origin conversion from wire to text form in \DDD notation.
+ if (s->dname == NULL) { // Use current origin.
+ wire_dname_to_str(s->zone_origin,
+ s->zone_origin_length,
+ (char *)s->buffer);
+ } else { // Use specified origin.
+ wire_dname_to_str(s->r_data,
+ s->r_data_length,
+ (char *)s->buffer);
+ }
+
+ // Let the caller to solve the include.
+ if (s->process.automatic) {
+ // Create new scanner for included zone file.
+ zs_scanner_t *ss = malloc(sizeof(zs_scanner_t));
+ if (ss == NULL) {
+ ERR(ZS_UNPROCESSED_INCLUDE);
+ p--; {goto st268;}
+ }
+
+ // Parse included zone file.
+ if (zs_init(ss, (char *)s->buffer, s->default_class,
+ s->default_ttl) != 0 ||
+ zs_set_input_file(ss, (char *)(s->include_filename)) != 0 ||
+ zs_set_processing(ss, s->process.record, s->process.error,
+ s->process.data) != 0 ||
+ zs_parse_all(ss) != 0) {
+ // File internal errors are handled by error callback.
+ if (ss->error.counter > 0) {
+ s->error.counter += ss->error.counter;
+ ERR(ZS_UNPROCESSED_INCLUDE);
+ // General include file error.
+ } else {
+ ERR(ss->error.code);
+ }
+ zs_deinit(ss);
+ free(ss);
+ p--; {goto st268;}
+ }
+ zs_deinit(ss);
+ free(ss);
+ } else {
+ s->state = ZS_STATE_INCLUDE;
+ p--; cs = 1127; {p++; goto _out;}
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ {
+ s->line_counter++;
+ }
+ goto _again;
+tr1077:
+ cs = 1143;
+ {
+ // Enough room for the terminal label is guaranteed (_label_exit).
+ (s->dname)[s->dname_tmp_length++] = 0;
+ }
+ {
+ s->r_data_length = s->dname_tmp_length;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ // Extend relative file path.
+ if (s->include_filename[0] != '/') {
+ int ret = snprintf((char *)(s->buffer), sizeof(s->buffer),
+ "%s/%s", s->path, s->include_filename);
+ if (ret <= 0 || ret > sizeof(s->buffer)) {
+ ERR(ZS_BAD_INCLUDE_FILENAME);
+ p--; {goto st268;}
+ }
+ memcpy(s->include_filename, s->buffer, ret);
+ }
+
+ // Origin conversion from wire to text form in \DDD notation.
+ if (s->dname == NULL) { // Use current origin.
+ wire_dname_to_str(s->zone_origin,
+ s->zone_origin_length,
+ (char *)s->buffer);
+ } else { // Use specified origin.
+ wire_dname_to_str(s->r_data,
+ s->r_data_length,
+ (char *)s->buffer);
+ }
+
+ // Let the caller to solve the include.
+ if (s->process.automatic) {
+ // Create new scanner for included zone file.
+ zs_scanner_t *ss = malloc(sizeof(zs_scanner_t));
+ if (ss == NULL) {
+ ERR(ZS_UNPROCESSED_INCLUDE);
+ p--; {goto st268;}
+ }
+
+ // Parse included zone file.
+ if (zs_init(ss, (char *)s->buffer, s->default_class,
+ s->default_ttl) != 0 ||
+ zs_set_input_file(ss, (char *)(s->include_filename)) != 0 ||
+ zs_set_processing(ss, s->process.record, s->process.error,
+ s->process.data) != 0 ||
+ zs_parse_all(ss) != 0) {
+ // File internal errors are handled by error callback.
+ if (ss->error.counter > 0) {
+ s->error.counter += ss->error.counter;
+ ERR(ZS_UNPROCESSED_INCLUDE);
+ // General include file error.
+ } else {
+ ERR(ss->error.code);
+ }
+ zs_deinit(ss);
+ free(ss);
+ p--; {goto st268;}
+ }
+ zs_deinit(ss);
+ free(ss);
+ } else {
+ s->state = ZS_STATE_INCLUDE;
+ p--; cs = 1127; {p++; goto _out;}
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ {
+ s->line_counter++;
+ }
+ goto _again;
+tr1083:
+ cs = 1143;
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ // Extend relative file path.
+ if (s->include_filename[0] != '/') {
+ int ret = snprintf((char *)(s->buffer), sizeof(s->buffer),
+ "%s/%s", s->path, s->include_filename);
+ if (ret <= 0 || ret > sizeof(s->buffer)) {
+ ERR(ZS_BAD_INCLUDE_FILENAME);
+ p--; {goto st268;}
+ }
+ memcpy(s->include_filename, s->buffer, ret);
+ }
+
+ // Origin conversion from wire to text form in \DDD notation.
+ if (s->dname == NULL) { // Use current origin.
+ wire_dname_to_str(s->zone_origin,
+ s->zone_origin_length,
+ (char *)s->buffer);
+ } else { // Use specified origin.
+ wire_dname_to_str(s->r_data,
+ s->r_data_length,
+ (char *)s->buffer);
+ }
+
+ // Let the caller to solve the include.
+ if (s->process.automatic) {
+ // Create new scanner for included zone file.
+ zs_scanner_t *ss = malloc(sizeof(zs_scanner_t));
+ if (ss == NULL) {
+ ERR(ZS_UNPROCESSED_INCLUDE);
+ p--; {goto st268;}
+ }
+
+ // Parse included zone file.
+ if (zs_init(ss, (char *)s->buffer, s->default_class,
+ s->default_ttl) != 0 ||
+ zs_set_input_file(ss, (char *)(s->include_filename)) != 0 ||
+ zs_set_processing(ss, s->process.record, s->process.error,
+ s->process.data) != 0 ||
+ zs_parse_all(ss) != 0) {
+ // File internal errors are handled by error callback.
+ if (ss->error.counter > 0) {
+ s->error.counter += ss->error.counter;
+ ERR(ZS_UNPROCESSED_INCLUDE);
+ // General include file error.
+ } else {
+ ERR(ss->error.code);
+ }
+ zs_deinit(ss);
+ free(ss);
+ p--; {goto st268;}
+ }
+ zs_deinit(ss);
+ free(ss);
+ } else {
+ s->state = ZS_STATE_INCLUDE;
+ p--; cs = 1127; {p++; goto _out;}
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ {
+ s->line_counter++;
+ }
+ goto _again;
+st1143:
+ if ( ++p == pe )
+ goto _test_eof1143;
+case 1143:
+ goto st0;
+tr1066:
+ {
+ s->buffer_length = 0;
+ }
+ goto st319;
+tr1082:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st319;
+tr1056:
+ {
+ size_t len = rdata_tail - s->r_data;
+ if (len >= sizeof(s->include_filename)) {
+ ERR(ZS_BAD_INCLUDE_FILENAME);
+ p--; {goto st268;}
+ }
+
+ // Store zero terminated include filename.
+ memcpy(s->include_filename, s->r_data, len);
+ s->include_filename[len] = '\0';
+
+ // For detection whether origin is not present.
+ s->dname = NULL;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st319;
+tr1078:
+ {
+ // Enough room for the terminal label is guaranteed (_label_exit).
+ (s->dname)[s->dname_tmp_length++] = 0;
+ }
+ {
+ s->r_data_length = s->dname_tmp_length;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st319;
+st319:
+ if ( ++p == pe )
+ goto _test_eof319;
+case 319:
+ if ( (*p) == 10 )
+ goto tr1083;
+ goto tr1082;
+tr1076:
+ {
+ s->item_length = 0;
+ s->item_length_position = s->dname_tmp_length++;
+ }
+ goto st320;
+tr1090:
+ {
+ s->dname_tmp_length++;
+ }
+ goto st320;
+tr1064:
+ {
+ s->dname = s->r_data;
+ }
+ {
+ s->item_length_position = 0;
+ s->dname_tmp_length = 0;
+ }
+ {
+ s->item_length = 0;
+ s->item_length_position = s->dname_tmp_length++;
+ }
+ goto st320;
+st320:
+ if ( ++p == pe )
+ goto _test_eof320;
+case 320:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr1084;
+ goto tr1069;
+tr1084:
+ {
+ if (s->item_length < ZS_MAX_LABEL_LENGTH) {
+ (s->dname)[s->dname_tmp_length] = 0;
+ s->item_length++;
+ } else {
+ WARN(ZS_LABEL_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ (s->dname)[s->dname_tmp_length] *= 10;
+ (s->dname)[s->dname_tmp_length] += digit_to_num[(uint8_t)(*p)];
+ }
+ goto st321;
+st321:
+ if ( ++p == pe )
+ goto _test_eof321;
+case 321:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr1086;
+ goto tr1085;
+tr1086:
+ {
+ (s->dname)[s->dname_tmp_length] *= 10;
+ (s->dname)[s->dname_tmp_length] += digit_to_num[(uint8_t)(*p)];
+ }
+ goto st322;
+st322:
+ if ( ++p == pe )
+ goto _test_eof322;
+case 322:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr1087;
+ goto tr1085;
+tr1087:
+ {
+ (s->dname)[s->dname_tmp_length] *= 10;
+ (s->dname)[s->dname_tmp_length] += digit_to_num[(uint8_t)(*p)];
+ }
+ goto st323;
+st323:
+ if ( ++p == pe )
+ goto _test_eof323;
+case 323:
+ switch( (*p) ) {
+ case 42: goto tr1088;
+ case 46: goto tr1089;
+ case 92: goto tr1090;
+ case 95: goto tr1088;
+ }
+ if ( (*p) < 65 ) {
+ if ( 45 <= (*p) && (*p) <= 57 )
+ goto tr1088;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr1088;
+ } else
+ goto tr1088;
+ goto tr1085;
+tr1063:
+ {
+ s->dname = s->r_data;
+ }
+ {
+ s->item_length_position = 0;
+ s->dname_tmp_length = 0;
+ }
+ goto st324;
+st324:
+ if ( ++p == pe )
+ goto _test_eof324;
+case 324:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr1072;
+ case 32: goto tr1072;
+ case 40: goto tr1073;
+ case 41: goto tr1074;
+ case 778: goto tr1077;
+ case 827: goto tr1078;
+ case 1034: goto tr1077;
+ case 1083: goto tr1078;
+ }
+ goto tr1058;
+tr1067:
+ {
+ s->buffer_length = 0;
+ }
+ goto st325;
+tr1091:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st325;
+tr1057:
+ {
+ size_t len = rdata_tail - s->r_data;
+ if (len >= sizeof(s->include_filename)) {
+ ERR(ZS_BAD_INCLUDE_FILENAME);
+ p--; {goto st268;}
+ }
+
+ // Store zero terminated include filename.
+ memcpy(s->include_filename, s->r_data, len);
+ s->include_filename[len] = '\0';
+
+ // For detection whether origin is not present.
+ s->dname = NULL;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ goto st325;
+st325:
+ if ( ++p == pe )
+ goto _test_eof325;
+case 325:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 778: goto tr1083;
+ case 1034: goto tr1092;
+ }
+ if ( _widec > 895 ) {
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr1091;
+ } else if ( _widec >= 640 )
+ goto tr1082;
+ goto tr85;
+tr1092:
+ cs = 1144;
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ // Extend relative file path.
+ if (s->include_filename[0] != '/') {
+ int ret = snprintf((char *)(s->buffer), sizeof(s->buffer),
+ "%s/%s", s->path, s->include_filename);
+ if (ret <= 0 || ret > sizeof(s->buffer)) {
+ ERR(ZS_BAD_INCLUDE_FILENAME);
+ p--; {goto st268;}
+ }
+ memcpy(s->include_filename, s->buffer, ret);
+ }
+
+ // Origin conversion from wire to text form in \DDD notation.
+ if (s->dname == NULL) { // Use current origin.
+ wire_dname_to_str(s->zone_origin,
+ s->zone_origin_length,
+ (char *)s->buffer);
+ } else { // Use specified origin.
+ wire_dname_to_str(s->r_data,
+ s->r_data_length,
+ (char *)s->buffer);
+ }
+
+ // Let the caller to solve the include.
+ if (s->process.automatic) {
+ // Create new scanner for included zone file.
+ zs_scanner_t *ss = malloc(sizeof(zs_scanner_t));
+ if (ss == NULL) {
+ ERR(ZS_UNPROCESSED_INCLUDE);
+ p--; {goto st268;}
+ }
+
+ // Parse included zone file.
+ if (zs_init(ss, (char *)s->buffer, s->default_class,
+ s->default_ttl) != 0 ||
+ zs_set_input_file(ss, (char *)(s->include_filename)) != 0 ||
+ zs_set_processing(ss, s->process.record, s->process.error,
+ s->process.data) != 0 ||
+ zs_parse_all(ss) != 0) {
+ // File internal errors are handled by error callback.
+ if (ss->error.counter > 0) {
+ s->error.counter += ss->error.counter;
+ ERR(ZS_UNPROCESSED_INCLUDE);
+ // General include file error.
+ } else {
+ ERR(ss->error.code);
+ }
+ zs_deinit(ss);
+ free(ss);
+ p--; {goto st268;}
+ }
+ zs_deinit(ss);
+ free(ss);
+ } else {
+ s->state = ZS_STATE_INCLUDE;
+ p--; cs = 1127; {p++; goto _out;}
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto _again;
+st1144:
+ if ( ++p == pe )
+ goto _test_eof1144;
+case 1144:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st326;
+ case 32: goto st326;
+ case 40: goto tr1094;
+ case 41: goto tr1095;
+ case 42: goto tr1062;
+ case 46: goto tr1063;
+ case 92: goto tr1064;
+ case 95: goto tr1062;
+ case 1034: goto tr1096;
+ case 1083: goto tr1097;
+ }
+ if ( _widec < 65 ) {
+ if ( 45 <= _widec && _widec <= 57 )
+ goto tr1062;
+ } else if ( _widec > 90 ) {
+ if ( 97 <= _widec && _widec <= 122 )
+ goto tr1062;
+ } else
+ goto tr1062;
+ goto tr1068;
+tr1094:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st326;
+tr1095:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st326;
+tr1096:
+ {
+ s->line_counter++;
+ }
+ goto st326;
+tr1099:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st326;
+st326:
+ if ( ++p == pe )
+ goto _test_eof326;
+case 326:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st326;
+ case 32: goto st326;
+ case 40: goto tr1094;
+ case 41: goto tr1095;
+ case 42: goto tr1062;
+ case 46: goto tr1063;
+ case 92: goto tr1064;
+ case 95: goto tr1062;
+ case 1034: goto tr1096;
+ case 1083: goto tr1097;
+ }
+ if ( _widec < 65 ) {
+ if ( 45 <= _widec && _widec <= 57 )
+ goto tr1062;
+ } else if ( _widec > 90 ) {
+ if ( 97 <= _widec && _widec <= 122 )
+ goto tr1062;
+ } else
+ goto tr1062;
+ goto tr1068;
+tr1097:
+ {
+ s->buffer_length = 0;
+ }
+ goto st327;
+tr1098:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st327;
+st327:
+ if ( ++p == pe )
+ goto _test_eof327;
+case 327:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr1099;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr1098;
+ goto st0;
+tr1048:
+ {
+ s->buffer_length = 0;
+ }
+ goto st328;
+tr1100:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st328;
+st328:
+ if ( ++p == pe )
+ goto _test_eof328;
+case 328:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr1101;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr1100;
+ goto st0;
+st329:
+ if ( ++p == pe )
+ goto _test_eof329;
+case 329:
+ if ( (*p) == 43 )
+ goto tr1103;
+ if ( (*p) < 65 ) {
+ if ( 47 <= (*p) && (*p) <= 57 )
+ goto tr1103;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr1103;
+ } else
+ goto tr1103;
+ goto tr1102;
+tr1103:
+ {
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = first_base64_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st330;
+st330:
+ if ( ++p == pe )
+ goto _test_eof330;
+case 330:
+ if ( (*p) == 43 )
+ goto tr1104;
+ if ( (*p) < 65 ) {
+ if ( 47 <= (*p) && (*p) <= 57 )
+ goto tr1104;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr1104;
+ } else
+ goto tr1104;
+ goto tr1102;
+tr1104:
+ {
+ *(rdata_tail++) += second_left_base64_to_num[(uint8_t)(*p)];
+
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = second_right_base64_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st331;
+st331:
+ if ( ++p == pe )
+ goto _test_eof331;
+case 331:
+ switch( (*p) ) {
+ case 43: goto tr1105;
+ case 61: goto st335;
+ }
+ if ( (*p) < 65 ) {
+ if ( 47 <= (*p) && (*p) <= 57 )
+ goto tr1105;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr1105;
+ } else
+ goto tr1105;
+ goto tr1102;
+tr1105:
+ {
+ *(rdata_tail++) += third_left_base64_to_num[(uint8_t)(*p)];
+
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = third_right_base64_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st332;
+st332:
+ if ( ++p == pe )
+ goto _test_eof332;
+case 332:
+ switch( (*p) ) {
+ case 43: goto tr1107;
+ case 61: goto st333;
+ }
+ if ( (*p) < 65 ) {
+ if ( 47 <= (*p) && (*p) <= 57 )
+ goto tr1107;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr1107;
+ } else
+ goto tr1107;
+ goto tr1102;
+tr1109:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st333;
+tr1110:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st333;
+tr1111:
+ {
+ s->line_counter++;
+ }
+ goto st333;
+tr1117:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st333;
+tr1107:
+ {
+ *(rdata_tail++) += fourth_base64_to_num[(uint8_t)(*p)];
+ }
+ goto st333;
+st333:
+ if ( ++p == pe )
+ goto _test_eof333;
+case 333:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st333;
+ case 32: goto st333;
+ case 40: goto tr1109;
+ case 41: goto tr1110;
+ case 43: goto tr1103;
+ case 2058: goto tr1111;
+ case 2107: goto tr1112;
+ case 2314: goto tr1113;
+ case 2363: goto tr1113;
+ case 2570: goto tr1114;
+ case 2619: goto tr1115;
+ }
+ if ( _widec < 65 ) {
+ if ( 47 <= _widec && _widec <= 57 )
+ goto tr1103;
+ } else if ( _widec > 90 ) {
+ if ( 97 <= _widec && _widec <= 122 )
+ goto tr1103;
+ } else
+ goto tr1103;
+ goto tr1102;
+tr1112:
+ {
+ s->buffer_length = 0;
+ }
+ goto st334;
+tr1116:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st334;
+st334:
+ if ( ++p == pe )
+ goto _test_eof334;
+case 334:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr1117;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr1116;
+ goto tr1102;
+tr1113:
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1145;
+st1145:
+ if ( ++p == pe )
+ goto _test_eof1145;
+case 1145:
+ goto st0;
+tr1114:
+ {
+ s->line_counter++;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1146;
+st1146:
+ if ( ++p == pe )
+ goto _test_eof1146;
+case 1146:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st333;
+ case 32: goto st333;
+ case 40: goto tr1109;
+ case 41: goto tr1110;
+ case 43: goto tr1103;
+ case 2058: goto tr1111;
+ case 2107: goto tr1112;
+ case 2314: goto tr1113;
+ case 2363: goto tr1113;
+ case 2570: goto tr1114;
+ case 2619: goto tr1115;
+ }
+ if ( _widec < 65 ) {
+ if ( 47 <= _widec && _widec <= 57 )
+ goto tr1103;
+ } else if ( _widec > 90 ) {
+ if ( 97 <= _widec && _widec <= 122 )
+ goto tr1103;
+ } else
+ goto tr1103;
+ goto tr1102;
+tr1115:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1147;
+st1147:
+ if ( ++p == pe )
+ goto _test_eof1147;
+case 1147:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr1117;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr1116;
+ goto tr1102;
+st335:
+ if ( ++p == pe )
+ goto _test_eof335;
+case 335:
+ if ( (*p) == 61 )
+ goto st333;
+ goto tr1102;
+st336:
+ if ( ++p == pe )
+ goto _test_eof336;
+case 336:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1119;
+ case 32: goto tr1119;
+ case 40: goto tr1120;
+ case 41: goto tr1121;
+ case 2058: goto tr1122;
+ case 2107: goto tr1123;
+ case 2314: goto tr1124;
+ case 2363: goto tr1124;
+ case 2570: goto tr1125;
+ case 2619: goto tr1126;
+ }
+ goto tr1118;
+tr1128:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1129:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1145:
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1172:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1119:
+ {
+ memset(s->windows, 0, sizeof(s->windows));
+ s->last_window = -1;
+ }
+ goto st337;
+tr1120:
+ {
+ memset(s->windows, 0, sizeof(s->windows));
+ s->last_window = -1;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1121:
+ {
+ memset(s->windows, 0, sizeof(s->windows));
+ s->last_window = -1;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1122:
+ {
+ memset(s->windows, 0, sizeof(s->windows));
+ s->last_window = -1;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1150:
+ { window_add_bit(KNOT_RRTYPE_A, s); }
+ goto st337;
+tr1151:
+ { window_add_bit(KNOT_RRTYPE_A, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1152:
+ { window_add_bit(KNOT_RRTYPE_A, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1156:
+ { window_add_bit(KNOT_RRTYPE_A, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1163:
+ { window_add_bit(KNOT_RRTYPE_AAAA, s); }
+ goto st337;
+tr1164:
+ { window_add_bit(KNOT_RRTYPE_AAAA, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1165:
+ { window_add_bit(KNOT_RRTYPE_AAAA, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1166:
+ { window_add_bit(KNOT_RRTYPE_AAAA, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1178:
+ { window_add_bit(KNOT_RRTYPE_CAA, s); }
+ goto st337;
+tr1179:
+ { window_add_bit(KNOT_RRTYPE_CAA, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1180:
+ { window_add_bit(KNOT_RRTYPE_CAA, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1181:
+ { window_add_bit(KNOT_RRTYPE_CAA, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1192:
+ { window_add_bit(KNOT_RRTYPE_CDNSKEY, s); }
+ goto st337;
+tr1193:
+ { window_add_bit(KNOT_RRTYPE_CDNSKEY, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1194:
+ { window_add_bit(KNOT_RRTYPE_CDNSKEY, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1195:
+ { window_add_bit(KNOT_RRTYPE_CDNSKEY, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1200:
+ { window_add_bit(KNOT_RRTYPE_CDS, s); }
+ goto st337;
+tr1201:
+ { window_add_bit(KNOT_RRTYPE_CDS, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1202:
+ { window_add_bit(KNOT_RRTYPE_CDS, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1203:
+ { window_add_bit(KNOT_RRTYPE_CDS, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1210:
+ { window_add_bit(KNOT_RRTYPE_CERT, s); }
+ goto st337;
+tr1211:
+ { window_add_bit(KNOT_RRTYPE_CERT, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1212:
+ { window_add_bit(KNOT_RRTYPE_CERT, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1213:
+ { window_add_bit(KNOT_RRTYPE_CERT, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1221:
+ { window_add_bit(KNOT_RRTYPE_CNAME, s); }
+ goto st337;
+tr1222:
+ { window_add_bit(KNOT_RRTYPE_CNAME, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1223:
+ { window_add_bit(KNOT_RRTYPE_CNAME, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1224:
+ { window_add_bit(KNOT_RRTYPE_CNAME, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1235:
+ { window_add_bit(KNOT_RRTYPE_DHCID, s); }
+ goto st337;
+tr1236:
+ { window_add_bit(KNOT_RRTYPE_DHCID, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1237:
+ { window_add_bit(KNOT_RRTYPE_DHCID, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1238:
+ { window_add_bit(KNOT_RRTYPE_DHCID, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1247:
+ { window_add_bit(KNOT_RRTYPE_DNAME, s); }
+ goto st337;
+tr1248:
+ { window_add_bit(KNOT_RRTYPE_DNAME, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1249:
+ { window_add_bit(KNOT_RRTYPE_DNAME, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1250:
+ { window_add_bit(KNOT_RRTYPE_DNAME, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1258:
+ { window_add_bit(KNOT_RRTYPE_DNSKEY, s); }
+ goto st337;
+tr1259:
+ { window_add_bit(KNOT_RRTYPE_DNSKEY, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1260:
+ { window_add_bit(KNOT_RRTYPE_DNSKEY, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1261:
+ { window_add_bit(KNOT_RRTYPE_DNSKEY, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1266:
+ { window_add_bit(KNOT_RRTYPE_DS, s); }
+ goto st337;
+tr1267:
+ { window_add_bit(KNOT_RRTYPE_DS, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1268:
+ { window_add_bit(KNOT_RRTYPE_DS, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1269:
+ { window_add_bit(KNOT_RRTYPE_DS, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1279:
+ { window_add_bit(KNOT_RRTYPE_EUI48, s); }
+ goto st337;
+tr1280:
+ { window_add_bit(KNOT_RRTYPE_EUI48, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1281:
+ { window_add_bit(KNOT_RRTYPE_EUI48, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1282:
+ { window_add_bit(KNOT_RRTYPE_EUI48, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1288:
+ { window_add_bit(KNOT_RRTYPE_EUI64, s); }
+ goto st337;
+tr1289:
+ { window_add_bit(KNOT_RRTYPE_EUI64, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1290:
+ { window_add_bit(KNOT_RRTYPE_EUI64, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1291:
+ { window_add_bit(KNOT_RRTYPE_EUI64, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1300:
+ { window_add_bit(KNOT_RRTYPE_HINFO, s); }
+ goto st337;
+tr1301:
+ { window_add_bit(KNOT_RRTYPE_HINFO, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1302:
+ { window_add_bit(KNOT_RRTYPE_HINFO, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1303:
+ { window_add_bit(KNOT_RRTYPE_HINFO, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1315:
+ { window_add_bit(KNOT_RRTYPE_IPSECKEY, s); }
+ goto st337;
+tr1316:
+ { window_add_bit(KNOT_RRTYPE_IPSECKEY, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1317:
+ { window_add_bit(KNOT_RRTYPE_IPSECKEY, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1318:
+ { window_add_bit(KNOT_RRTYPE_IPSECKEY, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1326:
+ { window_add_bit(KNOT_RRTYPE_KEY, s); }
+ goto st337;
+tr1327:
+ { window_add_bit(KNOT_RRTYPE_KEY, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1328:
+ { window_add_bit(KNOT_RRTYPE_KEY, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1329:
+ { window_add_bit(KNOT_RRTYPE_KEY, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1334:
+ { window_add_bit(KNOT_RRTYPE_KX, s); }
+ goto st337;
+tr1335:
+ { window_add_bit(KNOT_RRTYPE_KX, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1336:
+ { window_add_bit(KNOT_RRTYPE_KX, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1337:
+ { window_add_bit(KNOT_RRTYPE_KX, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1347:
+ { window_add_bit(KNOT_RRTYPE_L32, s); }
+ goto st337;
+tr1348:
+ { window_add_bit(KNOT_RRTYPE_L32, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1349:
+ { window_add_bit(KNOT_RRTYPE_L32, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1350:
+ { window_add_bit(KNOT_RRTYPE_L32, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1356:
+ { window_add_bit(KNOT_RRTYPE_L64, s); }
+ goto st337;
+tr1357:
+ { window_add_bit(KNOT_RRTYPE_L64, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1358:
+ { window_add_bit(KNOT_RRTYPE_L64, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1359:
+ { window_add_bit(KNOT_RRTYPE_L64, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1365:
+ { window_add_bit(KNOT_RRTYPE_LOC, s); }
+ goto st337;
+tr1366:
+ { window_add_bit(KNOT_RRTYPE_LOC, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1367:
+ { window_add_bit(KNOT_RRTYPE_LOC, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1368:
+ { window_add_bit(KNOT_RRTYPE_LOC, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1373:
+ { window_add_bit(KNOT_RRTYPE_LP, s); }
+ goto st337;
+tr1374:
+ { window_add_bit(KNOT_RRTYPE_LP, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1375:
+ { window_add_bit(KNOT_RRTYPE_LP, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1376:
+ { window_add_bit(KNOT_RRTYPE_LP, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1386:
+ { window_add_bit(KNOT_RRTYPE_MINFO, s); }
+ goto st337;
+tr1387:
+ { window_add_bit(KNOT_RRTYPE_MINFO, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1388:
+ { window_add_bit(KNOT_RRTYPE_MINFO, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1389:
+ { window_add_bit(KNOT_RRTYPE_MINFO, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1394:
+ { window_add_bit(KNOT_RRTYPE_MX, s); }
+ goto st337;
+tr1395:
+ { window_add_bit(KNOT_RRTYPE_MX, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1396:
+ { window_add_bit(KNOT_RRTYPE_MX, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1397:
+ { window_add_bit(KNOT_RRTYPE_MX, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1408:
+ { window_add_bit(KNOT_RRTYPE_NAPTR, s); }
+ goto st337;
+tr1409:
+ { window_add_bit(KNOT_RRTYPE_NAPTR, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1410:
+ { window_add_bit(KNOT_RRTYPE_NAPTR, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1411:
+ { window_add_bit(KNOT_RRTYPE_NAPTR, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1417:
+ { window_add_bit(KNOT_RRTYPE_NID, s); }
+ goto st337;
+tr1418:
+ { window_add_bit(KNOT_RRTYPE_NID, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1419:
+ { window_add_bit(KNOT_RRTYPE_NID, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1420:
+ { window_add_bit(KNOT_RRTYPE_NID, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1425:
+ { window_add_bit(KNOT_RRTYPE_NS, s); }
+ goto st337;
+tr1426:
+ { window_add_bit(KNOT_RRTYPE_NS, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1427:
+ { window_add_bit(KNOT_RRTYPE_NS, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1429:
+ { window_add_bit(KNOT_RRTYPE_NS, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1435:
+ { window_add_bit(KNOT_RRTYPE_NSEC, s); }
+ goto st337;
+tr1436:
+ { window_add_bit(KNOT_RRTYPE_NSEC, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1437:
+ { window_add_bit(KNOT_RRTYPE_NSEC, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1439:
+ { window_add_bit(KNOT_RRTYPE_NSEC, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1444:
+ { window_add_bit(KNOT_RRTYPE_NSEC3, s); }
+ goto st337;
+tr1445:
+ { window_add_bit(KNOT_RRTYPE_NSEC3, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1446:
+ { window_add_bit(KNOT_RRTYPE_NSEC3, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1448:
+ { window_add_bit(KNOT_RRTYPE_NSEC3, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1457:
+ { window_add_bit(KNOT_RRTYPE_NSEC3PARAM, s); }
+ goto st337;
+tr1458:
+ { window_add_bit(KNOT_RRTYPE_NSEC3PARAM, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1459:
+ { window_add_bit(KNOT_RRTYPE_NSEC3PARAM, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1460:
+ { window_add_bit(KNOT_RRTYPE_NSEC3PARAM, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1467:
+ { window_add_bit(KNOT_RRTYPE_PTR, s); }
+ goto st337;
+tr1468:
+ { window_add_bit(KNOT_RRTYPE_PTR, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1469:
+ { window_add_bit(KNOT_RRTYPE_PTR, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1470:
+ { window_add_bit(KNOT_RRTYPE_PTR, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1478:
+ { window_add_bit(KNOT_RRTYPE_RP, s); }
+ goto st337;
+tr1479:
+ { window_add_bit(KNOT_RRTYPE_RP, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1480:
+ { window_add_bit(KNOT_RRTYPE_RP, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1481:
+ { window_add_bit(KNOT_RRTYPE_RP, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1489:
+ { window_add_bit(KNOT_RRTYPE_RRSIG, s); }
+ goto st337;
+tr1490:
+ { window_add_bit(KNOT_RRTYPE_RRSIG, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1491:
+ { window_add_bit(KNOT_RRTYPE_RRSIG, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1492:
+ { window_add_bit(KNOT_RRTYPE_RRSIG, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1497:
+ { window_add_bit(KNOT_RRTYPE_RT, s); }
+ goto st337;
+tr1498:
+ { window_add_bit(KNOT_RRTYPE_RT, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1499:
+ { window_add_bit(KNOT_RRTYPE_RT, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1500:
+ { window_add_bit(KNOT_RRTYPE_RT, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1510:
+ { window_add_bit(KNOT_RRTYPE_SOA, s); }
+ goto st337;
+tr1511:
+ { window_add_bit(KNOT_RRTYPE_SOA, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1512:
+ { window_add_bit(KNOT_RRTYPE_SOA, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1513:
+ { window_add_bit(KNOT_RRTYPE_SOA, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1519:
+ { window_add_bit(KNOT_RRTYPE_SPF, s); }
+ goto st337;
+tr1520:
+ { window_add_bit(KNOT_RRTYPE_SPF, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1521:
+ { window_add_bit(KNOT_RRTYPE_SPF, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1522:
+ { window_add_bit(KNOT_RRTYPE_SPF, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1528:
+ { window_add_bit(KNOT_RRTYPE_SRV, s); }
+ goto st337;
+tr1529:
+ { window_add_bit(KNOT_RRTYPE_SRV, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1530:
+ { window_add_bit(KNOT_RRTYPE_SRV, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1531:
+ { window_add_bit(KNOT_RRTYPE_SRV, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1539:
+ { window_add_bit(KNOT_RRTYPE_SSHFP, s); }
+ goto st337;
+tr1540:
+ { window_add_bit(KNOT_RRTYPE_SSHFP, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1541:
+ { window_add_bit(KNOT_RRTYPE_SSHFP, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1542:
+ { window_add_bit(KNOT_RRTYPE_SSHFP, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1552:
+ { window_add_bit(KNOT_RRTYPE_TLSA, s); }
+ goto st337;
+tr1553:
+ { window_add_bit(KNOT_RRTYPE_TLSA, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1554:
+ { window_add_bit(KNOT_RRTYPE_TLSA, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1555:
+ { window_add_bit(KNOT_RRTYPE_TLSA, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1561:
+ { window_add_bit(KNOT_RRTYPE_TXT, s); }
+ goto st337;
+tr1562:
+ { window_add_bit(KNOT_RRTYPE_TXT, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1563:
+ { window_add_bit(KNOT_RRTYPE_TXT, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1564:
+ { window_add_bit(KNOT_RRTYPE_TXT, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1572:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ window_add_bit(s->number64, s);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st337;
+tr1573:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ window_add_bit(s->number64, s);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1574:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ window_add_bit(s->number64, s);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1576:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ window_add_bit(s->number64, s);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1583:
+ { window_add_bit(KNOT_RRTYPE_URI, s); }
+ goto st337;
+tr1584:
+ { window_add_bit(KNOT_RRTYPE_URI, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1585:
+ { window_add_bit(KNOT_RRTYPE_URI, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1586:
+ { window_add_bit(KNOT_RRTYPE_URI, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1594:
+ { window_add_bit(KNOT_RRTYPE_AFSDB, s); }
+ goto st337;
+tr1595:
+ { window_add_bit(KNOT_RRTYPE_AFSDB, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1596:
+ { window_add_bit(KNOT_RRTYPE_AFSDB, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1597:
+ { window_add_bit(KNOT_RRTYPE_AFSDB, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+tr1603:
+ { window_add_bit(KNOT_RRTYPE_APL, s); }
+ goto st337;
+tr1604:
+ { window_add_bit(KNOT_RRTYPE_APL, s); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st337;
+tr1605:
+ { window_add_bit(KNOT_RRTYPE_APL, s); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st337;
+tr1606:
+ { window_add_bit(KNOT_RRTYPE_APL, s); }
+ {
+ s->line_counter++;
+ }
+ goto st337;
+st337:
+ if ( ++p == pe )
+ goto _test_eof337;
+case 337:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st337;
+ case 32: goto st337;
+ case 40: goto tr1128;
+ case 41: goto tr1129;
+ case 65: goto st338;
+ case 67: goto st343;
+ case 68: goto st360;
+ case 69: goto st374;
+ case 72: goto st381;
+ case 73: goto st386;
+ case 75: goto st394;
+ case 76: goto st398;
+ case 77: goto st406;
+ case 78: goto st412;
+ case 80: goto st428;
+ case 82: goto st431;
+ case 83: goto st438;
+ case 84: goto st449;
+ case 85: goto st459;
+ case 97: goto st338;
+ case 99: goto st343;
+ case 100: goto st360;
+ case 101: goto st374;
+ case 104: goto st381;
+ case 105: goto st386;
+ case 107: goto st394;
+ case 108: goto st398;
+ case 109: goto st406;
+ case 110: goto st412;
+ case 112: goto st428;
+ case 114: goto st431;
+ case 115: goto st438;
+ case 116: goto st449;
+ case 117: goto st459;
+ case 2058: goto tr1145;
+ case 2107: goto tr1146;
+ case 2314: goto tr1147;
+ case 2363: goto tr1147;
+ case 2570: goto tr1148;
+ case 2619: goto tr1149;
+ }
+ goto tr1118;
+st338:
+ if ( ++p == pe )
+ goto _test_eof338;
+case 338:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1150;
+ case 32: goto tr1150;
+ case 40: goto tr1151;
+ case 41: goto tr1152;
+ case 65: goto st339;
+ case 70: goto st462;
+ case 80: goto st466;
+ case 97: goto st339;
+ case 102: goto st462;
+ case 112: goto st466;
+ case 2058: goto tr1156;
+ case 2107: goto tr1157;
+ case 2314: goto tr1158;
+ case 2363: goto tr1158;
+ case 2570: goto tr1159;
+ case 2619: goto tr1160;
+ }
+ goto tr1118;
+st339:
+ if ( ++p == pe )
+ goto _test_eof339;
+case 339:
+ switch( (*p) ) {
+ case 65: goto st340;
+ case 97: goto st340;
+ }
+ goto tr1118;
+st340:
+ if ( ++p == pe )
+ goto _test_eof340;
+case 340:
+ switch( (*p) ) {
+ case 65: goto st341;
+ case 97: goto st341;
+ }
+ goto tr1118;
+st341:
+ if ( ++p == pe )
+ goto _test_eof341;
+case 341:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1163;
+ case 32: goto tr1163;
+ case 40: goto tr1164;
+ case 41: goto tr1165;
+ case 2058: goto tr1166;
+ case 2107: goto tr1167;
+ case 2314: goto tr1168;
+ case 2363: goto tr1168;
+ case 2570: goto tr1169;
+ case 2619: goto tr1170;
+ }
+ goto tr1118;
+tr1146:
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1171:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st342;
+tr1123:
+ {
+ memset(s->windows, 0, sizeof(s->windows));
+ s->last_window = -1;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1157:
+ { window_add_bit(KNOT_RRTYPE_A, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1167:
+ { window_add_bit(KNOT_RRTYPE_AAAA, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1182:
+ { window_add_bit(KNOT_RRTYPE_CAA, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1196:
+ { window_add_bit(KNOT_RRTYPE_CDNSKEY, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1204:
+ { window_add_bit(KNOT_RRTYPE_CDS, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1214:
+ { window_add_bit(KNOT_RRTYPE_CERT, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1225:
+ { window_add_bit(KNOT_RRTYPE_CNAME, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1239:
+ { window_add_bit(KNOT_RRTYPE_DHCID, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1251:
+ { window_add_bit(KNOT_RRTYPE_DNAME, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1262:
+ { window_add_bit(KNOT_RRTYPE_DNSKEY, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1270:
+ { window_add_bit(KNOT_RRTYPE_DS, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1283:
+ { window_add_bit(KNOT_RRTYPE_EUI48, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1292:
+ { window_add_bit(KNOT_RRTYPE_EUI64, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1304:
+ { window_add_bit(KNOT_RRTYPE_HINFO, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1319:
+ { window_add_bit(KNOT_RRTYPE_IPSECKEY, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1330:
+ { window_add_bit(KNOT_RRTYPE_KEY, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1338:
+ { window_add_bit(KNOT_RRTYPE_KX, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1351:
+ { window_add_bit(KNOT_RRTYPE_L32, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1360:
+ { window_add_bit(KNOT_RRTYPE_L64, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1369:
+ { window_add_bit(KNOT_RRTYPE_LOC, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1377:
+ { window_add_bit(KNOT_RRTYPE_LP, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1390:
+ { window_add_bit(KNOT_RRTYPE_MINFO, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1398:
+ { window_add_bit(KNOT_RRTYPE_MX, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1412:
+ { window_add_bit(KNOT_RRTYPE_NAPTR, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1421:
+ { window_add_bit(KNOT_RRTYPE_NID, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1430:
+ { window_add_bit(KNOT_RRTYPE_NS, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1440:
+ { window_add_bit(KNOT_RRTYPE_NSEC, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1449:
+ { window_add_bit(KNOT_RRTYPE_NSEC3, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1461:
+ { window_add_bit(KNOT_RRTYPE_NSEC3PARAM, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1471:
+ { window_add_bit(KNOT_RRTYPE_PTR, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1482:
+ { window_add_bit(KNOT_RRTYPE_RP, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1493:
+ { window_add_bit(KNOT_RRTYPE_RRSIG, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1501:
+ { window_add_bit(KNOT_RRTYPE_RT, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1514:
+ { window_add_bit(KNOT_RRTYPE_SOA, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1523:
+ { window_add_bit(KNOT_RRTYPE_SPF, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1532:
+ { window_add_bit(KNOT_RRTYPE_SRV, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1543:
+ { window_add_bit(KNOT_RRTYPE_SSHFP, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1556:
+ { window_add_bit(KNOT_RRTYPE_TLSA, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1565:
+ { window_add_bit(KNOT_RRTYPE_TXT, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1577:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ window_add_bit(s->number64, s);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1587:
+ { window_add_bit(KNOT_RRTYPE_URI, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1598:
+ { window_add_bit(KNOT_RRTYPE_AFSDB, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+tr1607:
+ { window_add_bit(KNOT_RRTYPE_APL, s); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st342;
+st342:
+ if ( ++p == pe )
+ goto _test_eof342;
+case 342:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr1172;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr1171;
+ goto tr1118;
+tr1124:
+ {
+ memset(s->windows, 0, sizeof(s->windows));
+ s->last_window = -1;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1147:
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1158:
+ { window_add_bit(KNOT_RRTYPE_A, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1168:
+ { window_add_bit(KNOT_RRTYPE_AAAA, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1183:
+ { window_add_bit(KNOT_RRTYPE_CAA, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1197:
+ { window_add_bit(KNOT_RRTYPE_CDNSKEY, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1205:
+ { window_add_bit(KNOT_RRTYPE_CDS, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1215:
+ { window_add_bit(KNOT_RRTYPE_CERT, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1226:
+ { window_add_bit(KNOT_RRTYPE_CNAME, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1240:
+ { window_add_bit(KNOT_RRTYPE_DHCID, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1252:
+ { window_add_bit(KNOT_RRTYPE_DNAME, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1263:
+ { window_add_bit(KNOT_RRTYPE_DNSKEY, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1271:
+ { window_add_bit(KNOT_RRTYPE_DS, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1284:
+ { window_add_bit(KNOT_RRTYPE_EUI48, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1293:
+ { window_add_bit(KNOT_RRTYPE_EUI64, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1305:
+ { window_add_bit(KNOT_RRTYPE_HINFO, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1320:
+ { window_add_bit(KNOT_RRTYPE_IPSECKEY, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1331:
+ { window_add_bit(KNOT_RRTYPE_KEY, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1339:
+ { window_add_bit(KNOT_RRTYPE_KX, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1352:
+ { window_add_bit(KNOT_RRTYPE_L32, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1361:
+ { window_add_bit(KNOT_RRTYPE_L64, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1370:
+ { window_add_bit(KNOT_RRTYPE_LOC, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1378:
+ { window_add_bit(KNOT_RRTYPE_LP, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1391:
+ { window_add_bit(KNOT_RRTYPE_MINFO, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1399:
+ { window_add_bit(KNOT_RRTYPE_MX, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1413:
+ { window_add_bit(KNOT_RRTYPE_NAPTR, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1422:
+ { window_add_bit(KNOT_RRTYPE_NID, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1431:
+ { window_add_bit(KNOT_RRTYPE_NS, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1441:
+ { window_add_bit(KNOT_RRTYPE_NSEC, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1450:
+ { window_add_bit(KNOT_RRTYPE_NSEC3, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1462:
+ { window_add_bit(KNOT_RRTYPE_NSEC3PARAM, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1472:
+ { window_add_bit(KNOT_RRTYPE_PTR, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1483:
+ { window_add_bit(KNOT_RRTYPE_RP, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1494:
+ { window_add_bit(KNOT_RRTYPE_RRSIG, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1502:
+ { window_add_bit(KNOT_RRTYPE_RT, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1515:
+ { window_add_bit(KNOT_RRTYPE_SOA, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1524:
+ { window_add_bit(KNOT_RRTYPE_SPF, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1533:
+ { window_add_bit(KNOT_RRTYPE_SRV, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1544:
+ { window_add_bit(KNOT_RRTYPE_SSHFP, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1557:
+ { window_add_bit(KNOT_RRTYPE_TLSA, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1566:
+ { window_add_bit(KNOT_RRTYPE_TXT, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1578:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ window_add_bit(s->number64, s);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1588:
+ { window_add_bit(KNOT_RRTYPE_URI, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1599:
+ { window_add_bit(KNOT_RRTYPE_AFSDB, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+tr1608:
+ { window_add_bit(KNOT_RRTYPE_APL, s); }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1148;
+st1148:
+ if ( ++p == pe )
+ goto _test_eof1148;
+case 1148:
+ goto st0;
+tr1125:
+ {
+ memset(s->windows, 0, sizeof(s->windows));
+ s->last_window = -1;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1148:
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1159:
+ { window_add_bit(KNOT_RRTYPE_A, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1169:
+ { window_add_bit(KNOT_RRTYPE_AAAA, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1184:
+ { window_add_bit(KNOT_RRTYPE_CAA, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1198:
+ { window_add_bit(KNOT_RRTYPE_CDNSKEY, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1206:
+ { window_add_bit(KNOT_RRTYPE_CDS, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1216:
+ { window_add_bit(KNOT_RRTYPE_CERT, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1227:
+ { window_add_bit(KNOT_RRTYPE_CNAME, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1241:
+ { window_add_bit(KNOT_RRTYPE_DHCID, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1253:
+ { window_add_bit(KNOT_RRTYPE_DNAME, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1264:
+ { window_add_bit(KNOT_RRTYPE_DNSKEY, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1272:
+ { window_add_bit(KNOT_RRTYPE_DS, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1285:
+ { window_add_bit(KNOT_RRTYPE_EUI48, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1294:
+ { window_add_bit(KNOT_RRTYPE_EUI64, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1306:
+ { window_add_bit(KNOT_RRTYPE_HINFO, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1321:
+ { window_add_bit(KNOT_RRTYPE_IPSECKEY, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1332:
+ { window_add_bit(KNOT_RRTYPE_KEY, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1340:
+ { window_add_bit(KNOT_RRTYPE_KX, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1353:
+ { window_add_bit(KNOT_RRTYPE_L32, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1362:
+ { window_add_bit(KNOT_RRTYPE_L64, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1371:
+ { window_add_bit(KNOT_RRTYPE_LOC, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1379:
+ { window_add_bit(KNOT_RRTYPE_LP, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1392:
+ { window_add_bit(KNOT_RRTYPE_MINFO, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1400:
+ { window_add_bit(KNOT_RRTYPE_MX, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1414:
+ { window_add_bit(KNOT_RRTYPE_NAPTR, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1423:
+ { window_add_bit(KNOT_RRTYPE_NID, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1432:
+ { window_add_bit(KNOT_RRTYPE_NS, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1442:
+ { window_add_bit(KNOT_RRTYPE_NSEC, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1451:
+ { window_add_bit(KNOT_RRTYPE_NSEC3, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1463:
+ { window_add_bit(KNOT_RRTYPE_NSEC3PARAM, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1473:
+ { window_add_bit(KNOT_RRTYPE_PTR, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1484:
+ { window_add_bit(KNOT_RRTYPE_RP, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1495:
+ { window_add_bit(KNOT_RRTYPE_RRSIG, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1503:
+ { window_add_bit(KNOT_RRTYPE_RT, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1516:
+ { window_add_bit(KNOT_RRTYPE_SOA, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1525:
+ { window_add_bit(KNOT_RRTYPE_SPF, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1534:
+ { window_add_bit(KNOT_RRTYPE_SRV, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1545:
+ { window_add_bit(KNOT_RRTYPE_SSHFP, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1558:
+ { window_add_bit(KNOT_RRTYPE_TLSA, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1567:
+ { window_add_bit(KNOT_RRTYPE_TXT, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1579:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ window_add_bit(s->number64, s);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1589:
+ { window_add_bit(KNOT_RRTYPE_URI, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1600:
+ { window_add_bit(KNOT_RRTYPE_AFSDB, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+tr1609:
+ { window_add_bit(KNOT_RRTYPE_APL, s); }
+ {
+ s->line_counter++;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1149;
+st1149:
+ if ( ++p == pe )
+ goto _test_eof1149;
+case 1149:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st337;
+ case 32: goto st337;
+ case 40: goto tr1128;
+ case 41: goto tr1129;
+ case 65: goto st338;
+ case 67: goto st343;
+ case 68: goto st360;
+ case 69: goto st374;
+ case 72: goto st381;
+ case 73: goto st386;
+ case 75: goto st394;
+ case 76: goto st398;
+ case 77: goto st406;
+ case 78: goto st412;
+ case 80: goto st428;
+ case 82: goto st431;
+ case 83: goto st438;
+ case 84: goto st449;
+ case 85: goto st459;
+ case 97: goto st338;
+ case 99: goto st343;
+ case 100: goto st360;
+ case 101: goto st374;
+ case 104: goto st381;
+ case 105: goto st386;
+ case 107: goto st394;
+ case 108: goto st398;
+ case 109: goto st406;
+ case 110: goto st412;
+ case 112: goto st428;
+ case 114: goto st431;
+ case 115: goto st438;
+ case 116: goto st449;
+ case 117: goto st459;
+ case 2058: goto tr1145;
+ case 2107: goto tr1146;
+ case 2314: goto tr1147;
+ case 2363: goto tr1147;
+ case 2570: goto tr1148;
+ case 2619: goto tr1149;
+ }
+ goto tr1118;
+st343:
+ if ( ++p == pe )
+ goto _test_eof343;
+case 343:
+ switch( (*p) ) {
+ case 65: goto st344;
+ case 68: goto st346;
+ case 69: goto st353;
+ case 78: goto st356;
+ case 97: goto st344;
+ case 100: goto st346;
+ case 101: goto st353;
+ case 110: goto st356;
+ }
+ goto tr1118;
+st344:
+ if ( ++p == pe )
+ goto _test_eof344;
+case 344:
+ switch( (*p) ) {
+ case 65: goto st345;
+ case 97: goto st345;
+ }
+ goto tr1118;
+st345:
+ if ( ++p == pe )
+ goto _test_eof345;
+case 345:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1178;
+ case 32: goto tr1178;
+ case 40: goto tr1179;
+ case 41: goto tr1180;
+ case 2058: goto tr1181;
+ case 2107: goto tr1182;
+ case 2314: goto tr1183;
+ case 2363: goto tr1183;
+ case 2570: goto tr1184;
+ case 2619: goto tr1185;
+ }
+ goto tr1118;
+tr1126:
+ {
+ memset(s->windows, 0, sizeof(s->windows));
+ s->last_window = -1;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1149:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1160:
+ { window_add_bit(KNOT_RRTYPE_A, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1170:
+ { window_add_bit(KNOT_RRTYPE_AAAA, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1185:
+ { window_add_bit(KNOT_RRTYPE_CAA, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1199:
+ { window_add_bit(KNOT_RRTYPE_CDNSKEY, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1207:
+ { window_add_bit(KNOT_RRTYPE_CDS, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1217:
+ { window_add_bit(KNOT_RRTYPE_CERT, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1228:
+ { window_add_bit(KNOT_RRTYPE_CNAME, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1242:
+ { window_add_bit(KNOT_RRTYPE_DHCID, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1254:
+ { window_add_bit(KNOT_RRTYPE_DNAME, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1265:
+ { window_add_bit(KNOT_RRTYPE_DNSKEY, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1273:
+ { window_add_bit(KNOT_RRTYPE_DS, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1286:
+ { window_add_bit(KNOT_RRTYPE_EUI48, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1295:
+ { window_add_bit(KNOT_RRTYPE_EUI64, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1307:
+ { window_add_bit(KNOT_RRTYPE_HINFO, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1322:
+ { window_add_bit(KNOT_RRTYPE_IPSECKEY, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1333:
+ { window_add_bit(KNOT_RRTYPE_KEY, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1341:
+ { window_add_bit(KNOT_RRTYPE_KX, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1354:
+ { window_add_bit(KNOT_RRTYPE_L32, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1363:
+ { window_add_bit(KNOT_RRTYPE_L64, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1372:
+ { window_add_bit(KNOT_RRTYPE_LOC, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1380:
+ { window_add_bit(KNOT_RRTYPE_LP, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1393:
+ { window_add_bit(KNOT_RRTYPE_MINFO, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1401:
+ { window_add_bit(KNOT_RRTYPE_MX, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1415:
+ { window_add_bit(KNOT_RRTYPE_NAPTR, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1424:
+ { window_add_bit(KNOT_RRTYPE_NID, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1433:
+ { window_add_bit(KNOT_RRTYPE_NS, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1443:
+ { window_add_bit(KNOT_RRTYPE_NSEC, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1452:
+ { window_add_bit(KNOT_RRTYPE_NSEC3, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1464:
+ { window_add_bit(KNOT_RRTYPE_NSEC3PARAM, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1474:
+ { window_add_bit(KNOT_RRTYPE_PTR, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1485:
+ { window_add_bit(KNOT_RRTYPE_RP, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1496:
+ { window_add_bit(KNOT_RRTYPE_RRSIG, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1504:
+ { window_add_bit(KNOT_RRTYPE_RT, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1517:
+ { window_add_bit(KNOT_RRTYPE_SOA, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1526:
+ { window_add_bit(KNOT_RRTYPE_SPF, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1535:
+ { window_add_bit(KNOT_RRTYPE_SRV, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1546:
+ { window_add_bit(KNOT_RRTYPE_SSHFP, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1559:
+ { window_add_bit(KNOT_RRTYPE_TLSA, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1568:
+ { window_add_bit(KNOT_RRTYPE_TXT, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1580:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ window_add_bit(s->number64, s);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1590:
+ { window_add_bit(KNOT_RRTYPE_URI, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1601:
+ { window_add_bit(KNOT_RRTYPE_AFSDB, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+tr1610:
+ { window_add_bit(KNOT_RRTYPE_APL, s); }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1150;
+st1150:
+ if ( ++p == pe )
+ goto _test_eof1150;
+case 1150:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr1172;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr1171;
+ goto tr1118;
+st346:
+ if ( ++p == pe )
+ goto _test_eof346;
+case 346:
+ switch( (*p) ) {
+ case 78: goto st347;
+ case 83: goto st352;
+ case 110: goto st347;
+ case 115: goto st352;
+ }
+ goto tr1118;
+st347:
+ if ( ++p == pe )
+ goto _test_eof347;
+case 347:
+ switch( (*p) ) {
+ case 83: goto st348;
+ case 115: goto st348;
+ }
+ goto tr1118;
+st348:
+ if ( ++p == pe )
+ goto _test_eof348;
+case 348:
+ switch( (*p) ) {
+ case 75: goto st349;
+ case 107: goto st349;
+ }
+ goto tr1118;
+st349:
+ if ( ++p == pe )
+ goto _test_eof349;
+case 349:
+ switch( (*p) ) {
+ case 69: goto st350;
+ case 101: goto st350;
+ }
+ goto tr1118;
+st350:
+ if ( ++p == pe )
+ goto _test_eof350;
+case 350:
+ switch( (*p) ) {
+ case 89: goto st351;
+ case 121: goto st351;
+ }
+ goto tr1118;
+st351:
+ if ( ++p == pe )
+ goto _test_eof351;
+case 351:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1192;
+ case 32: goto tr1192;
+ case 40: goto tr1193;
+ case 41: goto tr1194;
+ case 2058: goto tr1195;
+ case 2107: goto tr1196;
+ case 2314: goto tr1197;
+ case 2363: goto tr1197;
+ case 2570: goto tr1198;
+ case 2619: goto tr1199;
+ }
+ goto tr1118;
+st352:
+ if ( ++p == pe )
+ goto _test_eof352;
+case 352:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1200;
+ case 32: goto tr1200;
+ case 40: goto tr1201;
+ case 41: goto tr1202;
+ case 2058: goto tr1203;
+ case 2107: goto tr1204;
+ case 2314: goto tr1205;
+ case 2363: goto tr1205;
+ case 2570: goto tr1206;
+ case 2619: goto tr1207;
+ }
+ goto tr1118;
+st353:
+ if ( ++p == pe )
+ goto _test_eof353;
+case 353:
+ switch( (*p) ) {
+ case 82: goto st354;
+ case 114: goto st354;
+ }
+ goto tr1118;
+st354:
+ if ( ++p == pe )
+ goto _test_eof354;
+case 354:
+ switch( (*p) ) {
+ case 84: goto st355;
+ case 116: goto st355;
+ }
+ goto tr1118;
+st355:
+ if ( ++p == pe )
+ goto _test_eof355;
+case 355:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1210;
+ case 32: goto tr1210;
+ case 40: goto tr1211;
+ case 41: goto tr1212;
+ case 2058: goto tr1213;
+ case 2107: goto tr1214;
+ case 2314: goto tr1215;
+ case 2363: goto tr1215;
+ case 2570: goto tr1216;
+ case 2619: goto tr1217;
+ }
+ goto tr1118;
+st356:
+ if ( ++p == pe )
+ goto _test_eof356;
+case 356:
+ switch( (*p) ) {
+ case 65: goto st357;
+ case 97: goto st357;
+ }
+ goto tr1118;
+st357:
+ if ( ++p == pe )
+ goto _test_eof357;
+case 357:
+ switch( (*p) ) {
+ case 77: goto st358;
+ case 109: goto st358;
+ }
+ goto tr1118;
+st358:
+ if ( ++p == pe )
+ goto _test_eof358;
+case 358:
+ switch( (*p) ) {
+ case 69: goto st359;
+ case 101: goto st359;
+ }
+ goto tr1118;
+st359:
+ if ( ++p == pe )
+ goto _test_eof359;
+case 359:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1221;
+ case 32: goto tr1221;
+ case 40: goto tr1222;
+ case 41: goto tr1223;
+ case 2058: goto tr1224;
+ case 2107: goto tr1225;
+ case 2314: goto tr1226;
+ case 2363: goto tr1226;
+ case 2570: goto tr1227;
+ case 2619: goto tr1228;
+ }
+ goto tr1118;
+st360:
+ if ( ++p == pe )
+ goto _test_eof360;
+case 360:
+ switch( (*p) ) {
+ case 72: goto st361;
+ case 78: goto st365;
+ case 83: goto st373;
+ case 104: goto st361;
+ case 110: goto st365;
+ case 115: goto st373;
+ }
+ goto tr1118;
+st361:
+ if ( ++p == pe )
+ goto _test_eof361;
+case 361:
+ switch( (*p) ) {
+ case 67: goto st362;
+ case 99: goto st362;
+ }
+ goto tr1118;
+st362:
+ if ( ++p == pe )
+ goto _test_eof362;
+case 362:
+ switch( (*p) ) {
+ case 73: goto st363;
+ case 105: goto st363;
+ }
+ goto tr1118;
+st363:
+ if ( ++p == pe )
+ goto _test_eof363;
+case 363:
+ switch( (*p) ) {
+ case 68: goto st364;
+ case 100: goto st364;
+ }
+ goto tr1118;
+st364:
+ if ( ++p == pe )
+ goto _test_eof364;
+case 364:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1235;
+ case 32: goto tr1235;
+ case 40: goto tr1236;
+ case 41: goto tr1237;
+ case 2058: goto tr1238;
+ case 2107: goto tr1239;
+ case 2314: goto tr1240;
+ case 2363: goto tr1240;
+ case 2570: goto tr1241;
+ case 2619: goto tr1242;
+ }
+ goto tr1118;
+st365:
+ if ( ++p == pe )
+ goto _test_eof365;
+case 365:
+ switch( (*p) ) {
+ case 65: goto st366;
+ case 83: goto st369;
+ case 97: goto st366;
+ case 115: goto st369;
+ }
+ goto tr1118;
+st366:
+ if ( ++p == pe )
+ goto _test_eof366;
+case 366:
+ switch( (*p) ) {
+ case 77: goto st367;
+ case 109: goto st367;
+ }
+ goto tr1118;
+st367:
+ if ( ++p == pe )
+ goto _test_eof367;
+case 367:
+ switch( (*p) ) {
+ case 69: goto st368;
+ case 101: goto st368;
+ }
+ goto tr1118;
+st368:
+ if ( ++p == pe )
+ goto _test_eof368;
+case 368:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1247;
+ case 32: goto tr1247;
+ case 40: goto tr1248;
+ case 41: goto tr1249;
+ case 2058: goto tr1250;
+ case 2107: goto tr1251;
+ case 2314: goto tr1252;
+ case 2363: goto tr1252;
+ case 2570: goto tr1253;
+ case 2619: goto tr1254;
+ }
+ goto tr1118;
+st369:
+ if ( ++p == pe )
+ goto _test_eof369;
+case 369:
+ switch( (*p) ) {
+ case 75: goto st370;
+ case 107: goto st370;
+ }
+ goto tr1118;
+st370:
+ if ( ++p == pe )
+ goto _test_eof370;
+case 370:
+ switch( (*p) ) {
+ case 69: goto st371;
+ case 101: goto st371;
+ }
+ goto tr1118;
+st371:
+ if ( ++p == pe )
+ goto _test_eof371;
+case 371:
+ switch( (*p) ) {
+ case 89: goto st372;
+ case 121: goto st372;
+ }
+ goto tr1118;
+st372:
+ if ( ++p == pe )
+ goto _test_eof372;
+case 372:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1258;
+ case 32: goto tr1258;
+ case 40: goto tr1259;
+ case 41: goto tr1260;
+ case 2058: goto tr1261;
+ case 2107: goto tr1262;
+ case 2314: goto tr1263;
+ case 2363: goto tr1263;
+ case 2570: goto tr1264;
+ case 2619: goto tr1265;
+ }
+ goto tr1118;
+st373:
+ if ( ++p == pe )
+ goto _test_eof373;
+case 373:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1266;
+ case 32: goto tr1266;
+ case 40: goto tr1267;
+ case 41: goto tr1268;
+ case 2058: goto tr1269;
+ case 2107: goto tr1270;
+ case 2314: goto tr1271;
+ case 2363: goto tr1271;
+ case 2570: goto tr1272;
+ case 2619: goto tr1273;
+ }
+ goto tr1118;
+st374:
+ if ( ++p == pe )
+ goto _test_eof374;
+case 374:
+ switch( (*p) ) {
+ case 85: goto st375;
+ case 117: goto st375;
+ }
+ goto tr1118;
+st375:
+ if ( ++p == pe )
+ goto _test_eof375;
+case 375:
+ switch( (*p) ) {
+ case 73: goto st376;
+ case 105: goto st376;
+ }
+ goto tr1118;
+st376:
+ if ( ++p == pe )
+ goto _test_eof376;
+case 376:
+ switch( (*p) ) {
+ case 52: goto st377;
+ case 54: goto st379;
+ }
+ goto tr1118;
+st377:
+ if ( ++p == pe )
+ goto _test_eof377;
+case 377:
+ if ( (*p) == 56 )
+ goto st378;
+ goto tr1118;
+st378:
+ if ( ++p == pe )
+ goto _test_eof378;
+case 378:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1279;
+ case 32: goto tr1279;
+ case 40: goto tr1280;
+ case 41: goto tr1281;
+ case 2058: goto tr1282;
+ case 2107: goto tr1283;
+ case 2314: goto tr1284;
+ case 2363: goto tr1284;
+ case 2570: goto tr1285;
+ case 2619: goto tr1286;
+ }
+ goto tr1118;
+st379:
+ if ( ++p == pe )
+ goto _test_eof379;
+case 379:
+ if ( (*p) == 52 )
+ goto st380;
+ goto tr1118;
+st380:
+ if ( ++p == pe )
+ goto _test_eof380;
+case 380:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1288;
+ case 32: goto tr1288;
+ case 40: goto tr1289;
+ case 41: goto tr1290;
+ case 2058: goto tr1291;
+ case 2107: goto tr1292;
+ case 2314: goto tr1293;
+ case 2363: goto tr1293;
+ case 2570: goto tr1294;
+ case 2619: goto tr1295;
+ }
+ goto tr1118;
+st381:
+ if ( ++p == pe )
+ goto _test_eof381;
+case 381:
+ switch( (*p) ) {
+ case 73: goto st382;
+ case 105: goto st382;
+ }
+ goto tr1118;
+st382:
+ if ( ++p == pe )
+ goto _test_eof382;
+case 382:
+ switch( (*p) ) {
+ case 78: goto st383;
+ case 110: goto st383;
+ }
+ goto tr1118;
+st383:
+ if ( ++p == pe )
+ goto _test_eof383;
+case 383:
+ switch( (*p) ) {
+ case 70: goto st384;
+ case 102: goto st384;
+ }
+ goto tr1118;
+st384:
+ if ( ++p == pe )
+ goto _test_eof384;
+case 384:
+ switch( (*p) ) {
+ case 79: goto st385;
+ case 111: goto st385;
+ }
+ goto tr1118;
+st385:
+ if ( ++p == pe )
+ goto _test_eof385;
+case 385:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1300;
+ case 32: goto tr1300;
+ case 40: goto tr1301;
+ case 41: goto tr1302;
+ case 2058: goto tr1303;
+ case 2107: goto tr1304;
+ case 2314: goto tr1305;
+ case 2363: goto tr1305;
+ case 2570: goto tr1306;
+ case 2619: goto tr1307;
+ }
+ goto tr1118;
+st386:
+ if ( ++p == pe )
+ goto _test_eof386;
+case 386:
+ switch( (*p) ) {
+ case 80: goto st387;
+ case 112: goto st387;
+ }
+ goto tr1118;
+st387:
+ if ( ++p == pe )
+ goto _test_eof387;
+case 387:
+ switch( (*p) ) {
+ case 83: goto st388;
+ case 115: goto st388;
+ }
+ goto tr1118;
+st388:
+ if ( ++p == pe )
+ goto _test_eof388;
+case 388:
+ switch( (*p) ) {
+ case 69: goto st389;
+ case 101: goto st389;
+ }
+ goto tr1118;
+st389:
+ if ( ++p == pe )
+ goto _test_eof389;
+case 389:
+ switch( (*p) ) {
+ case 67: goto st390;
+ case 99: goto st390;
+ }
+ goto tr1118;
+st390:
+ if ( ++p == pe )
+ goto _test_eof390;
+case 390:
+ switch( (*p) ) {
+ case 75: goto st391;
+ case 107: goto st391;
+ }
+ goto tr1118;
+st391:
+ if ( ++p == pe )
+ goto _test_eof391;
+case 391:
+ switch( (*p) ) {
+ case 69: goto st392;
+ case 101: goto st392;
+ }
+ goto tr1118;
+st392:
+ if ( ++p == pe )
+ goto _test_eof392;
+case 392:
+ switch( (*p) ) {
+ case 89: goto st393;
+ case 121: goto st393;
+ }
+ goto tr1118;
+st393:
+ if ( ++p == pe )
+ goto _test_eof393;
+case 393:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1315;
+ case 32: goto tr1315;
+ case 40: goto tr1316;
+ case 41: goto tr1317;
+ case 2058: goto tr1318;
+ case 2107: goto tr1319;
+ case 2314: goto tr1320;
+ case 2363: goto tr1320;
+ case 2570: goto tr1321;
+ case 2619: goto tr1322;
+ }
+ goto tr1118;
+st394:
+ if ( ++p == pe )
+ goto _test_eof394;
+case 394:
+ switch( (*p) ) {
+ case 69: goto st395;
+ case 88: goto st397;
+ case 101: goto st395;
+ case 120: goto st397;
+ }
+ goto tr1118;
+st395:
+ if ( ++p == pe )
+ goto _test_eof395;
+case 395:
+ switch( (*p) ) {
+ case 89: goto st396;
+ case 121: goto st396;
+ }
+ goto tr1118;
+st396:
+ if ( ++p == pe )
+ goto _test_eof396;
+case 396:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1326;
+ case 32: goto tr1326;
+ case 40: goto tr1327;
+ case 41: goto tr1328;
+ case 2058: goto tr1329;
+ case 2107: goto tr1330;
+ case 2314: goto tr1331;
+ case 2363: goto tr1331;
+ case 2570: goto tr1332;
+ case 2619: goto tr1333;
+ }
+ goto tr1118;
+st397:
+ if ( ++p == pe )
+ goto _test_eof397;
+case 397:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1334;
+ case 32: goto tr1334;
+ case 40: goto tr1335;
+ case 41: goto tr1336;
+ case 2058: goto tr1337;
+ case 2107: goto tr1338;
+ case 2314: goto tr1339;
+ case 2363: goto tr1339;
+ case 2570: goto tr1340;
+ case 2619: goto tr1341;
+ }
+ goto tr1118;
+st398:
+ if ( ++p == pe )
+ goto _test_eof398;
+case 398:
+ switch( (*p) ) {
+ case 51: goto st399;
+ case 54: goto st401;
+ case 79: goto st403;
+ case 80: goto st405;
+ case 111: goto st403;
+ case 112: goto st405;
+ }
+ goto tr1118;
+st399:
+ if ( ++p == pe )
+ goto _test_eof399;
+case 399:
+ if ( (*p) == 50 )
+ goto st400;
+ goto tr1118;
+st400:
+ if ( ++p == pe )
+ goto _test_eof400;
+case 400:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1347;
+ case 32: goto tr1347;
+ case 40: goto tr1348;
+ case 41: goto tr1349;
+ case 2058: goto tr1350;
+ case 2107: goto tr1351;
+ case 2314: goto tr1352;
+ case 2363: goto tr1352;
+ case 2570: goto tr1353;
+ case 2619: goto tr1354;
+ }
+ goto tr1118;
+st401:
+ if ( ++p == pe )
+ goto _test_eof401;
+case 401:
+ if ( (*p) == 52 )
+ goto st402;
+ goto tr1118;
+st402:
+ if ( ++p == pe )
+ goto _test_eof402;
+case 402:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1356;
+ case 32: goto tr1356;
+ case 40: goto tr1357;
+ case 41: goto tr1358;
+ case 2058: goto tr1359;
+ case 2107: goto tr1360;
+ case 2314: goto tr1361;
+ case 2363: goto tr1361;
+ case 2570: goto tr1362;
+ case 2619: goto tr1363;
+ }
+ goto tr1118;
+st403:
+ if ( ++p == pe )
+ goto _test_eof403;
+case 403:
+ switch( (*p) ) {
+ case 67: goto st404;
+ case 99: goto st404;
+ }
+ goto tr1118;
+st404:
+ if ( ++p == pe )
+ goto _test_eof404;
+case 404:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1365;
+ case 32: goto tr1365;
+ case 40: goto tr1366;
+ case 41: goto tr1367;
+ case 2058: goto tr1368;
+ case 2107: goto tr1369;
+ case 2314: goto tr1370;
+ case 2363: goto tr1370;
+ case 2570: goto tr1371;
+ case 2619: goto tr1372;
+ }
+ goto tr1118;
+st405:
+ if ( ++p == pe )
+ goto _test_eof405;
+case 405:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1373;
+ case 32: goto tr1373;
+ case 40: goto tr1374;
+ case 41: goto tr1375;
+ case 2058: goto tr1376;
+ case 2107: goto tr1377;
+ case 2314: goto tr1378;
+ case 2363: goto tr1378;
+ case 2570: goto tr1379;
+ case 2619: goto tr1380;
+ }
+ goto tr1118;
+st406:
+ if ( ++p == pe )
+ goto _test_eof406;
+case 406:
+ switch( (*p) ) {
+ case 73: goto st407;
+ case 88: goto st411;
+ case 105: goto st407;
+ case 120: goto st411;
+ }
+ goto tr1118;
+st407:
+ if ( ++p == pe )
+ goto _test_eof407;
+case 407:
+ switch( (*p) ) {
+ case 78: goto st408;
+ case 110: goto st408;
+ }
+ goto tr1118;
+st408:
+ if ( ++p == pe )
+ goto _test_eof408;
+case 408:
+ switch( (*p) ) {
+ case 70: goto st409;
+ case 102: goto st409;
+ }
+ goto tr1118;
+st409:
+ if ( ++p == pe )
+ goto _test_eof409;
+case 409:
+ switch( (*p) ) {
+ case 79: goto st410;
+ case 111: goto st410;
+ }
+ goto tr1118;
+st410:
+ if ( ++p == pe )
+ goto _test_eof410;
+case 410:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1386;
+ case 32: goto tr1386;
+ case 40: goto tr1387;
+ case 41: goto tr1388;
+ case 2058: goto tr1389;
+ case 2107: goto tr1390;
+ case 2314: goto tr1391;
+ case 2363: goto tr1391;
+ case 2570: goto tr1392;
+ case 2619: goto tr1393;
+ }
+ goto tr1118;
+st411:
+ if ( ++p == pe )
+ goto _test_eof411;
+case 411:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1394;
+ case 32: goto tr1394;
+ case 40: goto tr1395;
+ case 41: goto tr1396;
+ case 2058: goto tr1397;
+ case 2107: goto tr1398;
+ case 2314: goto tr1399;
+ case 2363: goto tr1399;
+ case 2570: goto tr1400;
+ case 2619: goto tr1401;
+ }
+ goto tr1118;
+st412:
+ if ( ++p == pe )
+ goto _test_eof412;
+case 412:
+ switch( (*p) ) {
+ case 65: goto st413;
+ case 73: goto st417;
+ case 83: goto st419;
+ case 97: goto st413;
+ case 105: goto st417;
+ case 115: goto st419;
+ }
+ goto tr1118;
+st413:
+ if ( ++p == pe )
+ goto _test_eof413;
+case 413:
+ switch( (*p) ) {
+ case 80: goto st414;
+ case 112: goto st414;
+ }
+ goto tr1118;
+st414:
+ if ( ++p == pe )
+ goto _test_eof414;
+case 414:
+ switch( (*p) ) {
+ case 84: goto st415;
+ case 116: goto st415;
+ }
+ goto tr1118;
+st415:
+ if ( ++p == pe )
+ goto _test_eof415;
+case 415:
+ switch( (*p) ) {
+ case 82: goto st416;
+ case 114: goto st416;
+ }
+ goto tr1118;
+st416:
+ if ( ++p == pe )
+ goto _test_eof416;
+case 416:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1408;
+ case 32: goto tr1408;
+ case 40: goto tr1409;
+ case 41: goto tr1410;
+ case 2058: goto tr1411;
+ case 2107: goto tr1412;
+ case 2314: goto tr1413;
+ case 2363: goto tr1413;
+ case 2570: goto tr1414;
+ case 2619: goto tr1415;
+ }
+ goto tr1118;
+st417:
+ if ( ++p == pe )
+ goto _test_eof417;
+case 417:
+ switch( (*p) ) {
+ case 68: goto st418;
+ case 100: goto st418;
+ }
+ goto tr1118;
+st418:
+ if ( ++p == pe )
+ goto _test_eof418;
+case 418:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1417;
+ case 32: goto tr1417;
+ case 40: goto tr1418;
+ case 41: goto tr1419;
+ case 2058: goto tr1420;
+ case 2107: goto tr1421;
+ case 2314: goto tr1422;
+ case 2363: goto tr1422;
+ case 2570: goto tr1423;
+ case 2619: goto tr1424;
+ }
+ goto tr1118;
+st419:
+ if ( ++p == pe )
+ goto _test_eof419;
+case 419:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1425;
+ case 32: goto tr1425;
+ case 40: goto tr1426;
+ case 41: goto tr1427;
+ case 69: goto st420;
+ case 101: goto st420;
+ case 2058: goto tr1429;
+ case 2107: goto tr1430;
+ case 2314: goto tr1431;
+ case 2363: goto tr1431;
+ case 2570: goto tr1432;
+ case 2619: goto tr1433;
+ }
+ goto tr1118;
+st420:
+ if ( ++p == pe )
+ goto _test_eof420;
+case 420:
+ switch( (*p) ) {
+ case 67: goto st421;
+ case 99: goto st421;
+ }
+ goto tr1118;
+st421:
+ if ( ++p == pe )
+ goto _test_eof421;
+case 421:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1435;
+ case 32: goto tr1435;
+ case 40: goto tr1436;
+ case 41: goto tr1437;
+ case 51: goto st422;
+ case 2058: goto tr1439;
+ case 2107: goto tr1440;
+ case 2314: goto tr1441;
+ case 2363: goto tr1441;
+ case 2570: goto tr1442;
+ case 2619: goto tr1443;
+ }
+ goto tr1118;
+st422:
+ if ( ++p == pe )
+ goto _test_eof422;
+case 422:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1444;
+ case 32: goto tr1444;
+ case 40: goto tr1445;
+ case 41: goto tr1446;
+ case 80: goto st423;
+ case 112: goto st423;
+ case 2058: goto tr1448;
+ case 2107: goto tr1449;
+ case 2314: goto tr1450;
+ case 2363: goto tr1450;
+ case 2570: goto tr1451;
+ case 2619: goto tr1452;
+ }
+ goto tr1118;
+st423:
+ if ( ++p == pe )
+ goto _test_eof423;
+case 423:
+ switch( (*p) ) {
+ case 65: goto st424;
+ case 97: goto st424;
+ }
+ goto tr1118;
+st424:
+ if ( ++p == pe )
+ goto _test_eof424;
+case 424:
+ switch( (*p) ) {
+ case 82: goto st425;
+ case 114: goto st425;
+ }
+ goto tr1118;
+st425:
+ if ( ++p == pe )
+ goto _test_eof425;
+case 425:
+ switch( (*p) ) {
+ case 65: goto st426;
+ case 97: goto st426;
+ }
+ goto tr1118;
+st426:
+ if ( ++p == pe )
+ goto _test_eof426;
+case 426:
+ switch( (*p) ) {
+ case 77: goto st427;
+ case 109: goto st427;
+ }
+ goto tr1118;
+st427:
+ if ( ++p == pe )
+ goto _test_eof427;
+case 427:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1457;
+ case 32: goto tr1457;
+ case 40: goto tr1458;
+ case 41: goto tr1459;
+ case 2058: goto tr1460;
+ case 2107: goto tr1461;
+ case 2314: goto tr1462;
+ case 2363: goto tr1462;
+ case 2570: goto tr1463;
+ case 2619: goto tr1464;
+ }
+ goto tr1118;
+st428:
+ if ( ++p == pe )
+ goto _test_eof428;
+case 428:
+ switch( (*p) ) {
+ case 84: goto st429;
+ case 116: goto st429;
+ }
+ goto tr1118;
+st429:
+ if ( ++p == pe )
+ goto _test_eof429;
+case 429:
+ switch( (*p) ) {
+ case 82: goto st430;
+ case 114: goto st430;
+ }
+ goto tr1118;
+st430:
+ if ( ++p == pe )
+ goto _test_eof430;
+case 430:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1467;
+ case 32: goto tr1467;
+ case 40: goto tr1468;
+ case 41: goto tr1469;
+ case 2058: goto tr1470;
+ case 2107: goto tr1471;
+ case 2314: goto tr1472;
+ case 2363: goto tr1472;
+ case 2570: goto tr1473;
+ case 2619: goto tr1474;
+ }
+ goto tr1118;
+st431:
+ if ( ++p == pe )
+ goto _test_eof431;
+case 431:
+ switch( (*p) ) {
+ case 80: goto st432;
+ case 82: goto st433;
+ case 84: goto st437;
+ case 112: goto st432;
+ case 114: goto st433;
+ case 116: goto st437;
+ }
+ goto tr1118;
+st432:
+ if ( ++p == pe )
+ goto _test_eof432;
+case 432:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1478;
+ case 32: goto tr1478;
+ case 40: goto tr1479;
+ case 41: goto tr1480;
+ case 2058: goto tr1481;
+ case 2107: goto tr1482;
+ case 2314: goto tr1483;
+ case 2363: goto tr1483;
+ case 2570: goto tr1484;
+ case 2619: goto tr1485;
+ }
+ goto tr1118;
+st433:
+ if ( ++p == pe )
+ goto _test_eof433;
+case 433:
+ switch( (*p) ) {
+ case 83: goto st434;
+ case 115: goto st434;
+ }
+ goto tr1118;
+st434:
+ if ( ++p == pe )
+ goto _test_eof434;
+case 434:
+ switch( (*p) ) {
+ case 73: goto st435;
+ case 105: goto st435;
+ }
+ goto tr1118;
+st435:
+ if ( ++p == pe )
+ goto _test_eof435;
+case 435:
+ switch( (*p) ) {
+ case 71: goto st436;
+ case 103: goto st436;
+ }
+ goto tr1118;
+st436:
+ if ( ++p == pe )
+ goto _test_eof436;
+case 436:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1489;
+ case 32: goto tr1489;
+ case 40: goto tr1490;
+ case 41: goto tr1491;
+ case 2058: goto tr1492;
+ case 2107: goto tr1493;
+ case 2314: goto tr1494;
+ case 2363: goto tr1494;
+ case 2570: goto tr1495;
+ case 2619: goto tr1496;
+ }
+ goto tr1118;
+st437:
+ if ( ++p == pe )
+ goto _test_eof437;
+case 437:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1497;
+ case 32: goto tr1497;
+ case 40: goto tr1498;
+ case 41: goto tr1499;
+ case 2058: goto tr1500;
+ case 2107: goto tr1501;
+ case 2314: goto tr1502;
+ case 2363: goto tr1502;
+ case 2570: goto tr1503;
+ case 2619: goto tr1504;
+ }
+ goto tr1118;
+st438:
+ if ( ++p == pe )
+ goto _test_eof438;
+case 438:
+ switch( (*p) ) {
+ case 79: goto st439;
+ case 80: goto st441;
+ case 82: goto st443;
+ case 83: goto st445;
+ case 111: goto st439;
+ case 112: goto st441;
+ case 114: goto st443;
+ case 115: goto st445;
+ }
+ goto tr1118;
+st439:
+ if ( ++p == pe )
+ goto _test_eof439;
+case 439:
+ switch( (*p) ) {
+ case 65: goto st440;
+ case 97: goto st440;
+ }
+ goto tr1118;
+st440:
+ if ( ++p == pe )
+ goto _test_eof440;
+case 440:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1510;
+ case 32: goto tr1510;
+ case 40: goto tr1511;
+ case 41: goto tr1512;
+ case 2058: goto tr1513;
+ case 2107: goto tr1514;
+ case 2314: goto tr1515;
+ case 2363: goto tr1515;
+ case 2570: goto tr1516;
+ case 2619: goto tr1517;
+ }
+ goto tr1118;
+st441:
+ if ( ++p == pe )
+ goto _test_eof441;
+case 441:
+ switch( (*p) ) {
+ case 70: goto st442;
+ case 102: goto st442;
+ }
+ goto tr1118;
+st442:
+ if ( ++p == pe )
+ goto _test_eof442;
+case 442:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1519;
+ case 32: goto tr1519;
+ case 40: goto tr1520;
+ case 41: goto tr1521;
+ case 2058: goto tr1522;
+ case 2107: goto tr1523;
+ case 2314: goto tr1524;
+ case 2363: goto tr1524;
+ case 2570: goto tr1525;
+ case 2619: goto tr1526;
+ }
+ goto tr1118;
+st443:
+ if ( ++p == pe )
+ goto _test_eof443;
+case 443:
+ switch( (*p) ) {
+ case 86: goto st444;
+ case 118: goto st444;
+ }
+ goto tr1118;
+st444:
+ if ( ++p == pe )
+ goto _test_eof444;
+case 444:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1528;
+ case 32: goto tr1528;
+ case 40: goto tr1529;
+ case 41: goto tr1530;
+ case 2058: goto tr1531;
+ case 2107: goto tr1532;
+ case 2314: goto tr1533;
+ case 2363: goto tr1533;
+ case 2570: goto tr1534;
+ case 2619: goto tr1535;
+ }
+ goto tr1118;
+st445:
+ if ( ++p == pe )
+ goto _test_eof445;
+case 445:
+ switch( (*p) ) {
+ case 72: goto st446;
+ case 104: goto st446;
+ }
+ goto tr1118;
+st446:
+ if ( ++p == pe )
+ goto _test_eof446;
+case 446:
+ switch( (*p) ) {
+ case 70: goto st447;
+ case 102: goto st447;
+ }
+ goto tr1118;
+st447:
+ if ( ++p == pe )
+ goto _test_eof447;
+case 447:
+ switch( (*p) ) {
+ case 80: goto st448;
+ case 112: goto st448;
+ }
+ goto tr1118;
+st448:
+ if ( ++p == pe )
+ goto _test_eof448;
+case 448:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1539;
+ case 32: goto tr1539;
+ case 40: goto tr1540;
+ case 41: goto tr1541;
+ case 2058: goto tr1542;
+ case 2107: goto tr1543;
+ case 2314: goto tr1544;
+ case 2363: goto tr1544;
+ case 2570: goto tr1545;
+ case 2619: goto tr1546;
+ }
+ goto tr1118;
+st449:
+ if ( ++p == pe )
+ goto _test_eof449;
+case 449:
+ switch( (*p) ) {
+ case 76: goto st450;
+ case 88: goto st453;
+ case 89: goto st455;
+ case 108: goto st450;
+ case 120: goto st453;
+ case 121: goto st455;
+ }
+ goto tr1118;
+st450:
+ if ( ++p == pe )
+ goto _test_eof450;
+case 450:
+ switch( (*p) ) {
+ case 83: goto st451;
+ case 115: goto st451;
+ }
+ goto tr1118;
+st451:
+ if ( ++p == pe )
+ goto _test_eof451;
+case 451:
+ switch( (*p) ) {
+ case 65: goto st452;
+ case 97: goto st452;
+ }
+ goto tr1118;
+st452:
+ if ( ++p == pe )
+ goto _test_eof452;
+case 452:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1552;
+ case 32: goto tr1552;
+ case 40: goto tr1553;
+ case 41: goto tr1554;
+ case 2058: goto tr1555;
+ case 2107: goto tr1556;
+ case 2314: goto tr1557;
+ case 2363: goto tr1557;
+ case 2570: goto tr1558;
+ case 2619: goto tr1559;
+ }
+ goto tr1118;
+st453:
+ if ( ++p == pe )
+ goto _test_eof453;
+case 453:
+ switch( (*p) ) {
+ case 84: goto st454;
+ case 116: goto st454;
+ }
+ goto tr1118;
+st454:
+ if ( ++p == pe )
+ goto _test_eof454;
+case 454:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1561;
+ case 32: goto tr1561;
+ case 40: goto tr1562;
+ case 41: goto tr1563;
+ case 2058: goto tr1564;
+ case 2107: goto tr1565;
+ case 2314: goto tr1566;
+ case 2363: goto tr1566;
+ case 2570: goto tr1567;
+ case 2619: goto tr1568;
+ }
+ goto tr1118;
+st455:
+ if ( ++p == pe )
+ goto _test_eof455;
+case 455:
+ switch( (*p) ) {
+ case 80: goto st456;
+ case 112: goto st456;
+ }
+ goto tr1118;
+st456:
+ if ( ++p == pe )
+ goto _test_eof456;
+case 456:
+ switch( (*p) ) {
+ case 69: goto st457;
+ case 101: goto st457;
+ }
+ goto tr1118;
+st457:
+ if ( ++p == pe )
+ goto _test_eof457;
+case 457:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr1571;
+ goto tr1118;
+tr1571:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st458;
+tr1575:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st458;
+st458:
+ if ( ++p == pe )
+ goto _test_eof458;
+case 458:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1572;
+ case 32: goto tr1572;
+ case 40: goto tr1573;
+ case 41: goto tr1574;
+ case 2058: goto tr1576;
+ case 2107: goto tr1577;
+ case 2314: goto tr1578;
+ case 2363: goto tr1578;
+ case 2570: goto tr1579;
+ case 2619: goto tr1580;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr1575;
+ goto tr1118;
+st459:
+ if ( ++p == pe )
+ goto _test_eof459;
+case 459:
+ switch( (*p) ) {
+ case 82: goto st460;
+ case 114: goto st460;
+ }
+ goto tr1118;
+st460:
+ if ( ++p == pe )
+ goto _test_eof460;
+case 460:
+ switch( (*p) ) {
+ case 73: goto st461;
+ case 105: goto st461;
+ }
+ goto tr1118;
+st461:
+ if ( ++p == pe )
+ goto _test_eof461;
+case 461:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1583;
+ case 32: goto tr1583;
+ case 40: goto tr1584;
+ case 41: goto tr1585;
+ case 2058: goto tr1586;
+ case 2107: goto tr1587;
+ case 2314: goto tr1588;
+ case 2363: goto tr1588;
+ case 2570: goto tr1589;
+ case 2619: goto tr1590;
+ }
+ goto tr1118;
+st462:
+ if ( ++p == pe )
+ goto _test_eof462;
+case 462:
+ switch( (*p) ) {
+ case 83: goto st463;
+ case 115: goto st463;
+ }
+ goto tr1118;
+st463:
+ if ( ++p == pe )
+ goto _test_eof463;
+case 463:
+ switch( (*p) ) {
+ case 68: goto st464;
+ case 100: goto st464;
+ }
+ goto tr1118;
+st464:
+ if ( ++p == pe )
+ goto _test_eof464;
+case 464:
+ switch( (*p) ) {
+ case 66: goto st465;
+ case 98: goto st465;
+ }
+ goto tr1118;
+st465:
+ if ( ++p == pe )
+ goto _test_eof465;
+case 465:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1594;
+ case 32: goto tr1594;
+ case 40: goto tr1595;
+ case 41: goto tr1596;
+ case 2058: goto tr1597;
+ case 2107: goto tr1598;
+ case 2314: goto tr1599;
+ case 2363: goto tr1599;
+ case 2570: goto tr1600;
+ case 2619: goto tr1601;
+ }
+ goto tr1118;
+st466:
+ if ( ++p == pe )
+ goto _test_eof466;
+case 466:
+ switch( (*p) ) {
+ case 76: goto st467;
+ case 108: goto st467;
+ }
+ goto tr1118;
+st467:
+ if ( ++p == pe )
+ goto _test_eof467;
+case 467:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr1603;
+ case 32: goto tr1603;
+ case 40: goto tr1604;
+ case 41: goto tr1605;
+ case 2058: goto tr1606;
+ case 2107: goto tr1607;
+ case 2314: goto tr1608;
+ case 2363: goto tr1608;
+ case 2570: goto tr1609;
+ case 2619: goto tr1610;
+ }
+ goto tr1118;
+st468:
+ if ( ++p == pe )
+ goto _test_eof468;
+case 468:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st469;
+ case 32: goto st469;
+ case 40: goto tr1613;
+ case 41: goto tr1614;
+ case 1034: goto tr1615;
+ case 1083: goto tr1616;
+ }
+ goto tr1611;
+tr1613:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st469;
+tr1614:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st469;
+tr1615:
+ {
+ s->line_counter++;
+ }
+ goto st469;
+tr1646:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st469;
+st469:
+ if ( ++p == pe )
+ goto _test_eof469;
+case 469:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st469;
+ case 32: goto st469;
+ case 40: goto tr1613;
+ case 41: goto tr1614;
+ case 1034: goto tr1615;
+ case 1083: goto tr1616;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr1618;
+ goto tr1617;
+tr1618:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st470;
+tr1622:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st470;
+st470:
+ if ( ++p == pe )
+ goto _test_eof470;
+case 470:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr1619;
+ case 32: goto tr1619;
+ case 40: goto tr1620;
+ case 41: goto tr1621;
+ case 1034: goto tr1623;
+ case 1083: goto tr1624;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr1622;
+ goto tr1617;
+tr1627:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st471;
+tr1628:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st471;
+tr1630:
+ {
+ s->line_counter++;
+ }
+ goto st471;
+tr1644:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st471;
+tr1619:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ s->r_data_length = (uint16_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st471;
+tr1620:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ s->r_data_length = (uint16_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st471;
+tr1621:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ s->r_data_length = (uint16_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st471;
+tr1623:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ s->r_data_length = (uint16_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st471;
+st471:
+ if ( ++p == pe )
+ goto _test_eof471;
+case 471:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st471;
+ case 32: goto st471;
+ case 40: goto tr1627;
+ case 41: goto tr1628;
+ case 1034: goto tr1630;
+ case 1083: goto tr1631;
+ }
+ if ( _widec < 65 ) {
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr1629;
+ } else if ( _widec > 70 ) {
+ if ( 97 <= _widec && _widec <= 102 )
+ goto tr1629;
+ } else
+ goto tr1629;
+ goto tr1625;
+tr1629:
+ {
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = first_hex_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st472;
+st472:
+ if ( ++p == pe )
+ goto _test_eof472;
+case 472:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr1632;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto tr1632;
+ } else
+ goto tr1632;
+ goto tr1625;
+tr1634:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st473;
+tr1635:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st473;
+tr1636:
+ {
+ s->line_counter++;
+ }
+ goto st473;
+tr1642:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st473;
+tr1632:
+ {
+ *rdata_tail += second_hex_to_num[(uint8_t)(*p)];
+ rdata_tail++;
+ }
+ goto st473;
+st473:
+ if ( ++p == pe )
+ goto _test_eof473;
+case 473:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st473;
+ case 32: goto st473;
+ case 40: goto tr1634;
+ case 41: goto tr1635;
+ case 2058: goto tr1636;
+ case 2107: goto tr1637;
+ case 2314: goto tr1638;
+ case 2363: goto tr1638;
+ case 2570: goto tr1639;
+ case 2619: goto tr1640;
+ }
+ if ( _widec < 65 ) {
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr1629;
+ } else if ( _widec > 70 ) {
+ if ( 97 <= _widec && _widec <= 102 )
+ goto tr1629;
+ } else
+ goto tr1629;
+ goto tr1625;
+tr1637:
+ {
+ s->buffer_length = 0;
+ }
+ goto st474;
+tr1641:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st474;
+st474:
+ if ( ++p == pe )
+ goto _test_eof474;
+case 474:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr1642;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr1641;
+ goto tr1625;
+tr1638:
+ {
+ if ((rdata_tail - s->r_data) != s->r_data_length) {
+ WARN(ZS_BAD_RDATA_LENGTH);
+ p--; {goto st268;}
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1151;
+st1151:
+ if ( ++p == pe )
+ goto _test_eof1151;
+case 1151:
+ goto st0;
+tr1639:
+ {
+ s->line_counter++;
+ }
+ {
+ if ((rdata_tail - s->r_data) != s->r_data_length) {
+ WARN(ZS_BAD_RDATA_LENGTH);
+ p--; {goto st268;}
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1152;
+st1152:
+ if ( ++p == pe )
+ goto _test_eof1152;
+case 1152:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st473;
+ case 32: goto st473;
+ case 40: goto tr1634;
+ case 41: goto tr1635;
+ case 2058: goto tr1636;
+ case 2107: goto tr1637;
+ case 2314: goto tr1638;
+ case 2363: goto tr1638;
+ case 2570: goto tr1639;
+ case 2619: goto tr1640;
+ }
+ if ( _widec < 65 ) {
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr1629;
+ } else if ( _widec > 70 ) {
+ if ( 97 <= _widec && _widec <= 102 )
+ goto tr1629;
+ } else
+ goto tr1629;
+ goto tr1625;
+tr1640:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ if ((rdata_tail - s->r_data) != s->r_data_length) {
+ WARN(ZS_BAD_RDATA_LENGTH);
+ p--; {goto st268;}
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1153;
+st1153:
+ if ( ++p == pe )
+ goto _test_eof1153;
+case 1153:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr1642;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr1641;
+ goto tr1625;
+tr1631:
+ {
+ s->buffer_length = 0;
+ }
+ goto st475;
+tr1643:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st475;
+tr1624:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ s->r_data_length = (uint16_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st475;
+st475:
+ if ( ++p == pe )
+ goto _test_eof475;
+case 475:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr1644;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr1643;
+ goto tr1611;
+tr1616:
+ {
+ s->buffer_length = 0;
+ }
+ goto st476;
+tr1645:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st476;
+st476:
+ if ( ++p == pe )
+ goto _test_eof476;
+case 476:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr1646;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr1645;
+ goto tr1611;
+st477:
+ if ( ++p == pe )
+ goto _test_eof477;
+case 477:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st478;
+ case 32: goto st478;
+ case 40: goto tr1648;
+ case 41: goto tr1649;
+ case 1034: goto tr1650;
+ case 1083: goto tr1651;
+ }
+ goto tr1611;
+tr1648:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st478;
+tr1649:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st478;
+tr1650:
+ {
+ s->line_counter++;
+ }
+ goto st478;
+tr1686:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st478;
+st478:
+ if ( ++p == pe )
+ goto _test_eof478;
+case 478:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st478;
+ case 32: goto st478;
+ case 40: goto tr1648;
+ case 41: goto tr1649;
+ case 48: goto tr1652;
+ case 1034: goto tr1650;
+ case 1083: goto tr1651;
+ }
+ if ( 49 <= _widec && _widec <= 57 )
+ goto tr1653;
+ goto tr1617;
+tr1652:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st479;
+st479:
+ if ( ++p == pe )
+ goto _test_eof479;
+case 479:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr1654;
+ case 32: goto tr1654;
+ case 40: goto tr1655;
+ case 41: goto tr1656;
+ case 778: goto tr1658;
+ case 827: goto tr1658;
+ case 1034: goto tr1659;
+ case 1083: goto tr1660;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr1657;
+ goto tr1617;
+tr1654:
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ {
+ if (s->number64 <= UINT16_MAX) {
+ s->r_data_length = (uint16_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1154;
+tr1655:
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ {
+ if (s->number64 <= UINT16_MAX) {
+ s->r_data_length = (uint16_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1154;
+tr1656:
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ {
+ if (s->number64 <= UINT16_MAX) {
+ s->r_data_length = (uint16_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1154;
+tr1659:
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ {
+ if (s->number64 <= UINT16_MAX) {
+ s->r_data_length = (uint16_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1154;
+st1154:
+ if ( ++p == pe )
+ goto _test_eof1154;
+case 1154:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st480;
+ case 32: goto st480;
+ case 40: goto tr1662;
+ case 41: goto tr1663;
+ case 1034: goto tr1665;
+ case 1083: goto tr1666;
+ }
+ if ( _widec < 65 ) {
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr1664;
+ } else if ( _widec > 70 ) {
+ if ( 97 <= _widec && _widec <= 102 )
+ goto tr1664;
+ } else
+ goto tr1664;
+ goto tr1625;
+tr1662:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st480;
+tr1663:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st480;
+tr1665:
+ {
+ s->line_counter++;
+ }
+ goto st480;
+tr1679:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st480;
+tr1680:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ s->r_data_length = (uint16_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st480;
+tr1681:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ s->r_data_length = (uint16_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st480;
+tr1682:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ s->r_data_length = (uint16_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st480;
+tr1683:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ s->r_data_length = (uint16_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st480;
+st480:
+ if ( ++p == pe )
+ goto _test_eof480;
+case 480:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st480;
+ case 32: goto st480;
+ case 40: goto tr1662;
+ case 41: goto tr1663;
+ case 1034: goto tr1665;
+ case 1083: goto tr1666;
+ }
+ if ( _widec < 65 ) {
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr1664;
+ } else if ( _widec > 70 ) {
+ if ( 97 <= _widec && _widec <= 102 )
+ goto tr1664;
+ } else
+ goto tr1664;
+ goto tr1625;
+tr1664:
+ {
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = first_hex_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st481;
+st481:
+ if ( ++p == pe )
+ goto _test_eof481;
+case 481:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr1667;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto tr1667;
+ } else
+ goto tr1667;
+ goto tr1625;
+tr1669:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st482;
+tr1670:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st482;
+tr1671:
+ {
+ s->line_counter++;
+ }
+ goto st482;
+tr1677:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st482;
+tr1667:
+ {
+ *rdata_tail += second_hex_to_num[(uint8_t)(*p)];
+ rdata_tail++;
+ }
+ goto st482;
+st482:
+ if ( ++p == pe )
+ goto _test_eof482;
+case 482:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st482;
+ case 32: goto st482;
+ case 40: goto tr1669;
+ case 41: goto tr1670;
+ case 2058: goto tr1671;
+ case 2107: goto tr1672;
+ case 2314: goto tr1673;
+ case 2363: goto tr1673;
+ case 2570: goto tr1674;
+ case 2619: goto tr1675;
+ }
+ if ( _widec < 65 ) {
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr1664;
+ } else if ( _widec > 70 ) {
+ if ( 97 <= _widec && _widec <= 102 )
+ goto tr1664;
+ } else
+ goto tr1664;
+ goto tr1625;
+tr1672:
+ {
+ s->buffer_length = 0;
+ }
+ goto st483;
+tr1676:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st483;
+st483:
+ if ( ++p == pe )
+ goto _test_eof483;
+case 483:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr1677;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr1676;
+ goto tr1625;
+tr1658:
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1155;
+tr1673:
+ {
+ if ((rdata_tail - s->r_data) != s->r_data_length) {
+ WARN(ZS_BAD_RDATA_LENGTH);
+ p--; {goto st268;}
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1155;
+st1155:
+ if ( ++p == pe )
+ goto _test_eof1155;
+case 1155:
+ goto tr1611;
+tr1674:
+ {
+ s->line_counter++;
+ }
+ {
+ if ((rdata_tail - s->r_data) != s->r_data_length) {
+ WARN(ZS_BAD_RDATA_LENGTH);
+ p--; {goto st268;}
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1156;
+st1156:
+ if ( ++p == pe )
+ goto _test_eof1156;
+case 1156:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st482;
+ case 32: goto st482;
+ case 40: goto tr1669;
+ case 41: goto tr1670;
+ case 2058: goto tr1671;
+ case 2107: goto tr1672;
+ case 2314: goto tr1673;
+ case 2363: goto tr1673;
+ case 2570: goto tr1674;
+ case 2619: goto tr1675;
+ }
+ if ( _widec < 65 ) {
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr1664;
+ } else if ( _widec > 70 ) {
+ if ( 97 <= _widec && _widec <= 102 )
+ goto tr1664;
+ } else
+ goto tr1664;
+ goto tr1625;
+tr1675:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ if ((rdata_tail - s->r_data) != s->r_data_length) {
+ WARN(ZS_BAD_RDATA_LENGTH);
+ p--; {goto st268;}
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1157;
+st1157:
+ if ( ++p == pe )
+ goto _test_eof1157;
+case 1157:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr1677;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr1676;
+ goto tr1625;
+tr1666:
+ {
+ s->buffer_length = 0;
+ }
+ goto st484;
+tr1678:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st484;
+tr1684:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ s->r_data_length = (uint16_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st484;
+st484:
+ if ( ++p == pe )
+ goto _test_eof484;
+case 484:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr1679;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr1678;
+ goto tr1611;
+tr1653:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st485;
+tr1657:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st485;
+st485:
+ if ( ++p == pe )
+ goto _test_eof485;
+case 485:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr1680;
+ case 32: goto tr1680;
+ case 40: goto tr1681;
+ case 41: goto tr1682;
+ case 1034: goto tr1683;
+ case 1083: goto tr1684;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr1657;
+ goto tr1617;
+tr1660:
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ {
+ if (s->number64 <= UINT16_MAX) {
+ s->r_data_length = (uint16_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st1158;
+st1158:
+ if ( ++p == pe )
+ goto _test_eof1158;
+case 1158:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr1679;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr1678;
+ goto tr1611;
+tr1651:
+ {
+ s->buffer_length = 0;
+ }
+ goto st486;
+tr1685:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st486;
+st486:
+ if ( ++p == pe )
+ goto _test_eof486;
+case 486:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr1686;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr1685;
+ goto tr1611;
+st487:
+ if ( ++p == pe )
+ goto _test_eof487;
+case 487:
+ switch( (*p) ) {
+ case 68: goto st489;
+ case 69: goto st504;
+ case 73: goto st543;
+ case 80: goto st551;
+ case 82: goto st564;
+ case 100: goto st489;
+ case 101: goto st504;
+ case 105: goto st543;
+ case 112: goto st551;
+ case 114: goto st564;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr1688;
+ goto tr1687;
+tr1688:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st488;
+tr1695:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st488;
+st488:
+ if ( ++p == pe )
+ goto _test_eof488;
+case 488:
+ switch( (*p) ) {
+ case 32: goto tr1694;
+ case 59: goto tr1694;
+ }
+ if ( (*p) < 40 ) {
+ if ( 9 <= (*p) && (*p) <= 10 )
+ goto tr1694;
+ } else if ( (*p) > 41 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr1695;
+ } else
+ goto tr1694;
+ goto tr1687;
+tr1694:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1159;
+tr1698:
+ {
+ *(rdata_tail++) = 2;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1159;
+tr1700:
+ {
+ *(rdata_tail++) = 3;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1159;
+tr1712:
+ {
+ *(rdata_tail++) = 6;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1159;
+tr1722:
+ {
+ *(rdata_tail++) = 12;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1159;
+tr1736:
+ {
+ *(rdata_tail++) = 13;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1159;
+tr1745:
+ {
+ *(rdata_tail++) = 14;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1159;
+tr1752:
+ {
+ *(rdata_tail++) = 15;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1159;
+tr1755:
+ {
+ *(rdata_tail++) = 16;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1159;
+tr1763:
+ {
+ *(rdata_tail++) = 252;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1159;
+tr1774:
+ {
+ *(rdata_tail++) = 253;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1159;
+tr1777:
+ {
+ *(rdata_tail++) = 254;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1159;
+tr1784:
+ {
+ *(rdata_tail++) = 1;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1159;
+tr1790:
+ {
+ *(rdata_tail++) = 5;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1159;
+tr1802:
+ {
+ *(rdata_tail++) = 7;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1159;
+tr1805:
+ {
+ *(rdata_tail++) = 8;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1159;
+tr1808:
+ {
+ *(rdata_tail++) = 10;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1159;
+st1159:
+ if ( ++p == pe )
+ goto _test_eof1159;
+case 1159:
+ goto st0;
+st489:
+ if ( ++p == pe )
+ goto _test_eof489;
+case 489:
+ switch( (*p) ) {
+ case 72: goto st490;
+ case 83: goto st491;
+ case 104: goto st490;
+ case 115: goto st491;
+ }
+ goto tr1687;
+st490:
+ if ( ++p == pe )
+ goto _test_eof490;
+case 490:
+ switch( (*p) ) {
+ case 32: goto tr1698;
+ case 59: goto tr1698;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr1698;
+ } else if ( (*p) >= 9 )
+ goto tr1698;
+ goto tr1687;
+st491:
+ if ( ++p == pe )
+ goto _test_eof491;
+case 491:
+ switch( (*p) ) {
+ case 65: goto st492;
+ case 97: goto st492;
+ }
+ goto tr1687;
+st492:
+ if ( ++p == pe )
+ goto _test_eof492;
+case 492:
+ switch( (*p) ) {
+ case 32: goto tr1700;
+ case 45: goto st493;
+ case 59: goto tr1700;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr1700;
+ } else if ( (*p) >= 9 )
+ goto tr1700;
+ goto tr1687;
+st493:
+ if ( ++p == pe )
+ goto _test_eof493;
+case 493:
+ switch( (*p) ) {
+ case 78: goto st494;
+ case 110: goto st494;
+ }
+ goto tr1687;
+st494:
+ if ( ++p == pe )
+ goto _test_eof494;
+case 494:
+ switch( (*p) ) {
+ case 83: goto st495;
+ case 115: goto st495;
+ }
+ goto tr1687;
+st495:
+ if ( ++p == pe )
+ goto _test_eof495;
+case 495:
+ switch( (*p) ) {
+ case 69: goto st496;
+ case 101: goto st496;
+ }
+ goto tr1687;
+st496:
+ if ( ++p == pe )
+ goto _test_eof496;
+case 496:
+ switch( (*p) ) {
+ case 67: goto st497;
+ case 99: goto st497;
+ }
+ goto tr1687;
+st497:
+ if ( ++p == pe )
+ goto _test_eof497;
+case 497:
+ if ( (*p) == 51 )
+ goto st498;
+ goto tr1687;
+st498:
+ if ( ++p == pe )
+ goto _test_eof498;
+case 498:
+ if ( (*p) == 45 )
+ goto st499;
+ goto tr1687;
+st499:
+ if ( ++p == pe )
+ goto _test_eof499;
+case 499:
+ switch( (*p) ) {
+ case 83: goto st500;
+ case 115: goto st500;
+ }
+ goto tr1687;
+st500:
+ if ( ++p == pe )
+ goto _test_eof500;
+case 500:
+ switch( (*p) ) {
+ case 72: goto st501;
+ case 104: goto st501;
+ }
+ goto tr1687;
+st501:
+ if ( ++p == pe )
+ goto _test_eof501;
+case 501:
+ switch( (*p) ) {
+ case 65: goto st502;
+ case 97: goto st502;
+ }
+ goto tr1687;
+st502:
+ if ( ++p == pe )
+ goto _test_eof502;
+case 502:
+ if ( (*p) == 49 )
+ goto st503;
+ goto tr1687;
+st503:
+ if ( ++p == pe )
+ goto _test_eof503;
+case 503:
+ switch( (*p) ) {
+ case 32: goto tr1712;
+ case 59: goto tr1712;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr1712;
+ } else if ( (*p) >= 9 )
+ goto tr1712;
+ goto tr1687;
+st504:
+ if ( ++p == pe )
+ goto _test_eof504;
+case 504:
+ switch( (*p) ) {
+ case 67: goto st505;
+ case 68: goto st534;
+ case 99: goto st505;
+ case 100: goto st534;
+ }
+ goto tr1687;
+st505:
+ if ( ++p == pe )
+ goto _test_eof505;
+case 505:
+ switch( (*p) ) {
+ case 67: goto st506;
+ case 68: goto st512;
+ case 99: goto st506;
+ case 100: goto st512;
+ }
+ goto tr1687;
+st506:
+ if ( ++p == pe )
+ goto _test_eof506;
+case 506:
+ if ( (*p) == 45 )
+ goto st507;
+ goto tr1687;
+st507:
+ if ( ++p == pe )
+ goto _test_eof507;
+case 507:
+ switch( (*p) ) {
+ case 71: goto st508;
+ case 103: goto st508;
+ }
+ goto tr1687;
+st508:
+ if ( ++p == pe )
+ goto _test_eof508;
+case 508:
+ switch( (*p) ) {
+ case 79: goto st509;
+ case 111: goto st509;
+ }
+ goto tr1687;
+st509:
+ if ( ++p == pe )
+ goto _test_eof509;
+case 509:
+ switch( (*p) ) {
+ case 83: goto st510;
+ case 115: goto st510;
+ }
+ goto tr1687;
+st510:
+ if ( ++p == pe )
+ goto _test_eof510;
+case 510:
+ switch( (*p) ) {
+ case 84: goto st511;
+ case 116: goto st511;
+ }
+ goto tr1687;
+st511:
+ if ( ++p == pe )
+ goto _test_eof511;
+case 511:
+ switch( (*p) ) {
+ case 32: goto tr1722;
+ case 59: goto tr1722;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr1722;
+ } else if ( (*p) >= 9 )
+ goto tr1722;
+ goto tr1687;
+st512:
+ if ( ++p == pe )
+ goto _test_eof512;
+case 512:
+ switch( (*p) ) {
+ case 83: goto st513;
+ case 115: goto st513;
+ }
+ goto tr1687;
+st513:
+ if ( ++p == pe )
+ goto _test_eof513;
+case 513:
+ switch( (*p) ) {
+ case 65: goto st514;
+ case 97: goto st514;
+ }
+ goto tr1687;
+st514:
+ if ( ++p == pe )
+ goto _test_eof514;
+case 514:
+ switch( (*p) ) {
+ case 80: goto st515;
+ case 112: goto st515;
+ }
+ goto tr1687;
+st515:
+ if ( ++p == pe )
+ goto _test_eof515;
+case 515:
+ switch( (*p) ) {
+ case 50: goto st516;
+ case 51: goto st525;
+ }
+ goto tr1687;
+st516:
+ if ( ++p == pe )
+ goto _test_eof516;
+case 516:
+ if ( (*p) == 53 )
+ goto st517;
+ goto tr1687;
+st517:
+ if ( ++p == pe )
+ goto _test_eof517;
+case 517:
+ if ( (*p) == 54 )
+ goto st518;
+ goto tr1687;
+st518:
+ if ( ++p == pe )
+ goto _test_eof518;
+case 518:
+ switch( (*p) ) {
+ case 83: goto st519;
+ case 115: goto st519;
+ }
+ goto tr1687;
+st519:
+ if ( ++p == pe )
+ goto _test_eof519;
+case 519:
+ switch( (*p) ) {
+ case 72: goto st520;
+ case 104: goto st520;
+ }
+ goto tr1687;
+st520:
+ if ( ++p == pe )
+ goto _test_eof520;
+case 520:
+ switch( (*p) ) {
+ case 65: goto st521;
+ case 97: goto st521;
+ }
+ goto tr1687;
+st521:
+ if ( ++p == pe )
+ goto _test_eof521;
+case 521:
+ if ( (*p) == 50 )
+ goto st522;
+ goto tr1687;
+st522:
+ if ( ++p == pe )
+ goto _test_eof522;
+case 522:
+ if ( (*p) == 53 )
+ goto st523;
+ goto tr1687;
+st523:
+ if ( ++p == pe )
+ goto _test_eof523;
+case 523:
+ if ( (*p) == 54 )
+ goto st524;
+ goto tr1687;
+st524:
+ if ( ++p == pe )
+ goto _test_eof524;
+case 524:
+ switch( (*p) ) {
+ case 32: goto tr1736;
+ case 59: goto tr1736;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr1736;
+ } else if ( (*p) >= 9 )
+ goto tr1736;
+ goto tr1687;
+st525:
+ if ( ++p == pe )
+ goto _test_eof525;
+case 525:
+ if ( (*p) == 56 )
+ goto st526;
+ goto tr1687;
+st526:
+ if ( ++p == pe )
+ goto _test_eof526;
+case 526:
+ if ( (*p) == 52 )
+ goto st527;
+ goto tr1687;
+st527:
+ if ( ++p == pe )
+ goto _test_eof527;
+case 527:
+ switch( (*p) ) {
+ case 83: goto st528;
+ case 115: goto st528;
+ }
+ goto tr1687;
+st528:
+ if ( ++p == pe )
+ goto _test_eof528;
+case 528:
+ switch( (*p) ) {
+ case 72: goto st529;
+ case 104: goto st529;
+ }
+ goto tr1687;
+st529:
+ if ( ++p == pe )
+ goto _test_eof529;
+case 529:
+ switch( (*p) ) {
+ case 65: goto st530;
+ case 97: goto st530;
+ }
+ goto tr1687;
+st530:
+ if ( ++p == pe )
+ goto _test_eof530;
+case 530:
+ if ( (*p) == 51 )
+ goto st531;
+ goto tr1687;
+st531:
+ if ( ++p == pe )
+ goto _test_eof531;
+case 531:
+ if ( (*p) == 56 )
+ goto st532;
+ goto tr1687;
+st532:
+ if ( ++p == pe )
+ goto _test_eof532;
+case 532:
+ if ( (*p) == 52 )
+ goto st533;
+ goto tr1687;
+st533:
+ if ( ++p == pe )
+ goto _test_eof533;
+case 533:
+ switch( (*p) ) {
+ case 32: goto tr1745;
+ case 59: goto tr1745;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr1745;
+ } else if ( (*p) >= 9 )
+ goto tr1745;
+ goto tr1687;
+st534:
+ if ( ++p == pe )
+ goto _test_eof534;
+case 534:
+ switch( (*p) ) {
+ case 50: goto st535;
+ case 52: goto st540;
+ }
+ goto tr1687;
+st535:
+ if ( ++p == pe )
+ goto _test_eof535;
+case 535:
+ if ( (*p) == 53 )
+ goto st536;
+ goto tr1687;
+st536:
+ if ( ++p == pe )
+ goto _test_eof536;
+case 536:
+ if ( (*p) == 53 )
+ goto st537;
+ goto tr1687;
+st537:
+ if ( ++p == pe )
+ goto _test_eof537;
+case 537:
+ if ( (*p) == 49 )
+ goto st538;
+ goto tr1687;
+st538:
+ if ( ++p == pe )
+ goto _test_eof538;
+case 538:
+ if ( (*p) == 57 )
+ goto st539;
+ goto tr1687;
+st539:
+ if ( ++p == pe )
+ goto _test_eof539;
+case 539:
+ switch( (*p) ) {
+ case 32: goto tr1752;
+ case 59: goto tr1752;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr1752;
+ } else if ( (*p) >= 9 )
+ goto tr1752;
+ goto tr1687;
+st540:
+ if ( ++p == pe )
+ goto _test_eof540;
+case 540:
+ if ( (*p) == 52 )
+ goto st541;
+ goto tr1687;
+st541:
+ if ( ++p == pe )
+ goto _test_eof541;
+case 541:
+ if ( (*p) == 56 )
+ goto st542;
+ goto tr1687;
+st542:
+ if ( ++p == pe )
+ goto _test_eof542;
+case 542:
+ switch( (*p) ) {
+ case 32: goto tr1755;
+ case 59: goto tr1755;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr1755;
+ } else if ( (*p) >= 9 )
+ goto tr1755;
+ goto tr1687;
+st543:
+ if ( ++p == pe )
+ goto _test_eof543;
+case 543:
+ switch( (*p) ) {
+ case 78: goto st544;
+ case 110: goto st544;
+ }
+ goto tr1687;
+st544:
+ if ( ++p == pe )
+ goto _test_eof544;
+case 544:
+ switch( (*p) ) {
+ case 68: goto st545;
+ case 100: goto st545;
+ }
+ goto tr1687;
+st545:
+ if ( ++p == pe )
+ goto _test_eof545;
+case 545:
+ switch( (*p) ) {
+ case 73: goto st546;
+ case 105: goto st546;
+ }
+ goto tr1687;
+st546:
+ if ( ++p == pe )
+ goto _test_eof546;
+case 546:
+ switch( (*p) ) {
+ case 82: goto st547;
+ case 114: goto st547;
+ }
+ goto tr1687;
+st547:
+ if ( ++p == pe )
+ goto _test_eof547;
+case 547:
+ switch( (*p) ) {
+ case 69: goto st548;
+ case 101: goto st548;
+ }
+ goto tr1687;
+st548:
+ if ( ++p == pe )
+ goto _test_eof548;
+case 548:
+ switch( (*p) ) {
+ case 67: goto st549;
+ case 99: goto st549;
+ }
+ goto tr1687;
+st549:
+ if ( ++p == pe )
+ goto _test_eof549;
+case 549:
+ switch( (*p) ) {
+ case 84: goto st550;
+ case 116: goto st550;
+ }
+ goto tr1687;
+st550:
+ if ( ++p == pe )
+ goto _test_eof550;
+case 550:
+ switch( (*p) ) {
+ case 32: goto tr1763;
+ case 59: goto tr1763;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr1763;
+ } else if ( (*p) >= 9 )
+ goto tr1763;
+ goto tr1687;
+st551:
+ if ( ++p == pe )
+ goto _test_eof551;
+case 551:
+ switch( (*p) ) {
+ case 82: goto st552;
+ case 114: goto st552;
+ }
+ goto tr1687;
+st552:
+ if ( ++p == pe )
+ goto _test_eof552;
+case 552:
+ switch( (*p) ) {
+ case 73: goto st553;
+ case 105: goto st553;
+ }
+ goto tr1687;
+st553:
+ if ( ++p == pe )
+ goto _test_eof553;
+case 553:
+ switch( (*p) ) {
+ case 86: goto st554;
+ case 118: goto st554;
+ }
+ goto tr1687;
+st554:
+ if ( ++p == pe )
+ goto _test_eof554;
+case 554:
+ switch( (*p) ) {
+ case 65: goto st555;
+ case 97: goto st555;
+ }
+ goto tr1687;
+st555:
+ if ( ++p == pe )
+ goto _test_eof555;
+case 555:
+ switch( (*p) ) {
+ case 84: goto st556;
+ case 116: goto st556;
+ }
+ goto tr1687;
+st556:
+ if ( ++p == pe )
+ goto _test_eof556;
+case 556:
+ switch( (*p) ) {
+ case 69: goto st557;
+ case 101: goto st557;
+ }
+ goto tr1687;
+st557:
+ if ( ++p == pe )
+ goto _test_eof557;
+case 557:
+ switch( (*p) ) {
+ case 68: goto st558;
+ case 79: goto st561;
+ case 100: goto st558;
+ case 111: goto st561;
+ }
+ goto tr1687;
+st558:
+ if ( ++p == pe )
+ goto _test_eof558;
+case 558:
+ switch( (*p) ) {
+ case 78: goto st559;
+ case 110: goto st559;
+ }
+ goto tr1687;
+st559:
+ if ( ++p == pe )
+ goto _test_eof559;
+case 559:
+ switch( (*p) ) {
+ case 83: goto st560;
+ case 115: goto st560;
+ }
+ goto tr1687;
+st560:
+ if ( ++p == pe )
+ goto _test_eof560;
+case 560:
+ switch( (*p) ) {
+ case 32: goto tr1774;
+ case 59: goto tr1774;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr1774;
+ } else if ( (*p) >= 9 )
+ goto tr1774;
+ goto tr1687;
+st561:
+ if ( ++p == pe )
+ goto _test_eof561;
+case 561:
+ switch( (*p) ) {
+ case 73: goto st562;
+ case 105: goto st562;
+ }
+ goto tr1687;
+st562:
+ if ( ++p == pe )
+ goto _test_eof562;
+case 562:
+ switch( (*p) ) {
+ case 68: goto st563;
+ case 100: goto st563;
+ }
+ goto tr1687;
+st563:
+ if ( ++p == pe )
+ goto _test_eof563;
+case 563:
+ switch( (*p) ) {
+ case 32: goto tr1777;
+ case 59: goto tr1777;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr1777;
+ } else if ( (*p) >= 9 )
+ goto tr1777;
+ goto tr1687;
+st564:
+ if ( ++p == pe )
+ goto _test_eof564;
+case 564:
+ switch( (*p) ) {
+ case 83: goto st565;
+ case 115: goto st565;
+ }
+ goto tr1687;
+st565:
+ if ( ++p == pe )
+ goto _test_eof565;
+case 565:
+ switch( (*p) ) {
+ case 65: goto st566;
+ case 97: goto st566;
+ }
+ goto tr1687;
+st566:
+ if ( ++p == pe )
+ goto _test_eof566;
+case 566:
+ switch( (*p) ) {
+ case 77: goto st567;
+ case 83: goto st570;
+ case 109: goto st567;
+ case 115: goto st570;
+ }
+ goto tr1687;
+st567:
+ if ( ++p == pe )
+ goto _test_eof567;
+case 567:
+ switch( (*p) ) {
+ case 68: goto st568;
+ case 100: goto st568;
+ }
+ goto tr1687;
+st568:
+ if ( ++p == pe )
+ goto _test_eof568;
+case 568:
+ if ( (*p) == 53 )
+ goto st569;
+ goto tr1687;
+st569:
+ if ( ++p == pe )
+ goto _test_eof569;
+case 569:
+ switch( (*p) ) {
+ case 32: goto tr1784;
+ case 59: goto tr1784;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr1784;
+ } else if ( (*p) >= 9 )
+ goto tr1784;
+ goto tr1687;
+st570:
+ if ( ++p == pe )
+ goto _test_eof570;
+case 570:
+ switch( (*p) ) {
+ case 72: goto st571;
+ case 104: goto st571;
+ }
+ goto tr1687;
+st571:
+ if ( ++p == pe )
+ goto _test_eof571;
+case 571:
+ switch( (*p) ) {
+ case 65: goto st572;
+ case 97: goto st572;
+ }
+ goto tr1687;
+st572:
+ if ( ++p == pe )
+ goto _test_eof572;
+case 572:
+ switch( (*p) ) {
+ case 49: goto st573;
+ case 50: goto st585;
+ case 53: goto st588;
+ }
+ goto tr1687;
+st573:
+ if ( ++p == pe )
+ goto _test_eof573;
+case 573:
+ switch( (*p) ) {
+ case 32: goto tr1790;
+ case 45: goto st574;
+ case 59: goto tr1790;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr1790;
+ } else if ( (*p) >= 9 )
+ goto tr1790;
+ goto tr1687;
+st574:
+ if ( ++p == pe )
+ goto _test_eof574;
+case 574:
+ switch( (*p) ) {
+ case 78: goto st575;
+ case 110: goto st575;
+ }
+ goto tr1687;
+st575:
+ if ( ++p == pe )
+ goto _test_eof575;
+case 575:
+ switch( (*p) ) {
+ case 83: goto st576;
+ case 115: goto st576;
+ }
+ goto tr1687;
+st576:
+ if ( ++p == pe )
+ goto _test_eof576;
+case 576:
+ switch( (*p) ) {
+ case 69: goto st577;
+ case 101: goto st577;
+ }
+ goto tr1687;
+st577:
+ if ( ++p == pe )
+ goto _test_eof577;
+case 577:
+ switch( (*p) ) {
+ case 67: goto st578;
+ case 99: goto st578;
+ }
+ goto tr1687;
+st578:
+ if ( ++p == pe )
+ goto _test_eof578;
+case 578:
+ if ( (*p) == 51 )
+ goto st579;
+ goto tr1687;
+st579:
+ if ( ++p == pe )
+ goto _test_eof579;
+case 579:
+ if ( (*p) == 45 )
+ goto st580;
+ goto tr1687;
+st580:
+ if ( ++p == pe )
+ goto _test_eof580;
+case 580:
+ switch( (*p) ) {
+ case 83: goto st581;
+ case 115: goto st581;
+ }
+ goto tr1687;
+st581:
+ if ( ++p == pe )
+ goto _test_eof581;
+case 581:
+ switch( (*p) ) {
+ case 72: goto st582;
+ case 104: goto st582;
+ }
+ goto tr1687;
+st582:
+ if ( ++p == pe )
+ goto _test_eof582;
+case 582:
+ switch( (*p) ) {
+ case 65: goto st583;
+ case 97: goto st583;
+ }
+ goto tr1687;
+st583:
+ if ( ++p == pe )
+ goto _test_eof583;
+case 583:
+ if ( (*p) == 49 )
+ goto st584;
+ goto tr1687;
+st584:
+ if ( ++p == pe )
+ goto _test_eof584;
+case 584:
+ switch( (*p) ) {
+ case 32: goto tr1802;
+ case 59: goto tr1802;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr1802;
+ } else if ( (*p) >= 9 )
+ goto tr1802;
+ goto tr1687;
+st585:
+ if ( ++p == pe )
+ goto _test_eof585;
+case 585:
+ if ( (*p) == 53 )
+ goto st586;
+ goto tr1687;
+st586:
+ if ( ++p == pe )
+ goto _test_eof586;
+case 586:
+ if ( (*p) == 54 )
+ goto st587;
+ goto tr1687;
+st587:
+ if ( ++p == pe )
+ goto _test_eof587;
+case 587:
+ switch( (*p) ) {
+ case 32: goto tr1805;
+ case 59: goto tr1805;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr1805;
+ } else if ( (*p) >= 9 )
+ goto tr1805;
+ goto tr1687;
+st588:
+ if ( ++p == pe )
+ goto _test_eof588;
+case 588:
+ if ( (*p) == 49 )
+ goto st589;
+ goto tr1687;
+st589:
+ if ( ++p == pe )
+ goto _test_eof589;
+case 589:
+ if ( (*p) == 50 )
+ goto st590;
+ goto tr1687;
+st590:
+ if ( ++p == pe )
+ goto _test_eof590;
+case 590:
+ switch( (*p) ) {
+ case 32: goto tr1808;
+ case 59: goto tr1808;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr1808;
+ } else if ( (*p) >= 9 )
+ goto tr1808;
+ goto tr1687;
+st591:
+ if ( ++p == pe )
+ goto _test_eof591;
+case 591:
+ switch( (*p) ) {
+ case 65: goto st593;
+ case 73: goto st599;
+ case 79: goto st616;
+ case 80: goto st619;
+ case 83: goto st625;
+ case 85: goto st629;
+ case 97: goto st593;
+ case 105: goto st599;
+ case 111: goto st616;
+ case 112: goto st619;
+ case 115: goto st625;
+ case 117: goto st629;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr1810;
+ goto tr1809;
+tr1810:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st592;
+tr1818:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st592;
+st592:
+ if ( ++p == pe )
+ goto _test_eof592;
+case 592:
+ switch( (*p) ) {
+ case 32: goto tr1817;
+ case 59: goto tr1817;
+ }
+ if ( (*p) < 40 ) {
+ if ( 9 <= (*p) && (*p) <= 10 )
+ goto tr1817;
+ } else if ( (*p) > 41 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr1818;
+ } else
+ goto tr1817;
+ goto tr1809;
+tr1817:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1160;
+tr1824:
+ {
+ *((uint16_t *)rdata_tail) = htons(7);
+ rdata_tail += 2;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1160;
+tr1833:
+ {
+ *((uint16_t *)rdata_tail) = htons(8);
+ rdata_tail += 2;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1160;
+tr1837:
+ {
+ *((uint16_t *)rdata_tail) = htons(6);
+ rdata_tail += 2;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1160;
+tr1840:
+ {
+ *((uint16_t *)rdata_tail) = htons(4);
+ rdata_tail += 2;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1160;
+tr1844:
+ {
+ *((uint16_t *)rdata_tail) = htons(5);
+ rdata_tail += 2;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1160;
+tr1847:
+ {
+ *((uint16_t *)rdata_tail) = htons(254);
+ rdata_tail += 2;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1160;
+tr1851:
+ {
+ *((uint16_t *)rdata_tail) = htons(3);
+ rdata_tail += 2;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1160;
+tr1854:
+ {
+ *((uint16_t *)rdata_tail) = htons(1);
+ rdata_tail += 2;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1160;
+tr1858:
+ {
+ *((uint16_t *)rdata_tail) = htons(2);
+ rdata_tail += 2;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1160;
+tr1861:
+ {
+ *((uint16_t *)rdata_tail) = htons(253);
+ rdata_tail += 2;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1160;
+st1160:
+ if ( ++p == pe )
+ goto _test_eof1160;
+case 1160:
+ goto st0;
+st593:
+ if ( ++p == pe )
+ goto _test_eof593;
+case 593:
+ switch( (*p) ) {
+ case 67: goto st594;
+ case 99: goto st594;
+ }
+ goto tr1809;
+st594:
+ if ( ++p == pe )
+ goto _test_eof594;
+case 594:
+ switch( (*p) ) {
+ case 80: goto st595;
+ case 112: goto st595;
+ }
+ goto tr1809;
+st595:
+ if ( ++p == pe )
+ goto _test_eof595;
+case 595:
+ switch( (*p) ) {
+ case 75: goto st596;
+ case 107: goto st596;
+ }
+ goto tr1809;
+st596:
+ if ( ++p == pe )
+ goto _test_eof596;
+case 596:
+ switch( (*p) ) {
+ case 73: goto st597;
+ case 105: goto st597;
+ }
+ goto tr1809;
+st597:
+ if ( ++p == pe )
+ goto _test_eof597;
+case 597:
+ switch( (*p) ) {
+ case 88: goto st598;
+ case 120: goto st598;
+ }
+ goto tr1809;
+st598:
+ if ( ++p == pe )
+ goto _test_eof598;
+case 598:
+ switch( (*p) ) {
+ case 32: goto tr1824;
+ case 59: goto tr1824;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr1824;
+ } else if ( (*p) >= 9 )
+ goto tr1824;
+ goto tr1809;
+st599:
+ if ( ++p == pe )
+ goto _test_eof599;
+case 599:
+ switch( (*p) ) {
+ case 65: goto st600;
+ case 80: goto st606;
+ case 83: goto st612;
+ case 97: goto st600;
+ case 112: goto st606;
+ case 115: goto st612;
+ }
+ goto tr1809;
+st600:
+ if ( ++p == pe )
+ goto _test_eof600;
+case 600:
+ switch( (*p) ) {
+ case 67: goto st601;
+ case 99: goto st601;
+ }
+ goto tr1809;
+st601:
+ if ( ++p == pe )
+ goto _test_eof601;
+case 601:
+ switch( (*p) ) {
+ case 80: goto st602;
+ case 112: goto st602;
+ }
+ goto tr1809;
+st602:
+ if ( ++p == pe )
+ goto _test_eof602;
+case 602:
+ switch( (*p) ) {
+ case 75: goto st603;
+ case 107: goto st603;
+ }
+ goto tr1809;
+st603:
+ if ( ++p == pe )
+ goto _test_eof603;
+case 603:
+ switch( (*p) ) {
+ case 73: goto st604;
+ case 105: goto st604;
+ }
+ goto tr1809;
+st604:
+ if ( ++p == pe )
+ goto _test_eof604;
+case 604:
+ switch( (*p) ) {
+ case 88: goto st605;
+ case 120: goto st605;
+ }
+ goto tr1809;
+st605:
+ if ( ++p == pe )
+ goto _test_eof605;
+case 605:
+ switch( (*p) ) {
+ case 32: goto tr1833;
+ case 59: goto tr1833;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr1833;
+ } else if ( (*p) >= 9 )
+ goto tr1833;
+ goto tr1809;
+st606:
+ if ( ++p == pe )
+ goto _test_eof606;
+case 606:
+ switch( (*p) ) {
+ case 71: goto st607;
+ case 75: goto st609;
+ case 103: goto st607;
+ case 107: goto st609;
+ }
+ goto tr1809;
+st607:
+ if ( ++p == pe )
+ goto _test_eof607;
+case 607:
+ switch( (*p) ) {
+ case 80: goto st608;
+ case 112: goto st608;
+ }
+ goto tr1809;
+st608:
+ if ( ++p == pe )
+ goto _test_eof608;
+case 608:
+ switch( (*p) ) {
+ case 32: goto tr1837;
+ case 59: goto tr1837;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr1837;
+ } else if ( (*p) >= 9 )
+ goto tr1837;
+ goto tr1809;
+st609:
+ if ( ++p == pe )
+ goto _test_eof609;
+case 609:
+ switch( (*p) ) {
+ case 73: goto st610;
+ case 105: goto st610;
+ }
+ goto tr1809;
+st610:
+ if ( ++p == pe )
+ goto _test_eof610;
+case 610:
+ switch( (*p) ) {
+ case 88: goto st611;
+ case 120: goto st611;
+ }
+ goto tr1809;
+st611:
+ if ( ++p == pe )
+ goto _test_eof611;
+case 611:
+ switch( (*p) ) {
+ case 32: goto tr1840;
+ case 59: goto tr1840;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr1840;
+ } else if ( (*p) >= 9 )
+ goto tr1840;
+ goto tr1809;
+st612:
+ if ( ++p == pe )
+ goto _test_eof612;
+case 612:
+ switch( (*p) ) {
+ case 80: goto st613;
+ case 112: goto st613;
+ }
+ goto tr1809;
+st613:
+ if ( ++p == pe )
+ goto _test_eof613;
+case 613:
+ switch( (*p) ) {
+ case 75: goto st614;
+ case 107: goto st614;
+ }
+ goto tr1809;
+st614:
+ if ( ++p == pe )
+ goto _test_eof614;
+case 614:
+ switch( (*p) ) {
+ case 73: goto st615;
+ case 105: goto st615;
+ }
+ goto tr1809;
+st615:
+ if ( ++p == pe )
+ goto _test_eof615;
+case 615:
+ switch( (*p) ) {
+ case 32: goto tr1844;
+ case 59: goto tr1844;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr1844;
+ } else if ( (*p) >= 9 )
+ goto tr1844;
+ goto tr1809;
+st616:
+ if ( ++p == pe )
+ goto _test_eof616;
+case 616:
+ switch( (*p) ) {
+ case 73: goto st617;
+ case 105: goto st617;
+ }
+ goto tr1809;
+st617:
+ if ( ++p == pe )
+ goto _test_eof617;
+case 617:
+ switch( (*p) ) {
+ case 68: goto st618;
+ case 100: goto st618;
+ }
+ goto tr1809;
+st618:
+ if ( ++p == pe )
+ goto _test_eof618;
+case 618:
+ switch( (*p) ) {
+ case 32: goto tr1847;
+ case 59: goto tr1847;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr1847;
+ } else if ( (*p) >= 9 )
+ goto tr1847;
+ goto tr1809;
+st619:
+ if ( ++p == pe )
+ goto _test_eof619;
+case 619:
+ switch( (*p) ) {
+ case 71: goto st620;
+ case 75: goto st622;
+ case 103: goto st620;
+ case 107: goto st622;
+ }
+ goto tr1809;
+st620:
+ if ( ++p == pe )
+ goto _test_eof620;
+case 620:
+ switch( (*p) ) {
+ case 80: goto st621;
+ case 112: goto st621;
+ }
+ goto tr1809;
+st621:
+ if ( ++p == pe )
+ goto _test_eof621;
+case 621:
+ switch( (*p) ) {
+ case 32: goto tr1851;
+ case 59: goto tr1851;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr1851;
+ } else if ( (*p) >= 9 )
+ goto tr1851;
+ goto tr1809;
+st622:
+ if ( ++p == pe )
+ goto _test_eof622;
+case 622:
+ switch( (*p) ) {
+ case 73: goto st623;
+ case 105: goto st623;
+ }
+ goto tr1809;
+st623:
+ if ( ++p == pe )
+ goto _test_eof623;
+case 623:
+ switch( (*p) ) {
+ case 88: goto st624;
+ case 120: goto st624;
+ }
+ goto tr1809;
+st624:
+ if ( ++p == pe )
+ goto _test_eof624;
+case 624:
+ switch( (*p) ) {
+ case 32: goto tr1854;
+ case 59: goto tr1854;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr1854;
+ } else if ( (*p) >= 9 )
+ goto tr1854;
+ goto tr1809;
+st625:
+ if ( ++p == pe )
+ goto _test_eof625;
+case 625:
+ switch( (*p) ) {
+ case 80: goto st626;
+ case 112: goto st626;
+ }
+ goto tr1809;
+st626:
+ if ( ++p == pe )
+ goto _test_eof626;
+case 626:
+ switch( (*p) ) {
+ case 75: goto st627;
+ case 107: goto st627;
+ }
+ goto tr1809;
+st627:
+ if ( ++p == pe )
+ goto _test_eof627;
+case 627:
+ switch( (*p) ) {
+ case 73: goto st628;
+ case 105: goto st628;
+ }
+ goto tr1809;
+st628:
+ if ( ++p == pe )
+ goto _test_eof628;
+case 628:
+ switch( (*p) ) {
+ case 32: goto tr1858;
+ case 59: goto tr1858;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr1858;
+ } else if ( (*p) >= 9 )
+ goto tr1858;
+ goto tr1809;
+st629:
+ if ( ++p == pe )
+ goto _test_eof629;
+case 629:
+ switch( (*p) ) {
+ case 82: goto st630;
+ case 114: goto st630;
+ }
+ goto tr1809;
+st630:
+ if ( ++p == pe )
+ goto _test_eof630;
+case 630:
+ switch( (*p) ) {
+ case 73: goto st631;
+ case 105: goto st631;
+ }
+ goto tr1809;
+st631:
+ if ( ++p == pe )
+ goto _test_eof631;
+case 631:
+ switch( (*p) ) {
+ case 32: goto tr1861;
+ case 59: goto tr1861;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr1861;
+ } else if ( (*p) >= 9 )
+ goto tr1861;
+ goto tr1809;
+st632:
+ if ( ++p == pe )
+ goto _test_eof632;
+case 632:
+ if ( (*p) == 46 )
+ goto tr1863;
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr1863;
+ goto tr1862;
+tr1863:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st633;
+tr1865:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st633;
+st633:
+ if ( ++p == pe )
+ goto _test_eof633;
+case 633:
+ switch( (*p) ) {
+ case 32: goto tr1864;
+ case 46: goto tr1865;
+ case 59: goto tr1864;
+ }
+ if ( (*p) < 40 ) {
+ if ( 9 <= (*p) && (*p) <= 10 )
+ goto tr1864;
+ } else if ( (*p) > 41 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr1865;
+ } else
+ goto tr1864;
+ goto tr1862;
+tr1864:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV4);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET4_ADDR_LENGTH);
+ rdata_tail += ZS_INET4_ADDR_LENGTH;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1161;
+st1161:
+ if ( ++p == pe )
+ goto _test_eof1161;
+case 1161:
+ goto st0;
+st634:
+ if ( ++p == pe )
+ goto _test_eof634;
+case 634:
+ switch( (*p) ) {
+ case 42: goto tr1866;
+ case 92: goto tr1866;
+ case 95: goto tr1866;
+ }
+ if ( (*p) < 64 ) {
+ if ( 45 <= (*p) && (*p) <= 57 )
+ goto tr1866;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr1866;
+ } else
+ goto tr1866;
+ goto tr71;
+tr1866:
+ {
+ s->dname = rdata_tail;
+ }
+ { p--; {stack[top++] = 635;goto st270;} }
+ goto st635;
+st635:
+ if ( ++p == pe )
+ goto _test_eof635;
+case 635:
+ switch( (*p) ) {
+ case 32: goto tr1867;
+ case 59: goto tr1867;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr1867;
+ } else if ( (*p) >= 9 )
+ goto tr1867;
+ goto tr71;
+tr1867:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1162;
+st1162:
+ if ( ++p == pe )
+ goto _test_eof1162;
+case 1162:
+ goto st0;
+st636:
+ if ( ++p == pe )
+ goto _test_eof636;
+case 636:
+ switch( (*p) ) {
+ case 42: goto tr1868;
+ case 92: goto tr1868;
+ case 95: goto tr1868;
+ }
+ if ( (*p) < 64 ) {
+ if ( 45 <= (*p) && (*p) <= 57 )
+ goto tr1868;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr1868;
+ } else
+ goto tr1868;
+ goto tr71;
+tr1868:
+ {
+ s->dname = rdata_tail;
+ }
+ { p--; {stack[top++] = 637;goto st270;} }
+ goto st637;
+st637:
+ if ( ++p == pe )
+ goto _test_eof637;
+case 637:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr1869;
+ case 32: goto tr1869;
+ case 40: goto tr1870;
+ case 41: goto tr1871;
+ case 1034: goto tr1872;
+ case 1083: goto tr1873;
+ }
+ goto tr71;
+tr1875:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st638;
+tr1876:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st638;
+tr1878:
+ {
+ s->line_counter++;
+ }
+ goto st638;
+tr2022:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st638;
+tr1869:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ goto st638;
+tr1870:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st638;
+tr1871:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st638;
+tr1872:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st638;
+st638:
+ if ( ++p == pe )
+ goto _test_eof638;
+case 638:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st638;
+ case 32: goto st638;
+ case 40: goto tr1875;
+ case 41: goto tr1876;
+ case 42: goto tr1877;
+ case 92: goto tr1877;
+ case 95: goto tr1877;
+ case 1034: goto tr1878;
+ case 1083: goto tr1879;
+ }
+ if ( _widec < 64 ) {
+ if ( 45 <= _widec && _widec <= 57 )
+ goto tr1877;
+ } else if ( _widec > 90 ) {
+ if ( 97 <= _widec && _widec <= 122 )
+ goto tr1877;
+ } else
+ goto tr1877;
+ goto tr71;
+tr1877:
+ {
+ s->dname = rdata_tail;
+ }
+ { p--; {stack[top++] = 639;goto st270;} }
+ goto st639;
+st639:
+ if ( ++p == pe )
+ goto _test_eof639;
+case 639:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr1880;
+ case 32: goto tr1880;
+ case 40: goto tr1881;
+ case 41: goto tr1882;
+ case 1034: goto tr1883;
+ case 1083: goto tr1884;
+ }
+ goto tr71;
+tr1887:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st640;
+tr1888:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st640;
+tr1890:
+ {
+ s->line_counter++;
+ }
+ goto st640;
+tr2020:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st640;
+tr1880:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ goto st640;
+tr1881:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st640;
+tr1882:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st640;
+tr1883:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st640;
+st640:
+ if ( ++p == pe )
+ goto _test_eof640;
+case 640:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st640;
+ case 32: goto st640;
+ case 40: goto tr1887;
+ case 41: goto tr1888;
+ case 1034: goto tr1890;
+ case 1083: goto tr1891;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr1889;
+ goto tr1885;
+tr1889:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st641;
+tr1895:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st641;
+st641:
+ if ( ++p == pe )
+ goto _test_eof641;
+case 641:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr1892;
+ case 32: goto tr1892;
+ case 40: goto tr1893;
+ case 41: goto tr1894;
+ case 1034: goto tr1896;
+ case 1083: goto tr1897;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr1895;
+ goto tr1885;
+tr1899:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st642;
+tr1900:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st642;
+tr1902:
+ {
+ s->line_counter++;
+ }
+ goto st642;
+tr2018:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st642;
+tr1892:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st642;
+tr1893:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st642;
+tr1894:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st642;
+tr1896:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st642;
+st642:
+ if ( ++p == pe )
+ goto _test_eof642;
+case 642:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st642;
+ case 32: goto st642;
+ case 40: goto tr1899;
+ case 41: goto tr1900;
+ case 1034: goto tr1902;
+ case 1083: goto tr1903;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr1901;
+ goto tr1885;
+tr1901:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st643;
+tr1908:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st643;
+st643:
+ if ( ++p == pe )
+ goto _test_eof643;
+case 643:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr1905;
+ case 32: goto tr1905;
+ case 40: goto tr1906;
+ case 41: goto tr1907;
+ case 68: goto tr1909;
+ case 72: goto tr1910;
+ case 77: goto tr1911;
+ case 83: goto st662;
+ case 87: goto tr1913;
+ case 100: goto tr1909;
+ case 104: goto tr1910;
+ case 109: goto tr1911;
+ case 115: goto st662;
+ case 119: goto tr1913;
+ case 1034: goto tr1914;
+ case 1083: goto tr1915;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr1908;
+ goto tr1904;
+tr1917:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st644;
+tr1918:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st644;
+tr1920:
+ {
+ s->line_counter++;
+ }
+ goto st644;
+tr2003:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st644;
+tr1905:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st644;
+tr1906:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st644;
+tr1907:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st644;
+tr1914:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st644;
+tr2011:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st644;
+tr2012:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st644;
+tr2013:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st644;
+tr2015:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st644;
+st644:
+ if ( ++p == pe )
+ goto _test_eof644;
+case 644:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st644;
+ case 32: goto st644;
+ case 40: goto tr1917;
+ case 41: goto tr1918;
+ case 1034: goto tr1920;
+ case 1083: goto tr1921;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr1919;
+ goto tr1885;
+tr1919:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st645;
+tr1925:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st645;
+st645:
+ if ( ++p == pe )
+ goto _test_eof645;
+case 645:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr1922;
+ case 32: goto tr1922;
+ case 40: goto tr1923;
+ case 41: goto tr1924;
+ case 68: goto tr1926;
+ case 72: goto tr1927;
+ case 77: goto tr1928;
+ case 83: goto st658;
+ case 87: goto tr1930;
+ case 100: goto tr1926;
+ case 104: goto tr1927;
+ case 109: goto tr1928;
+ case 115: goto st658;
+ case 119: goto tr1930;
+ case 1034: goto tr1931;
+ case 1083: goto tr1932;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr1925;
+ goto tr1904;
+tr1934:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st646;
+tr1935:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st646;
+tr1937:
+ {
+ s->line_counter++;
+ }
+ goto st646;
+tr1988:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st646;
+tr1922:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st646;
+tr1923:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st646;
+tr1924:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st646;
+tr1931:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st646;
+tr1996:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st646;
+tr1997:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st646;
+tr1998:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st646;
+tr2000:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st646;
+st646:
+ if ( ++p == pe )
+ goto _test_eof646;
+case 646:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st646;
+ case 32: goto st646;
+ case 40: goto tr1934;
+ case 41: goto tr1935;
+ case 1034: goto tr1937;
+ case 1083: goto tr1938;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr1936;
+ goto tr1885;
+tr1936:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st647;
+tr1942:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st647;
+st647:
+ if ( ++p == pe )
+ goto _test_eof647;
+case 647:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr1939;
+ case 32: goto tr1939;
+ case 40: goto tr1940;
+ case 41: goto tr1941;
+ case 68: goto tr1943;
+ case 72: goto tr1944;
+ case 77: goto tr1945;
+ case 83: goto st654;
+ case 87: goto tr1947;
+ case 100: goto tr1943;
+ case 104: goto tr1944;
+ case 109: goto tr1945;
+ case 115: goto st654;
+ case 119: goto tr1947;
+ case 1034: goto tr1948;
+ case 1083: goto tr1949;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr1942;
+ goto tr1904;
+tr1951:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st648;
+tr1952:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st648;
+tr1954:
+ {
+ s->line_counter++;
+ }
+ goto st648;
+tr1973:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st648;
+tr1939:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st648;
+tr1940:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st648;
+tr1941:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st648;
+tr1948:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st648;
+tr1981:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st648;
+tr1982:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st648;
+tr1983:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st648;
+tr1985:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st648;
+st648:
+ if ( ++p == pe )
+ goto _test_eof648;
+case 648:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st648;
+ case 32: goto st648;
+ case 40: goto tr1951;
+ case 41: goto tr1952;
+ case 1034: goto tr1954;
+ case 1083: goto tr1955;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr1953;
+ goto tr1885;
+tr1953:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st649;
+tr1957:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st649;
+st649:
+ if ( ++p == pe )
+ goto _test_eof649;
+case 649:
+ switch( (*p) ) {
+ case 32: goto tr1956;
+ case 59: goto tr1956;
+ case 68: goto tr1958;
+ case 72: goto tr1959;
+ case 77: goto tr1960;
+ case 83: goto st650;
+ case 87: goto tr1962;
+ case 100: goto tr1958;
+ case 104: goto tr1959;
+ case 109: goto tr1960;
+ case 115: goto st650;
+ case 119: goto tr1962;
+ }
+ if ( (*p) < 40 ) {
+ if ( 9 <= (*p) && (*p) <= 10 )
+ goto tr1956;
+ } else if ( (*p) > 41 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr1957;
+ } else
+ goto tr1956;
+ goto tr1904;
+tr1956:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1163;
+tr1970:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1163;
+st1163:
+ if ( ++p == pe )
+ goto _test_eof1163;
+case 1163:
+ goto st0;
+tr1958:
+ { if (s->number64 <= (UINT32_MAX / 86400)) {
+ s->number64 *= 86400;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st650;
+tr1959:
+ { if (s->number64 <= (UINT32_MAX / 3600)) {
+ s->number64 *= 3600;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st650;
+tr1960:
+ { if (s->number64 <= (UINT32_MAX / 60)) {
+ s->number64 *= 60;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st650;
+tr1962:
+ { if (s->number64 <= (UINT32_MAX / 604800)) {
+ s->number64 *= 604800;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st650;
+st650:
+ if ( ++p == pe )
+ goto _test_eof650;
+case 650:
+ switch( (*p) ) {
+ case 32: goto tr1956;
+ case 59: goto tr1956;
+ }
+ if ( (*p) < 40 ) {
+ if ( 9 <= (*p) && (*p) <= 10 )
+ goto tr1956;
+ } else if ( (*p) > 41 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr1963;
+ } else
+ goto tr1956;
+ goto tr1904;
+tr1964:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st651;
+tr1963:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st651;
+tr1971:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st651;
+st651:
+ if ( ++p == pe )
+ goto _test_eof651;
+case 651:
+ switch( (*p) ) {
+ case 68: goto tr1965;
+ case 72: goto tr1966;
+ case 77: goto tr1967;
+ case 83: goto st652;
+ case 87: goto tr1969;
+ case 100: goto tr1965;
+ case 104: goto tr1966;
+ case 109: goto tr1967;
+ case 115: goto st652;
+ case 119: goto tr1969;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr1964;
+ goto tr1904;
+tr1965:
+ { if (s->number64 <= (UINT32_MAX / 86400)) {
+ s->number64 *= 86400;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st652;
+tr1966:
+ { if (s->number64 <= (UINT32_MAX / 3600)) {
+ s->number64 *= 3600;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st652;
+tr1967:
+ { if (s->number64 <= (UINT32_MAX / 60)) {
+ s->number64 *= 60;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st652;
+tr1969:
+ { if (s->number64 <= (UINT32_MAX / 604800)) {
+ s->number64 *= 604800;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st652;
+st652:
+ if ( ++p == pe )
+ goto _test_eof652;
+case 652:
+ switch( (*p) ) {
+ case 32: goto tr1970;
+ case 59: goto tr1970;
+ }
+ if ( (*p) < 40 ) {
+ if ( 9 <= (*p) && (*p) <= 10 )
+ goto tr1970;
+ } else if ( (*p) > 41 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr1971;
+ } else
+ goto tr1970;
+ goto tr1904;
+tr1955:
+ {
+ s->buffer_length = 0;
+ }
+ goto st653;
+tr1972:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st653;
+tr1949:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st653;
+tr1986:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st653;
+st653:
+ if ( ++p == pe )
+ goto _test_eof653;
+case 653:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr1973;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr1972;
+ goto tr71;
+tr1943:
+ { if (s->number64 <= (UINT32_MAX / 86400)) {
+ s->number64 *= 86400;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st654;
+tr1944:
+ { if (s->number64 <= (UINT32_MAX / 3600)) {
+ s->number64 *= 3600;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st654;
+tr1945:
+ { if (s->number64 <= (UINT32_MAX / 60)) {
+ s->number64 *= 60;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st654;
+tr1947:
+ { if (s->number64 <= (UINT32_MAX / 604800)) {
+ s->number64 *= 604800;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st654;
+st654:
+ if ( ++p == pe )
+ goto _test_eof654;
+case 654:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr1939;
+ case 32: goto tr1939;
+ case 40: goto tr1940;
+ case 41: goto tr1941;
+ case 1034: goto tr1948;
+ case 1083: goto tr1949;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr1974;
+ goto tr1904;
+tr1975:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st655;
+tr1974:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st655;
+tr1984:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st655;
+st655:
+ if ( ++p == pe )
+ goto _test_eof655;
+case 655:
+ switch( (*p) ) {
+ case 68: goto tr1976;
+ case 72: goto tr1977;
+ case 77: goto tr1978;
+ case 83: goto st656;
+ case 87: goto tr1980;
+ case 100: goto tr1976;
+ case 104: goto tr1977;
+ case 109: goto tr1978;
+ case 115: goto st656;
+ case 119: goto tr1980;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr1975;
+ goto tr1904;
+tr1976:
+ { if (s->number64 <= (UINT32_MAX / 86400)) {
+ s->number64 *= 86400;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st656;
+tr1977:
+ { if (s->number64 <= (UINT32_MAX / 3600)) {
+ s->number64 *= 3600;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st656;
+tr1978:
+ { if (s->number64 <= (UINT32_MAX / 60)) {
+ s->number64 *= 60;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st656;
+tr1980:
+ { if (s->number64 <= (UINT32_MAX / 604800)) {
+ s->number64 *= 604800;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st656;
+st656:
+ if ( ++p == pe )
+ goto _test_eof656;
+case 656:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr1981;
+ case 32: goto tr1981;
+ case 40: goto tr1982;
+ case 41: goto tr1983;
+ case 1034: goto tr1985;
+ case 1083: goto tr1986;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr1984;
+ goto tr1904;
+tr1938:
+ {
+ s->buffer_length = 0;
+ }
+ goto st657;
+tr1987:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st657;
+tr1932:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st657;
+tr2001:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st657;
+st657:
+ if ( ++p == pe )
+ goto _test_eof657;
+case 657:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr1988;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr1987;
+ goto tr71;
+tr1926:
+ { if (s->number64 <= (UINT32_MAX / 86400)) {
+ s->number64 *= 86400;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st658;
+tr1927:
+ { if (s->number64 <= (UINT32_MAX / 3600)) {
+ s->number64 *= 3600;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st658;
+tr1928:
+ { if (s->number64 <= (UINT32_MAX / 60)) {
+ s->number64 *= 60;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st658;
+tr1930:
+ { if (s->number64 <= (UINT32_MAX / 604800)) {
+ s->number64 *= 604800;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st658;
+st658:
+ if ( ++p == pe )
+ goto _test_eof658;
+case 658:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr1922;
+ case 32: goto tr1922;
+ case 40: goto tr1923;
+ case 41: goto tr1924;
+ case 1034: goto tr1931;
+ case 1083: goto tr1932;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr1989;
+ goto tr1904;
+tr1990:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st659;
+tr1989:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st659;
+tr1999:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st659;
+st659:
+ if ( ++p == pe )
+ goto _test_eof659;
+case 659:
+ switch( (*p) ) {
+ case 68: goto tr1991;
+ case 72: goto tr1992;
+ case 77: goto tr1993;
+ case 83: goto st660;
+ case 87: goto tr1995;
+ case 100: goto tr1991;
+ case 104: goto tr1992;
+ case 109: goto tr1993;
+ case 115: goto st660;
+ case 119: goto tr1995;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr1990;
+ goto tr1904;
+tr1991:
+ { if (s->number64 <= (UINT32_MAX / 86400)) {
+ s->number64 *= 86400;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st660;
+tr1992:
+ { if (s->number64 <= (UINT32_MAX / 3600)) {
+ s->number64 *= 3600;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st660;
+tr1993:
+ { if (s->number64 <= (UINT32_MAX / 60)) {
+ s->number64 *= 60;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st660;
+tr1995:
+ { if (s->number64 <= (UINT32_MAX / 604800)) {
+ s->number64 *= 604800;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st660;
+st660:
+ if ( ++p == pe )
+ goto _test_eof660;
+case 660:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr1996;
+ case 32: goto tr1996;
+ case 40: goto tr1997;
+ case 41: goto tr1998;
+ case 1034: goto tr2000;
+ case 1083: goto tr2001;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr1999;
+ goto tr1904;
+tr1921:
+ {
+ s->buffer_length = 0;
+ }
+ goto st661;
+tr2002:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st661;
+tr1915:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st661;
+tr2016:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st661;
+st661:
+ if ( ++p == pe )
+ goto _test_eof661;
+case 661:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2003;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2002;
+ goto tr71;
+tr1909:
+ { if (s->number64 <= (UINT32_MAX / 86400)) {
+ s->number64 *= 86400;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st662;
+tr1910:
+ { if (s->number64 <= (UINT32_MAX / 3600)) {
+ s->number64 *= 3600;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st662;
+tr1911:
+ { if (s->number64 <= (UINT32_MAX / 60)) {
+ s->number64 *= 60;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st662;
+tr1913:
+ { if (s->number64 <= (UINT32_MAX / 604800)) {
+ s->number64 *= 604800;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st662;
+st662:
+ if ( ++p == pe )
+ goto _test_eof662;
+case 662:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr1905;
+ case 32: goto tr1905;
+ case 40: goto tr1906;
+ case 41: goto tr1907;
+ case 1034: goto tr1914;
+ case 1083: goto tr1915;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2004;
+ goto tr1904;
+tr2005:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st663;
+tr2004:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st663;
+tr2014:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st663;
+st663:
+ if ( ++p == pe )
+ goto _test_eof663;
+case 663:
+ switch( (*p) ) {
+ case 68: goto tr2006;
+ case 72: goto tr2007;
+ case 77: goto tr2008;
+ case 83: goto st664;
+ case 87: goto tr2010;
+ case 100: goto tr2006;
+ case 104: goto tr2007;
+ case 109: goto tr2008;
+ case 115: goto st664;
+ case 119: goto tr2010;
+ }
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr2005;
+ goto tr1904;
+tr2006:
+ { if (s->number64 <= (UINT32_MAX / 86400)) {
+ s->number64 *= 86400;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st664;
+tr2007:
+ { if (s->number64 <= (UINT32_MAX / 3600)) {
+ s->number64 *= 3600;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st664;
+tr2008:
+ { if (s->number64 <= (UINT32_MAX / 60)) {
+ s->number64 *= 60;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st664;
+tr2010:
+ { if (s->number64 <= (UINT32_MAX / 604800)) {
+ s->number64 *= 604800;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st664;
+st664:
+ if ( ++p == pe )
+ goto _test_eof664;
+case 664:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2011;
+ case 32: goto tr2011;
+ case 40: goto tr2012;
+ case 41: goto tr2013;
+ case 1034: goto tr2015;
+ case 1083: goto tr2016;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2014;
+ goto tr1904;
+tr1903:
+ {
+ s->buffer_length = 0;
+ }
+ goto st665;
+tr2017:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st665;
+tr1897:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st665;
+st665:
+ if ( ++p == pe )
+ goto _test_eof665;
+case 665:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2018;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2017;
+ goto tr71;
+tr1891:
+ {
+ s->buffer_length = 0;
+ }
+ goto st666;
+tr2019:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st666;
+tr1884:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st666;
+st666:
+ if ( ++p == pe )
+ goto _test_eof666;
+case 666:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2020;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2019;
+ goto tr71;
+tr1879:
+ {
+ s->buffer_length = 0;
+ }
+ goto st667;
+tr2021:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st667;
+tr1873:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st667;
+st667:
+ if ( ++p == pe )
+ goto _test_eof667;
+case 667:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2022;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2021;
+ goto tr71;
+st668:
+ if ( ++p == pe )
+ goto _test_eof668;
+case 668:
+ switch( (*p) ) {
+ case 32: goto tr71;
+ case 59: goto tr71;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr71;
+ } else if ( (*p) >= 9 )
+ goto tr71;
+ goto tr2023;
+tr2023:
+ {
+ if (rdata_tail <= rdata_stop) {
+ s->item_length_location = rdata_tail++;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ { p--; {stack[top++] = 669;goto st279;} }
+ goto st669;
+st669:
+ if ( ++p == pe )
+ goto _test_eof669;
+case 669:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2024;
+ case 32: goto tr2024;
+ case 40: goto tr2025;
+ case 41: goto tr2026;
+ case 1034: goto tr2027;
+ case 1083: goto tr2028;
+ }
+ goto tr71;
+tr2031:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st670;
+tr2032:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st670;
+tr2033:
+ {
+ s->line_counter++;
+ }
+ goto st670;
+tr2037:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st670;
+tr2024:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st670;
+tr2025:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st670;
+tr2026:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st670;
+tr2027:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st670;
+st670:
+ if ( ++p == pe )
+ goto _test_eof670;
+case 670:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st670;
+ case 32: goto st670;
+ case 40: goto tr2031;
+ case 41: goto tr2032;
+ case 1034: goto tr2033;
+ case 1083: goto tr2034;
+ }
+ if ( _widec < 11 ) {
+ if ( _widec <= 8 )
+ goto tr2029;
+ } else if ( _widec > 58 ) {
+ if ( 60 <= _widec )
+ goto tr2029;
+ } else
+ goto tr2029;
+ goto tr71;
+tr2029:
+ {
+ if (rdata_tail <= rdata_stop) {
+ s->item_length_location = rdata_tail++;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ { p--; {stack[top++] = 671;goto st279;} }
+ goto st671;
+st671:
+ if ( ++p == pe )
+ goto _test_eof671;
+case 671:
+ switch( (*p) ) {
+ case 32: goto tr2035;
+ case 59: goto tr2035;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr2035;
+ } else if ( (*p) >= 9 )
+ goto tr2035;
+ goto tr71;
+tr2035:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1164;
+st1164:
+ if ( ++p == pe )
+ goto _test_eof1164;
+case 1164:
+ goto st0;
+tr2034:
+ {
+ s->buffer_length = 0;
+ }
+ goto st672;
+tr2036:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st672;
+tr2028:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st672;
+st672:
+ if ( ++p == pe )
+ goto _test_eof672;
+case 672:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2037;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2036;
+ goto tr71;
+st673:
+ if ( ++p == pe )
+ goto _test_eof673;
+case 673:
+ switch( (*p) ) {
+ case 42: goto tr2038;
+ case 92: goto tr2038;
+ case 95: goto tr2038;
+ }
+ if ( (*p) < 64 ) {
+ if ( 45 <= (*p) && (*p) <= 57 )
+ goto tr2038;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr2038;
+ } else
+ goto tr2038;
+ goto tr71;
+tr2038:
+ {
+ s->dname = rdata_tail;
+ }
+ { p--; {stack[top++] = 674;goto st270;} }
+ goto st674;
+st674:
+ if ( ++p == pe )
+ goto _test_eof674;
+case 674:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2039;
+ case 32: goto tr2039;
+ case 40: goto tr2040;
+ case 41: goto tr2041;
+ case 1034: goto tr2042;
+ case 1083: goto tr2043;
+ }
+ goto tr71;
+tr2045:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st675;
+tr2046:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st675;
+tr2048:
+ {
+ s->line_counter++;
+ }
+ goto st675;
+tr2052:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st675;
+tr2039:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ goto st675;
+tr2040:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st675;
+tr2041:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st675;
+tr2042:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st675;
+st675:
+ if ( ++p == pe )
+ goto _test_eof675;
+case 675:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st675;
+ case 32: goto st675;
+ case 40: goto tr2045;
+ case 41: goto tr2046;
+ case 42: goto tr2047;
+ case 92: goto tr2047;
+ case 95: goto tr2047;
+ case 1034: goto tr2048;
+ case 1083: goto tr2049;
+ }
+ if ( _widec < 64 ) {
+ if ( 45 <= _widec && _widec <= 57 )
+ goto tr2047;
+ } else if ( _widec > 90 ) {
+ if ( 97 <= _widec && _widec <= 122 )
+ goto tr2047;
+ } else
+ goto tr2047;
+ goto tr71;
+tr2047:
+ {
+ s->dname = rdata_tail;
+ }
+ { p--; {stack[top++] = 676;goto st270;} }
+ goto st676;
+st676:
+ if ( ++p == pe )
+ goto _test_eof676;
+case 676:
+ switch( (*p) ) {
+ case 32: goto tr2050;
+ case 59: goto tr2050;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr2050;
+ } else if ( (*p) >= 9 )
+ goto tr2050;
+ goto tr71;
+tr2050:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1165;
+st1165:
+ if ( ++p == pe )
+ goto _test_eof1165;
+case 1165:
+ goto st0;
+tr2049:
+ {
+ s->buffer_length = 0;
+ }
+ goto st677;
+tr2051:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st677;
+tr2043:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st677;
+st677:
+ if ( ++p == pe )
+ goto _test_eof677;
+case 677:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2052;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2051;
+ goto tr71;
+st678:
+ if ( ++p == pe )
+ goto _test_eof678;
+case 678:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr2053;
+ goto tr1885;
+tr2053:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st679;
+tr2057:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st679;
+st679:
+ if ( ++p == pe )
+ goto _test_eof679;
+case 679:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2054;
+ case 32: goto tr2054;
+ case 40: goto tr2055;
+ case 41: goto tr2056;
+ case 1034: goto tr2058;
+ case 1083: goto tr2059;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2057;
+ goto tr1885;
+tr2061:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st680;
+tr2062:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st680;
+tr2064:
+ {
+ s->line_counter++;
+ }
+ goto st680;
+tr2068:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st680;
+tr2054:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st680;
+tr2055:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st680;
+tr2056:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st680;
+tr2058:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st680;
+st680:
+ if ( ++p == pe )
+ goto _test_eof680;
+case 680:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st680;
+ case 32: goto st680;
+ case 40: goto tr2061;
+ case 41: goto tr2062;
+ case 42: goto tr2063;
+ case 92: goto tr2063;
+ case 95: goto tr2063;
+ case 1034: goto tr2064;
+ case 1083: goto tr2065;
+ }
+ if ( _widec < 64 ) {
+ if ( 45 <= _widec && _widec <= 57 )
+ goto tr2063;
+ } else if ( _widec > 90 ) {
+ if ( 97 <= _widec && _widec <= 122 )
+ goto tr2063;
+ } else
+ goto tr2063;
+ goto tr71;
+tr2063:
+ {
+ s->dname = rdata_tail;
+ }
+ { p--; {stack[top++] = 681;goto st270;} }
+ goto st681;
+st681:
+ if ( ++p == pe )
+ goto _test_eof681;
+case 681:
+ switch( (*p) ) {
+ case 32: goto tr2066;
+ case 59: goto tr2066;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr2066;
+ } else if ( (*p) >= 9 )
+ goto tr2066;
+ goto tr71;
+tr2066:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1166;
+st1166:
+ if ( ++p == pe )
+ goto _test_eof1166;
+case 1166:
+ goto st0;
+tr2065:
+ {
+ s->buffer_length = 0;
+ }
+ goto st682;
+tr2067:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st682;
+tr2059:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st682;
+st682:
+ if ( ++p == pe )
+ goto _test_eof682;
+case 682:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2068;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2067;
+ goto tr71;
+st683:
+ if ( ++p == pe )
+ goto _test_eof683;
+case 683:
+ switch( (*p) ) {
+ case 32: goto tr2070;
+ case 59: goto tr2070;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr2070;
+ } else if ( (*p) >= 9 )
+ goto tr2070;
+ goto tr2069;
+tr2079:
+ {
+ if (rdata_tail <= rdata_stop) {
+ s->item_length_location = rdata_tail++;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ { p--; {stack[top++] = 684;goto st279;} }
+ goto st684;
+tr2069:
+ {
+ s->long_string = true;
+ }
+ {
+ if (rdata_tail <= rdata_stop) {
+ s->item_length_location = rdata_tail++;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ { p--; {stack[top++] = 684;goto st279;} }
+ goto st684;
+st684:
+ if ( ++p == pe )
+ goto _test_eof684;
+case 684:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr2071;
+ case 32: goto tr2071;
+ case 40: goto tr2072;
+ case 41: goto tr2073;
+ case 2058: goto tr2074;
+ case 2107: goto tr2075;
+ case 2314: goto tr2076;
+ case 2363: goto tr2076;
+ case 2570: goto tr2077;
+ case 2619: goto tr2078;
+ }
+ goto tr2070;
+tr2081:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st685;
+tr2082:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st685;
+tr2083:
+ {
+ s->line_counter++;
+ }
+ goto st685;
+tr2089:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st685;
+tr2071:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st685;
+tr2072:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st685;
+tr2073:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st685;
+tr2074:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st685;
+st685:
+ if ( ++p == pe )
+ goto _test_eof685;
+case 685:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st685;
+ case 32: goto st685;
+ case 40: goto tr2081;
+ case 41: goto tr2082;
+ case 2058: goto tr2083;
+ case 2107: goto tr2084;
+ case 2314: goto tr2085;
+ case 2363: goto tr2085;
+ case 2570: goto tr2086;
+ case 2619: goto tr2087;
+ }
+ if ( _widec < 11 ) {
+ if ( _widec <= 8 )
+ goto tr2079;
+ } else if ( _widec > 58 ) {
+ if ( 60 <= _widec )
+ goto tr2079;
+ } else
+ goto tr2079;
+ goto tr2070;
+tr2084:
+ {
+ s->buffer_length = 0;
+ }
+ goto st686;
+tr2088:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st686;
+tr2075:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st686;
+st686:
+ if ( ++p == pe )
+ goto _test_eof686;
+case 686:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2089;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2088;
+ goto tr2070;
+tr2076:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->long_string = false;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1167;
+tr2085:
+ {
+ s->long_string = false;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1167;
+st1167:
+ if ( ++p == pe )
+ goto _test_eof1167;
+case 1167:
+ goto st0;
+tr2077:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ s->long_string = false;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1168;
+tr2086:
+ {
+ s->line_counter++;
+ }
+ {
+ s->long_string = false;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1168;
+st1168:
+ if ( ++p == pe )
+ goto _test_eof1168;
+case 1168:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st685;
+ case 32: goto st685;
+ case 40: goto tr2081;
+ case 41: goto tr2082;
+ case 2058: goto tr2083;
+ case 2107: goto tr2084;
+ case 2314: goto tr2085;
+ case 2363: goto tr2085;
+ case 2570: goto tr2086;
+ case 2619: goto tr2087;
+ }
+ if ( _widec < 11 ) {
+ if ( _widec <= 8 )
+ goto tr2079;
+ } else if ( _widec > 58 ) {
+ if ( 60 <= _widec )
+ goto tr2079;
+ } else
+ goto tr2079;
+ goto tr2070;
+tr2078:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ s->long_string = false;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1169;
+tr2087:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ s->long_string = false;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1169;
+st1169:
+ if ( ++p == pe )
+ goto _test_eof1169;
+case 1169:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2089;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2088;
+ goto tr2070;
+st687:
+ if ( ++p == pe )
+ goto _test_eof687;
+case 687:
+ if ( (*p) == 46 )
+ goto tr2090;
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 58 )
+ goto tr2090;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto tr2090;
+ } else
+ goto tr2090;
+ goto tr1862;
+tr2090:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st688;
+tr2092:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st688;
+st688:
+ if ( ++p == pe )
+ goto _test_eof688;
+case 688:
+ switch( (*p) ) {
+ case 32: goto tr2091;
+ case 46: goto tr2092;
+ case 59: goto tr2091;
+ }
+ if ( (*p) < 48 ) {
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr2091;
+ } else if ( (*p) >= 9 )
+ goto tr2091;
+ } else if ( (*p) > 58 ) {
+ if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto tr2092;
+ } else if ( (*p) >= 65 )
+ goto tr2092;
+ } else
+ goto tr2092;
+ goto tr1862;
+tr2091:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET6, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV6);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET6_ADDR_LENGTH);
+ rdata_tail += ZS_INET6_ADDR_LENGTH;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1170;
+st1170:
+ if ( ++p == pe )
+ goto _test_eof1170;
+case 1170:
+ goto st0;
+st689:
+ if ( ++p == pe )
+ goto _test_eof689;
+case 689:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr2094;
+ goto tr2093;
+tr2098:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st690;
+tr2094:
+ {
+ memset(&(s->loc), 0, sizeof(s->loc));
+ // Defaults.
+ s->loc.siz = 100;
+ s->loc.vp = 1000;
+ s->loc.hp = 1000000;
+ s->loc.lat_sign = 1;
+ s->loc.long_sign = 1;
+ s->loc.alt_sign = 1;
+ }
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st690;
+st690:
+ if ( ++p == pe )
+ goto _test_eof690;
+case 690:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2095;
+ case 32: goto tr2095;
+ case 40: goto tr2096;
+ case 41: goto tr2097;
+ case 1034: goto tr2099;
+ case 1083: goto tr2100;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2098;
+ goto tr2093;
+tr2102:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st691;
+tr2103:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st691;
+tr2107:
+ {
+ s->line_counter++;
+ }
+ goto st691;
+tr2350:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st691;
+tr2095:
+ {
+ if (s->number64 <= 90) {
+ s->loc.d1 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ goto st691;
+tr2096:
+ {
+ if (s->number64 <= 90) {
+ s->loc.d1 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st691;
+tr2097:
+ {
+ if (s->number64 <= 90) {
+ s->loc.d1 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st691;
+tr2099:
+ {
+ if (s->number64 <= 90) {
+ s->loc.d1 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st691;
+st691:
+ if ( ++p == pe )
+ goto _test_eof691;
+case 691:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st691;
+ case 32: goto st691;
+ case 40: goto tr2102;
+ case 41: goto tr2103;
+ case 78: goto st696;
+ case 83: goto st738;
+ case 1034: goto tr2107;
+ case 1083: goto tr2108;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2104;
+ goto tr2093;
+tr2104:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st692;
+tr2112:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st692;
+st692:
+ if ( ++p == pe )
+ goto _test_eof692;
+case 692:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2109;
+ case 32: goto tr2109;
+ case 40: goto tr2110;
+ case 41: goto tr2111;
+ case 1034: goto tr2113;
+ case 1083: goto tr2114;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2112;
+ goto tr2093;
+tr2116:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st693;
+tr2117:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st693;
+tr2119:
+ {
+ s->line_counter++;
+ }
+ goto st693;
+tr2348:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st693;
+tr2109:
+ {
+ if (s->number64 <= 59) {
+ s->loc.m1 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ goto st693;
+tr2110:
+ {
+ if (s->number64 <= 59) {
+ s->loc.m1 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st693;
+tr2111:
+ {
+ if (s->number64 <= 59) {
+ s->loc.m1 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st693;
+tr2113:
+ {
+ if (s->number64 <= 59) {
+ s->loc.m1 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st693;
+st693:
+ if ( ++p == pe )
+ goto _test_eof693;
+case 693:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st693;
+ case 32: goto st693;
+ case 40: goto tr2116;
+ case 41: goto tr2117;
+ case 78: goto st696;
+ case 83: goto st738;
+ case 1034: goto tr2119;
+ case 1083: goto tr2120;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2118;
+ goto tr2093;
+tr2125:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st694;
+tr2118:
+ {
+ s->decimals = 3;
+ }
+ {
+ s->decimal_counter = 0;
+ }
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st694;
+st694:
+ if ( ++p == pe )
+ goto _test_eof694;
+case 694:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2121;
+ case 32: goto tr2121;
+ case 40: goto tr2122;
+ case 41: goto tr2123;
+ case 46: goto st740;
+ case 1034: goto tr2126;
+ case 1083: goto tr2127;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2125;
+ goto tr2093;
+tr2129:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st695;
+tr2130:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st695;
+tr2131:
+ {
+ s->line_counter++;
+ }
+ goto st695;
+tr2339:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st695;
+tr2121:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 59999) {
+ s->loc.s1 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ goto st695;
+tr2122:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 59999) {
+ s->loc.s1 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st695;
+tr2123:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 59999) {
+ s->loc.s1 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st695;
+tr2126:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 59999) {
+ s->loc.s1 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st695;
+tr2340:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 59999) {
+ s->loc.s1 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ goto st695;
+tr2341:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 59999) {
+ s->loc.s1 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st695;
+tr2342:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 59999) {
+ s->loc.s1 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st695;
+tr2344:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 59999) {
+ s->loc.s1 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st695;
+st695:
+ if ( ++p == pe )
+ goto _test_eof695;
+case 695:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st695;
+ case 32: goto st695;
+ case 40: goto tr2129;
+ case 41: goto tr2130;
+ case 78: goto st696;
+ case 83: goto st738;
+ case 1034: goto tr2131;
+ case 1083: goto tr2132;
+ }
+ goto tr2093;
+st696:
+ if ( ++p == pe )
+ goto _test_eof696;
+case 696:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st697;
+ case 32: goto st697;
+ case 40: goto tr2134;
+ case 41: goto tr2135;
+ case 1034: goto tr2136;
+ case 1083: goto tr2137;
+ }
+ goto tr2093;
+tr2134:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st697;
+tr2135:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st697;
+tr2136:
+ {
+ s->line_counter++;
+ }
+ goto st697;
+tr2332:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st697;
+tr2333:
+ {
+ s->loc.lat_sign = -1;
+ }
+ goto st697;
+tr2334:
+ {
+ s->loc.lat_sign = -1;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st697;
+tr2335:
+ {
+ s->loc.lat_sign = -1;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st697;
+tr2336:
+ {
+ s->loc.lat_sign = -1;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st697;
+st697:
+ if ( ++p == pe )
+ goto _test_eof697;
+case 697:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st697;
+ case 32: goto st697;
+ case 40: goto tr2134;
+ case 41: goto tr2135;
+ case 1034: goto tr2136;
+ case 1083: goto tr2137;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2138;
+ goto tr2093;
+tr2138:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st698;
+tr2142:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st698;
+st698:
+ if ( ++p == pe )
+ goto _test_eof698;
+case 698:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2139;
+ case 32: goto tr2139;
+ case 40: goto tr2140;
+ case 41: goto tr2141;
+ case 1034: goto tr2143;
+ case 1083: goto tr2144;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2142;
+ goto tr2093;
+tr2146:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st699;
+tr2147:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st699;
+tr2151:
+ {
+ s->line_counter++;
+ }
+ goto st699;
+tr2330:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st699;
+tr2139:
+ {
+ if (s->number64 <= 180) {
+ s->loc.d2 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ goto st699;
+tr2140:
+ {
+ if (s->number64 <= 180) {
+ s->loc.d2 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st699;
+tr2141:
+ {
+ if (s->number64 <= 180) {
+ s->loc.d2 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st699;
+tr2143:
+ {
+ if (s->number64 <= 180) {
+ s->loc.d2 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st699;
+st699:
+ if ( ++p == pe )
+ goto _test_eof699;
+case 699:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st699;
+ case 32: goto st699;
+ case 40: goto tr2146;
+ case 41: goto tr2147;
+ case 69: goto st704;
+ case 87: goto st731;
+ case 1034: goto tr2151;
+ case 1083: goto tr2152;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2148;
+ goto tr2093;
+tr2148:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st700;
+tr2156:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st700;
+st700:
+ if ( ++p == pe )
+ goto _test_eof700;
+case 700:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2153;
+ case 32: goto tr2153;
+ case 40: goto tr2154;
+ case 41: goto tr2155;
+ case 1034: goto tr2157;
+ case 1083: goto tr2158;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2156;
+ goto tr2093;
+tr2160:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st701;
+tr2161:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st701;
+tr2163:
+ {
+ s->line_counter++;
+ }
+ goto st701;
+tr2328:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st701;
+tr2153:
+ {
+ if (s->number64 <= 59) {
+ s->loc.m2 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ goto st701;
+tr2154:
+ {
+ if (s->number64 <= 59) {
+ s->loc.m2 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st701;
+tr2155:
+ {
+ if (s->number64 <= 59) {
+ s->loc.m2 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st701;
+tr2157:
+ {
+ if (s->number64 <= 59) {
+ s->loc.m2 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st701;
+st701:
+ if ( ++p == pe )
+ goto _test_eof701;
+case 701:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st701;
+ case 32: goto st701;
+ case 40: goto tr2160;
+ case 41: goto tr2161;
+ case 69: goto st704;
+ case 87: goto st731;
+ case 1034: goto tr2163;
+ case 1083: goto tr2164;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2162;
+ goto tr2093;
+tr2169:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st702;
+tr2162:
+ {
+ s->decimals = 3;
+ }
+ {
+ s->decimal_counter = 0;
+ }
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st702;
+st702:
+ if ( ++p == pe )
+ goto _test_eof702;
+case 702:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2165;
+ case 32: goto tr2165;
+ case 40: goto tr2166;
+ case 41: goto tr2167;
+ case 46: goto st733;
+ case 1034: goto tr2170;
+ case 1083: goto tr2171;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2169;
+ goto tr2093;
+tr2173:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st703;
+tr2174:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st703;
+tr2175:
+ {
+ s->line_counter++;
+ }
+ goto st703;
+tr2319:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st703;
+tr2165:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 59999) {
+ s->loc.s2 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ goto st703;
+tr2166:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 59999) {
+ s->loc.s2 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st703;
+tr2167:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 59999) {
+ s->loc.s2 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st703;
+tr2170:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 59999) {
+ s->loc.s2 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st703;
+tr2320:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 59999) {
+ s->loc.s2 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ goto st703;
+tr2321:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 59999) {
+ s->loc.s2 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st703;
+tr2322:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 59999) {
+ s->loc.s2 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st703;
+tr2324:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 59999) {
+ s->loc.s2 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st703;
+st703:
+ if ( ++p == pe )
+ goto _test_eof703;
+case 703:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st703;
+ case 32: goto st703;
+ case 40: goto tr2173;
+ case 41: goto tr2174;
+ case 69: goto st704;
+ case 87: goto st731;
+ case 1034: goto tr2175;
+ case 1083: goto tr2176;
+ }
+ goto tr2093;
+st704:
+ if ( ++p == pe )
+ goto _test_eof704;
+case 704:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st705;
+ case 32: goto st705;
+ case 40: goto tr2178;
+ case 41: goto tr2179;
+ case 1034: goto tr2180;
+ case 1083: goto tr2181;
+ }
+ goto tr2093;
+tr2178:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st705;
+tr2179:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st705;
+tr2180:
+ {
+ s->line_counter++;
+ }
+ goto st705;
+tr2312:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st705;
+tr2313:
+ {
+ s->loc.long_sign = -1;
+ }
+ goto st705;
+tr2314:
+ {
+ s->loc.long_sign = -1;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st705;
+tr2315:
+ {
+ s->loc.long_sign = -1;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st705;
+tr2316:
+ {
+ s->loc.long_sign = -1;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st705;
+st705:
+ if ( ++p == pe )
+ goto _test_eof705;
+case 705:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st705;
+ case 32: goto st705;
+ case 40: goto tr2178;
+ case 41: goto tr2179;
+ case 45: goto st706;
+ case 1034: goto tr2180;
+ case 1083: goto tr2181;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2183;
+ goto tr2093;
+st706:
+ if ( ++p == pe )
+ goto _test_eof706;
+case 706:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr2184;
+ goto tr2093;
+tr2189:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st707;
+tr2183:
+ {
+ s->decimals = 2;
+ }
+ {
+ s->decimal_counter = 0;
+ }
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st707;
+tr2184:
+ {
+ s->loc.alt_sign = -1;
+ }
+ {
+ s->decimals = 2;
+ }
+ {
+ s->decimal_counter = 0;
+ }
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st707;
+st707:
+ if ( ++p == pe )
+ goto _test_eof707;
+case 707:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr2185;
+ case 32: goto tr2185;
+ case 40: goto tr2186;
+ case 41: goto tr2187;
+ case 46: goto st727;
+ case 109: goto tr2190;
+ case 2058: goto tr2191;
+ case 2107: goto tr2192;
+ case 2314: goto tr2193;
+ case 2363: goto tr2193;
+ case 2570: goto tr2194;
+ case 2619: goto tr2195;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2189;
+ goto tr2093;
+tr2197:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st708;
+tr2198:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st708;
+tr2200:
+ {
+ s->line_counter++;
+ }
+ goto st708;
+tr2299:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st708;
+tr2185:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if ((s->loc.alt_sign == 1 && s->number64 <= 4284967295) ||
+ (s->loc.alt_sign == -1 && s->number64 <= 10000000))
+ {
+ s->loc.alt = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ goto st708;
+tr2186:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if ((s->loc.alt_sign == 1 && s->number64 <= 4284967295) ||
+ (s->loc.alt_sign == -1 && s->number64 <= 10000000))
+ {
+ s->loc.alt = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st708;
+tr2187:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if ((s->loc.alt_sign == 1 && s->number64 <= 4284967295) ||
+ (s->loc.alt_sign == -1 && s->number64 <= 10000000))
+ {
+ s->loc.alt = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st708;
+tr2191:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if ((s->loc.alt_sign == 1 && s->number64 <= 4284967295) ||
+ (s->loc.alt_sign == -1 && s->number64 <= 10000000))
+ {
+ s->loc.alt = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st708;
+tr2300:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if ((s->loc.alt_sign == 1 && s->number64 <= 4284967295) ||
+ (s->loc.alt_sign == -1 && s->number64 <= 10000000))
+ {
+ s->loc.alt = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ goto st708;
+tr2301:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if ((s->loc.alt_sign == 1 && s->number64 <= 4284967295) ||
+ (s->loc.alt_sign == -1 && s->number64 <= 10000000))
+ {
+ s->loc.alt = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st708;
+tr2302:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if ((s->loc.alt_sign == 1 && s->number64 <= 4284967295) ||
+ (s->loc.alt_sign == -1 && s->number64 <= 10000000))
+ {
+ s->loc.alt = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st708;
+tr2305:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if ((s->loc.alt_sign == 1 && s->number64 <= 4284967295) ||
+ (s->loc.alt_sign == -1 && s->number64 <= 10000000))
+ {
+ s->loc.alt = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st708;
+st708:
+ if ( ++p == pe )
+ goto _test_eof708;
+case 708:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st708;
+ case 32: goto st708;
+ case 40: goto tr2197;
+ case 41: goto tr2198;
+ case 2058: goto tr2200;
+ case 2107: goto tr2201;
+ case 2314: goto tr2202;
+ case 2363: goto tr2202;
+ case 2570: goto tr2203;
+ case 2619: goto tr2204;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2199;
+ goto tr2093;
+tr2209:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st709;
+tr2199:
+ {
+ s->decimals = 2;
+ }
+ {
+ s->decimal_counter = 0;
+ }
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st709;
+st709:
+ if ( ++p == pe )
+ goto _test_eof709;
+case 709:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr2205;
+ case 32: goto tr2205;
+ case 40: goto tr2206;
+ case 41: goto tr2207;
+ case 46: goto st723;
+ case 109: goto tr2210;
+ case 2058: goto tr2211;
+ case 2107: goto tr2212;
+ case 2314: goto tr2213;
+ case 2363: goto tr2213;
+ case 2570: goto tr2214;
+ case 2619: goto tr2215;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2209;
+ goto tr2093;
+tr2217:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st710;
+tr2218:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st710;
+tr2220:
+ {
+ s->line_counter++;
+ }
+ goto st710;
+tr2286:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st710;
+tr2205:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.siz = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ goto st710;
+tr2206:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.siz = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st710;
+tr2207:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.siz = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st710;
+tr2211:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.siz = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st710;
+tr2287:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.siz = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ goto st710;
+tr2288:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.siz = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st710;
+tr2289:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.siz = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st710;
+tr2292:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.siz = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st710;
+st710:
+ if ( ++p == pe )
+ goto _test_eof710;
+case 710:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st710;
+ case 32: goto st710;
+ case 40: goto tr2217;
+ case 41: goto tr2218;
+ case 2058: goto tr2220;
+ case 2107: goto tr2221;
+ case 2314: goto tr2202;
+ case 2363: goto tr2202;
+ case 2570: goto tr2222;
+ case 2619: goto tr2223;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2219;
+ goto tr2093;
+tr2228:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st711;
+tr2219:
+ {
+ s->decimals = 2;
+ }
+ {
+ s->decimal_counter = 0;
+ }
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st711;
+st711:
+ if ( ++p == pe )
+ goto _test_eof711;
+case 711:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr2224;
+ case 32: goto tr2224;
+ case 40: goto tr2225;
+ case 41: goto tr2226;
+ case 46: goto st719;
+ case 109: goto tr2229;
+ case 2058: goto tr2230;
+ case 2107: goto tr2231;
+ case 2314: goto tr2232;
+ case 2363: goto tr2232;
+ case 2570: goto tr2233;
+ case 2619: goto tr2234;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2228;
+ goto tr2093;
+tr2236:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st712;
+tr2237:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st712;
+tr2239:
+ {
+ s->line_counter++;
+ }
+ goto st712;
+tr2273:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st712;
+tr2224:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.hp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ goto st712;
+tr2225:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.hp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st712;
+tr2226:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.hp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st712;
+tr2230:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.hp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st712;
+tr2274:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.hp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ goto st712;
+tr2275:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.hp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st712;
+tr2276:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.hp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st712;
+tr2279:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.hp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st712;
+st712:
+ if ( ++p == pe )
+ goto _test_eof712;
+case 712:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st712;
+ case 32: goto st712;
+ case 40: goto tr2236;
+ case 41: goto tr2237;
+ case 2058: goto tr2239;
+ case 2107: goto tr2240;
+ case 2314: goto tr2202;
+ case 2363: goto tr2202;
+ case 2570: goto tr2241;
+ case 2619: goto tr2242;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2238;
+ goto tr2093;
+tr2247:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st713;
+tr2238:
+ {
+ s->decimals = 2;
+ }
+ {
+ s->decimal_counter = 0;
+ }
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st713;
+st713:
+ if ( ++p == pe )
+ goto _test_eof713;
+case 713:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr2243;
+ case 32: goto tr2243;
+ case 40: goto tr2244;
+ case 41: goto tr2245;
+ case 46: goto st716;
+ case 109: goto tr2243;
+ case 2058: goto tr2248;
+ case 2107: goto tr2249;
+ case 2314: goto tr2250;
+ case 2363: goto tr2250;
+ case 2570: goto tr2251;
+ case 2619: goto tr2252;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2247;
+ goto tr2093;
+tr2254:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st714;
+tr2255:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st714;
+tr2256:
+ {
+ s->line_counter++;
+ }
+ goto st714;
+tr2261:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st714;
+tr2243:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.vp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ goto st714;
+tr2244:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.vp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st714;
+tr2245:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.vp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st714;
+tr2248:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.vp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st714;
+tr2262:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.vp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ goto st714;
+tr2263:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.vp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st714;
+tr2264:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.vp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st714;
+tr2266:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.vp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st714;
+st714:
+ if ( ++p == pe )
+ goto _test_eof714;
+case 714:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st714;
+ case 32: goto st714;
+ case 40: goto tr2254;
+ case 41: goto tr2255;
+ case 2058: goto tr2256;
+ case 2107: goto tr2257;
+ case 2314: goto tr2202;
+ case 2363: goto tr2202;
+ case 2570: goto tr2258;
+ case 2619: goto tr2259;
+ }
+ goto tr2093;
+tr2257:
+ {
+ s->buffer_length = 0;
+ }
+ goto st715;
+tr2260:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st715;
+tr2249:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.vp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st715;
+tr2267:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.vp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st715;
+st715:
+ if ( ++p == pe )
+ goto _test_eof715;
+case 715:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2261;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2260;
+ goto tr2093;
+tr2193:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if ((s->loc.alt_sign == 1 && s->number64 <= 4284967295) ||
+ (s->loc.alt_sign == -1 && s->number64 <= 10000000))
+ {
+ s->loc.alt = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1171;
+tr2202:
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1171;
+tr2213:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.siz = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1171;
+tr2232:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.hp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1171;
+tr2250:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.vp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1171;
+tr2268:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.vp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1171;
+tr2281:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.hp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1171;
+tr2294:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.siz = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1171;
+tr2307:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if ((s->loc.alt_sign == 1 && s->number64 <= 4284967295) ||
+ (s->loc.alt_sign == -1 && s->number64 <= 10000000))
+ {
+ s->loc.alt = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1171;
+st1171:
+ if ( ++p == pe )
+ goto _test_eof1171;
+case 1171:
+ goto st0;
+tr2258:
+ {
+ s->line_counter++;
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1172;
+tr2251:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.vp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1172;
+tr2269:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.vp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1172;
+st1172:
+ if ( ++p == pe )
+ goto _test_eof1172;
+case 1172:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st714;
+ case 32: goto st714;
+ case 40: goto tr2254;
+ case 41: goto tr2255;
+ case 2058: goto tr2256;
+ case 2107: goto tr2257;
+ case 2314: goto tr2202;
+ case 2363: goto tr2202;
+ case 2570: goto tr2258;
+ case 2619: goto tr2259;
+ }
+ goto tr2093;
+tr2259:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1173;
+tr2252:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.vp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1173;
+tr2270:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.vp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1173;
+st1173:
+ if ( ++p == pe )
+ goto _test_eof1173;
+case 1173:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2261;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2260;
+ goto tr2093;
+st716:
+ if ( ++p == pe )
+ goto _test_eof716;
+case 716:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr2262;
+ case 32: goto tr2262;
+ case 40: goto tr2263;
+ case 41: goto tr2264;
+ case 109: goto tr2262;
+ case 2058: goto tr2266;
+ case 2107: goto tr2267;
+ case 2314: goto tr2268;
+ case 2363: goto tr2268;
+ case 2570: goto tr2269;
+ case 2619: goto tr2270;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2265;
+ goto tr2093;
+tr2265:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->decimal_counter++;
+ }
+ goto st717;
+tr2271:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->decimal_counter++;
+ }
+ goto st717;
+st717:
+ if ( ++p == pe )
+ goto _test_eof717;
+case 717:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr2243;
+ case 32: goto tr2243;
+ case 40: goto tr2244;
+ case 41: goto tr2245;
+ case 109: goto tr2243;
+ case 2058: goto tr2248;
+ case 2107: goto tr2249;
+ case 2314: goto tr2250;
+ case 2363: goto tr2250;
+ case 2570: goto tr2251;
+ case 2619: goto tr2252;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2271;
+ goto tr2093;
+tr2240:
+ {
+ s->buffer_length = 0;
+ }
+ goto st718;
+tr2272:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st718;
+tr2231:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.hp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st718;
+tr2280:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.hp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st718;
+st718:
+ if ( ++p == pe )
+ goto _test_eof718;
+case 718:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2273;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2272;
+ goto tr2093;
+tr2241:
+ {
+ s->line_counter++;
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1174;
+tr2233:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.hp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1174;
+tr2282:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.hp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1174;
+st1174:
+ if ( ++p == pe )
+ goto _test_eof1174;
+case 1174:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st712;
+ case 32: goto st712;
+ case 40: goto tr2236;
+ case 41: goto tr2237;
+ case 2058: goto tr2239;
+ case 2107: goto tr2240;
+ case 2314: goto tr2202;
+ case 2363: goto tr2202;
+ case 2570: goto tr2241;
+ case 2619: goto tr2242;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2238;
+ goto tr2093;
+tr2242:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1175;
+tr2234:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.hp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1175;
+tr2283:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.hp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1175;
+st1175:
+ if ( ++p == pe )
+ goto _test_eof1175;
+case 1175:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2273;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2272;
+ goto tr2093;
+st719:
+ if ( ++p == pe )
+ goto _test_eof719;
+case 719:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr2274;
+ case 32: goto tr2274;
+ case 40: goto tr2275;
+ case 41: goto tr2276;
+ case 109: goto tr2278;
+ case 2058: goto tr2279;
+ case 2107: goto tr2280;
+ case 2314: goto tr2281;
+ case 2363: goto tr2281;
+ case 2570: goto tr2282;
+ case 2619: goto tr2283;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2277;
+ goto tr2093;
+tr2277:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->decimal_counter++;
+ }
+ goto st720;
+tr2284:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->decimal_counter++;
+ }
+ goto st720;
+st720:
+ if ( ++p == pe )
+ goto _test_eof720;
+case 720:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr2224;
+ case 32: goto tr2224;
+ case 40: goto tr2225;
+ case 41: goto tr2226;
+ case 109: goto tr2229;
+ case 2058: goto tr2230;
+ case 2107: goto tr2231;
+ case 2314: goto tr2232;
+ case 2363: goto tr2232;
+ case 2570: goto tr2233;
+ case 2619: goto tr2234;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2284;
+ goto tr2093;
+tr2229:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.hp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ goto st721;
+tr2278:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.hp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ goto st721;
+st721:
+ if ( ++p == pe )
+ goto _test_eof721;
+case 721:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st712;
+ case 32: goto st712;
+ case 40: goto tr2236;
+ case 41: goto tr2237;
+ case 2058: goto tr2239;
+ case 2107: goto tr2240;
+ case 2314: goto tr2202;
+ case 2363: goto tr2202;
+ case 2570: goto tr2241;
+ case 2619: goto tr2242;
+ }
+ goto tr2093;
+tr2221:
+ {
+ s->buffer_length = 0;
+ }
+ goto st722;
+tr2285:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st722;
+tr2212:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.siz = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st722;
+tr2293:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.siz = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st722;
+st722:
+ if ( ++p == pe )
+ goto _test_eof722;
+case 722:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2286;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2285;
+ goto tr2093;
+tr2222:
+ {
+ s->line_counter++;
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1176;
+tr2214:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.siz = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1176;
+tr2295:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.siz = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1176;
+st1176:
+ if ( ++p == pe )
+ goto _test_eof1176;
+case 1176:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st710;
+ case 32: goto st710;
+ case 40: goto tr2217;
+ case 41: goto tr2218;
+ case 2058: goto tr2220;
+ case 2107: goto tr2221;
+ case 2314: goto tr2202;
+ case 2363: goto tr2202;
+ case 2570: goto tr2222;
+ case 2619: goto tr2223;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2219;
+ goto tr2093;
+tr2223:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1177;
+tr2215:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.siz = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1177;
+tr2296:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.siz = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1177;
+st1177:
+ if ( ++p == pe )
+ goto _test_eof1177;
+case 1177:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2286;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2285;
+ goto tr2093;
+st723:
+ if ( ++p == pe )
+ goto _test_eof723;
+case 723:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr2287;
+ case 32: goto tr2287;
+ case 40: goto tr2288;
+ case 41: goto tr2289;
+ case 109: goto tr2291;
+ case 2058: goto tr2292;
+ case 2107: goto tr2293;
+ case 2314: goto tr2294;
+ case 2363: goto tr2294;
+ case 2570: goto tr2295;
+ case 2619: goto tr2296;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2290;
+ goto tr2093;
+tr2290:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->decimal_counter++;
+ }
+ goto st724;
+tr2297:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->decimal_counter++;
+ }
+ goto st724;
+st724:
+ if ( ++p == pe )
+ goto _test_eof724;
+case 724:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr2205;
+ case 32: goto tr2205;
+ case 40: goto tr2206;
+ case 41: goto tr2207;
+ case 109: goto tr2210;
+ case 2058: goto tr2211;
+ case 2107: goto tr2212;
+ case 2314: goto tr2213;
+ case 2363: goto tr2213;
+ case 2570: goto tr2214;
+ case 2619: goto tr2215;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2297;
+ goto tr2093;
+tr2210:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.siz = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ goto st725;
+tr2291:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.siz = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ goto st725;
+st725:
+ if ( ++p == pe )
+ goto _test_eof725;
+case 725:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st710;
+ case 32: goto st710;
+ case 40: goto tr2217;
+ case 41: goto tr2218;
+ case 2058: goto tr2220;
+ case 2107: goto tr2221;
+ case 2314: goto tr2202;
+ case 2363: goto tr2202;
+ case 2570: goto tr2222;
+ case 2619: goto tr2223;
+ }
+ goto tr2093;
+tr2201:
+ {
+ s->buffer_length = 0;
+ }
+ goto st726;
+tr2298:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st726;
+tr2192:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if ((s->loc.alt_sign == 1 && s->number64 <= 4284967295) ||
+ (s->loc.alt_sign == -1 && s->number64 <= 10000000))
+ {
+ s->loc.alt = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st726;
+tr2306:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if ((s->loc.alt_sign == 1 && s->number64 <= 4284967295) ||
+ (s->loc.alt_sign == -1 && s->number64 <= 10000000))
+ {
+ s->loc.alt = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st726;
+st726:
+ if ( ++p == pe )
+ goto _test_eof726;
+case 726:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2299;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2298;
+ goto tr2093;
+tr2194:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if ((s->loc.alt_sign == 1 && s->number64 <= 4284967295) ||
+ (s->loc.alt_sign == -1 && s->number64 <= 10000000))
+ {
+ s->loc.alt = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1178;
+tr2203:
+ {
+ s->line_counter++;
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1178;
+tr2308:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if ((s->loc.alt_sign == 1 && s->number64 <= 4284967295) ||
+ (s->loc.alt_sign == -1 && s->number64 <= 10000000))
+ {
+ s->loc.alt = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1178;
+st1178:
+ if ( ++p == pe )
+ goto _test_eof1178;
+case 1178:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st708;
+ case 32: goto st708;
+ case 40: goto tr2197;
+ case 41: goto tr2198;
+ case 2058: goto tr2200;
+ case 2107: goto tr2201;
+ case 2314: goto tr2202;
+ case 2363: goto tr2202;
+ case 2570: goto tr2203;
+ case 2619: goto tr2204;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2199;
+ goto tr2093;
+tr2195:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if ((s->loc.alt_sign == 1 && s->number64 <= 4284967295) ||
+ (s->loc.alt_sign == -1 && s->number64 <= 10000000))
+ {
+ s->loc.alt = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1179;
+tr2204:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1179;
+tr2309:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if ((s->loc.alt_sign == 1 && s->number64 <= 4284967295) ||
+ (s->loc.alt_sign == -1 && s->number64 <= 10000000))
+ {
+ s->loc.alt = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1179;
+st1179:
+ if ( ++p == pe )
+ goto _test_eof1179;
+case 1179:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2299;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2298;
+ goto tr2093;
+st727:
+ if ( ++p == pe )
+ goto _test_eof727;
+case 727:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr2300;
+ case 32: goto tr2300;
+ case 40: goto tr2301;
+ case 41: goto tr2302;
+ case 109: goto tr2304;
+ case 2058: goto tr2305;
+ case 2107: goto tr2306;
+ case 2314: goto tr2307;
+ case 2363: goto tr2307;
+ case 2570: goto tr2308;
+ case 2619: goto tr2309;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2303;
+ goto tr2093;
+tr2303:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->decimal_counter++;
+ }
+ goto st728;
+tr2310:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->decimal_counter++;
+ }
+ goto st728;
+st728:
+ if ( ++p == pe )
+ goto _test_eof728;
+case 728:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr2185;
+ case 32: goto tr2185;
+ case 40: goto tr2186;
+ case 41: goto tr2187;
+ case 109: goto tr2190;
+ case 2058: goto tr2191;
+ case 2107: goto tr2192;
+ case 2314: goto tr2193;
+ case 2363: goto tr2193;
+ case 2570: goto tr2194;
+ case 2619: goto tr2195;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2310;
+ goto tr2093;
+tr2190:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if ((s->loc.alt_sign == 1 && s->number64 <= 4284967295) ||
+ (s->loc.alt_sign == -1 && s->number64 <= 10000000))
+ {
+ s->loc.alt = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ goto st729;
+tr2304:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if ((s->loc.alt_sign == 1 && s->number64 <= 4284967295) ||
+ (s->loc.alt_sign == -1 && s->number64 <= 10000000))
+ {
+ s->loc.alt = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ goto st729;
+st729:
+ if ( ++p == pe )
+ goto _test_eof729;
+case 729:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st708;
+ case 32: goto st708;
+ case 40: goto tr2197;
+ case 41: goto tr2198;
+ case 2058: goto tr2200;
+ case 2107: goto tr2201;
+ case 2314: goto tr2202;
+ case 2363: goto tr2202;
+ case 2570: goto tr2203;
+ case 2619: goto tr2204;
+ }
+ goto tr2093;
+tr2181:
+ {
+ s->buffer_length = 0;
+ }
+ goto st730;
+tr2311:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st730;
+tr2317:
+ {
+ s->loc.long_sign = -1;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st730;
+st730:
+ if ( ++p == pe )
+ goto _test_eof730;
+case 730:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2312;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2311;
+ goto tr2093;
+st731:
+ if ( ++p == pe )
+ goto _test_eof731;
+case 731:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2313;
+ case 32: goto tr2313;
+ case 40: goto tr2314;
+ case 41: goto tr2315;
+ case 1034: goto tr2316;
+ case 1083: goto tr2317;
+ }
+ goto tr2093;
+tr2176:
+ {
+ s->buffer_length = 0;
+ }
+ goto st732;
+tr2318:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st732;
+tr2171:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 59999) {
+ s->loc.s2 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st732;
+tr2325:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 59999) {
+ s->loc.s2 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st732;
+st732:
+ if ( ++p == pe )
+ goto _test_eof732;
+case 732:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2319;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2318;
+ goto tr2093;
+st733:
+ if ( ++p == pe )
+ goto _test_eof733;
+case 733:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2320;
+ case 32: goto tr2320;
+ case 40: goto tr2321;
+ case 41: goto tr2322;
+ case 1034: goto tr2324;
+ case 1083: goto tr2325;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2323;
+ goto tr2093;
+tr2323:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->decimal_counter++;
+ }
+ goto st734;
+tr2326:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->decimal_counter++;
+ }
+ goto st734;
+st734:
+ if ( ++p == pe )
+ goto _test_eof734;
+case 734:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2165;
+ case 32: goto tr2165;
+ case 40: goto tr2166;
+ case 41: goto tr2167;
+ case 1034: goto tr2170;
+ case 1083: goto tr2171;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2326;
+ goto tr2093;
+tr2164:
+ {
+ s->buffer_length = 0;
+ }
+ goto st735;
+tr2327:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st735;
+tr2158:
+ {
+ if (s->number64 <= 59) {
+ s->loc.m2 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st735;
+st735:
+ if ( ++p == pe )
+ goto _test_eof735;
+case 735:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2328;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2327;
+ goto tr2093;
+tr2152:
+ {
+ s->buffer_length = 0;
+ }
+ goto st736;
+tr2329:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st736;
+tr2144:
+ {
+ if (s->number64 <= 180) {
+ s->loc.d2 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st736;
+st736:
+ if ( ++p == pe )
+ goto _test_eof736;
+case 736:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2330;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2329;
+ goto tr2093;
+tr2137:
+ {
+ s->buffer_length = 0;
+ }
+ goto st737;
+tr2331:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st737;
+tr2337:
+ {
+ s->loc.lat_sign = -1;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st737;
+st737:
+ if ( ++p == pe )
+ goto _test_eof737;
+case 737:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2332;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2331;
+ goto tr2093;
+st738:
+ if ( ++p == pe )
+ goto _test_eof738;
+case 738:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2333;
+ case 32: goto tr2333;
+ case 40: goto tr2334;
+ case 41: goto tr2335;
+ case 1034: goto tr2336;
+ case 1083: goto tr2337;
+ }
+ goto tr2093;
+tr2132:
+ {
+ s->buffer_length = 0;
+ }
+ goto st739;
+tr2338:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st739;
+tr2127:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 59999) {
+ s->loc.s1 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st739;
+tr2345:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->number64 <= 59999) {
+ s->loc.s1 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st739;
+st739:
+ if ( ++p == pe )
+ goto _test_eof739;
+case 739:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2339;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2338;
+ goto tr2093;
+st740:
+ if ( ++p == pe )
+ goto _test_eof740;
+case 740:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2340;
+ case 32: goto tr2340;
+ case 40: goto tr2341;
+ case 41: goto tr2342;
+ case 1034: goto tr2344;
+ case 1083: goto tr2345;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2343;
+ goto tr2093;
+tr2343:
+ {
+ s->number64_tmp = s->number64;
+ }
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->decimal_counter++;
+ }
+ goto st741;
+tr2346:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->decimal_counter++;
+ }
+ goto st741;
+st741:
+ if ( ++p == pe )
+ goto _test_eof741;
+case 741:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2121;
+ case 32: goto tr2121;
+ case 40: goto tr2122;
+ case 41: goto tr2123;
+ case 1034: goto tr2126;
+ case 1083: goto tr2127;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2346;
+ goto tr2093;
+tr2120:
+ {
+ s->buffer_length = 0;
+ }
+ goto st742;
+tr2347:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st742;
+tr2114:
+ {
+ if (s->number64 <= 59) {
+ s->loc.m1 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st742;
+st742:
+ if ( ++p == pe )
+ goto _test_eof742;
+case 742:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2348;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2347;
+ goto tr2093;
+tr2108:
+ {
+ s->buffer_length = 0;
+ }
+ goto st743;
+tr2349:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st743;
+tr2100:
+ {
+ if (s->number64 <= 90) {
+ s->loc.d1 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st743;
+st743:
+ if ( ++p == pe )
+ goto _test_eof743;
+case 743:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2350;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2349;
+ goto tr2093;
+st744:
+ if ( ++p == pe )
+ goto _test_eof744;
+case 744:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr2351;
+ goto tr1885;
+tr2351:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st745;
+tr2355:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st745;
+st745:
+ if ( ++p == pe )
+ goto _test_eof745;
+case 745:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2352;
+ case 32: goto tr2352;
+ case 40: goto tr2353;
+ case 41: goto tr2354;
+ case 1034: goto tr2356;
+ case 1083: goto tr2357;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2355;
+ goto tr1885;
+tr2359:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st746;
+tr2360:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st746;
+tr2362:
+ {
+ s->line_counter++;
+ }
+ goto st746;
+tr2394:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st746;
+tr2352:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st746;
+tr2353:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st746;
+tr2354:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st746;
+tr2356:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st746;
+st746:
+ if ( ++p == pe )
+ goto _test_eof746;
+case 746:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st746;
+ case 32: goto st746;
+ case 40: goto tr2359;
+ case 41: goto tr2360;
+ case 1034: goto tr2362;
+ case 1083: goto tr2363;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2361;
+ goto tr1885;
+tr2361:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st747;
+tr2367:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st747;
+st747:
+ if ( ++p == pe )
+ goto _test_eof747;
+case 747:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2364;
+ case 32: goto tr2364;
+ case 40: goto tr2365;
+ case 41: goto tr2366;
+ case 1034: goto tr2368;
+ case 1083: goto tr2369;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2367;
+ goto tr1885;
+tr2371:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st748;
+tr2372:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st748;
+tr2374:
+ {
+ s->line_counter++;
+ }
+ goto st748;
+tr2392:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st748;
+tr2364:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st748;
+tr2365:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st748;
+tr2366:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st748;
+tr2368:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st748;
+st748:
+ if ( ++p == pe )
+ goto _test_eof748;
+case 748:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st748;
+ case 32: goto st748;
+ case 40: goto tr2371;
+ case 41: goto tr2372;
+ case 1034: goto tr2374;
+ case 1083: goto tr2375;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2373;
+ goto tr1885;
+tr2373:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st749;
+tr2379:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st749;
+st749:
+ if ( ++p == pe )
+ goto _test_eof749;
+case 749:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2376;
+ case 32: goto tr2376;
+ case 40: goto tr2377;
+ case 41: goto tr2378;
+ case 1034: goto tr2380;
+ case 1083: goto tr2381;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2379;
+ goto tr1885;
+tr2383:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st750;
+tr2384:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st750;
+tr2386:
+ {
+ s->line_counter++;
+ }
+ goto st750;
+tr2390:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st750;
+tr2376:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st750;
+tr2377:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st750;
+tr2378:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st750;
+tr2380:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st750;
+st750:
+ if ( ++p == pe )
+ goto _test_eof750;
+case 750:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st750;
+ case 32: goto st750;
+ case 40: goto tr2383;
+ case 41: goto tr2384;
+ case 42: goto tr2385;
+ case 92: goto tr2385;
+ case 95: goto tr2385;
+ case 1034: goto tr2386;
+ case 1083: goto tr2387;
+ }
+ if ( _widec < 64 ) {
+ if ( 45 <= _widec && _widec <= 57 )
+ goto tr2385;
+ } else if ( _widec > 90 ) {
+ if ( 97 <= _widec && _widec <= 122 )
+ goto tr2385;
+ } else
+ goto tr2385;
+ goto tr71;
+tr2385:
+ {
+ s->dname = rdata_tail;
+ }
+ { p--; {stack[top++] = 751;goto st270;} }
+ goto st751;
+st751:
+ if ( ++p == pe )
+ goto _test_eof751;
+case 751:
+ switch( (*p) ) {
+ case 32: goto tr2388;
+ case 59: goto tr2388;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr2388;
+ } else if ( (*p) >= 9 )
+ goto tr2388;
+ goto tr71;
+tr2388:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1180;
+st1180:
+ if ( ++p == pe )
+ goto _test_eof1180;
+case 1180:
+ goto st0;
+tr2387:
+ {
+ s->buffer_length = 0;
+ }
+ goto st752;
+tr2389:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st752;
+tr2381:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st752;
+st752:
+ if ( ++p == pe )
+ goto _test_eof752;
+case 752:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2390;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2389;
+ goto tr71;
+tr2375:
+ {
+ s->buffer_length = 0;
+ }
+ goto st753;
+tr2391:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st753;
+tr2369:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st753;
+st753:
+ if ( ++p == pe )
+ goto _test_eof753;
+case 753:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2392;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2391;
+ goto tr71;
+tr2363:
+ {
+ s->buffer_length = 0;
+ }
+ goto st754;
+tr2393:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st754;
+tr2357:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st754;
+st754:
+ if ( ++p == pe )
+ goto _test_eof754;
+case 754:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2394;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2393;
+ goto tr71;
+st755:
+ if ( ++p == pe )
+ goto _test_eof755;
+case 755:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr2395;
+ goto tr1885;
+tr2395:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st756;
+tr2399:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st756;
+st756:
+ if ( ++p == pe )
+ goto _test_eof756;
+case 756:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2396;
+ case 32: goto tr2396;
+ case 40: goto tr2397;
+ case 41: goto tr2398;
+ case 1034: goto tr2400;
+ case 1083: goto tr2401;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2399;
+ goto tr1885;
+tr2403:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st757;
+tr2404:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st757;
+tr2406:
+ {
+ s->line_counter++;
+ }
+ goto st757;
+tr2463:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st757;
+tr2396:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st757;
+tr2397:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st757;
+tr2398:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st757;
+tr2400:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st757;
+st757:
+ if ( ++p == pe )
+ goto _test_eof757;
+case 757:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st757;
+ case 32: goto st757;
+ case 40: goto tr2403;
+ case 41: goto tr2404;
+ case 1034: goto tr2406;
+ case 1083: goto tr2407;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2405;
+ goto tr1885;
+tr2405:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st758;
+tr2411:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st758;
+st758:
+ if ( ++p == pe )
+ goto _test_eof758;
+case 758:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2408;
+ case 32: goto tr2408;
+ case 40: goto tr2409;
+ case 41: goto tr2410;
+ case 1034: goto tr2412;
+ case 1083: goto tr2413;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2411;
+ goto tr1885;
+tr2416:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st759;
+tr2417:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st759;
+tr2418:
+ {
+ s->line_counter++;
+ }
+ goto st759;
+tr2461:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st759;
+tr2408:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st759;
+tr2409:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st759;
+tr2410:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st759;
+tr2412:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st759;
+st759:
+ if ( ++p == pe )
+ goto _test_eof759;
+case 759:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st759;
+ case 32: goto st759;
+ case 40: goto tr2416;
+ case 41: goto tr2417;
+ case 1034: goto tr2418;
+ case 1083: goto tr2419;
+ }
+ if ( _widec < 11 ) {
+ if ( _widec <= 8 )
+ goto tr2414;
+ } else if ( _widec > 58 ) {
+ if ( 60 <= _widec )
+ goto tr2414;
+ } else
+ goto tr2414;
+ goto tr71;
+tr2414:
+ {
+ if (rdata_tail <= rdata_stop) {
+ s->item_length_location = rdata_tail++;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ { p--; {stack[top++] = 760;goto st279;} }
+ goto st760;
+st760:
+ if ( ++p == pe )
+ goto _test_eof760;
+case 760:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2420;
+ case 32: goto tr2420;
+ case 40: goto tr2421;
+ case 41: goto tr2422;
+ case 1034: goto tr2423;
+ case 1083: goto tr2424;
+ }
+ goto tr71;
+tr2427:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st761;
+tr2428:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st761;
+tr2429:
+ {
+ s->line_counter++;
+ }
+ goto st761;
+tr2459:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st761;
+tr2420:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st761;
+tr2421:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st761;
+tr2422:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st761;
+tr2423:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st761;
+st761:
+ if ( ++p == pe )
+ goto _test_eof761;
+case 761:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st761;
+ case 32: goto st761;
+ case 40: goto tr2427;
+ case 41: goto tr2428;
+ case 1034: goto tr2429;
+ case 1083: goto tr2430;
+ }
+ if ( _widec < 11 ) {
+ if ( _widec <= 8 )
+ goto tr2425;
+ } else if ( _widec > 58 ) {
+ if ( 60 <= _widec )
+ goto tr2425;
+ } else
+ goto tr2425;
+ goto tr71;
+tr2425:
+ {
+ if (rdata_tail <= rdata_stop) {
+ s->item_length_location = rdata_tail++;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ { p--; {stack[top++] = 762;goto st279;} }
+ goto st762;
+st762:
+ if ( ++p == pe )
+ goto _test_eof762;
+case 762:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2431;
+ case 32: goto tr2431;
+ case 40: goto tr2432;
+ case 41: goto tr2433;
+ case 1034: goto tr2434;
+ case 1083: goto tr2435;
+ }
+ goto tr71;
+tr2438:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st763;
+tr2439:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st763;
+tr2440:
+ {
+ s->line_counter++;
+ }
+ goto st763;
+tr2457:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st763;
+tr2431:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st763;
+tr2432:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st763;
+tr2433:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st763;
+tr2434:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st763;
+st763:
+ if ( ++p == pe )
+ goto _test_eof763;
+case 763:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st763;
+ case 32: goto st763;
+ case 40: goto tr2438;
+ case 41: goto tr2439;
+ case 1034: goto tr2440;
+ case 1083: goto tr2441;
+ }
+ if ( _widec < 11 ) {
+ if ( _widec <= 8 )
+ goto tr2436;
+ } else if ( _widec > 58 ) {
+ if ( 60 <= _widec )
+ goto tr2436;
+ } else
+ goto tr2436;
+ goto tr71;
+tr2436:
+ {
+ if (rdata_tail <= rdata_stop) {
+ s->item_length_location = rdata_tail++;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ { p--; {stack[top++] = 764;goto st279;} }
+ goto st764;
+st764:
+ if ( ++p == pe )
+ goto _test_eof764;
+case 764:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2442;
+ case 32: goto tr2442;
+ case 40: goto tr2443;
+ case 41: goto tr2444;
+ case 1034: goto tr2445;
+ case 1083: goto tr2446;
+ }
+ goto tr71;
+tr2448:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st765;
+tr2449:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st765;
+tr2451:
+ {
+ s->line_counter++;
+ }
+ goto st765;
+tr2455:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st765;
+tr2442:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st765;
+tr2443:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st765;
+tr2444:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st765;
+tr2445:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st765;
+st765:
+ if ( ++p == pe )
+ goto _test_eof765;
+case 765:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st765;
+ case 32: goto st765;
+ case 40: goto tr2448;
+ case 41: goto tr2449;
+ case 42: goto tr2450;
+ case 92: goto tr2450;
+ case 95: goto tr2450;
+ case 1034: goto tr2451;
+ case 1083: goto tr2452;
+ }
+ if ( _widec < 64 ) {
+ if ( 45 <= _widec && _widec <= 57 )
+ goto tr2450;
+ } else if ( _widec > 90 ) {
+ if ( 97 <= _widec && _widec <= 122 )
+ goto tr2450;
+ } else
+ goto tr2450;
+ goto tr71;
+tr2450:
+ {
+ s->dname = rdata_tail;
+ }
+ { p--; {stack[top++] = 766;goto st270;} }
+ goto st766;
+st766:
+ if ( ++p == pe )
+ goto _test_eof766;
+case 766:
+ switch( (*p) ) {
+ case 32: goto tr2453;
+ case 59: goto tr2453;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr2453;
+ } else if ( (*p) >= 9 )
+ goto tr2453;
+ goto tr71;
+tr2453:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1181;
+st1181:
+ if ( ++p == pe )
+ goto _test_eof1181;
+case 1181:
+ goto st0;
+tr2452:
+ {
+ s->buffer_length = 0;
+ }
+ goto st767;
+tr2454:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st767;
+tr2446:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st767;
+st767:
+ if ( ++p == pe )
+ goto _test_eof767;
+case 767:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2455;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2454;
+ goto tr71;
+tr2441:
+ {
+ s->buffer_length = 0;
+ }
+ goto st768;
+tr2456:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st768;
+tr2435:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st768;
+st768:
+ if ( ++p == pe )
+ goto _test_eof768;
+case 768:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2457;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2456;
+ goto tr71;
+tr2430:
+ {
+ s->buffer_length = 0;
+ }
+ goto st769;
+tr2458:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st769;
+tr2424:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st769;
+st769:
+ if ( ++p == pe )
+ goto _test_eof769;
+case 769:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2459;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2458;
+ goto tr71;
+tr2419:
+ {
+ s->buffer_length = 0;
+ }
+ goto st770;
+tr2460:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st770;
+tr2413:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st770;
+st770:
+ if ( ++p == pe )
+ goto _test_eof770;
+case 770:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2461;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2460;
+ goto tr71;
+tr2407:
+ {
+ s->buffer_length = 0;
+ }
+ goto st771;
+tr2462:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st771;
+tr2401:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st771;
+st771:
+ if ( ++p == pe )
+ goto _test_eof771;
+case 771:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2463;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2462;
+ goto tr71;
+st772:
+ if ( ++p == pe )
+ goto _test_eof772;
+case 772:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr2464;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr2464;
+ } else
+ goto tr2464;
+ goto tr71;
+tr2464:
+ { p--; {stack[top++] = 773;goto st591;} }
+ goto st773;
+st773:
+ if ( ++p == pe )
+ goto _test_eof773;
+case 773:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st774;
+ case 32: goto st774;
+ case 40: goto tr2466;
+ case 41: goto tr2467;
+ case 1034: goto tr2468;
+ case 1083: goto tr2469;
+ }
+ goto tr71;
+tr2466:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st774;
+tr2467:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st774;
+tr2468:
+ {
+ s->line_counter++;
+ }
+ goto st774;
+tr2495:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st774;
+st774:
+ if ( ++p == pe )
+ goto _test_eof774;
+case 774:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st774;
+ case 32: goto st774;
+ case 40: goto tr2466;
+ case 41: goto tr2467;
+ case 1034: goto tr2468;
+ case 1083: goto tr2469;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2470;
+ goto tr1885;
+tr2470:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st775;
+tr2474:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st775;
+st775:
+ if ( ++p == pe )
+ goto _test_eof775;
+case 775:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2471;
+ case 32: goto tr2471;
+ case 40: goto tr2472;
+ case 41: goto tr2473;
+ case 1034: goto tr2475;
+ case 1083: goto tr2476;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2474;
+ goto tr1885;
+tr2478:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st776;
+tr2479:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st776;
+tr2481:
+ {
+ s->line_counter++;
+ }
+ goto st776;
+tr2493:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st776;
+tr2471:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st776;
+tr2472:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st776;
+tr2473:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st776;
+tr2475:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st776;
+st776:
+ if ( ++p == pe )
+ goto _test_eof776;
+case 776:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st776;
+ case 32: goto st776;
+ case 40: goto tr2478;
+ case 41: goto tr2479;
+ case 1034: goto tr2481;
+ case 1083: goto tr2482;
+ }
+ if ( _widec < 65 ) {
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2480;
+ } else if ( _widec > 90 ) {
+ if ( 97 <= _widec && _widec <= 122 )
+ goto tr2480;
+ } else
+ goto tr2480;
+ goto tr71;
+tr2480:
+ { p--; {stack[top++] = 777;goto st487;} }
+ goto st777;
+st777:
+ if ( ++p == pe )
+ goto _test_eof777;
+case 777:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st778;
+ case 32: goto st778;
+ case 40: goto tr2484;
+ case 41: goto tr2485;
+ case 1034: goto tr2486;
+ case 1083: goto tr2487;
+ }
+ goto tr71;
+tr2484:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st778;
+tr2485:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st778;
+tr2486:
+ {
+ s->line_counter++;
+ }
+ goto st778;
+tr2491:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st778;
+st778:
+ if ( ++p == pe )
+ goto _test_eof778;
+case 778:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st778;
+ case 32: goto st778;
+ case 40: goto tr2484;
+ case 41: goto tr2485;
+ case 43: goto tr2488;
+ case 1034: goto tr2486;
+ case 1083: goto tr2487;
+ }
+ if ( _widec < 65 ) {
+ if ( 47 <= _widec && _widec <= 57 )
+ goto tr2488;
+ } else if ( _widec > 90 ) {
+ if ( 97 <= _widec && _widec <= 122 )
+ goto tr2488;
+ } else
+ goto tr2488;
+ goto tr71;
+tr2488:
+ { p--; {stack[top++] = 779;goto st329;} }
+ goto st779;
+st779:
+ if ( ++p == pe )
+ goto _test_eof779;
+case 779:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1152 + ((*p) - -128));
+ if (
+ !s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1152 + ((*p) - -128));
+ if (
+ !s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 1546: goto tr2489;
+ case 1595: goto tr2489;
+ }
+ goto tr71;
+tr2489:
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1182;
+st1182:
+ if ( ++p == pe )
+ goto _test_eof1182;
+case 1182:
+ goto st0;
+tr2487:
+ {
+ s->buffer_length = 0;
+ }
+ goto st780;
+tr2490:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st780;
+st780:
+ if ( ++p == pe )
+ goto _test_eof780;
+case 780:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2491;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2490;
+ goto tr71;
+tr2482:
+ {
+ s->buffer_length = 0;
+ }
+ goto st781;
+tr2492:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st781;
+tr2476:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st781;
+st781:
+ if ( ++p == pe )
+ goto _test_eof781;
+case 781:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2493;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2492;
+ goto tr71;
+tr2469:
+ {
+ s->buffer_length = 0;
+ }
+ goto st782;
+tr2494:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st782;
+st782:
+ if ( ++p == pe )
+ goto _test_eof782;
+case 782:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2495;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2494;
+ goto tr71;
+tr2499:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st783;
+tr2500:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st783;
+tr2503:
+ {
+ s->line_counter++;
+ }
+ goto st783;
+tr2526:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st783;
+tr2516:
+ {
+ if ((s->apl.addr_family == 1 && s->number64 <= 32) ||
+ (s->apl.addr_family == 2 && s->number64 <= 128)) {
+ s->apl.prefix_length = (uint8_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_APL);
+ p--; {goto st268;}
+ }
+ }
+ {
+ // Copy address to buffer.
+ uint8_t len;
+ switch (s->apl.addr_family) {
+ case 1:
+ len = ZS_INET4_ADDR_LENGTH;
+ memcpy(s->buffer, s->addr, len);
+ break;
+ case 2:
+ len = ZS_INET6_ADDR_LENGTH;
+ memcpy(s->buffer, s->addr, len);
+ break;
+ default:
+ WARN(ZS_BAD_APL);
+ p--; {goto st268;}
+ }
+ // Find prefix without trailing zeroes.
+ while (len > 0) {
+ if ((s->buffer[len - 1] & 255) != 0) {
+ break;
+ }
+ len--;
+ }
+ // Check for rdata overflow.
+ if (rdata_tail + 4 + len > rdata_stop) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ // Write address family.
+ *((uint16_t *)rdata_tail) = htons(s->apl.addr_family);
+ rdata_tail += 2;
+ // Write prefix length in bits.
+ *(rdata_tail) = s->apl.prefix_length;
+ rdata_tail += 1;
+ // Write negation flag + prefix length in bytes.
+ *(rdata_tail) = len + s->apl.excl_flag;
+ rdata_tail += 1;
+ // Write address prefix non-null data.
+ memcpy(rdata_tail, s->buffer, len);
+ rdata_tail += len;
+ }
+ goto st783;
+tr2517:
+ {
+ if ((s->apl.addr_family == 1 && s->number64 <= 32) ||
+ (s->apl.addr_family == 2 && s->number64 <= 128)) {
+ s->apl.prefix_length = (uint8_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_APL);
+ p--; {goto st268;}
+ }
+ }
+ {
+ // Copy address to buffer.
+ uint8_t len;
+ switch (s->apl.addr_family) {
+ case 1:
+ len = ZS_INET4_ADDR_LENGTH;
+ memcpy(s->buffer, s->addr, len);
+ break;
+ case 2:
+ len = ZS_INET6_ADDR_LENGTH;
+ memcpy(s->buffer, s->addr, len);
+ break;
+ default:
+ WARN(ZS_BAD_APL);
+ p--; {goto st268;}
+ }
+ // Find prefix without trailing zeroes.
+ while (len > 0) {
+ if ((s->buffer[len - 1] & 255) != 0) {
+ break;
+ }
+ len--;
+ }
+ // Check for rdata overflow.
+ if (rdata_tail + 4 + len > rdata_stop) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ // Write address family.
+ *((uint16_t *)rdata_tail) = htons(s->apl.addr_family);
+ rdata_tail += 2;
+ // Write prefix length in bits.
+ *(rdata_tail) = s->apl.prefix_length;
+ rdata_tail += 1;
+ // Write negation flag + prefix length in bytes.
+ *(rdata_tail) = len + s->apl.excl_flag;
+ rdata_tail += 1;
+ // Write address prefix non-null data.
+ memcpy(rdata_tail, s->buffer, len);
+ rdata_tail += len;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st783;
+tr2518:
+ {
+ if ((s->apl.addr_family == 1 && s->number64 <= 32) ||
+ (s->apl.addr_family == 2 && s->number64 <= 128)) {
+ s->apl.prefix_length = (uint8_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_APL);
+ p--; {goto st268;}
+ }
+ }
+ {
+ // Copy address to buffer.
+ uint8_t len;
+ switch (s->apl.addr_family) {
+ case 1:
+ len = ZS_INET4_ADDR_LENGTH;
+ memcpy(s->buffer, s->addr, len);
+ break;
+ case 2:
+ len = ZS_INET6_ADDR_LENGTH;
+ memcpy(s->buffer, s->addr, len);
+ break;
+ default:
+ WARN(ZS_BAD_APL);
+ p--; {goto st268;}
+ }
+ // Find prefix without trailing zeroes.
+ while (len > 0) {
+ if ((s->buffer[len - 1] & 255) != 0) {
+ break;
+ }
+ len--;
+ }
+ // Check for rdata overflow.
+ if (rdata_tail + 4 + len > rdata_stop) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ // Write address family.
+ *((uint16_t *)rdata_tail) = htons(s->apl.addr_family);
+ rdata_tail += 2;
+ // Write prefix length in bits.
+ *(rdata_tail) = s->apl.prefix_length;
+ rdata_tail += 1;
+ // Write negation flag + prefix length in bytes.
+ *(rdata_tail) = len + s->apl.excl_flag;
+ rdata_tail += 1;
+ // Write address prefix non-null data.
+ memcpy(rdata_tail, s->buffer, len);
+ rdata_tail += len;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st783;
+tr2520:
+ {
+ if ((s->apl.addr_family == 1 && s->number64 <= 32) ||
+ (s->apl.addr_family == 2 && s->number64 <= 128)) {
+ s->apl.prefix_length = (uint8_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_APL);
+ p--; {goto st268;}
+ }
+ }
+ {
+ // Copy address to buffer.
+ uint8_t len;
+ switch (s->apl.addr_family) {
+ case 1:
+ len = ZS_INET4_ADDR_LENGTH;
+ memcpy(s->buffer, s->addr, len);
+ break;
+ case 2:
+ len = ZS_INET6_ADDR_LENGTH;
+ memcpy(s->buffer, s->addr, len);
+ break;
+ default:
+ WARN(ZS_BAD_APL);
+ p--; {goto st268;}
+ }
+ // Find prefix without trailing zeroes.
+ while (len > 0) {
+ if ((s->buffer[len - 1] & 255) != 0) {
+ break;
+ }
+ len--;
+ }
+ // Check for rdata overflow.
+ if (rdata_tail + 4 + len > rdata_stop) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ // Write address family.
+ *((uint16_t *)rdata_tail) = htons(s->apl.addr_family);
+ rdata_tail += 2;
+ // Write prefix length in bits.
+ *(rdata_tail) = s->apl.prefix_length;
+ rdata_tail += 1;
+ // Write negation flag + prefix length in bytes.
+ *(rdata_tail) = len + s->apl.excl_flag;
+ rdata_tail += 1;
+ // Write address prefix non-null data.
+ memcpy(rdata_tail, s->buffer, len);
+ rdata_tail += len;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st783;
+st783:
+ if ( ++p == pe )
+ goto _test_eof783;
+case 783:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st783;
+ case 32: goto st783;
+ case 33: goto tr2498;
+ case 40: goto tr2499;
+ case 41: goto tr2500;
+ case 49: goto tr2501;
+ case 50: goto tr2502;
+ case 2058: goto tr2503;
+ case 2107: goto tr2504;
+ case 2314: goto tr2505;
+ case 2363: goto tr2505;
+ case 2570: goto tr2506;
+ case 2619: goto tr2507;
+ }
+ goto tr2496;
+tr2498:
+ {
+ memset(&(s->apl), 0, sizeof(s->apl));
+ }
+ {
+ s->apl.excl_flag = 128; // dec 128 = bin 10000000.
+ }
+ goto st784;
+st784:
+ if ( ++p == pe )
+ goto _test_eof784;
+case 784:
+ switch( (*p) ) {
+ case 49: goto tr2508;
+ case 50: goto tr2509;
+ }
+ goto tr2496;
+tr2501:
+ {
+ memset(&(s->apl), 0, sizeof(s->apl));
+ }
+ {
+ s->apl.addr_family = 1;
+ }
+ goto st785;
+tr2508:
+ {
+ s->apl.addr_family = 1;
+ }
+ goto st785;
+st785:
+ if ( ++p == pe )
+ goto _test_eof785;
+case 785:
+ if ( (*p) == 58 )
+ goto st786;
+ goto tr2496;
+st786:
+ if ( ++p == pe )
+ goto _test_eof786;
+case 786:
+ if ( (*p) == 46 )
+ goto tr2512;
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr2512;
+ goto tr2511;
+tr2512:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st787;
+tr2513:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st787;
+st787:
+ if ( ++p == pe )
+ goto _test_eof787;
+case 787:
+ if ( (*p) == 47 )
+ goto tr2514;
+ if ( 46 <= (*p) && (*p) <= 57 )
+ goto tr2513;
+ goto tr2511;
+tr2514:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV4);
+ p--; {goto st268;}
+ }
+ }
+ goto st788;
+tr2530:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET6, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV6);
+ p--; {goto st268;}
+ }
+ }
+ goto st788;
+st788:
+ if ( ++p == pe )
+ goto _test_eof788;
+case 788:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr2515;
+ goto tr2496;
+tr2515:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st789;
+tr2519:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st789;
+st789:
+ if ( ++p == pe )
+ goto _test_eof789;
+case 789:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto tr2516;
+ case 32: goto tr2516;
+ case 40: goto tr2517;
+ case 41: goto tr2518;
+ case 2058: goto tr2520;
+ case 2107: goto tr2521;
+ case 2314: goto tr2522;
+ case 2363: goto tr2522;
+ case 2570: goto tr2523;
+ case 2619: goto tr2524;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2519;
+ goto tr2496;
+tr2504:
+ {
+ s->buffer_length = 0;
+ }
+ goto st790;
+tr2525:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st790;
+tr2521:
+ {
+ if ((s->apl.addr_family == 1 && s->number64 <= 32) ||
+ (s->apl.addr_family == 2 && s->number64 <= 128)) {
+ s->apl.prefix_length = (uint8_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_APL);
+ p--; {goto st268;}
+ }
+ }
+ {
+ // Copy address to buffer.
+ uint8_t len;
+ switch (s->apl.addr_family) {
+ case 1:
+ len = ZS_INET4_ADDR_LENGTH;
+ memcpy(s->buffer, s->addr, len);
+ break;
+ case 2:
+ len = ZS_INET6_ADDR_LENGTH;
+ memcpy(s->buffer, s->addr, len);
+ break;
+ default:
+ WARN(ZS_BAD_APL);
+ p--; {goto st268;}
+ }
+ // Find prefix without trailing zeroes.
+ while (len > 0) {
+ if ((s->buffer[len - 1] & 255) != 0) {
+ break;
+ }
+ len--;
+ }
+ // Check for rdata overflow.
+ if (rdata_tail + 4 + len > rdata_stop) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ // Write address family.
+ *((uint16_t *)rdata_tail) = htons(s->apl.addr_family);
+ rdata_tail += 2;
+ // Write prefix length in bits.
+ *(rdata_tail) = s->apl.prefix_length;
+ rdata_tail += 1;
+ // Write negation flag + prefix length in bytes.
+ *(rdata_tail) = len + s->apl.excl_flag;
+ rdata_tail += 1;
+ // Write address prefix non-null data.
+ memcpy(rdata_tail, s->buffer, len);
+ rdata_tail += len;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st790;
+st790:
+ if ( ++p == pe )
+ goto _test_eof790;
+case 790:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2526;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2525;
+ goto tr71;
+tr2505:
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1183;
+tr2522:
+ {
+ if ((s->apl.addr_family == 1 && s->number64 <= 32) ||
+ (s->apl.addr_family == 2 && s->number64 <= 128)) {
+ s->apl.prefix_length = (uint8_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_APL);
+ p--; {goto st268;}
+ }
+ }
+ {
+ // Copy address to buffer.
+ uint8_t len;
+ switch (s->apl.addr_family) {
+ case 1:
+ len = ZS_INET4_ADDR_LENGTH;
+ memcpy(s->buffer, s->addr, len);
+ break;
+ case 2:
+ len = ZS_INET6_ADDR_LENGTH;
+ memcpy(s->buffer, s->addr, len);
+ break;
+ default:
+ WARN(ZS_BAD_APL);
+ p--; {goto st268;}
+ }
+ // Find prefix without trailing zeroes.
+ while (len > 0) {
+ if ((s->buffer[len - 1] & 255) != 0) {
+ break;
+ }
+ len--;
+ }
+ // Check for rdata overflow.
+ if (rdata_tail + 4 + len > rdata_stop) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ // Write address family.
+ *((uint16_t *)rdata_tail) = htons(s->apl.addr_family);
+ rdata_tail += 2;
+ // Write prefix length in bits.
+ *(rdata_tail) = s->apl.prefix_length;
+ rdata_tail += 1;
+ // Write negation flag + prefix length in bytes.
+ *(rdata_tail) = len + s->apl.excl_flag;
+ rdata_tail += 1;
+ // Write address prefix non-null data.
+ memcpy(rdata_tail, s->buffer, len);
+ rdata_tail += len;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1183;
+st1183:
+ if ( ++p == pe )
+ goto _test_eof1183;
+case 1183:
+ goto st0;
+tr2506:
+ {
+ s->line_counter++;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1184;
+tr2523:
+ {
+ if ((s->apl.addr_family == 1 && s->number64 <= 32) ||
+ (s->apl.addr_family == 2 && s->number64 <= 128)) {
+ s->apl.prefix_length = (uint8_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_APL);
+ p--; {goto st268;}
+ }
+ }
+ {
+ // Copy address to buffer.
+ uint8_t len;
+ switch (s->apl.addr_family) {
+ case 1:
+ len = ZS_INET4_ADDR_LENGTH;
+ memcpy(s->buffer, s->addr, len);
+ break;
+ case 2:
+ len = ZS_INET6_ADDR_LENGTH;
+ memcpy(s->buffer, s->addr, len);
+ break;
+ default:
+ WARN(ZS_BAD_APL);
+ p--; {goto st268;}
+ }
+ // Find prefix without trailing zeroes.
+ while (len > 0) {
+ if ((s->buffer[len - 1] & 255) != 0) {
+ break;
+ }
+ len--;
+ }
+ // Check for rdata overflow.
+ if (rdata_tail + 4 + len > rdata_stop) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ // Write address family.
+ *((uint16_t *)rdata_tail) = htons(s->apl.addr_family);
+ rdata_tail += 2;
+ // Write prefix length in bits.
+ *(rdata_tail) = s->apl.prefix_length;
+ rdata_tail += 1;
+ // Write negation flag + prefix length in bytes.
+ *(rdata_tail) = len + s->apl.excl_flag;
+ rdata_tail += 1;
+ // Write address prefix non-null data.
+ memcpy(rdata_tail, s->buffer, len);
+ rdata_tail += len;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1184;
+st1184:
+ if ( ++p == pe )
+ goto _test_eof1184;
+case 1184:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st783;
+ case 32: goto st783;
+ case 33: goto tr2498;
+ case 40: goto tr2499;
+ case 41: goto tr2500;
+ case 49: goto tr2501;
+ case 50: goto tr2502;
+ case 2058: goto tr2503;
+ case 2107: goto tr2504;
+ case 2314: goto tr2505;
+ case 2363: goto tr2505;
+ case 2570: goto tr2506;
+ case 2619: goto tr2507;
+ }
+ goto tr2496;
+tr2502:
+ {
+ memset(&(s->apl), 0, sizeof(s->apl));
+ }
+ {
+ s->apl.addr_family = 2;
+ }
+ goto st791;
+tr2509:
+ {
+ s->apl.addr_family = 2;
+ }
+ goto st791;
+st791:
+ if ( ++p == pe )
+ goto _test_eof791;
+case 791:
+ if ( (*p) == 58 )
+ goto st792;
+ goto tr2496;
+st792:
+ if ( ++p == pe )
+ goto _test_eof792;
+case 792:
+ if ( (*p) == 46 )
+ goto tr2528;
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 58 )
+ goto tr2528;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto tr2528;
+ } else
+ goto tr2528;
+ goto tr2511;
+tr2528:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st793;
+tr2529:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st793;
+st793:
+ if ( ++p == pe )
+ goto _test_eof793;
+case 793:
+ if ( (*p) == 47 )
+ goto tr2530;
+ if ( (*p) < 65 ) {
+ if ( 46 <= (*p) && (*p) <= 58 )
+ goto tr2529;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto tr2529;
+ } else
+ goto tr2529;
+ goto tr2511;
+tr2507:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1185;
+tr2524:
+ {
+ if ((s->apl.addr_family == 1 && s->number64 <= 32) ||
+ (s->apl.addr_family == 2 && s->number64 <= 128)) {
+ s->apl.prefix_length = (uint8_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_APL);
+ p--; {goto st268;}
+ }
+ }
+ {
+ // Copy address to buffer.
+ uint8_t len;
+ switch (s->apl.addr_family) {
+ case 1:
+ len = ZS_INET4_ADDR_LENGTH;
+ memcpy(s->buffer, s->addr, len);
+ break;
+ case 2:
+ len = ZS_INET6_ADDR_LENGTH;
+ memcpy(s->buffer, s->addr, len);
+ break;
+ default:
+ WARN(ZS_BAD_APL);
+ p--; {goto st268;}
+ }
+ // Find prefix without trailing zeroes.
+ while (len > 0) {
+ if ((s->buffer[len - 1] & 255) != 0) {
+ break;
+ }
+ len--;
+ }
+ // Check for rdata overflow.
+ if (rdata_tail + 4 + len > rdata_stop) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ // Write address family.
+ *((uint16_t *)rdata_tail) = htons(s->apl.addr_family);
+ rdata_tail += 2;
+ // Write prefix length in bits.
+ *(rdata_tail) = s->apl.prefix_length;
+ rdata_tail += 1;
+ // Write negation flag + prefix length in bytes.
+ *(rdata_tail) = len + s->apl.excl_flag;
+ rdata_tail += 1;
+ // Write address prefix non-null data.
+ memcpy(rdata_tail, s->buffer, len);
+ rdata_tail += len;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1185;
+st1185:
+ if ( ++p == pe )
+ goto _test_eof1185;
+case 1185:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2526;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2525;
+ goto tr71;
+st794:
+ if ( ++p == pe )
+ goto _test_eof794;
+case 794:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr2531;
+ goto tr1885;
+tr2531:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st795;
+tr2535:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st795;
+st795:
+ if ( ++p == pe )
+ goto _test_eof795;
+case 795:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2532;
+ case 32: goto tr2532;
+ case 40: goto tr2533;
+ case 41: goto tr2534;
+ case 1034: goto tr2536;
+ case 1083: goto tr2537;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2535;
+ goto tr1885;
+tr2539:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st796;
+tr2540:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st796;
+tr2542:
+ {
+ s->line_counter++;
+ }
+ goto st796;
+tr2579:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st796;
+tr2532:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st796;
+tr2533:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st796;
+tr2534:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st796;
+tr2536:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st796;
+st796:
+ if ( ++p == pe )
+ goto _test_eof796;
+case 796:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st796;
+ case 32: goto st796;
+ case 40: goto tr2539;
+ case 41: goto tr2540;
+ case 1034: goto tr2542;
+ case 1083: goto tr2543;
+ }
+ if ( _widec < 65 ) {
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2541;
+ } else if ( _widec > 90 ) {
+ if ( 97 <= _widec && _widec <= 122 )
+ goto tr2541;
+ } else
+ goto tr2541;
+ goto tr71;
+tr2541:
+ { p--; {stack[top++] = 797;goto st487;} }
+ goto st797;
+st797:
+ if ( ++p == pe )
+ goto _test_eof797;
+case 797:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st798;
+ case 32: goto st798;
+ case 40: goto tr2545;
+ case 41: goto tr2546;
+ case 1034: goto tr2547;
+ case 1083: goto tr2548;
+ }
+ goto tr71;
+tr2545:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st798;
+tr2546:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st798;
+tr2547:
+ {
+ s->line_counter++;
+ }
+ goto st798;
+tr2577:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st798;
+st798:
+ if ( ++p == pe )
+ goto _test_eof798;
+case 798:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st798;
+ case 32: goto st798;
+ case 40: goto tr2545;
+ case 41: goto tr2546;
+ case 1034: goto tr2547;
+ case 1083: goto tr2548;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2549;
+ goto tr1885;
+tr2549:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st799;
+tr2553:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st799;
+st799:
+ if ( ++p == pe )
+ goto _test_eof799;
+case 799:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2550;
+ case 32: goto tr2550;
+ case 40: goto tr2551;
+ case 41: goto tr2552;
+ case 1034: goto tr2554;
+ case 1083: goto tr2555;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2553;
+ goto tr1885;
+tr2558:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st800;
+tr2559:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st800;
+tr2561:
+ {
+ s->line_counter++;
+ }
+ goto st800;
+tr2575:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st800;
+tr2550:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st800;
+tr2551:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st800;
+tr2552:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st800;
+tr2554:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st800;
+st800:
+ if ( ++p == pe )
+ goto _test_eof800;
+case 800:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st800;
+ case 32: goto st800;
+ case 40: goto tr2558;
+ case 41: goto tr2559;
+ case 1034: goto tr2561;
+ case 1083: goto tr2562;
+ }
+ if ( _widec < 65 ) {
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2560;
+ } else if ( _widec > 70 ) {
+ if ( 97 <= _widec && _widec <= 102 )
+ goto tr2560;
+ } else
+ goto tr2560;
+ goto tr2556;
+tr2560:
+ {
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = first_hex_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st801;
+st801:
+ if ( ++p == pe )
+ goto _test_eof801;
+case 801:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr2563;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto tr2563;
+ } else
+ goto tr2563;
+ goto tr2556;
+tr2565:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st802;
+tr2566:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st802;
+tr2567:
+ {
+ s->line_counter++;
+ }
+ goto st802;
+tr2573:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st802;
+tr2563:
+ {
+ *rdata_tail += second_hex_to_num[(uint8_t)(*p)];
+ rdata_tail++;
+ }
+ goto st802;
+st802:
+ if ( ++p == pe )
+ goto _test_eof802;
+case 802:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st802;
+ case 32: goto st802;
+ case 40: goto tr2565;
+ case 41: goto tr2566;
+ case 2058: goto tr2567;
+ case 2107: goto tr2568;
+ case 2314: goto tr2569;
+ case 2363: goto tr2569;
+ case 2570: goto tr2570;
+ case 2619: goto tr2571;
+ }
+ if ( _widec < 65 ) {
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2560;
+ } else if ( _widec > 70 ) {
+ if ( 97 <= _widec && _widec <= 102 )
+ goto tr2560;
+ } else
+ goto tr2560;
+ goto tr2556;
+tr2568:
+ {
+ s->buffer_length = 0;
+ }
+ goto st803;
+tr2572:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st803;
+st803:
+ if ( ++p == pe )
+ goto _test_eof803;
+case 803:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2573;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2572;
+ goto tr2556;
+tr2569:
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1186;
+st1186:
+ if ( ++p == pe )
+ goto _test_eof1186;
+case 1186:
+ goto st0;
+tr2570:
+ {
+ s->line_counter++;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1187;
+st1187:
+ if ( ++p == pe )
+ goto _test_eof1187;
+case 1187:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st802;
+ case 32: goto st802;
+ case 40: goto tr2565;
+ case 41: goto tr2566;
+ case 2058: goto tr2567;
+ case 2107: goto tr2568;
+ case 2314: goto tr2569;
+ case 2363: goto tr2569;
+ case 2570: goto tr2570;
+ case 2619: goto tr2571;
+ }
+ if ( _widec < 65 ) {
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2560;
+ } else if ( _widec > 70 ) {
+ if ( 97 <= _widec && _widec <= 102 )
+ goto tr2560;
+ } else
+ goto tr2560;
+ goto tr2556;
+tr2571:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1188;
+st1188:
+ if ( ++p == pe )
+ goto _test_eof1188;
+case 1188:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2573;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2572;
+ goto tr2556;
+tr2562:
+ {
+ s->buffer_length = 0;
+ }
+ goto st804;
+tr2574:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st804;
+tr2555:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st804;
+st804:
+ if ( ++p == pe )
+ goto _test_eof804;
+case 804:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2575;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2574;
+ goto tr71;
+tr2548:
+ {
+ s->buffer_length = 0;
+ }
+ goto st805;
+tr2576:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st805;
+st805:
+ if ( ++p == pe )
+ goto _test_eof805;
+case 805:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2577;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2576;
+ goto tr71;
+tr2543:
+ {
+ s->buffer_length = 0;
+ }
+ goto st806;
+tr2578:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st806;
+tr2537:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st806;
+st806:
+ if ( ++p == pe )
+ goto _test_eof806;
+case 806:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2579;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2578;
+ goto tr71;
+st807:
+ if ( ++p == pe )
+ goto _test_eof807;
+case 807:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr2580;
+ goto tr1885;
+tr2580:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st808;
+tr2584:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st808;
+st808:
+ if ( ++p == pe )
+ goto _test_eof808;
+case 808:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2581;
+ case 32: goto tr2581;
+ case 40: goto tr2582;
+ case 41: goto tr2583;
+ case 1034: goto tr2585;
+ case 1083: goto tr2586;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2584;
+ goto tr1885;
+tr2588:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st809;
+tr2589:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st809;
+tr2591:
+ {
+ s->line_counter++;
+ }
+ goto st809;
+tr2619:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st809;
+tr2581:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st809;
+tr2582:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st809;
+tr2583:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st809;
+tr2585:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st809;
+st809:
+ if ( ++p == pe )
+ goto _test_eof809;
+case 809:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st809;
+ case 32: goto st809;
+ case 40: goto tr2588;
+ case 41: goto tr2589;
+ case 1034: goto tr2591;
+ case 1083: goto tr2592;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2590;
+ goto tr1885;
+tr2590:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st810;
+tr2596:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st810;
+st810:
+ if ( ++p == pe )
+ goto _test_eof810;
+case 810:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2593;
+ case 32: goto tr2593;
+ case 40: goto tr2594;
+ case 41: goto tr2595;
+ case 1034: goto tr2597;
+ case 1083: goto tr2598;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2596;
+ goto tr1885;
+tr2600:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st811;
+tr2601:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st811;
+tr2603:
+ {
+ s->line_counter++;
+ }
+ goto st811;
+tr2617:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st811;
+tr2593:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st811;
+tr2594:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st811;
+tr2595:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st811;
+tr2597:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st811;
+st811:
+ if ( ++p == pe )
+ goto _test_eof811;
+case 811:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st811;
+ case 32: goto st811;
+ case 40: goto tr2600;
+ case 41: goto tr2601;
+ case 1034: goto tr2603;
+ case 1083: goto tr2604;
+ }
+ if ( _widec < 65 ) {
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2602;
+ } else if ( _widec > 70 ) {
+ if ( 97 <= _widec && _widec <= 102 )
+ goto tr2602;
+ } else
+ goto tr2602;
+ goto tr2556;
+tr2602:
+ {
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = first_hex_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st812;
+st812:
+ if ( ++p == pe )
+ goto _test_eof812;
+case 812:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr2605;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto tr2605;
+ } else
+ goto tr2605;
+ goto tr2556;
+tr2607:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st813;
+tr2608:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st813;
+tr2609:
+ {
+ s->line_counter++;
+ }
+ goto st813;
+tr2615:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st813;
+tr2605:
+ {
+ *rdata_tail += second_hex_to_num[(uint8_t)(*p)];
+ rdata_tail++;
+ }
+ goto st813;
+st813:
+ if ( ++p == pe )
+ goto _test_eof813;
+case 813:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st813;
+ case 32: goto st813;
+ case 40: goto tr2607;
+ case 41: goto tr2608;
+ case 2058: goto tr2609;
+ case 2107: goto tr2610;
+ case 2314: goto tr2611;
+ case 2363: goto tr2611;
+ case 2570: goto tr2612;
+ case 2619: goto tr2613;
+ }
+ if ( _widec < 65 ) {
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2602;
+ } else if ( _widec > 70 ) {
+ if ( 97 <= _widec && _widec <= 102 )
+ goto tr2602;
+ } else
+ goto tr2602;
+ goto tr2556;
+tr2610:
+ {
+ s->buffer_length = 0;
+ }
+ goto st814;
+tr2614:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st814;
+st814:
+ if ( ++p == pe )
+ goto _test_eof814;
+case 814:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2615;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2614;
+ goto tr2556;
+tr2611:
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1189;
+st1189:
+ if ( ++p == pe )
+ goto _test_eof1189;
+case 1189:
+ goto st0;
+tr2612:
+ {
+ s->line_counter++;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1190;
+st1190:
+ if ( ++p == pe )
+ goto _test_eof1190;
+case 1190:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st813;
+ case 32: goto st813;
+ case 40: goto tr2607;
+ case 41: goto tr2608;
+ case 2058: goto tr2609;
+ case 2107: goto tr2610;
+ case 2314: goto tr2611;
+ case 2363: goto tr2611;
+ case 2570: goto tr2612;
+ case 2619: goto tr2613;
+ }
+ if ( _widec < 65 ) {
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2602;
+ } else if ( _widec > 70 ) {
+ if ( 97 <= _widec && _widec <= 102 )
+ goto tr2602;
+ } else
+ goto tr2602;
+ goto tr2556;
+tr2613:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1191;
+st1191:
+ if ( ++p == pe )
+ goto _test_eof1191;
+case 1191:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2615;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2614;
+ goto tr2556;
+tr2604:
+ {
+ s->buffer_length = 0;
+ }
+ goto st815;
+tr2616:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st815;
+tr2598:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st815;
+st815:
+ if ( ++p == pe )
+ goto _test_eof815;
+case 815:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2617;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2616;
+ goto tr71;
+tr2592:
+ {
+ s->buffer_length = 0;
+ }
+ goto st816;
+tr2618:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st816;
+tr2586:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st816;
+st816:
+ if ( ++p == pe )
+ goto _test_eof816;
+case 816:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2619;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2618;
+ goto tr71;
+st817:
+ if ( ++p == pe )
+ goto _test_eof817;
+case 817:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr2620;
+ goto tr1885;
+tr2620:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st818;
+tr2624:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st818;
+st818:
+ if ( ++p == pe )
+ goto _test_eof818;
+case 818:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2621;
+ case 32: goto tr2621;
+ case 40: goto tr2622;
+ case 41: goto tr2623;
+ case 1034: goto tr2625;
+ case 1083: goto tr2626;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2624;
+ goto tr1885;
+tr2629:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st819;
+tr2630:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st819;
+tr2635:
+ {
+ s->line_counter++;
+ }
+ goto st819;
+tr2828:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st819;
+tr2621:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st819;
+tr2622:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st819;
+tr2623:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st819;
+tr2625:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st819;
+st819:
+ if ( ++p == pe )
+ goto _test_eof819;
+case 819:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st819;
+ case 32: goto st819;
+ case 40: goto tr2629;
+ case 41: goto tr2630;
+ case 48: goto tr2631;
+ case 49: goto tr2632;
+ case 50: goto tr2633;
+ case 51: goto tr2634;
+ case 1034: goto tr2635;
+ case 1083: goto tr2636;
+ }
+ goto tr2627;
+tr2631:
+ {
+ *(rdata_tail++) = 0;
+ }
+ goto st820;
+st820:
+ if ( ++p == pe )
+ goto _test_eof820;
+case 820:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st821;
+ case 32: goto st821;
+ case 40: goto tr2638;
+ case 41: goto tr2639;
+ case 1034: goto tr2640;
+ case 1083: goto tr2641;
+ }
+ goto tr2627;
+tr2638:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st821;
+tr2639:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st821;
+tr2640:
+ {
+ s->line_counter++;
+ }
+ goto st821;
+tr2690:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st821;
+st821:
+ if ( ++p == pe )
+ goto _test_eof821;
+case 821:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st821;
+ case 32: goto st821;
+ case 40: goto tr2638;
+ case 41: goto tr2639;
+ case 1034: goto tr2640;
+ case 1083: goto tr2641;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2643;
+ goto tr2642;
+tr2643:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st822;
+tr2647:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st822;
+st822:
+ if ( ++p == pe )
+ goto _test_eof822;
+case 822:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2644;
+ case 32: goto tr2644;
+ case 40: goto tr2645;
+ case 41: goto tr2646;
+ case 1034: goto tr2648;
+ case 1083: goto tr2649;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2647;
+ goto tr2642;
+tr2651:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st823;
+tr2652:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st823;
+tr2654:
+ {
+ s->line_counter++;
+ }
+ goto st823;
+tr2688:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st823;
+tr2644:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st823;
+tr2645:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st823;
+tr2646:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st823;
+tr2648:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st823;
+st823:
+ if ( ++p == pe )
+ goto _test_eof823;
+case 823:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st823;
+ case 32: goto st823;
+ case 40: goto tr2651;
+ case 41: goto tr2652;
+ case 46: goto st824;
+ case 1034: goto tr2654;
+ case 1083: goto tr2655;
+ }
+ goto tr2627;
+st824:
+ if ( ++p == pe )
+ goto _test_eof824;
+case 824:
+ _widec = (*p);
+ if ( (*p) < 32 ) {
+ if ( (*p) > 9 ) {
+ if ( 10 <= (*p) && (*p) <= 10 ) {
+ _widec = (short)(8832 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ if (
+ s->number64 != 0 ) _widec += 1024;
+ if (
+ s->number64 == 0 ) _widec += 2048;
+ }
+ } else if ( (*p) >= 9 ) {
+ _widec = (short)(5760 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ } else if ( (*p) > 32 ) {
+ if ( (*p) < 41 ) {
+ if ( 40 <= (*p) && (*p) <= 40 ) {
+ _widec = (short)(5760 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ } else if ( (*p) > 41 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(8832 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ if (
+ s->number64 != 0 ) _widec += 1024;
+ if (
+ s->number64 == 0 ) _widec += 2048;
+ }
+ } else {
+ _widec = (short)(5760 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ } else {
+ _widec = (short)(5760 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 6153: goto st825;
+ case 6176: goto st825;
+ case 6184: goto tr2658;
+ case 6185: goto tr2659;
+ case 6409: goto st828;
+ case 6432: goto st828;
+ case 6440: goto tr2661;
+ case 6441: goto tr2662;
+ case 6665: goto st830;
+ case 6688: goto st830;
+ case 6696: goto tr2664;
+ case 6697: goto tr2665;
+ case 9482: goto tr2666;
+ case 9531: goto tr2666;
+ case 9738: goto tr2666;
+ case 9787: goto tr2666;
+ case 10250: goto tr2667;
+ case 10299: goto tr2668;
+ case 10506: goto tr2666;
+ case 10555: goto tr2666;
+ case 10762: goto tr2669;
+ case 10811: goto tr2670;
+ case 11274: goto tr2671;
+ case 11323: goto tr2672;
+ case 11530: goto tr2666;
+ case 11579: goto tr2666;
+ case 11786: goto tr2673;
+ case 11835: goto tr2674;
+ case 12298: goto tr2675;
+ case 12347: goto tr2676;
+ case 12554: goto tr2666;
+ case 12603: goto tr2666;
+ case 12810: goto tr2677;
+ case 12859: goto tr2678;
+ }
+ goto tr2656;
+tr2658:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st825;
+tr2659:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st825;
+tr2667:
+ {
+ s->line_counter++;
+ }
+ goto st825;
+tr2682:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st825;
+tr2801:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ goto st825;
+tr2802:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st825;
+tr2803:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st825;
+tr2811:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st825;
+tr2712:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV4);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET4_ADDR_LENGTH);
+ rdata_tail += ZS_INET4_ADDR_LENGTH;
+ }
+ goto st825;
+tr2713:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV4);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET4_ADDR_LENGTH);
+ rdata_tail += ZS_INET4_ADDR_LENGTH;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st825;
+tr2714:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV4);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET4_ADDR_LENGTH);
+ rdata_tail += ZS_INET4_ADDR_LENGTH;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st825;
+tr2722:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV4);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET4_ADDR_LENGTH);
+ rdata_tail += ZS_INET4_ADDR_LENGTH;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st825;
+tr2757:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET6, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV6);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET6_ADDR_LENGTH);
+ rdata_tail += ZS_INET6_ADDR_LENGTH;
+ }
+ goto st825;
+tr2758:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET6, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV6);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET6_ADDR_LENGTH);
+ rdata_tail += ZS_INET6_ADDR_LENGTH;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st825;
+tr2759:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET6, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV6);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET6_ADDR_LENGTH);
+ rdata_tail += ZS_INET6_ADDR_LENGTH;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st825;
+tr2767:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET6, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV6);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET6_ADDR_LENGTH);
+ rdata_tail += ZS_INET6_ADDR_LENGTH;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st825;
+st825:
+ if ( ++p == pe )
+ goto _test_eof825;
+case 825:
+ _widec = (*p);
+ if ( (*p) < 43 ) {
+ if ( (*p) < 32 ) {
+ if ( (*p) > 9 ) {
+ if ( 10 <= (*p) && (*p) <= 10 ) {
+ _widec = (short)(3200 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ s->number64 != 0 ) _widec += 512;
+ }
+ } else if ( (*p) >= 9 ) {
+ _widec = (short)(2688 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ }
+ } else if ( (*p) > 32 ) {
+ if ( (*p) > 40 ) {
+ if ( 41 <= (*p) && (*p) <= 41 ) {
+ _widec = (short)(2688 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ }
+ } else if ( (*p) >= 40 ) {
+ _widec = (short)(2688 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(2688 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ }
+ } else if ( (*p) > 43 ) {
+ if ( (*p) < 59 ) {
+ if ( (*p) > 47 ) {
+ if ( 48 <= (*p) && (*p) <= 57 ) {
+ _widec = (short)(2688 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ }
+ } else if ( (*p) >= 47 ) {
+ _widec = (short)(2688 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ }
+ } else if ( (*p) > 59 ) {
+ if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 ) {
+ _widec = (short)(2688 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ }
+ } else if ( (*p) >= 65 ) {
+ _widec = (short)(2688 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(3200 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ s->number64 != 0 ) _widec += 512;
+ }
+ } else {
+ _widec = (short)(2688 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 3081: goto st825;
+ case 3104: goto st825;
+ case 3112: goto tr2658;
+ case 3113: goto tr2659;
+ case 3115: goto tr2680;
+ case 4106: goto tr2667;
+ case 4155: goto tr2668;
+ }
+ if ( _widec < 3137 ) {
+ if ( 3119 <= _widec && _widec <= 3129 )
+ goto tr2680;
+ } else if ( _widec > 3162 ) {
+ if ( 3169 <= _widec && _widec <= 3194 )
+ goto tr2680;
+ } else
+ goto tr2680;
+ goto tr2679;
+tr2680:
+ { p--; {stack[top++] = 826;goto st329;} }
+ goto st826;
+st826:
+ if ( ++p == pe )
+ goto _test_eof826;
+case 826:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1152 + ((*p) - -128));
+ if (
+ !s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1152 + ((*p) - -128));
+ if (
+ !s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 1546: goto tr2666;
+ case 1595: goto tr2666;
+ }
+ goto tr2679;
+tr2666:
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1192;
+tr2721:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV4);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET4_ADDR_LENGTH);
+ rdata_tail += ZS_INET4_ADDR_LENGTH;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1192;
+tr2810:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1192;
+tr2766:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET6, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV6);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET6_ADDR_LENGTH);
+ rdata_tail += ZS_INET6_ADDR_LENGTH;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1192;
+st1192:
+ if ( ++p == pe )
+ goto _test_eof1192;
+case 1192:
+ goto st0;
+tr2668:
+ {
+ s->buffer_length = 0;
+ }
+ goto st827;
+tr2681:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st827;
+tr2812:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st827;
+tr2723:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV4);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET4_ADDR_LENGTH);
+ rdata_tail += ZS_INET4_ADDR_LENGTH;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st827;
+tr2768:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET6, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV6);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET6_ADDR_LENGTH);
+ rdata_tail += ZS_INET6_ADDR_LENGTH;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st827;
+st827:
+ if ( ++p == pe )
+ goto _test_eof827;
+case 827:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(3200 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ s->number64 != 0 ) _widec += 512;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(3200 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ s->number64 != 0 ) _widec += 512;
+ }
+ } else {
+ _widec = (short)(3200 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ s->number64 != 0 ) _widec += 512;
+ }
+ if ( _widec == 4106 )
+ goto tr2682;
+ if ( 3968 <= _widec && _widec <= 4223 )
+ goto tr2681;
+ goto tr2679;
+tr2661:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st828;
+tr2662:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st828;
+tr2671:
+ {
+ s->line_counter++;
+ }
+ goto st828;
+tr2684:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st828;
+tr2804:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ goto st828;
+tr2805:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st828;
+tr2806:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st828;
+tr2815:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st828;
+tr2715:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV4);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET4_ADDR_LENGTH);
+ rdata_tail += ZS_INET4_ADDR_LENGTH;
+ }
+ goto st828;
+tr2716:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV4);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET4_ADDR_LENGTH);
+ rdata_tail += ZS_INET4_ADDR_LENGTH;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st828;
+tr2717:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV4);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET4_ADDR_LENGTH);
+ rdata_tail += ZS_INET4_ADDR_LENGTH;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st828;
+tr2726:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV4);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET4_ADDR_LENGTH);
+ rdata_tail += ZS_INET4_ADDR_LENGTH;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st828;
+tr2760:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET6, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV6);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET6_ADDR_LENGTH);
+ rdata_tail += ZS_INET6_ADDR_LENGTH;
+ }
+ goto st828;
+tr2761:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET6, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV6);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET6_ADDR_LENGTH);
+ rdata_tail += ZS_INET6_ADDR_LENGTH;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st828;
+tr2762:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET6, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV6);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET6_ADDR_LENGTH);
+ rdata_tail += ZS_INET6_ADDR_LENGTH;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st828;
+tr2771:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET6, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV6);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET6_ADDR_LENGTH);
+ rdata_tail += ZS_INET6_ADDR_LENGTH;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st828;
+st828:
+ if ( ++p == pe )
+ goto _test_eof828;
+case 828:
+ _widec = (*p);
+ if ( (*p) < 32 ) {
+ if ( (*p) > 9 ) {
+ if ( 10 <= (*p) && (*p) <= 10 ) {
+ _widec = (short)(12928 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ if (
+ s->number64 == 0 ) _widec += 1024;
+ }
+ } else if ( (*p) >= 9 ) {
+ _widec = (short)(4224 + ((*p) - -128));
+ if (
+ s->number64 == 0 ) _widec += 256;
+ }
+ } else if ( (*p) > 32 ) {
+ if ( (*p) < 41 ) {
+ if ( 40 <= (*p) && (*p) <= 40 ) {
+ _widec = (short)(4224 + ((*p) - -128));
+ if (
+ s->number64 == 0 ) _widec += 256;
+ }
+ } else if ( (*p) > 41 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(12928 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ if (
+ s->number64 == 0 ) _widec += 1024;
+ }
+ } else {
+ _widec = (short)(4224 + ((*p) - -128));
+ if (
+ s->number64 == 0 ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(4224 + ((*p) - -128));
+ if (
+ s->number64 == 0 ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 4617: goto st828;
+ case 4640: goto st828;
+ case 4648: goto tr2661;
+ case 4649: goto tr2662;
+ case 13578: goto tr2666;
+ case 13627: goto tr2666;
+ case 13834: goto tr2666;
+ case 13883: goto tr2666;
+ case 14346: goto tr2671;
+ case 14395: goto tr2672;
+ case 14602: goto tr2666;
+ case 14651: goto tr2666;
+ case 14858: goto tr2673;
+ case 14907: goto tr2674;
+ }
+ goto tr2679;
+tr2672:
+ {
+ s->buffer_length = 0;
+ }
+ goto st829;
+tr2683:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st829;
+tr2816:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st829;
+tr2727:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV4);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET4_ADDR_LENGTH);
+ rdata_tail += ZS_INET4_ADDR_LENGTH;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st829;
+tr2772:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET6, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV6);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET6_ADDR_LENGTH);
+ rdata_tail += ZS_INET6_ADDR_LENGTH;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st829;
+st829:
+ if ( ++p == pe )
+ goto _test_eof829;
+case 829:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(4736 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(4736 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ } else {
+ _widec = (short)(4736 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ if ( _widec == 5642 )
+ goto tr2684;
+ if ( 5504 <= _widec && _widec <= 5759 )
+ goto tr2683;
+ goto tr2679;
+tr2673:
+ {
+ s->line_counter++;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1193;
+tr2728:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV4);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET4_ADDR_LENGTH);
+ rdata_tail += ZS_INET4_ADDR_LENGTH;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1193;
+tr2773:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET6, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV6);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET6_ADDR_LENGTH);
+ rdata_tail += ZS_INET6_ADDR_LENGTH;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1193;
+tr2817:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1193;
+st1193:
+ if ( ++p == pe )
+ goto _test_eof1193;
+case 1193:
+ _widec = (*p);
+ if ( (*p) < 32 ) {
+ if ( (*p) > 9 ) {
+ if ( 10 <= (*p) && (*p) <= 10 ) {
+ _widec = (short)(12928 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ if (
+ s->number64 == 0 ) _widec += 1024;
+ }
+ } else if ( (*p) >= 9 ) {
+ _widec = (short)(4224 + ((*p) - -128));
+ if (
+ s->number64 == 0 ) _widec += 256;
+ }
+ } else if ( (*p) > 32 ) {
+ if ( (*p) < 41 ) {
+ if ( 40 <= (*p) && (*p) <= 40 ) {
+ _widec = (short)(4224 + ((*p) - -128));
+ if (
+ s->number64 == 0 ) _widec += 256;
+ }
+ } else if ( (*p) > 41 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(12928 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ if (
+ s->number64 == 0 ) _widec += 1024;
+ }
+ } else {
+ _widec = (short)(4224 + ((*p) - -128));
+ if (
+ s->number64 == 0 ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(4224 + ((*p) - -128));
+ if (
+ s->number64 == 0 ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 4617: goto st828;
+ case 4640: goto st828;
+ case 4648: goto tr2661;
+ case 4649: goto tr2662;
+ case 13578: goto tr2666;
+ case 13627: goto tr2666;
+ case 13834: goto tr2666;
+ case 13883: goto tr2666;
+ case 14346: goto tr2671;
+ case 14395: goto tr2672;
+ case 14602: goto tr2666;
+ case 14651: goto tr2666;
+ case 14858: goto tr2673;
+ case 14907: goto tr2674;
+ }
+ goto tr2679;
+tr2674:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1194;
+tr2729:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV4);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET4_ADDR_LENGTH);
+ rdata_tail += ZS_INET4_ADDR_LENGTH;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1194;
+tr2774:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET6, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV6);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET6_ADDR_LENGTH);
+ rdata_tail += ZS_INET6_ADDR_LENGTH;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1194;
+tr2818:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1194;
+st1194:
+ if ( ++p == pe )
+ goto _test_eof1194;
+case 1194:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(4736 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(4736 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ } else {
+ _widec = (short)(4736 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ if ( _widec == 5642 )
+ goto tr2684;
+ if ( 5504 <= _widec && _widec <= 5759 )
+ goto tr2683;
+ goto tr2679;
+tr2664:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st830;
+tr2665:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st830;
+tr2675:
+ {
+ s->line_counter++;
+ }
+ goto st830;
+tr2686:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st830;
+tr2807:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ goto st830;
+tr2808:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st830;
+tr2809:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st830;
+tr2819:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st830;
+tr2718:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV4);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET4_ADDR_LENGTH);
+ rdata_tail += ZS_INET4_ADDR_LENGTH;
+ }
+ goto st830;
+tr2719:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV4);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET4_ADDR_LENGTH);
+ rdata_tail += ZS_INET4_ADDR_LENGTH;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st830;
+tr2720:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV4);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET4_ADDR_LENGTH);
+ rdata_tail += ZS_INET4_ADDR_LENGTH;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st830;
+tr2730:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV4);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET4_ADDR_LENGTH);
+ rdata_tail += ZS_INET4_ADDR_LENGTH;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st830;
+tr2763:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET6, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV6);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET6_ADDR_LENGTH);
+ rdata_tail += ZS_INET6_ADDR_LENGTH;
+ }
+ goto st830;
+tr2764:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET6, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV6);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET6_ADDR_LENGTH);
+ rdata_tail += ZS_INET6_ADDR_LENGTH;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st830;
+tr2765:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET6, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV6);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET6_ADDR_LENGTH);
+ rdata_tail += ZS_INET6_ADDR_LENGTH;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st830;
+tr2775:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET6, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV6);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET6_ADDR_LENGTH);
+ rdata_tail += ZS_INET6_ADDR_LENGTH;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st830;
+st830:
+ if ( ++p == pe )
+ goto _test_eof830;
+case 830:
+ _widec = (*p);
+ if ( (*p) < 43 ) {
+ if ( (*p) < 32 ) {
+ if ( (*p) > 9 ) {
+ if ( 10 <= (*p) && (*p) <= 10 ) {
+ _widec = (short)(8832 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ if (
+ s->number64 != 0 ) _widec += 1024;
+ if (
+ s->number64 == 0 ) _widec += 2048;
+ }
+ } else if ( (*p) >= 9 ) {
+ _widec = (short)(5760 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ } else if ( (*p) > 32 ) {
+ if ( (*p) > 40 ) {
+ if ( 41 <= (*p) && (*p) <= 41 ) {
+ _widec = (short)(5760 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ } else if ( (*p) >= 40 ) {
+ _widec = (short)(5760 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ } else {
+ _widec = (short)(5760 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ } else if ( (*p) > 43 ) {
+ if ( (*p) < 59 ) {
+ if ( (*p) > 47 ) {
+ if ( 48 <= (*p) && (*p) <= 57 ) {
+ _widec = (short)(2688 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ }
+ } else if ( (*p) >= 47 ) {
+ _widec = (short)(2688 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ }
+ } else if ( (*p) > 59 ) {
+ if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 ) {
+ _widec = (short)(2688 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ }
+ } else if ( (*p) >= 65 ) {
+ _widec = (short)(2688 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(8832 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ if (
+ s->number64 != 0 ) _widec += 1024;
+ if (
+ s->number64 == 0 ) _widec += 2048;
+ }
+ } else {
+ _widec = (short)(2688 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 3115: goto tr2680;
+ case 6153: goto st825;
+ case 6176: goto st825;
+ case 6184: goto tr2658;
+ case 6185: goto tr2659;
+ case 6409: goto st828;
+ case 6432: goto st828;
+ case 6440: goto tr2661;
+ case 6441: goto tr2662;
+ case 6665: goto st830;
+ case 6688: goto st830;
+ case 6696: goto tr2664;
+ case 6697: goto tr2665;
+ case 9482: goto tr2666;
+ case 9531: goto tr2666;
+ case 9738: goto tr2666;
+ case 9787: goto tr2666;
+ case 10250: goto tr2667;
+ case 10299: goto tr2668;
+ case 10506: goto tr2666;
+ case 10555: goto tr2666;
+ case 10762: goto tr2669;
+ case 10811: goto tr2670;
+ case 11274: goto tr2671;
+ case 11323: goto tr2672;
+ case 11530: goto tr2666;
+ case 11579: goto tr2666;
+ case 11786: goto tr2673;
+ case 11835: goto tr2674;
+ case 12298: goto tr2675;
+ case 12347: goto tr2676;
+ case 12554: goto tr2666;
+ case 12603: goto tr2666;
+ case 12810: goto tr2677;
+ case 12859: goto tr2678;
+ }
+ if ( _widec < 3137 ) {
+ if ( 3119 <= _widec && _widec <= 3129 )
+ goto tr2680;
+ } else if ( _widec > 3162 ) {
+ if ( 3169 <= _widec && _widec <= 3194 )
+ goto tr2680;
+ } else
+ goto tr2680;
+ goto tr2679;
+tr2669:
+ {
+ s->line_counter++;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1195;
+tr2724:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV4);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET4_ADDR_LENGTH);
+ rdata_tail += ZS_INET4_ADDR_LENGTH;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1195;
+tr2769:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET6, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV6);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET6_ADDR_LENGTH);
+ rdata_tail += ZS_INET6_ADDR_LENGTH;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1195;
+tr2813:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1195;
+st1195:
+ if ( ++p == pe )
+ goto _test_eof1195;
+case 1195:
+ _widec = (*p);
+ if ( (*p) < 43 ) {
+ if ( (*p) < 32 ) {
+ if ( (*p) > 9 ) {
+ if ( 10 <= (*p) && (*p) <= 10 ) {
+ _widec = (short)(3200 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ s->number64 != 0 ) _widec += 512;
+ }
+ } else if ( (*p) >= 9 ) {
+ _widec = (short)(2688 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ }
+ } else if ( (*p) > 32 ) {
+ if ( (*p) > 40 ) {
+ if ( 41 <= (*p) && (*p) <= 41 ) {
+ _widec = (short)(2688 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ }
+ } else if ( (*p) >= 40 ) {
+ _widec = (short)(2688 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(2688 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ }
+ } else if ( (*p) > 43 ) {
+ if ( (*p) < 59 ) {
+ if ( (*p) > 47 ) {
+ if ( 48 <= (*p) && (*p) <= 57 ) {
+ _widec = (short)(2688 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ }
+ } else if ( (*p) >= 47 ) {
+ _widec = (short)(2688 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ }
+ } else if ( (*p) > 59 ) {
+ if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 ) {
+ _widec = (short)(2688 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ }
+ } else if ( (*p) >= 65 ) {
+ _widec = (short)(2688 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(3200 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ s->number64 != 0 ) _widec += 512;
+ }
+ } else {
+ _widec = (short)(2688 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 3081: goto st825;
+ case 3104: goto st825;
+ case 3112: goto tr2658;
+ case 3113: goto tr2659;
+ case 3115: goto tr2680;
+ case 4106: goto tr2667;
+ case 4155: goto tr2668;
+ }
+ if ( _widec < 3137 ) {
+ if ( 3119 <= _widec && _widec <= 3129 )
+ goto tr2680;
+ } else if ( _widec > 3162 ) {
+ if ( 3169 <= _widec && _widec <= 3194 )
+ goto tr2680;
+ } else
+ goto tr2680;
+ goto tr2679;
+tr2670:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1196;
+tr2725:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV4);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET4_ADDR_LENGTH);
+ rdata_tail += ZS_INET4_ADDR_LENGTH;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1196;
+tr2770:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET6, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV6);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET6_ADDR_LENGTH);
+ rdata_tail += ZS_INET6_ADDR_LENGTH;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1196;
+tr2814:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1196;
+st1196:
+ if ( ++p == pe )
+ goto _test_eof1196;
+case 1196:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(3200 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ s->number64 != 0 ) _widec += 512;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(3200 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ s->number64 != 0 ) _widec += 512;
+ }
+ } else {
+ _widec = (short)(3200 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ s->number64 != 0 ) _widec += 512;
+ }
+ if ( _widec == 4106 )
+ goto tr2682;
+ if ( 3968 <= _widec && _widec <= 4223 )
+ goto tr2681;
+ goto tr2679;
+tr2676:
+ {
+ s->buffer_length = 0;
+ }
+ goto st831;
+tr2685:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st831;
+tr2820:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st831;
+tr2731:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV4);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET4_ADDR_LENGTH);
+ rdata_tail += ZS_INET4_ADDR_LENGTH;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st831;
+tr2776:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET6, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV6);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET6_ADDR_LENGTH);
+ rdata_tail += ZS_INET6_ADDR_LENGTH;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st831;
+st831:
+ if ( ++p == pe )
+ goto _test_eof831;
+case 831:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(6784 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ s->number64 != 0 ) _widec += 512;
+ if (
+ s->number64 == 0 ) _widec += 1024;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(6784 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ s->number64 != 0 ) _widec += 512;
+ if (
+ s->number64 == 0 ) _widec += 1024;
+ }
+ } else {
+ _widec = (short)(6784 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ s->number64 != 0 ) _widec += 512;
+ if (
+ s->number64 == 0 ) _widec += 1024;
+ }
+ switch( _widec ) {
+ case 7690: goto tr2682;
+ case 8202: goto tr2684;
+ case 8714: goto tr2686;
+ }
+ if ( _widec < 8064 ) {
+ if ( 7552 <= _widec && _widec <= 7807 )
+ goto tr2681;
+ } else if ( _widec > 8319 ) {
+ if ( 8576 <= _widec && _widec <= 8831 )
+ goto tr2685;
+ } else
+ goto tr2683;
+ goto tr2679;
+tr2677:
+ {
+ s->line_counter++;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1197;
+tr2732:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV4);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET4_ADDR_LENGTH);
+ rdata_tail += ZS_INET4_ADDR_LENGTH;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1197;
+tr2777:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET6, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV6);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET6_ADDR_LENGTH);
+ rdata_tail += ZS_INET6_ADDR_LENGTH;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1197;
+tr2821:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ s->line_counter++;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1197;
+st1197:
+ if ( ++p == pe )
+ goto _test_eof1197;
+case 1197:
+ _widec = (*p);
+ if ( (*p) < 43 ) {
+ if ( (*p) < 32 ) {
+ if ( (*p) > 9 ) {
+ if ( 10 <= (*p) && (*p) <= 10 ) {
+ _widec = (short)(8832 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ if (
+ s->number64 != 0 ) _widec += 1024;
+ if (
+ s->number64 == 0 ) _widec += 2048;
+ }
+ } else if ( (*p) >= 9 ) {
+ _widec = (short)(5760 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ } else if ( (*p) > 32 ) {
+ if ( (*p) > 40 ) {
+ if ( 41 <= (*p) && (*p) <= 41 ) {
+ _widec = (short)(5760 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ } else if ( (*p) >= 40 ) {
+ _widec = (short)(5760 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ } else {
+ _widec = (short)(5760 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ } else if ( (*p) > 43 ) {
+ if ( (*p) < 59 ) {
+ if ( (*p) > 47 ) {
+ if ( 48 <= (*p) && (*p) <= 57 ) {
+ _widec = (short)(2688 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ }
+ } else if ( (*p) >= 47 ) {
+ _widec = (short)(2688 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ }
+ } else if ( (*p) > 59 ) {
+ if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 ) {
+ _widec = (short)(2688 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ }
+ } else if ( (*p) >= 65 ) {
+ _widec = (short)(2688 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(8832 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ if (
+ s->number64 != 0 ) _widec += 1024;
+ if (
+ s->number64 == 0 ) _widec += 2048;
+ }
+ } else {
+ _widec = (short)(2688 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 3115: goto tr2680;
+ case 6153: goto st825;
+ case 6176: goto st825;
+ case 6184: goto tr2658;
+ case 6185: goto tr2659;
+ case 6409: goto st828;
+ case 6432: goto st828;
+ case 6440: goto tr2661;
+ case 6441: goto tr2662;
+ case 6665: goto st830;
+ case 6688: goto st830;
+ case 6696: goto tr2664;
+ case 6697: goto tr2665;
+ case 9482: goto tr2666;
+ case 9531: goto tr2666;
+ case 9738: goto tr2666;
+ case 9787: goto tr2666;
+ case 10250: goto tr2667;
+ case 10299: goto tr2668;
+ case 10506: goto tr2666;
+ case 10555: goto tr2666;
+ case 10762: goto tr2669;
+ case 10811: goto tr2670;
+ case 11274: goto tr2671;
+ case 11323: goto tr2672;
+ case 11530: goto tr2666;
+ case 11579: goto tr2666;
+ case 11786: goto tr2673;
+ case 11835: goto tr2674;
+ case 12298: goto tr2675;
+ case 12347: goto tr2676;
+ case 12554: goto tr2666;
+ case 12603: goto tr2666;
+ case 12810: goto tr2677;
+ case 12859: goto tr2678;
+ }
+ if ( _widec < 3137 ) {
+ if ( 3119 <= _widec && _widec <= 3129 )
+ goto tr2680;
+ } else if ( _widec > 3162 ) {
+ if ( 3169 <= _widec && _widec <= 3194 )
+ goto tr2680;
+ } else
+ goto tr2680;
+ goto tr2679;
+tr2678:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1198;
+tr2733:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV4);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET4_ADDR_LENGTH);
+ rdata_tail += ZS_INET4_ADDR_LENGTH;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1198;
+tr2778:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET6, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV6);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET6_ADDR_LENGTH);
+ rdata_tail += ZS_INET6_ADDR_LENGTH;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1198;
+tr2822:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1198;
+st1198:
+ if ( ++p == pe )
+ goto _test_eof1198;
+case 1198:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(6784 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ s->number64 != 0 ) _widec += 512;
+ if (
+ s->number64 == 0 ) _widec += 1024;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(6784 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ s->number64 != 0 ) _widec += 512;
+ if (
+ s->number64 == 0 ) _widec += 1024;
+ }
+ } else {
+ _widec = (short)(6784 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ s->number64 != 0 ) _widec += 512;
+ if (
+ s->number64 == 0 ) _widec += 1024;
+ }
+ switch( _widec ) {
+ case 7690: goto tr2682;
+ case 8202: goto tr2684;
+ case 8714: goto tr2686;
+ }
+ if ( _widec < 8064 ) {
+ if ( 7552 <= _widec && _widec <= 7807 )
+ goto tr2681;
+ } else if ( _widec > 8319 ) {
+ if ( 8576 <= _widec && _widec <= 8831 )
+ goto tr2685;
+ } else
+ goto tr2683;
+ goto tr2679;
+tr2655:
+ {
+ s->buffer_length = 0;
+ }
+ goto st832;
+tr2687:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st832;
+tr2649:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st832;
+st832:
+ if ( ++p == pe )
+ goto _test_eof832;
+case 832:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2688;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2687;
+ goto tr2627;
+tr2641:
+ {
+ s->buffer_length = 0;
+ }
+ goto st833;
+tr2689:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st833;
+st833:
+ if ( ++p == pe )
+ goto _test_eof833;
+case 833:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2690;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2689;
+ goto tr2627;
+tr2632:
+ {
+ *(rdata_tail++) = 1;
+ }
+ goto st834;
+st834:
+ if ( ++p == pe )
+ goto _test_eof834;
+case 834:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st835;
+ case 32: goto st835;
+ case 40: goto tr2692;
+ case 41: goto tr2693;
+ case 1034: goto tr2694;
+ case 1083: goto tr2695;
+ }
+ goto tr2627;
+tr2692:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st835;
+tr2693:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st835;
+tr2694:
+ {
+ s->line_counter++;
+ }
+ goto st835;
+tr2737:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st835;
+st835:
+ if ( ++p == pe )
+ goto _test_eof835;
+case 835:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st835;
+ case 32: goto st835;
+ case 40: goto tr2692;
+ case 41: goto tr2693;
+ case 1034: goto tr2694;
+ case 1083: goto tr2695;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2696;
+ goto tr2642;
+tr2696:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st836;
+tr2700:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st836;
+st836:
+ if ( ++p == pe )
+ goto _test_eof836;
+case 836:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2697;
+ case 32: goto tr2697;
+ case 40: goto tr2698;
+ case 41: goto tr2699;
+ case 1034: goto tr2701;
+ case 1083: goto tr2702;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2700;
+ goto tr2642;
+tr2705:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st837;
+tr2706:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st837;
+tr2708:
+ {
+ s->line_counter++;
+ }
+ goto st837;
+tr2735:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st837;
+tr2697:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st837;
+tr2698:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st837;
+tr2699:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st837;
+tr2701:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st837;
+st837:
+ if ( ++p == pe )
+ goto _test_eof837;
+case 837:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st837;
+ case 32: goto st837;
+ case 40: goto tr2705;
+ case 41: goto tr2706;
+ case 46: goto tr2707;
+ case 1034: goto tr2708;
+ case 1083: goto tr2709;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2707;
+ goto tr2703;
+tr2707:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st838;
+tr2711:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st838;
+st838:
+ if ( ++p == pe )
+ goto _test_eof838;
+case 838:
+ _widec = (*p);
+ if ( (*p) < 32 ) {
+ if ( (*p) > 9 ) {
+ if ( 10 <= (*p) && (*p) <= 10 ) {
+ _widec = (short)(8832 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ if (
+ s->number64 != 0 ) _widec += 1024;
+ if (
+ s->number64 == 0 ) _widec += 2048;
+ }
+ } else if ( (*p) >= 9 ) {
+ _widec = (short)(5760 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ } else if ( (*p) > 32 ) {
+ if ( (*p) < 41 ) {
+ if ( 40 <= (*p) && (*p) <= 40 ) {
+ _widec = (short)(5760 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ } else if ( (*p) > 41 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(8832 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ if (
+ s->number64 != 0 ) _widec += 1024;
+ if (
+ s->number64 == 0 ) _widec += 2048;
+ }
+ } else {
+ _widec = (short)(5760 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ } else {
+ _widec = (short)(5760 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 46: goto tr2711;
+ case 6153: goto tr2712;
+ case 6176: goto tr2712;
+ case 6184: goto tr2713;
+ case 6185: goto tr2714;
+ case 6409: goto tr2715;
+ case 6432: goto tr2715;
+ case 6440: goto tr2716;
+ case 6441: goto tr2717;
+ case 6665: goto tr2718;
+ case 6688: goto tr2718;
+ case 6696: goto tr2719;
+ case 6697: goto tr2720;
+ case 9482: goto tr2721;
+ case 9531: goto tr2721;
+ case 9738: goto tr2721;
+ case 9787: goto tr2721;
+ case 10250: goto tr2722;
+ case 10299: goto tr2723;
+ case 10506: goto tr2721;
+ case 10555: goto tr2721;
+ case 10762: goto tr2724;
+ case 10811: goto tr2725;
+ case 11274: goto tr2726;
+ case 11323: goto tr2727;
+ case 11530: goto tr2721;
+ case 11579: goto tr2721;
+ case 11786: goto tr2728;
+ case 11835: goto tr2729;
+ case 12298: goto tr2730;
+ case 12347: goto tr2731;
+ case 12554: goto tr2721;
+ case 12603: goto tr2721;
+ case 12810: goto tr2732;
+ case 12859: goto tr2733;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2711;
+ goto tr2710;
+tr2709:
+ {
+ s->buffer_length = 0;
+ }
+ goto st839;
+tr2734:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st839;
+tr2702:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st839;
+st839:
+ if ( ++p == pe )
+ goto _test_eof839;
+case 839:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2735;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2734;
+ goto tr2627;
+tr2695:
+ {
+ s->buffer_length = 0;
+ }
+ goto st840;
+tr2736:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st840;
+st840:
+ if ( ++p == pe )
+ goto _test_eof840;
+case 840:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2737;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2736;
+ goto tr2627;
+tr2633:
+ {
+ *(rdata_tail++) = 2;
+ }
+ goto st841;
+st841:
+ if ( ++p == pe )
+ goto _test_eof841;
+case 841:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st842;
+ case 32: goto st842;
+ case 40: goto tr2739;
+ case 41: goto tr2740;
+ case 1034: goto tr2741;
+ case 1083: goto tr2742;
+ }
+ goto tr2627;
+tr2739:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st842;
+tr2740:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st842;
+tr2741:
+ {
+ s->line_counter++;
+ }
+ goto st842;
+tr2782:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st842;
+st842:
+ if ( ++p == pe )
+ goto _test_eof842;
+case 842:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st842;
+ case 32: goto st842;
+ case 40: goto tr2739;
+ case 41: goto tr2740;
+ case 1034: goto tr2741;
+ case 1083: goto tr2742;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2743;
+ goto tr2642;
+tr2743:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st843;
+tr2747:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st843;
+st843:
+ if ( ++p == pe )
+ goto _test_eof843;
+case 843:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2744;
+ case 32: goto tr2744;
+ case 40: goto tr2745;
+ case 41: goto tr2746;
+ case 1034: goto tr2748;
+ case 1083: goto tr2749;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2747;
+ goto tr2642;
+tr2751:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st844;
+tr2752:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st844;
+tr2754:
+ {
+ s->line_counter++;
+ }
+ goto st844;
+tr2780:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st844;
+tr2744:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st844;
+tr2745:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st844;
+tr2746:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st844;
+tr2748:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st844;
+st844:
+ if ( ++p == pe )
+ goto _test_eof844;
+case 844:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st844;
+ case 32: goto st844;
+ case 40: goto tr2751;
+ case 41: goto tr2752;
+ case 46: goto tr2753;
+ case 1034: goto tr2754;
+ case 1083: goto tr2755;
+ }
+ if ( _widec < 65 ) {
+ if ( 48 <= _widec && _widec <= 58 )
+ goto tr2753;
+ } else if ( _widec > 70 ) {
+ if ( 97 <= _widec && _widec <= 102 )
+ goto tr2753;
+ } else
+ goto tr2753;
+ goto tr2703;
+tr2753:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st845;
+tr2756:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st845;
+st845:
+ if ( ++p == pe )
+ goto _test_eof845;
+case 845:
+ _widec = (*p);
+ if ( (*p) < 32 ) {
+ if ( (*p) > 9 ) {
+ if ( 10 <= (*p) && (*p) <= 10 ) {
+ _widec = (short)(8832 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ if (
+ s->number64 != 0 ) _widec += 1024;
+ if (
+ s->number64 == 0 ) _widec += 2048;
+ }
+ } else if ( (*p) >= 9 ) {
+ _widec = (short)(5760 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ } else if ( (*p) > 32 ) {
+ if ( (*p) < 41 ) {
+ if ( 40 <= (*p) && (*p) <= 40 ) {
+ _widec = (short)(5760 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ } else if ( (*p) > 41 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(8832 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ if (
+ s->number64 != 0 ) _widec += 1024;
+ if (
+ s->number64 == 0 ) _widec += 2048;
+ }
+ } else {
+ _widec = (short)(5760 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ } else {
+ _widec = (short)(5760 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 46: goto tr2756;
+ case 6153: goto tr2757;
+ case 6176: goto tr2757;
+ case 6184: goto tr2758;
+ case 6185: goto tr2759;
+ case 6409: goto tr2760;
+ case 6432: goto tr2760;
+ case 6440: goto tr2761;
+ case 6441: goto tr2762;
+ case 6665: goto tr2763;
+ case 6688: goto tr2763;
+ case 6696: goto tr2764;
+ case 6697: goto tr2765;
+ case 9482: goto tr2766;
+ case 9531: goto tr2766;
+ case 9738: goto tr2766;
+ case 9787: goto tr2766;
+ case 10250: goto tr2767;
+ case 10299: goto tr2768;
+ case 10506: goto tr2766;
+ case 10555: goto tr2766;
+ case 10762: goto tr2769;
+ case 10811: goto tr2770;
+ case 11274: goto tr2771;
+ case 11323: goto tr2772;
+ case 11530: goto tr2766;
+ case 11579: goto tr2766;
+ case 11786: goto tr2773;
+ case 11835: goto tr2774;
+ case 12298: goto tr2775;
+ case 12347: goto tr2776;
+ case 12554: goto tr2766;
+ case 12603: goto tr2766;
+ case 12810: goto tr2777;
+ case 12859: goto tr2778;
+ }
+ if ( _widec < 65 ) {
+ if ( 48 <= _widec && _widec <= 58 )
+ goto tr2756;
+ } else if ( _widec > 70 ) {
+ if ( 97 <= _widec && _widec <= 102 )
+ goto tr2756;
+ } else
+ goto tr2756;
+ goto tr2710;
+tr2755:
+ {
+ s->buffer_length = 0;
+ }
+ goto st846;
+tr2779:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st846;
+tr2749:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st846;
+st846:
+ if ( ++p == pe )
+ goto _test_eof846;
+case 846:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2780;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2779;
+ goto tr2627;
+tr2742:
+ {
+ s->buffer_length = 0;
+ }
+ goto st847;
+tr2781:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st847;
+st847:
+ if ( ++p == pe )
+ goto _test_eof847;
+case 847:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2782;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2781;
+ goto tr2627;
+tr2634:
+ {
+ *(rdata_tail++) = 3;
+ }
+ goto st848;
+st848:
+ if ( ++p == pe )
+ goto _test_eof848;
+case 848:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st849;
+ case 32: goto st849;
+ case 40: goto tr2784;
+ case 41: goto tr2785;
+ case 1034: goto tr2786;
+ case 1083: goto tr2787;
+ }
+ goto tr2627;
+tr2784:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st849;
+tr2785:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st849;
+tr2786:
+ {
+ s->line_counter++;
+ }
+ goto st849;
+tr2826:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st849;
+st849:
+ if ( ++p == pe )
+ goto _test_eof849;
+case 849:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st849;
+ case 32: goto st849;
+ case 40: goto tr2784;
+ case 41: goto tr2785;
+ case 1034: goto tr2786;
+ case 1083: goto tr2787;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2788;
+ goto tr2642;
+tr2788:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st850;
+tr2792:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st850;
+st850:
+ if ( ++p == pe )
+ goto _test_eof850;
+case 850:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2789;
+ case 32: goto tr2789;
+ case 40: goto tr2790;
+ case 41: goto tr2791;
+ case 1034: goto tr2793;
+ case 1083: goto tr2794;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2792;
+ goto tr2642;
+tr2796:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st851;
+tr2797:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st851;
+tr2799:
+ {
+ s->line_counter++;
+ }
+ goto st851;
+tr2824:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st851;
+tr2789:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st851;
+tr2790:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st851;
+tr2791:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st851;
+tr2793:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st851;
+st851:
+ if ( ++p == pe )
+ goto _test_eof851;
+case 851:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st851;
+ case 32: goto st851;
+ case 40: goto tr2796;
+ case 41: goto tr2797;
+ case 42: goto tr2798;
+ case 92: goto tr2798;
+ case 95: goto tr2798;
+ case 1034: goto tr2799;
+ case 1083: goto tr2800;
+ }
+ if ( _widec < 64 ) {
+ if ( 45 <= _widec && _widec <= 57 )
+ goto tr2798;
+ } else if ( _widec > 90 ) {
+ if ( 97 <= _widec && _widec <= 122 )
+ goto tr2798;
+ } else
+ goto tr2798;
+ goto tr2627;
+tr2798:
+ {
+ s->dname = rdata_tail;
+ }
+ { p--; {stack[top++] = 852;goto st270;} }
+ goto st852;
+st852:
+ if ( ++p == pe )
+ goto _test_eof852;
+case 852:
+ _widec = (*p);
+ if ( (*p) < 32 ) {
+ if ( (*p) > 9 ) {
+ if ( 10 <= (*p) && (*p) <= 10 ) {
+ _widec = (short)(8832 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ if (
+ s->number64 != 0 ) _widec += 1024;
+ if (
+ s->number64 == 0 ) _widec += 2048;
+ }
+ } else if ( (*p) >= 9 ) {
+ _widec = (short)(5760 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ } else if ( (*p) > 32 ) {
+ if ( (*p) < 41 ) {
+ if ( 40 <= (*p) && (*p) <= 40 ) {
+ _widec = (short)(5760 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ } else if ( (*p) > 41 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(8832 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ if (
+ s->number64 != 0 ) _widec += 1024;
+ if (
+ s->number64 == 0 ) _widec += 2048;
+ }
+ } else {
+ _widec = (short)(5760 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ } else {
+ _widec = (short)(5760 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 6153: goto tr2801;
+ case 6176: goto tr2801;
+ case 6184: goto tr2802;
+ case 6185: goto tr2803;
+ case 6409: goto tr2804;
+ case 6432: goto tr2804;
+ case 6440: goto tr2805;
+ case 6441: goto tr2806;
+ case 6665: goto tr2807;
+ case 6688: goto tr2807;
+ case 6696: goto tr2808;
+ case 6697: goto tr2809;
+ case 9482: goto tr2810;
+ case 9531: goto tr2810;
+ case 9738: goto tr2810;
+ case 9787: goto tr2810;
+ case 10250: goto tr2811;
+ case 10299: goto tr2812;
+ case 10506: goto tr2810;
+ case 10555: goto tr2810;
+ case 10762: goto tr2813;
+ case 10811: goto tr2814;
+ case 11274: goto tr2815;
+ case 11323: goto tr2816;
+ case 11530: goto tr2810;
+ case 11579: goto tr2810;
+ case 11786: goto tr2817;
+ case 11835: goto tr2818;
+ case 12298: goto tr2819;
+ case 12347: goto tr2820;
+ case 12554: goto tr2810;
+ case 12603: goto tr2810;
+ case 12810: goto tr2821;
+ case 12859: goto tr2822;
+ }
+ goto tr2656;
+tr2800:
+ {
+ s->buffer_length = 0;
+ }
+ goto st853;
+tr2823:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st853;
+tr2794:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st853;
+st853:
+ if ( ++p == pe )
+ goto _test_eof853;
+case 853:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2824;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2823;
+ goto tr2627;
+tr2787:
+ {
+ s->buffer_length = 0;
+ }
+ goto st854;
+tr2825:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st854;
+st854:
+ if ( ++p == pe )
+ goto _test_eof854;
+case 854:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2826;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2825;
+ goto tr2627;
+tr2636:
+ {
+ s->buffer_length = 0;
+ }
+ goto st855;
+tr2827:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st855;
+tr2626:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st855;
+st855:
+ if ( ++p == pe )
+ goto _test_eof855;
+case 855:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2828;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2827;
+ goto tr71;
+st856:
+ if ( ++p == pe )
+ goto _test_eof856;
+case 856:
+ switch( (*p) ) {
+ case 65: goto st857;
+ case 67: goto st891;
+ case 68: goto st908;
+ case 69: goto st922;
+ case 72: goto st929;
+ case 73: goto st934;
+ case 75: goto st942;
+ case 76: goto st946;
+ case 77: goto st954;
+ case 78: goto st960;
+ case 80: goto st976;
+ case 82: goto st979;
+ case 83: goto st986;
+ case 84: goto st997;
+ case 85: goto st1007;
+ case 97: goto st857;
+ case 99: goto st891;
+ case 100: goto st908;
+ case 101: goto st922;
+ case 104: goto st929;
+ case 105: goto st934;
+ case 107: goto st942;
+ case 108: goto st946;
+ case 109: goto st954;
+ case 110: goto st960;
+ case 112: goto st976;
+ case 114: goto st979;
+ case 115: goto st986;
+ case 116: goto st997;
+ case 117: goto st1007;
+ }
+ goto tr2829;
+st857:
+ if ( ++p == pe )
+ goto _test_eof857;
+case 857:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2845;
+ case 32: goto tr2845;
+ case 40: goto tr2846;
+ case 41: goto tr2847;
+ case 65: goto st882;
+ case 70: goto st885;
+ case 80: goto st889;
+ case 97: goto st882;
+ case 102: goto st885;
+ case 112: goto st889;
+ case 1034: goto tr2851;
+ case 1083: goto tr2852;
+ }
+ goto tr2829;
+tr2854:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr2855:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr2857:
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr2953:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3264:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st858;
+tr3265:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3266:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3268:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr2845:
+ { type_num(KNOT_RRTYPE_A, &rdata_tail); }
+ goto st858;
+tr2846:
+ { type_num(KNOT_RRTYPE_A, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr2847:
+ { type_num(KNOT_RRTYPE_A, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr2851:
+ { type_num(KNOT_RRTYPE_A, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr2956:
+ { type_num(KNOT_RRTYPE_AAAA, &rdata_tail); }
+ goto st858;
+tr2957:
+ { type_num(KNOT_RRTYPE_AAAA, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr2958:
+ { type_num(KNOT_RRTYPE_AAAA, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr2959:
+ { type_num(KNOT_RRTYPE_AAAA, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr2964:
+ { type_num(KNOT_RRTYPE_AFSDB, &rdata_tail); }
+ goto st858;
+tr2965:
+ { type_num(KNOT_RRTYPE_AFSDB, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr2966:
+ { type_num(KNOT_RRTYPE_AFSDB, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr2967:
+ { type_num(KNOT_RRTYPE_AFSDB, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr2970:
+ { type_num(KNOT_RRTYPE_APL, &rdata_tail); }
+ goto st858;
+tr2971:
+ { type_num(KNOT_RRTYPE_APL, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr2972:
+ { type_num(KNOT_RRTYPE_APL, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr2973:
+ { type_num(KNOT_RRTYPE_APL, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr2980:
+ { type_num(KNOT_RRTYPE_CAA, &rdata_tail); }
+ goto st858;
+tr2981:
+ { type_num(KNOT_RRTYPE_CAA, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr2982:
+ { type_num(KNOT_RRTYPE_CAA, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr2983:
+ { type_num(KNOT_RRTYPE_CAA, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr2991:
+ { type_num(KNOT_RRTYPE_CDNSKEY, &rdata_tail); }
+ goto st858;
+tr2992:
+ { type_num(KNOT_RRTYPE_CDNSKEY, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr2993:
+ { type_num(KNOT_RRTYPE_CDNSKEY, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr2994:
+ { type_num(KNOT_RRTYPE_CDNSKEY, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr2996:
+ { type_num(KNOT_RRTYPE_CDS, &rdata_tail); }
+ goto st858;
+tr2997:
+ { type_num(KNOT_RRTYPE_CDS, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr2998:
+ { type_num(KNOT_RRTYPE_CDS, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr2999:
+ { type_num(KNOT_RRTYPE_CDS, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3003:
+ { type_num(KNOT_RRTYPE_CERT, &rdata_tail); }
+ goto st858;
+tr3004:
+ { type_num(KNOT_RRTYPE_CERT, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3005:
+ { type_num(KNOT_RRTYPE_CERT, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3006:
+ { type_num(KNOT_RRTYPE_CERT, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3011:
+ { type_num(KNOT_RRTYPE_CNAME, &rdata_tail); }
+ goto st858;
+tr3012:
+ { type_num(KNOT_RRTYPE_CNAME, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3013:
+ { type_num(KNOT_RRTYPE_CNAME, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3014:
+ { type_num(KNOT_RRTYPE_CNAME, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3022:
+ { type_num(KNOT_RRTYPE_DHCID, &rdata_tail); }
+ goto st858;
+tr3023:
+ { type_num(KNOT_RRTYPE_DHCID, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3024:
+ { type_num(KNOT_RRTYPE_DHCID, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3025:
+ { type_num(KNOT_RRTYPE_DHCID, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3031:
+ { type_num(KNOT_RRTYPE_DNAME, &rdata_tail); }
+ goto st858;
+tr3032:
+ { type_num(KNOT_RRTYPE_DNAME, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3033:
+ { type_num(KNOT_RRTYPE_DNAME, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3034:
+ { type_num(KNOT_RRTYPE_DNAME, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3039:
+ { type_num(KNOT_RRTYPE_DNSKEY, &rdata_tail); }
+ goto st858;
+tr3040:
+ { type_num(KNOT_RRTYPE_DNSKEY, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3041:
+ { type_num(KNOT_RRTYPE_DNSKEY, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3042:
+ { type_num(KNOT_RRTYPE_DNSKEY, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3044:
+ { type_num(KNOT_RRTYPE_DS, &rdata_tail); }
+ goto st858;
+tr3045:
+ { type_num(KNOT_RRTYPE_DS, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3046:
+ { type_num(KNOT_RRTYPE_DS, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3047:
+ { type_num(KNOT_RRTYPE_DS, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3054:
+ { type_num(KNOT_RRTYPE_EUI48, &rdata_tail); }
+ goto st858;
+tr3055:
+ { type_num(KNOT_RRTYPE_EUI48, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3056:
+ { type_num(KNOT_RRTYPE_EUI48, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3057:
+ { type_num(KNOT_RRTYPE_EUI48, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3060:
+ { type_num(KNOT_RRTYPE_EUI64, &rdata_tail); }
+ goto st858;
+tr3061:
+ { type_num(KNOT_RRTYPE_EUI64, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3062:
+ { type_num(KNOT_RRTYPE_EUI64, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3063:
+ { type_num(KNOT_RRTYPE_EUI64, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3069:
+ { type_num(KNOT_RRTYPE_HINFO, &rdata_tail); }
+ goto st858;
+tr3070:
+ { type_num(KNOT_RRTYPE_HINFO, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3071:
+ { type_num(KNOT_RRTYPE_HINFO, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3072:
+ { type_num(KNOT_RRTYPE_HINFO, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3081:
+ { type_num(KNOT_RRTYPE_IPSECKEY, &rdata_tail); }
+ goto st858;
+tr3082:
+ { type_num(KNOT_RRTYPE_IPSECKEY, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3083:
+ { type_num(KNOT_RRTYPE_IPSECKEY, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3084:
+ { type_num(KNOT_RRTYPE_IPSECKEY, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3089:
+ { type_num(KNOT_RRTYPE_KEY, &rdata_tail); }
+ goto st858;
+tr3090:
+ { type_num(KNOT_RRTYPE_KEY, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3091:
+ { type_num(KNOT_RRTYPE_KEY, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3092:
+ { type_num(KNOT_RRTYPE_KEY, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3094:
+ { type_num(KNOT_RRTYPE_KX, &rdata_tail); }
+ goto st858;
+tr3095:
+ { type_num(KNOT_RRTYPE_KX, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3096:
+ { type_num(KNOT_RRTYPE_KX, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3097:
+ { type_num(KNOT_RRTYPE_KX, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3104:
+ { type_num(KNOT_RRTYPE_L32, &rdata_tail); }
+ goto st858;
+tr3105:
+ { type_num(KNOT_RRTYPE_L32, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3106:
+ { type_num(KNOT_RRTYPE_L32, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3107:
+ { type_num(KNOT_RRTYPE_L32, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3110:
+ { type_num(KNOT_RRTYPE_L64, &rdata_tail); }
+ goto st858;
+tr3111:
+ { type_num(KNOT_RRTYPE_L64, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3112:
+ { type_num(KNOT_RRTYPE_L64, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3113:
+ { type_num(KNOT_RRTYPE_L64, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3116:
+ { type_num(KNOT_RRTYPE_LOC, &rdata_tail); }
+ goto st858;
+tr3117:
+ { type_num(KNOT_RRTYPE_LOC, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3118:
+ { type_num(KNOT_RRTYPE_LOC, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3119:
+ { type_num(KNOT_RRTYPE_LOC, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3121:
+ { type_num(KNOT_RRTYPE_LP, &rdata_tail); }
+ goto st858;
+tr3122:
+ { type_num(KNOT_RRTYPE_LP, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3123:
+ { type_num(KNOT_RRTYPE_LP, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3124:
+ { type_num(KNOT_RRTYPE_LP, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3131:
+ { type_num(KNOT_RRTYPE_MINFO, &rdata_tail); }
+ goto st858;
+tr3132:
+ { type_num(KNOT_RRTYPE_MINFO, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3133:
+ { type_num(KNOT_RRTYPE_MINFO, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3134:
+ { type_num(KNOT_RRTYPE_MINFO, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3136:
+ { type_num(KNOT_RRTYPE_MX, &rdata_tail); }
+ goto st858;
+tr3137:
+ { type_num(KNOT_RRTYPE_MX, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3138:
+ { type_num(KNOT_RRTYPE_MX, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3139:
+ { type_num(KNOT_RRTYPE_MX, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3147:
+ { type_num(KNOT_RRTYPE_NAPTR, &rdata_tail); }
+ goto st858;
+tr3148:
+ { type_num(KNOT_RRTYPE_NAPTR, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3149:
+ { type_num(KNOT_RRTYPE_NAPTR, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3150:
+ { type_num(KNOT_RRTYPE_NAPTR, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3153:
+ { type_num(KNOT_RRTYPE_NID, &rdata_tail); }
+ goto st858;
+tr3154:
+ { type_num(KNOT_RRTYPE_NID, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3155:
+ { type_num(KNOT_RRTYPE_NID, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3156:
+ { type_num(KNOT_RRTYPE_NID, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3158:
+ { type_num(KNOT_RRTYPE_NS, &rdata_tail); }
+ goto st858;
+tr3159:
+ { type_num(KNOT_RRTYPE_NS, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3160:
+ { type_num(KNOT_RRTYPE_NS, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3162:
+ { type_num(KNOT_RRTYPE_NS, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3165:
+ { type_num(KNOT_RRTYPE_NSEC, &rdata_tail); }
+ goto st858;
+tr3166:
+ { type_num(KNOT_RRTYPE_NSEC, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3167:
+ { type_num(KNOT_RRTYPE_NSEC, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3169:
+ { type_num(KNOT_RRTYPE_NSEC, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3171:
+ { type_num(KNOT_RRTYPE_NSEC3, &rdata_tail); }
+ goto st858;
+tr3172:
+ { type_num(KNOT_RRTYPE_NSEC3, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3173:
+ { type_num(KNOT_RRTYPE_NSEC3, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3175:
+ { type_num(KNOT_RRTYPE_NSEC3, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3181:
+ { type_num(KNOT_RRTYPE_NSEC3PARAM, &rdata_tail); }
+ goto st858;
+tr3182:
+ { type_num(KNOT_RRTYPE_NSEC3PARAM, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3183:
+ { type_num(KNOT_RRTYPE_NSEC3PARAM, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3184:
+ { type_num(KNOT_RRTYPE_NSEC3PARAM, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3188:
+ { type_num(KNOT_RRTYPE_PTR, &rdata_tail); }
+ goto st858;
+tr3189:
+ { type_num(KNOT_RRTYPE_PTR, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3190:
+ { type_num(KNOT_RRTYPE_PTR, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3191:
+ { type_num(KNOT_RRTYPE_PTR, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3196:
+ { type_num(KNOT_RRTYPE_RP, &rdata_tail); }
+ goto st858;
+tr3197:
+ { type_num(KNOT_RRTYPE_RP, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3198:
+ { type_num(KNOT_RRTYPE_RP, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3199:
+ { type_num(KNOT_RRTYPE_RP, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3204:
+ { type_num(KNOT_RRTYPE_RRSIG, &rdata_tail); }
+ goto st858;
+tr3205:
+ { type_num(KNOT_RRTYPE_RRSIG, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3206:
+ { type_num(KNOT_RRTYPE_RRSIG, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3207:
+ { type_num(KNOT_RRTYPE_RRSIG, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3209:
+ { type_num(KNOT_RRTYPE_RT, &rdata_tail); }
+ goto st858;
+tr3210:
+ { type_num(KNOT_RRTYPE_RT, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3211:
+ { type_num(KNOT_RRTYPE_RT, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3212:
+ { type_num(KNOT_RRTYPE_RT, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3219:
+ { type_num(KNOT_RRTYPE_SOA, &rdata_tail); }
+ goto st858;
+tr3220:
+ { type_num(KNOT_RRTYPE_SOA, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3221:
+ { type_num(KNOT_RRTYPE_SOA, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3222:
+ { type_num(KNOT_RRTYPE_SOA, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3225:
+ { type_num(KNOT_RRTYPE_SPF, &rdata_tail); }
+ goto st858;
+tr3226:
+ { type_num(KNOT_RRTYPE_SPF, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3227:
+ { type_num(KNOT_RRTYPE_SPF, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3228:
+ { type_num(KNOT_RRTYPE_SPF, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3231:
+ { type_num(KNOT_RRTYPE_SRV, &rdata_tail); }
+ goto st858;
+tr3232:
+ { type_num(KNOT_RRTYPE_SRV, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3233:
+ { type_num(KNOT_RRTYPE_SRV, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3234:
+ { type_num(KNOT_RRTYPE_SRV, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3239:
+ { type_num(KNOT_RRTYPE_SSHFP, &rdata_tail); }
+ goto st858;
+tr3240:
+ { type_num(KNOT_RRTYPE_SSHFP, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3241:
+ { type_num(KNOT_RRTYPE_SSHFP, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3242:
+ { type_num(KNOT_RRTYPE_SSHFP, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3249:
+ { type_num(KNOT_RRTYPE_TLSA, &rdata_tail); }
+ goto st858;
+tr3250:
+ { type_num(KNOT_RRTYPE_TLSA, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3251:
+ { type_num(KNOT_RRTYPE_TLSA, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3252:
+ { type_num(KNOT_RRTYPE_TLSA, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3255:
+ { type_num(KNOT_RRTYPE_TXT, &rdata_tail); }
+ goto st858;
+tr3256:
+ { type_num(KNOT_RRTYPE_TXT, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3257:
+ { type_num(KNOT_RRTYPE_TXT, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3258:
+ { type_num(KNOT_RRTYPE_TXT, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+tr3272:
+ { type_num(KNOT_RRTYPE_URI, &rdata_tail); }
+ goto st858;
+tr3273:
+ { type_num(KNOT_RRTYPE_URI, &rdata_tail); }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st858;
+tr3274:
+ { type_num(KNOT_RRTYPE_URI, &rdata_tail); }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st858;
+tr3275:
+ { type_num(KNOT_RRTYPE_URI, &rdata_tail); }
+ {
+ s->line_counter++;
+ }
+ goto st858;
+st858:
+ if ( ++p == pe )
+ goto _test_eof858;
+case 858:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st858;
+ case 32: goto st858;
+ case 40: goto tr2854;
+ case 41: goto tr2855;
+ case 1034: goto tr2857;
+ case 1083: goto tr2858;
+ }
+ if ( _widec < 65 ) {
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2856;
+ } else if ( _widec > 90 ) {
+ if ( 97 <= _widec && _widec <= 122 )
+ goto tr2856;
+ } else
+ goto tr2856;
+ goto tr71;
+tr2856:
+ { p--; {stack[top++] = 859;goto st487;} }
+ goto st859;
+st859:
+ if ( ++p == pe )
+ goto _test_eof859;
+case 859:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st860;
+ case 32: goto st860;
+ case 40: goto tr2860;
+ case 41: goto tr2861;
+ case 1034: goto tr2862;
+ case 1083: goto tr2863;
+ }
+ goto tr71;
+tr2860:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st860;
+tr2861:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st860;
+tr2862:
+ {
+ s->line_counter++;
+ }
+ goto st860;
+tr2951:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st860;
+st860:
+ if ( ++p == pe )
+ goto _test_eof860;
+case 860:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st860;
+ case 32: goto st860;
+ case 40: goto tr2860;
+ case 41: goto tr2861;
+ case 1034: goto tr2862;
+ case 1083: goto tr2863;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2864;
+ goto tr1885;
+tr2864:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st861;
+tr2868:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st861;
+st861:
+ if ( ++p == pe )
+ goto _test_eof861;
+case 861:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2865;
+ case 32: goto tr2865;
+ case 40: goto tr2866;
+ case 41: goto tr2867;
+ case 1034: goto tr2869;
+ case 1083: goto tr2870;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2868;
+ goto tr1885;
+tr2872:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st862;
+tr2873:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st862;
+tr2875:
+ {
+ s->line_counter++;
+ }
+ goto st862;
+tr2949:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st862;
+tr2865:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st862;
+tr2866:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st862;
+tr2867:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st862;
+tr2869:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st862;
+st862:
+ if ( ++p == pe )
+ goto _test_eof862;
+case 862:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st862;
+ case 32: goto st862;
+ case 40: goto tr2872;
+ case 41: goto tr2873;
+ case 1034: goto tr2875;
+ case 1083: goto tr2876;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2874;
+ goto tr1885;
+tr2874:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st863;
+tr2880:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st863;
+st863:
+ if ( ++p == pe )
+ goto _test_eof863;
+case 863:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2877;
+ case 32: goto tr2877;
+ case 40: goto tr2878;
+ case 41: goto tr2879;
+ case 1034: goto tr2881;
+ case 1083: goto tr2882;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2880;
+ goto tr1885;
+tr2885:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st864;
+tr2886:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st864;
+tr2888:
+ {
+ s->line_counter++;
+ }
+ goto st864;
+tr2947:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st864;
+tr2877:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st864;
+tr2878:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st864;
+tr2879:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st864;
+tr2881:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st864;
+st864:
+ if ( ++p == pe )
+ goto _test_eof864;
+case 864:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st864;
+ case 32: goto st864;
+ case 40: goto tr2885;
+ case 41: goto tr2886;
+ case 1034: goto tr2888;
+ case 1083: goto tr2889;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2887;
+ goto tr2883;
+tr2887:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st865;
+tr2893:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st865;
+st865:
+ if ( ++p == pe )
+ goto _test_eof865;
+case 865:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2890;
+ case 32: goto tr2890;
+ case 40: goto tr2891;
+ case 41: goto tr2892;
+ case 1034: goto tr2894;
+ case 1083: goto tr2895;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2893;
+ goto tr2883;
+tr2897:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st866;
+tr2898:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st866;
+tr2900:
+ {
+ s->line_counter++;
+ }
+ goto st866;
+tr2945:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st866;
+tr2890:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (s->buffer_length == 14) { // Date; 14 = len("YYYYMMDDHHmmSS").
+ uint32_t timestamp;
+ int ret = date_to_timestamp(s->buffer, &timestamp);
+
+ if (ret == ZS_OK) {
+ *((uint32_t *)rdata_tail) = htonl(timestamp);
+ rdata_tail += 4;
+ } else {
+ WARN(ret);
+ p--; {goto st268;}
+ }
+ } else if (s->buffer_length <= 10) { // Timestamp format.
+ char *end;
+
+ s->number64 = strtoull((char *)(s->buffer), &end, 10);
+
+ if (end == (char *)(s->buffer) || *end != '\0') {
+ WARN(ZS_BAD_TIMESTAMP);
+ p--; {goto st268;}
+ }
+
+ if (s->number64 <= UINT32_MAX) {
+ *((uint32_t *)rdata_tail) = htonl((uint32_t)s->number64);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ } else {
+ WARN(ZS_BAD_TIMESTAMP_LENGTH);
+ p--; {goto st268;}
+ }
+ }
+ goto st866;
+tr2891:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (s->buffer_length == 14) { // Date; 14 = len("YYYYMMDDHHmmSS").
+ uint32_t timestamp;
+ int ret = date_to_timestamp(s->buffer, &timestamp);
+
+ if (ret == ZS_OK) {
+ *((uint32_t *)rdata_tail) = htonl(timestamp);
+ rdata_tail += 4;
+ } else {
+ WARN(ret);
+ p--; {goto st268;}
+ }
+ } else if (s->buffer_length <= 10) { // Timestamp format.
+ char *end;
+
+ s->number64 = strtoull((char *)(s->buffer), &end, 10);
+
+ if (end == (char *)(s->buffer) || *end != '\0') {
+ WARN(ZS_BAD_TIMESTAMP);
+ p--; {goto st268;}
+ }
+
+ if (s->number64 <= UINT32_MAX) {
+ *((uint32_t *)rdata_tail) = htonl((uint32_t)s->number64);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ } else {
+ WARN(ZS_BAD_TIMESTAMP_LENGTH);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st866;
+tr2892:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (s->buffer_length == 14) { // Date; 14 = len("YYYYMMDDHHmmSS").
+ uint32_t timestamp;
+ int ret = date_to_timestamp(s->buffer, &timestamp);
+
+ if (ret == ZS_OK) {
+ *((uint32_t *)rdata_tail) = htonl(timestamp);
+ rdata_tail += 4;
+ } else {
+ WARN(ret);
+ p--; {goto st268;}
+ }
+ } else if (s->buffer_length <= 10) { // Timestamp format.
+ char *end;
+
+ s->number64 = strtoull((char *)(s->buffer), &end, 10);
+
+ if (end == (char *)(s->buffer) || *end != '\0') {
+ WARN(ZS_BAD_TIMESTAMP);
+ p--; {goto st268;}
+ }
+
+ if (s->number64 <= UINT32_MAX) {
+ *((uint32_t *)rdata_tail) = htonl((uint32_t)s->number64);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ } else {
+ WARN(ZS_BAD_TIMESTAMP_LENGTH);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st866;
+tr2894:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (s->buffer_length == 14) { // Date; 14 = len("YYYYMMDDHHmmSS").
+ uint32_t timestamp;
+ int ret = date_to_timestamp(s->buffer, &timestamp);
+
+ if (ret == ZS_OK) {
+ *((uint32_t *)rdata_tail) = htonl(timestamp);
+ rdata_tail += 4;
+ } else {
+ WARN(ret);
+ p--; {goto st268;}
+ }
+ } else if (s->buffer_length <= 10) { // Timestamp format.
+ char *end;
+
+ s->number64 = strtoull((char *)(s->buffer), &end, 10);
+
+ if (end == (char *)(s->buffer) || *end != '\0') {
+ WARN(ZS_BAD_TIMESTAMP);
+ p--; {goto st268;}
+ }
+
+ if (s->number64 <= UINT32_MAX) {
+ *((uint32_t *)rdata_tail) = htonl((uint32_t)s->number64);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ } else {
+ WARN(ZS_BAD_TIMESTAMP_LENGTH);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st866;
+st866:
+ if ( ++p == pe )
+ goto _test_eof866;
+case 866:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st866;
+ case 32: goto st866;
+ case 40: goto tr2897;
+ case 41: goto tr2898;
+ case 1034: goto tr2900;
+ case 1083: goto tr2901;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2899;
+ goto tr2883;
+tr2899:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st867;
+tr2905:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st867;
+st867:
+ if ( ++p == pe )
+ goto _test_eof867;
+case 867:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2902;
+ case 32: goto tr2902;
+ case 40: goto tr2903;
+ case 41: goto tr2904;
+ case 1034: goto tr2906;
+ case 1083: goto tr2907;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2905;
+ goto tr2883;
+tr2909:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st868;
+tr2910:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st868;
+tr2912:
+ {
+ s->line_counter++;
+ }
+ goto st868;
+tr2943:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st868;
+tr2902:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (s->buffer_length == 14) { // Date; 14 = len("YYYYMMDDHHmmSS").
+ uint32_t timestamp;
+ int ret = date_to_timestamp(s->buffer, &timestamp);
+
+ if (ret == ZS_OK) {
+ *((uint32_t *)rdata_tail) = htonl(timestamp);
+ rdata_tail += 4;
+ } else {
+ WARN(ret);
+ p--; {goto st268;}
+ }
+ } else if (s->buffer_length <= 10) { // Timestamp format.
+ char *end;
+
+ s->number64 = strtoull((char *)(s->buffer), &end, 10);
+
+ if (end == (char *)(s->buffer) || *end != '\0') {
+ WARN(ZS_BAD_TIMESTAMP);
+ p--; {goto st268;}
+ }
+
+ if (s->number64 <= UINT32_MAX) {
+ *((uint32_t *)rdata_tail) = htonl((uint32_t)s->number64);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ } else {
+ WARN(ZS_BAD_TIMESTAMP_LENGTH);
+ p--; {goto st268;}
+ }
+ }
+ goto st868;
+tr2903:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (s->buffer_length == 14) { // Date; 14 = len("YYYYMMDDHHmmSS").
+ uint32_t timestamp;
+ int ret = date_to_timestamp(s->buffer, &timestamp);
+
+ if (ret == ZS_OK) {
+ *((uint32_t *)rdata_tail) = htonl(timestamp);
+ rdata_tail += 4;
+ } else {
+ WARN(ret);
+ p--; {goto st268;}
+ }
+ } else if (s->buffer_length <= 10) { // Timestamp format.
+ char *end;
+
+ s->number64 = strtoull((char *)(s->buffer), &end, 10);
+
+ if (end == (char *)(s->buffer) || *end != '\0') {
+ WARN(ZS_BAD_TIMESTAMP);
+ p--; {goto st268;}
+ }
+
+ if (s->number64 <= UINT32_MAX) {
+ *((uint32_t *)rdata_tail) = htonl((uint32_t)s->number64);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ } else {
+ WARN(ZS_BAD_TIMESTAMP_LENGTH);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st868;
+tr2904:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (s->buffer_length == 14) { // Date; 14 = len("YYYYMMDDHHmmSS").
+ uint32_t timestamp;
+ int ret = date_to_timestamp(s->buffer, &timestamp);
+
+ if (ret == ZS_OK) {
+ *((uint32_t *)rdata_tail) = htonl(timestamp);
+ rdata_tail += 4;
+ } else {
+ WARN(ret);
+ p--; {goto st268;}
+ }
+ } else if (s->buffer_length <= 10) { // Timestamp format.
+ char *end;
+
+ s->number64 = strtoull((char *)(s->buffer), &end, 10);
+
+ if (end == (char *)(s->buffer) || *end != '\0') {
+ WARN(ZS_BAD_TIMESTAMP);
+ p--; {goto st268;}
+ }
+
+ if (s->number64 <= UINT32_MAX) {
+ *((uint32_t *)rdata_tail) = htonl((uint32_t)s->number64);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ } else {
+ WARN(ZS_BAD_TIMESTAMP_LENGTH);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st868;
+tr2906:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (s->buffer_length == 14) { // Date; 14 = len("YYYYMMDDHHmmSS").
+ uint32_t timestamp;
+ int ret = date_to_timestamp(s->buffer, &timestamp);
+
+ if (ret == ZS_OK) {
+ *((uint32_t *)rdata_tail) = htonl(timestamp);
+ rdata_tail += 4;
+ } else {
+ WARN(ret);
+ p--; {goto st268;}
+ }
+ } else if (s->buffer_length <= 10) { // Timestamp format.
+ char *end;
+
+ s->number64 = strtoull((char *)(s->buffer), &end, 10);
+
+ if (end == (char *)(s->buffer) || *end != '\0') {
+ WARN(ZS_BAD_TIMESTAMP);
+ p--; {goto st268;}
+ }
+
+ if (s->number64 <= UINT32_MAX) {
+ *((uint32_t *)rdata_tail) = htonl((uint32_t)s->number64);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ } else {
+ WARN(ZS_BAD_TIMESTAMP_LENGTH);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st868;
+st868:
+ if ( ++p == pe )
+ goto _test_eof868;
+case 868:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st868;
+ case 32: goto st868;
+ case 40: goto tr2909;
+ case 41: goto tr2910;
+ case 1034: goto tr2912;
+ case 1083: goto tr2913;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2911;
+ goto tr1885;
+tr2911:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st869;
+tr2917:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st869;
+st869:
+ if ( ++p == pe )
+ goto _test_eof869;
+case 869:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2914;
+ case 32: goto tr2914;
+ case 40: goto tr2915;
+ case 41: goto tr2916;
+ case 1034: goto tr2918;
+ case 1083: goto tr2919;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr2917;
+ goto tr1885;
+tr2921:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st870;
+tr2922:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st870;
+tr2924:
+ {
+ s->line_counter++;
+ }
+ goto st870;
+tr2941:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st870;
+tr2914:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st870;
+tr2915:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st870;
+tr2916:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st870;
+tr2918:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st870;
+st870:
+ if ( ++p == pe )
+ goto _test_eof870;
+case 870:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st870;
+ case 32: goto st870;
+ case 40: goto tr2921;
+ case 41: goto tr2922;
+ case 42: goto tr2923;
+ case 92: goto tr2923;
+ case 95: goto tr2923;
+ case 1034: goto tr2924;
+ case 1083: goto tr2925;
+ }
+ if ( _widec < 64 ) {
+ if ( 45 <= _widec && _widec <= 57 )
+ goto tr2923;
+ } else if ( _widec > 90 ) {
+ if ( 97 <= _widec && _widec <= 122 )
+ goto tr2923;
+ } else
+ goto tr2923;
+ goto tr71;
+tr2923:
+ {
+ s->dname = rdata_tail;
+ }
+ { p--; {stack[top++] = 871;goto st270;} }
+ goto st871;
+st871:
+ if ( ++p == pe )
+ goto _test_eof871;
+case 871:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2926;
+ case 32: goto tr2926;
+ case 40: goto tr2927;
+ case 41: goto tr2928;
+ case 1034: goto tr2929;
+ case 1083: goto tr2930;
+ }
+ goto tr71;
+tr2932:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st872;
+tr2933:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st872;
+tr2935:
+ {
+ s->line_counter++;
+ }
+ goto st872;
+tr2939:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st872;
+tr2926:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ goto st872;
+tr2927:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st872;
+tr2928:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st872;
+tr2929:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st872;
+st872:
+ if ( ++p == pe )
+ goto _test_eof872;
+case 872:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st872;
+ case 32: goto st872;
+ case 40: goto tr2932;
+ case 41: goto tr2933;
+ case 43: goto tr2934;
+ case 1034: goto tr2935;
+ case 1083: goto tr2936;
+ }
+ if ( _widec < 65 ) {
+ if ( 47 <= _widec && _widec <= 57 )
+ goto tr2934;
+ } else if ( _widec > 90 ) {
+ if ( 97 <= _widec && _widec <= 122 )
+ goto tr2934;
+ } else
+ goto tr2934;
+ goto tr71;
+tr2934:
+ { p--; {stack[top++] = 873;goto st329;} }
+ goto st873;
+st873:
+ if ( ++p == pe )
+ goto _test_eof873;
+case 873:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1152 + ((*p) - -128));
+ if (
+ !s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1152 + ((*p) - -128));
+ if (
+ !s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 1546: goto tr2937;
+ case 1595: goto tr2937;
+ }
+ goto tr71;
+tr2937:
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1199;
+st1199:
+ if ( ++p == pe )
+ goto _test_eof1199;
+case 1199:
+ goto st0;
+tr2936:
+ {
+ s->buffer_length = 0;
+ }
+ goto st874;
+tr2938:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st874;
+tr2930:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st874;
+st874:
+ if ( ++p == pe )
+ goto _test_eof874;
+case 874:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2939;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2938;
+ goto tr71;
+tr2925:
+ {
+ s->buffer_length = 0;
+ }
+ goto st875;
+tr2940:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st875;
+tr2919:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st875;
+st875:
+ if ( ++p == pe )
+ goto _test_eof875;
+case 875:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2941;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2940;
+ goto tr71;
+tr2913:
+ {
+ s->buffer_length = 0;
+ }
+ goto st876;
+tr2942:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st876;
+tr2907:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (s->buffer_length == 14) { // Date; 14 = len("YYYYMMDDHHmmSS").
+ uint32_t timestamp;
+ int ret = date_to_timestamp(s->buffer, &timestamp);
+
+ if (ret == ZS_OK) {
+ *((uint32_t *)rdata_tail) = htonl(timestamp);
+ rdata_tail += 4;
+ } else {
+ WARN(ret);
+ p--; {goto st268;}
+ }
+ } else if (s->buffer_length <= 10) { // Timestamp format.
+ char *end;
+
+ s->number64 = strtoull((char *)(s->buffer), &end, 10);
+
+ if (end == (char *)(s->buffer) || *end != '\0') {
+ WARN(ZS_BAD_TIMESTAMP);
+ p--; {goto st268;}
+ }
+
+ if (s->number64 <= UINT32_MAX) {
+ *((uint32_t *)rdata_tail) = htonl((uint32_t)s->number64);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ } else {
+ WARN(ZS_BAD_TIMESTAMP_LENGTH);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st876;
+st876:
+ if ( ++p == pe )
+ goto _test_eof876;
+case 876:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2943;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2942;
+ goto tr71;
+tr2901:
+ {
+ s->buffer_length = 0;
+ }
+ goto st877;
+tr2944:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st877;
+tr2895:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (s->buffer_length == 14) { // Date; 14 = len("YYYYMMDDHHmmSS").
+ uint32_t timestamp;
+ int ret = date_to_timestamp(s->buffer, &timestamp);
+
+ if (ret == ZS_OK) {
+ *((uint32_t *)rdata_tail) = htonl(timestamp);
+ rdata_tail += 4;
+ } else {
+ WARN(ret);
+ p--; {goto st268;}
+ }
+ } else if (s->buffer_length <= 10) { // Timestamp format.
+ char *end;
+
+ s->number64 = strtoull((char *)(s->buffer), &end, 10);
+
+ if (end == (char *)(s->buffer) || *end != '\0') {
+ WARN(ZS_BAD_TIMESTAMP);
+ p--; {goto st268;}
+ }
+
+ if (s->number64 <= UINT32_MAX) {
+ *((uint32_t *)rdata_tail) = htonl((uint32_t)s->number64);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ } else {
+ WARN(ZS_BAD_TIMESTAMP_LENGTH);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st877;
+st877:
+ if ( ++p == pe )
+ goto _test_eof877;
+case 877:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2945;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2944;
+ goto tr71;
+tr2889:
+ {
+ s->buffer_length = 0;
+ }
+ goto st878;
+tr2946:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st878;
+tr2882:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st878;
+st878:
+ if ( ++p == pe )
+ goto _test_eof878;
+case 878:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2947;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2946;
+ goto tr71;
+tr2876:
+ {
+ s->buffer_length = 0;
+ }
+ goto st879;
+tr2948:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st879;
+tr2870:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st879;
+st879:
+ if ( ++p == pe )
+ goto _test_eof879;
+case 879:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2949;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2948;
+ goto tr71;
+tr2863:
+ {
+ s->buffer_length = 0;
+ }
+ goto st880;
+tr2950:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st880;
+st880:
+ if ( ++p == pe )
+ goto _test_eof880;
+case 880:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2951;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2950;
+ goto tr71;
+tr2858:
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr2952:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st881;
+tr3269:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr2852:
+ { type_num(KNOT_RRTYPE_A, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr2960:
+ { type_num(KNOT_RRTYPE_AAAA, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr2968:
+ { type_num(KNOT_RRTYPE_AFSDB, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr2974:
+ { type_num(KNOT_RRTYPE_APL, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr2984:
+ { type_num(KNOT_RRTYPE_CAA, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr2995:
+ { type_num(KNOT_RRTYPE_CDNSKEY, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3000:
+ { type_num(KNOT_RRTYPE_CDS, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3007:
+ { type_num(KNOT_RRTYPE_CERT, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3015:
+ { type_num(KNOT_RRTYPE_CNAME, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3026:
+ { type_num(KNOT_RRTYPE_DHCID, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3035:
+ { type_num(KNOT_RRTYPE_DNAME, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3043:
+ { type_num(KNOT_RRTYPE_DNSKEY, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3048:
+ { type_num(KNOT_RRTYPE_DS, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3058:
+ { type_num(KNOT_RRTYPE_EUI48, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3064:
+ { type_num(KNOT_RRTYPE_EUI64, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3073:
+ { type_num(KNOT_RRTYPE_HINFO, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3085:
+ { type_num(KNOT_RRTYPE_IPSECKEY, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3093:
+ { type_num(KNOT_RRTYPE_KEY, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3098:
+ { type_num(KNOT_RRTYPE_KX, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3108:
+ { type_num(KNOT_RRTYPE_L32, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3114:
+ { type_num(KNOT_RRTYPE_L64, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3120:
+ { type_num(KNOT_RRTYPE_LOC, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3125:
+ { type_num(KNOT_RRTYPE_LP, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3135:
+ { type_num(KNOT_RRTYPE_MINFO, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3140:
+ { type_num(KNOT_RRTYPE_MX, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3151:
+ { type_num(KNOT_RRTYPE_NAPTR, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3157:
+ { type_num(KNOT_RRTYPE_NID, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3163:
+ { type_num(KNOT_RRTYPE_NS, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3170:
+ { type_num(KNOT_RRTYPE_NSEC, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3176:
+ { type_num(KNOT_RRTYPE_NSEC3, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3185:
+ { type_num(KNOT_RRTYPE_NSEC3PARAM, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3192:
+ { type_num(KNOT_RRTYPE_PTR, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3200:
+ { type_num(KNOT_RRTYPE_RP, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3208:
+ { type_num(KNOT_RRTYPE_RRSIG, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3213:
+ { type_num(KNOT_RRTYPE_RT, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3223:
+ { type_num(KNOT_RRTYPE_SOA, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3229:
+ { type_num(KNOT_RRTYPE_SPF, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3235:
+ { type_num(KNOT_RRTYPE_SRV, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3243:
+ { type_num(KNOT_RRTYPE_SSHFP, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3253:
+ { type_num(KNOT_RRTYPE_TLSA, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3259:
+ { type_num(KNOT_RRTYPE_TXT, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+tr3276:
+ { type_num(KNOT_RRTYPE_URI, &rdata_tail); }
+ {
+ s->buffer_length = 0;
+ }
+ goto st881;
+st881:
+ if ( ++p == pe )
+ goto _test_eof881;
+case 881:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr2953;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr2952;
+ goto tr71;
+st882:
+ if ( ++p == pe )
+ goto _test_eof882;
+case 882:
+ switch( (*p) ) {
+ case 65: goto st883;
+ case 97: goto st883;
+ }
+ goto tr2829;
+st883:
+ if ( ++p == pe )
+ goto _test_eof883;
+case 883:
+ switch( (*p) ) {
+ case 65: goto st884;
+ case 97: goto st884;
+ }
+ goto tr2829;
+st884:
+ if ( ++p == pe )
+ goto _test_eof884;
+case 884:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2956;
+ case 32: goto tr2956;
+ case 40: goto tr2957;
+ case 41: goto tr2958;
+ case 1034: goto tr2959;
+ case 1083: goto tr2960;
+ }
+ goto tr2829;
+st885:
+ if ( ++p == pe )
+ goto _test_eof885;
+case 885:
+ switch( (*p) ) {
+ case 83: goto st886;
+ case 115: goto st886;
+ }
+ goto tr2829;
+st886:
+ if ( ++p == pe )
+ goto _test_eof886;
+case 886:
+ switch( (*p) ) {
+ case 68: goto st887;
+ case 100: goto st887;
+ }
+ goto tr2829;
+st887:
+ if ( ++p == pe )
+ goto _test_eof887;
+case 887:
+ switch( (*p) ) {
+ case 66: goto st888;
+ case 98: goto st888;
+ }
+ goto tr2829;
+st888:
+ if ( ++p == pe )
+ goto _test_eof888;
+case 888:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2964;
+ case 32: goto tr2964;
+ case 40: goto tr2965;
+ case 41: goto tr2966;
+ case 1034: goto tr2967;
+ case 1083: goto tr2968;
+ }
+ goto tr2829;
+st889:
+ if ( ++p == pe )
+ goto _test_eof889;
+case 889:
+ switch( (*p) ) {
+ case 76: goto st890;
+ case 108: goto st890;
+ }
+ goto tr2829;
+st890:
+ if ( ++p == pe )
+ goto _test_eof890;
+case 890:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2970;
+ case 32: goto tr2970;
+ case 40: goto tr2971;
+ case 41: goto tr2972;
+ case 1034: goto tr2973;
+ case 1083: goto tr2974;
+ }
+ goto tr2829;
+st891:
+ if ( ++p == pe )
+ goto _test_eof891;
+case 891:
+ switch( (*p) ) {
+ case 65: goto st892;
+ case 68: goto st894;
+ case 69: goto st901;
+ case 78: goto st904;
+ case 97: goto st892;
+ case 100: goto st894;
+ case 101: goto st901;
+ case 110: goto st904;
+ }
+ goto tr2829;
+st892:
+ if ( ++p == pe )
+ goto _test_eof892;
+case 892:
+ switch( (*p) ) {
+ case 65: goto st893;
+ case 97: goto st893;
+ }
+ goto tr2829;
+st893:
+ if ( ++p == pe )
+ goto _test_eof893;
+case 893:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2980;
+ case 32: goto tr2980;
+ case 40: goto tr2981;
+ case 41: goto tr2982;
+ case 1034: goto tr2983;
+ case 1083: goto tr2984;
+ }
+ goto tr2829;
+st894:
+ if ( ++p == pe )
+ goto _test_eof894;
+case 894:
+ switch( (*p) ) {
+ case 78: goto st895;
+ case 83: goto st900;
+ case 110: goto st895;
+ case 115: goto st900;
+ }
+ goto tr2829;
+st895:
+ if ( ++p == pe )
+ goto _test_eof895;
+case 895:
+ switch( (*p) ) {
+ case 83: goto st896;
+ case 115: goto st896;
+ }
+ goto tr2829;
+st896:
+ if ( ++p == pe )
+ goto _test_eof896;
+case 896:
+ switch( (*p) ) {
+ case 75: goto st897;
+ case 107: goto st897;
+ }
+ goto tr2829;
+st897:
+ if ( ++p == pe )
+ goto _test_eof897;
+case 897:
+ switch( (*p) ) {
+ case 69: goto st898;
+ case 101: goto st898;
+ }
+ goto tr2829;
+st898:
+ if ( ++p == pe )
+ goto _test_eof898;
+case 898:
+ switch( (*p) ) {
+ case 89: goto st899;
+ case 121: goto st899;
+ }
+ goto tr2829;
+st899:
+ if ( ++p == pe )
+ goto _test_eof899;
+case 899:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2991;
+ case 32: goto tr2991;
+ case 40: goto tr2992;
+ case 41: goto tr2993;
+ case 1034: goto tr2994;
+ case 1083: goto tr2995;
+ }
+ goto tr2829;
+st900:
+ if ( ++p == pe )
+ goto _test_eof900;
+case 900:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr2996;
+ case 32: goto tr2996;
+ case 40: goto tr2997;
+ case 41: goto tr2998;
+ case 1034: goto tr2999;
+ case 1083: goto tr3000;
+ }
+ goto tr2829;
+st901:
+ if ( ++p == pe )
+ goto _test_eof901;
+case 901:
+ switch( (*p) ) {
+ case 82: goto st902;
+ case 114: goto st902;
+ }
+ goto tr2829;
+st902:
+ if ( ++p == pe )
+ goto _test_eof902;
+case 902:
+ switch( (*p) ) {
+ case 84: goto st903;
+ case 116: goto st903;
+ }
+ goto tr2829;
+st903:
+ if ( ++p == pe )
+ goto _test_eof903;
+case 903:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3003;
+ case 32: goto tr3003;
+ case 40: goto tr3004;
+ case 41: goto tr3005;
+ case 1034: goto tr3006;
+ case 1083: goto tr3007;
+ }
+ goto tr2829;
+st904:
+ if ( ++p == pe )
+ goto _test_eof904;
+case 904:
+ switch( (*p) ) {
+ case 65: goto st905;
+ case 97: goto st905;
+ }
+ goto tr2829;
+st905:
+ if ( ++p == pe )
+ goto _test_eof905;
+case 905:
+ switch( (*p) ) {
+ case 77: goto st906;
+ case 109: goto st906;
+ }
+ goto tr2829;
+st906:
+ if ( ++p == pe )
+ goto _test_eof906;
+case 906:
+ switch( (*p) ) {
+ case 69: goto st907;
+ case 101: goto st907;
+ }
+ goto tr2829;
+st907:
+ if ( ++p == pe )
+ goto _test_eof907;
+case 907:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3011;
+ case 32: goto tr3011;
+ case 40: goto tr3012;
+ case 41: goto tr3013;
+ case 1034: goto tr3014;
+ case 1083: goto tr3015;
+ }
+ goto tr2829;
+st908:
+ if ( ++p == pe )
+ goto _test_eof908;
+case 908:
+ switch( (*p) ) {
+ case 72: goto st909;
+ case 78: goto st913;
+ case 83: goto st921;
+ case 104: goto st909;
+ case 110: goto st913;
+ case 115: goto st921;
+ }
+ goto tr2829;
+st909:
+ if ( ++p == pe )
+ goto _test_eof909;
+case 909:
+ switch( (*p) ) {
+ case 67: goto st910;
+ case 99: goto st910;
+ }
+ goto tr2829;
+st910:
+ if ( ++p == pe )
+ goto _test_eof910;
+case 910:
+ switch( (*p) ) {
+ case 73: goto st911;
+ case 105: goto st911;
+ }
+ goto tr2829;
+st911:
+ if ( ++p == pe )
+ goto _test_eof911;
+case 911:
+ switch( (*p) ) {
+ case 68: goto st912;
+ case 100: goto st912;
+ }
+ goto tr2829;
+st912:
+ if ( ++p == pe )
+ goto _test_eof912;
+case 912:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3022;
+ case 32: goto tr3022;
+ case 40: goto tr3023;
+ case 41: goto tr3024;
+ case 1034: goto tr3025;
+ case 1083: goto tr3026;
+ }
+ goto tr2829;
+st913:
+ if ( ++p == pe )
+ goto _test_eof913;
+case 913:
+ switch( (*p) ) {
+ case 65: goto st914;
+ case 83: goto st917;
+ case 97: goto st914;
+ case 115: goto st917;
+ }
+ goto tr2829;
+st914:
+ if ( ++p == pe )
+ goto _test_eof914;
+case 914:
+ switch( (*p) ) {
+ case 77: goto st915;
+ case 109: goto st915;
+ }
+ goto tr2829;
+st915:
+ if ( ++p == pe )
+ goto _test_eof915;
+case 915:
+ switch( (*p) ) {
+ case 69: goto st916;
+ case 101: goto st916;
+ }
+ goto tr2829;
+st916:
+ if ( ++p == pe )
+ goto _test_eof916;
+case 916:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3031;
+ case 32: goto tr3031;
+ case 40: goto tr3032;
+ case 41: goto tr3033;
+ case 1034: goto tr3034;
+ case 1083: goto tr3035;
+ }
+ goto tr2829;
+st917:
+ if ( ++p == pe )
+ goto _test_eof917;
+case 917:
+ switch( (*p) ) {
+ case 75: goto st918;
+ case 107: goto st918;
+ }
+ goto tr2829;
+st918:
+ if ( ++p == pe )
+ goto _test_eof918;
+case 918:
+ switch( (*p) ) {
+ case 69: goto st919;
+ case 101: goto st919;
+ }
+ goto tr2829;
+st919:
+ if ( ++p == pe )
+ goto _test_eof919;
+case 919:
+ switch( (*p) ) {
+ case 89: goto st920;
+ case 121: goto st920;
+ }
+ goto tr2829;
+st920:
+ if ( ++p == pe )
+ goto _test_eof920;
+case 920:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3039;
+ case 32: goto tr3039;
+ case 40: goto tr3040;
+ case 41: goto tr3041;
+ case 1034: goto tr3042;
+ case 1083: goto tr3043;
+ }
+ goto tr2829;
+st921:
+ if ( ++p == pe )
+ goto _test_eof921;
+case 921:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3044;
+ case 32: goto tr3044;
+ case 40: goto tr3045;
+ case 41: goto tr3046;
+ case 1034: goto tr3047;
+ case 1083: goto tr3048;
+ }
+ goto tr2829;
+st922:
+ if ( ++p == pe )
+ goto _test_eof922;
+case 922:
+ switch( (*p) ) {
+ case 85: goto st923;
+ case 117: goto st923;
+ }
+ goto tr2829;
+st923:
+ if ( ++p == pe )
+ goto _test_eof923;
+case 923:
+ switch( (*p) ) {
+ case 73: goto st924;
+ case 105: goto st924;
+ }
+ goto tr2829;
+st924:
+ if ( ++p == pe )
+ goto _test_eof924;
+case 924:
+ switch( (*p) ) {
+ case 52: goto st925;
+ case 54: goto st927;
+ }
+ goto tr2829;
+st925:
+ if ( ++p == pe )
+ goto _test_eof925;
+case 925:
+ if ( (*p) == 56 )
+ goto st926;
+ goto tr2829;
+st926:
+ if ( ++p == pe )
+ goto _test_eof926;
+case 926:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3054;
+ case 32: goto tr3054;
+ case 40: goto tr3055;
+ case 41: goto tr3056;
+ case 1034: goto tr3057;
+ case 1083: goto tr3058;
+ }
+ goto tr2829;
+st927:
+ if ( ++p == pe )
+ goto _test_eof927;
+case 927:
+ if ( (*p) == 52 )
+ goto st928;
+ goto tr2829;
+st928:
+ if ( ++p == pe )
+ goto _test_eof928;
+case 928:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3060;
+ case 32: goto tr3060;
+ case 40: goto tr3061;
+ case 41: goto tr3062;
+ case 1034: goto tr3063;
+ case 1083: goto tr3064;
+ }
+ goto tr2829;
+st929:
+ if ( ++p == pe )
+ goto _test_eof929;
+case 929:
+ switch( (*p) ) {
+ case 73: goto st930;
+ case 105: goto st930;
+ }
+ goto tr2829;
+st930:
+ if ( ++p == pe )
+ goto _test_eof930;
+case 930:
+ switch( (*p) ) {
+ case 78: goto st931;
+ case 110: goto st931;
+ }
+ goto tr2829;
+st931:
+ if ( ++p == pe )
+ goto _test_eof931;
+case 931:
+ switch( (*p) ) {
+ case 70: goto st932;
+ case 102: goto st932;
+ }
+ goto tr2829;
+st932:
+ if ( ++p == pe )
+ goto _test_eof932;
+case 932:
+ switch( (*p) ) {
+ case 79: goto st933;
+ case 111: goto st933;
+ }
+ goto tr2829;
+st933:
+ if ( ++p == pe )
+ goto _test_eof933;
+case 933:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3069;
+ case 32: goto tr3069;
+ case 40: goto tr3070;
+ case 41: goto tr3071;
+ case 1034: goto tr3072;
+ case 1083: goto tr3073;
+ }
+ goto tr2829;
+st934:
+ if ( ++p == pe )
+ goto _test_eof934;
+case 934:
+ switch( (*p) ) {
+ case 80: goto st935;
+ case 112: goto st935;
+ }
+ goto tr2829;
+st935:
+ if ( ++p == pe )
+ goto _test_eof935;
+case 935:
+ switch( (*p) ) {
+ case 83: goto st936;
+ case 115: goto st936;
+ }
+ goto tr2829;
+st936:
+ if ( ++p == pe )
+ goto _test_eof936;
+case 936:
+ switch( (*p) ) {
+ case 69: goto st937;
+ case 101: goto st937;
+ }
+ goto tr2829;
+st937:
+ if ( ++p == pe )
+ goto _test_eof937;
+case 937:
+ switch( (*p) ) {
+ case 67: goto st938;
+ case 99: goto st938;
+ }
+ goto tr2829;
+st938:
+ if ( ++p == pe )
+ goto _test_eof938;
+case 938:
+ switch( (*p) ) {
+ case 75: goto st939;
+ case 107: goto st939;
+ }
+ goto tr2829;
+st939:
+ if ( ++p == pe )
+ goto _test_eof939;
+case 939:
+ switch( (*p) ) {
+ case 69: goto st940;
+ case 101: goto st940;
+ }
+ goto tr2829;
+st940:
+ if ( ++p == pe )
+ goto _test_eof940;
+case 940:
+ switch( (*p) ) {
+ case 89: goto st941;
+ case 121: goto st941;
+ }
+ goto tr2829;
+st941:
+ if ( ++p == pe )
+ goto _test_eof941;
+case 941:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3081;
+ case 32: goto tr3081;
+ case 40: goto tr3082;
+ case 41: goto tr3083;
+ case 1034: goto tr3084;
+ case 1083: goto tr3085;
+ }
+ goto tr2829;
+st942:
+ if ( ++p == pe )
+ goto _test_eof942;
+case 942:
+ switch( (*p) ) {
+ case 69: goto st943;
+ case 88: goto st945;
+ case 101: goto st943;
+ case 120: goto st945;
+ }
+ goto tr2829;
+st943:
+ if ( ++p == pe )
+ goto _test_eof943;
+case 943:
+ switch( (*p) ) {
+ case 89: goto st944;
+ case 121: goto st944;
+ }
+ goto tr2829;
+st944:
+ if ( ++p == pe )
+ goto _test_eof944;
+case 944:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3089;
+ case 32: goto tr3089;
+ case 40: goto tr3090;
+ case 41: goto tr3091;
+ case 1034: goto tr3092;
+ case 1083: goto tr3093;
+ }
+ goto tr2829;
+st945:
+ if ( ++p == pe )
+ goto _test_eof945;
+case 945:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3094;
+ case 32: goto tr3094;
+ case 40: goto tr3095;
+ case 41: goto tr3096;
+ case 1034: goto tr3097;
+ case 1083: goto tr3098;
+ }
+ goto tr2829;
+st946:
+ if ( ++p == pe )
+ goto _test_eof946;
+case 946:
+ switch( (*p) ) {
+ case 51: goto st947;
+ case 54: goto st949;
+ case 79: goto st951;
+ case 80: goto st953;
+ case 111: goto st951;
+ case 112: goto st953;
+ }
+ goto tr2829;
+st947:
+ if ( ++p == pe )
+ goto _test_eof947;
+case 947:
+ if ( (*p) == 50 )
+ goto st948;
+ goto tr2829;
+st948:
+ if ( ++p == pe )
+ goto _test_eof948;
+case 948:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3104;
+ case 32: goto tr3104;
+ case 40: goto tr3105;
+ case 41: goto tr3106;
+ case 1034: goto tr3107;
+ case 1083: goto tr3108;
+ }
+ goto tr2829;
+st949:
+ if ( ++p == pe )
+ goto _test_eof949;
+case 949:
+ if ( (*p) == 52 )
+ goto st950;
+ goto tr2829;
+st950:
+ if ( ++p == pe )
+ goto _test_eof950;
+case 950:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3110;
+ case 32: goto tr3110;
+ case 40: goto tr3111;
+ case 41: goto tr3112;
+ case 1034: goto tr3113;
+ case 1083: goto tr3114;
+ }
+ goto tr2829;
+st951:
+ if ( ++p == pe )
+ goto _test_eof951;
+case 951:
+ switch( (*p) ) {
+ case 67: goto st952;
+ case 99: goto st952;
+ }
+ goto tr2829;
+st952:
+ if ( ++p == pe )
+ goto _test_eof952;
+case 952:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3116;
+ case 32: goto tr3116;
+ case 40: goto tr3117;
+ case 41: goto tr3118;
+ case 1034: goto tr3119;
+ case 1083: goto tr3120;
+ }
+ goto tr2829;
+st953:
+ if ( ++p == pe )
+ goto _test_eof953;
+case 953:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3121;
+ case 32: goto tr3121;
+ case 40: goto tr3122;
+ case 41: goto tr3123;
+ case 1034: goto tr3124;
+ case 1083: goto tr3125;
+ }
+ goto tr2829;
+st954:
+ if ( ++p == pe )
+ goto _test_eof954;
+case 954:
+ switch( (*p) ) {
+ case 73: goto st955;
+ case 88: goto st959;
+ case 105: goto st955;
+ case 120: goto st959;
+ }
+ goto tr2829;
+st955:
+ if ( ++p == pe )
+ goto _test_eof955;
+case 955:
+ switch( (*p) ) {
+ case 78: goto st956;
+ case 110: goto st956;
+ }
+ goto tr2829;
+st956:
+ if ( ++p == pe )
+ goto _test_eof956;
+case 956:
+ switch( (*p) ) {
+ case 70: goto st957;
+ case 102: goto st957;
+ }
+ goto tr2829;
+st957:
+ if ( ++p == pe )
+ goto _test_eof957;
+case 957:
+ switch( (*p) ) {
+ case 79: goto st958;
+ case 111: goto st958;
+ }
+ goto tr2829;
+st958:
+ if ( ++p == pe )
+ goto _test_eof958;
+case 958:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3131;
+ case 32: goto tr3131;
+ case 40: goto tr3132;
+ case 41: goto tr3133;
+ case 1034: goto tr3134;
+ case 1083: goto tr3135;
+ }
+ goto tr2829;
+st959:
+ if ( ++p == pe )
+ goto _test_eof959;
+case 959:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3136;
+ case 32: goto tr3136;
+ case 40: goto tr3137;
+ case 41: goto tr3138;
+ case 1034: goto tr3139;
+ case 1083: goto tr3140;
+ }
+ goto tr2829;
+st960:
+ if ( ++p == pe )
+ goto _test_eof960;
+case 960:
+ switch( (*p) ) {
+ case 65: goto st961;
+ case 73: goto st965;
+ case 83: goto st967;
+ case 97: goto st961;
+ case 105: goto st965;
+ case 115: goto st967;
+ }
+ goto tr2829;
+st961:
+ if ( ++p == pe )
+ goto _test_eof961;
+case 961:
+ switch( (*p) ) {
+ case 80: goto st962;
+ case 112: goto st962;
+ }
+ goto tr2829;
+st962:
+ if ( ++p == pe )
+ goto _test_eof962;
+case 962:
+ switch( (*p) ) {
+ case 84: goto st963;
+ case 116: goto st963;
+ }
+ goto tr2829;
+st963:
+ if ( ++p == pe )
+ goto _test_eof963;
+case 963:
+ switch( (*p) ) {
+ case 82: goto st964;
+ case 114: goto st964;
+ }
+ goto tr2829;
+st964:
+ if ( ++p == pe )
+ goto _test_eof964;
+case 964:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3147;
+ case 32: goto tr3147;
+ case 40: goto tr3148;
+ case 41: goto tr3149;
+ case 1034: goto tr3150;
+ case 1083: goto tr3151;
+ }
+ goto tr2829;
+st965:
+ if ( ++p == pe )
+ goto _test_eof965;
+case 965:
+ switch( (*p) ) {
+ case 68: goto st966;
+ case 100: goto st966;
+ }
+ goto tr2829;
+st966:
+ if ( ++p == pe )
+ goto _test_eof966;
+case 966:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3153;
+ case 32: goto tr3153;
+ case 40: goto tr3154;
+ case 41: goto tr3155;
+ case 1034: goto tr3156;
+ case 1083: goto tr3157;
+ }
+ goto tr2829;
+st967:
+ if ( ++p == pe )
+ goto _test_eof967;
+case 967:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3158;
+ case 32: goto tr3158;
+ case 40: goto tr3159;
+ case 41: goto tr3160;
+ case 69: goto st968;
+ case 101: goto st968;
+ case 1034: goto tr3162;
+ case 1083: goto tr3163;
+ }
+ goto tr2829;
+st968:
+ if ( ++p == pe )
+ goto _test_eof968;
+case 968:
+ switch( (*p) ) {
+ case 67: goto st969;
+ case 99: goto st969;
+ }
+ goto tr2829;
+st969:
+ if ( ++p == pe )
+ goto _test_eof969;
+case 969:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3165;
+ case 32: goto tr3165;
+ case 40: goto tr3166;
+ case 41: goto tr3167;
+ case 51: goto st970;
+ case 1034: goto tr3169;
+ case 1083: goto tr3170;
+ }
+ goto tr2829;
+st970:
+ if ( ++p == pe )
+ goto _test_eof970;
+case 970:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3171;
+ case 32: goto tr3171;
+ case 40: goto tr3172;
+ case 41: goto tr3173;
+ case 80: goto st971;
+ case 112: goto st971;
+ case 1034: goto tr3175;
+ case 1083: goto tr3176;
+ }
+ goto tr2829;
+st971:
+ if ( ++p == pe )
+ goto _test_eof971;
+case 971:
+ switch( (*p) ) {
+ case 65: goto st972;
+ case 97: goto st972;
+ }
+ goto tr2829;
+st972:
+ if ( ++p == pe )
+ goto _test_eof972;
+case 972:
+ switch( (*p) ) {
+ case 82: goto st973;
+ case 114: goto st973;
+ }
+ goto tr2829;
+st973:
+ if ( ++p == pe )
+ goto _test_eof973;
+case 973:
+ switch( (*p) ) {
+ case 65: goto st974;
+ case 97: goto st974;
+ }
+ goto tr2829;
+st974:
+ if ( ++p == pe )
+ goto _test_eof974;
+case 974:
+ switch( (*p) ) {
+ case 77: goto st975;
+ case 109: goto st975;
+ }
+ goto tr2829;
+st975:
+ if ( ++p == pe )
+ goto _test_eof975;
+case 975:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3181;
+ case 32: goto tr3181;
+ case 40: goto tr3182;
+ case 41: goto tr3183;
+ case 1034: goto tr3184;
+ case 1083: goto tr3185;
+ }
+ goto tr2829;
+st976:
+ if ( ++p == pe )
+ goto _test_eof976;
+case 976:
+ switch( (*p) ) {
+ case 84: goto st977;
+ case 116: goto st977;
+ }
+ goto tr2829;
+st977:
+ if ( ++p == pe )
+ goto _test_eof977;
+case 977:
+ switch( (*p) ) {
+ case 82: goto st978;
+ case 114: goto st978;
+ }
+ goto tr2829;
+st978:
+ if ( ++p == pe )
+ goto _test_eof978;
+case 978:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3188;
+ case 32: goto tr3188;
+ case 40: goto tr3189;
+ case 41: goto tr3190;
+ case 1034: goto tr3191;
+ case 1083: goto tr3192;
+ }
+ goto tr2829;
+st979:
+ if ( ++p == pe )
+ goto _test_eof979;
+case 979:
+ switch( (*p) ) {
+ case 80: goto st980;
+ case 82: goto st981;
+ case 84: goto st985;
+ case 112: goto st980;
+ case 114: goto st981;
+ case 116: goto st985;
+ }
+ goto tr2829;
+st980:
+ if ( ++p == pe )
+ goto _test_eof980;
+case 980:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3196;
+ case 32: goto tr3196;
+ case 40: goto tr3197;
+ case 41: goto tr3198;
+ case 1034: goto tr3199;
+ case 1083: goto tr3200;
+ }
+ goto tr2829;
+st981:
+ if ( ++p == pe )
+ goto _test_eof981;
+case 981:
+ switch( (*p) ) {
+ case 83: goto st982;
+ case 115: goto st982;
+ }
+ goto tr2829;
+st982:
+ if ( ++p == pe )
+ goto _test_eof982;
+case 982:
+ switch( (*p) ) {
+ case 73: goto st983;
+ case 105: goto st983;
+ }
+ goto tr2829;
+st983:
+ if ( ++p == pe )
+ goto _test_eof983;
+case 983:
+ switch( (*p) ) {
+ case 71: goto st984;
+ case 103: goto st984;
+ }
+ goto tr2829;
+st984:
+ if ( ++p == pe )
+ goto _test_eof984;
+case 984:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3204;
+ case 32: goto tr3204;
+ case 40: goto tr3205;
+ case 41: goto tr3206;
+ case 1034: goto tr3207;
+ case 1083: goto tr3208;
+ }
+ goto tr2829;
+st985:
+ if ( ++p == pe )
+ goto _test_eof985;
+case 985:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3209;
+ case 32: goto tr3209;
+ case 40: goto tr3210;
+ case 41: goto tr3211;
+ case 1034: goto tr3212;
+ case 1083: goto tr3213;
+ }
+ goto tr2829;
+st986:
+ if ( ++p == pe )
+ goto _test_eof986;
+case 986:
+ switch( (*p) ) {
+ case 79: goto st987;
+ case 80: goto st989;
+ case 82: goto st991;
+ case 83: goto st993;
+ case 111: goto st987;
+ case 112: goto st989;
+ case 114: goto st991;
+ case 115: goto st993;
+ }
+ goto tr2829;
+st987:
+ if ( ++p == pe )
+ goto _test_eof987;
+case 987:
+ switch( (*p) ) {
+ case 65: goto st988;
+ case 97: goto st988;
+ }
+ goto tr2829;
+st988:
+ if ( ++p == pe )
+ goto _test_eof988;
+case 988:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3219;
+ case 32: goto tr3219;
+ case 40: goto tr3220;
+ case 41: goto tr3221;
+ case 1034: goto tr3222;
+ case 1083: goto tr3223;
+ }
+ goto tr2829;
+st989:
+ if ( ++p == pe )
+ goto _test_eof989;
+case 989:
+ switch( (*p) ) {
+ case 70: goto st990;
+ case 102: goto st990;
+ }
+ goto tr2829;
+st990:
+ if ( ++p == pe )
+ goto _test_eof990;
+case 990:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3225;
+ case 32: goto tr3225;
+ case 40: goto tr3226;
+ case 41: goto tr3227;
+ case 1034: goto tr3228;
+ case 1083: goto tr3229;
+ }
+ goto tr2829;
+st991:
+ if ( ++p == pe )
+ goto _test_eof991;
+case 991:
+ switch( (*p) ) {
+ case 86: goto st992;
+ case 118: goto st992;
+ }
+ goto tr2829;
+st992:
+ if ( ++p == pe )
+ goto _test_eof992;
+case 992:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3231;
+ case 32: goto tr3231;
+ case 40: goto tr3232;
+ case 41: goto tr3233;
+ case 1034: goto tr3234;
+ case 1083: goto tr3235;
+ }
+ goto tr2829;
+st993:
+ if ( ++p == pe )
+ goto _test_eof993;
+case 993:
+ switch( (*p) ) {
+ case 72: goto st994;
+ case 104: goto st994;
+ }
+ goto tr2829;
+st994:
+ if ( ++p == pe )
+ goto _test_eof994;
+case 994:
+ switch( (*p) ) {
+ case 70: goto st995;
+ case 102: goto st995;
+ }
+ goto tr2829;
+st995:
+ if ( ++p == pe )
+ goto _test_eof995;
+case 995:
+ switch( (*p) ) {
+ case 80: goto st996;
+ case 112: goto st996;
+ }
+ goto tr2829;
+st996:
+ if ( ++p == pe )
+ goto _test_eof996;
+case 996:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3239;
+ case 32: goto tr3239;
+ case 40: goto tr3240;
+ case 41: goto tr3241;
+ case 1034: goto tr3242;
+ case 1083: goto tr3243;
+ }
+ goto tr2829;
+st997:
+ if ( ++p == pe )
+ goto _test_eof997;
+case 997:
+ switch( (*p) ) {
+ case 76: goto st998;
+ case 88: goto st1001;
+ case 89: goto st1003;
+ case 108: goto st998;
+ case 120: goto st1001;
+ case 121: goto st1003;
+ }
+ goto tr2829;
+st998:
+ if ( ++p == pe )
+ goto _test_eof998;
+case 998:
+ switch( (*p) ) {
+ case 83: goto st999;
+ case 115: goto st999;
+ }
+ goto tr2829;
+st999:
+ if ( ++p == pe )
+ goto _test_eof999;
+case 999:
+ switch( (*p) ) {
+ case 65: goto st1000;
+ case 97: goto st1000;
+ }
+ goto tr2829;
+st1000:
+ if ( ++p == pe )
+ goto _test_eof1000;
+case 1000:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3249;
+ case 32: goto tr3249;
+ case 40: goto tr3250;
+ case 41: goto tr3251;
+ case 1034: goto tr3252;
+ case 1083: goto tr3253;
+ }
+ goto tr2829;
+st1001:
+ if ( ++p == pe )
+ goto _test_eof1001;
+case 1001:
+ switch( (*p) ) {
+ case 84: goto st1002;
+ case 116: goto st1002;
+ }
+ goto tr2829;
+st1002:
+ if ( ++p == pe )
+ goto _test_eof1002;
+case 1002:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3255;
+ case 32: goto tr3255;
+ case 40: goto tr3256;
+ case 41: goto tr3257;
+ case 1034: goto tr3258;
+ case 1083: goto tr3259;
+ }
+ goto tr2829;
+st1003:
+ if ( ++p == pe )
+ goto _test_eof1003;
+case 1003:
+ switch( (*p) ) {
+ case 80: goto st1004;
+ case 112: goto st1004;
+ }
+ goto tr2829;
+st1004:
+ if ( ++p == pe )
+ goto _test_eof1004;
+case 1004:
+ switch( (*p) ) {
+ case 69: goto st1005;
+ case 101: goto st1005;
+ }
+ goto tr2829;
+st1005:
+ if ( ++p == pe )
+ goto _test_eof1005;
+case 1005:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3263;
+ goto tr3262;
+tr3263:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1006;
+tr3267:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1006;
+st1006:
+ if ( ++p == pe )
+ goto _test_eof1006;
+case 1006:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3264;
+ case 32: goto tr3264;
+ case 40: goto tr3265;
+ case 41: goto tr3266;
+ case 1034: goto tr3268;
+ case 1083: goto tr3269;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3267;
+ goto tr3262;
+st1007:
+ if ( ++p == pe )
+ goto _test_eof1007;
+case 1007:
+ switch( (*p) ) {
+ case 82: goto st1008;
+ case 114: goto st1008;
+ }
+ goto tr2829;
+st1008:
+ if ( ++p == pe )
+ goto _test_eof1008;
+case 1008:
+ switch( (*p) ) {
+ case 73: goto st1009;
+ case 105: goto st1009;
+ }
+ goto tr2829;
+st1009:
+ if ( ++p == pe )
+ goto _test_eof1009;
+case 1009:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3272;
+ case 32: goto tr3272;
+ case 40: goto tr3273;
+ case 41: goto tr3274;
+ case 1034: goto tr3275;
+ case 1083: goto tr3276;
+ }
+ goto tr2829;
+st1010:
+ if ( ++p == pe )
+ goto _test_eof1010;
+case 1010:
+ switch( (*p) ) {
+ case 42: goto tr3277;
+ case 92: goto tr3277;
+ case 95: goto tr3277;
+ }
+ if ( (*p) < 64 ) {
+ if ( 45 <= (*p) && (*p) <= 57 )
+ goto tr3277;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr3277;
+ } else
+ goto tr3277;
+ goto tr71;
+tr3277:
+ {
+ s->dname = rdata_tail;
+ }
+ { p--; {stack[top++] = 1011;goto st270;} }
+ goto st1011;
+st1011:
+ if ( ++p == pe )
+ goto _test_eof1011;
+case 1011:
+ switch( (*p) ) {
+ case 32: goto tr3278;
+ case 59: goto tr3278;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr3278;
+ } else if ( (*p) >= 9 )
+ goto tr3278;
+ goto tr71;
+tr3278:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ { p--; {stack[top++] = 1012;goto st336;} }
+ goto st1012;
+st1012:
+ if ( ++p == pe )
+ goto _test_eof1012;
+case 1012:
+ switch( (*p) ) {
+ case 32: goto tr3279;
+ case 59: goto tr3279;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr3279;
+ } else if ( (*p) >= 9 )
+ goto tr3279;
+ goto tr71;
+tr3279:
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1200;
+st1200:
+ if ( ++p == pe )
+ goto _test_eof1200;
+case 1200:
+ goto st0;
+st1013:
+ if ( ++p == pe )
+ goto _test_eof1013;
+case 1013:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3280;
+ goto tr1885;
+tr3280:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1014;
+tr3284:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1014;
+st1014:
+ if ( ++p == pe )
+ goto _test_eof1014;
+case 1014:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3281;
+ case 32: goto tr3281;
+ case 40: goto tr3282;
+ case 41: goto tr3283;
+ case 1034: goto tr3285;
+ case 1083: goto tr3286;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3284;
+ goto tr1885;
+tr3288:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1015;
+tr3289:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1015;
+tr3291:
+ {
+ s->line_counter++;
+ }
+ goto st1015;
+tr3317:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1015;
+tr3281:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1015;
+tr3282:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1015;
+tr3283:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1015;
+tr3285:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1015;
+st1015:
+ if ( ++p == pe )
+ goto _test_eof1015;
+case 1015:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st1015;
+ case 32: goto st1015;
+ case 40: goto tr3288;
+ case 41: goto tr3289;
+ case 1034: goto tr3291;
+ case 1083: goto tr3292;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3290;
+ goto tr1885;
+tr3290:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1016;
+tr3296:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1016;
+st1016:
+ if ( ++p == pe )
+ goto _test_eof1016;
+case 1016:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3293;
+ case 32: goto tr3293;
+ case 40: goto tr3294;
+ case 41: goto tr3295;
+ case 1034: goto tr3297;
+ case 1083: goto tr3298;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3296;
+ goto tr1885;
+tr3300:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1017;
+tr3301:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1017;
+tr3303:
+ {
+ s->line_counter++;
+ }
+ goto st1017;
+tr3315:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1017;
+tr3293:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1017;
+tr3294:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1017;
+tr3295:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1017;
+tr3297:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1017;
+st1017:
+ if ( ++p == pe )
+ goto _test_eof1017;
+case 1017:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st1017;
+ case 32: goto st1017;
+ case 40: goto tr3300;
+ case 41: goto tr3301;
+ case 1034: goto tr3303;
+ case 1083: goto tr3304;
+ }
+ if ( _widec < 65 ) {
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3302;
+ } else if ( _widec > 90 ) {
+ if ( 97 <= _widec && _widec <= 122 )
+ goto tr3302;
+ } else
+ goto tr3302;
+ goto tr71;
+tr3302:
+ { p--; {stack[top++] = 1018;goto st487;} }
+ goto st1018;
+st1018:
+ if ( ++p == pe )
+ goto _test_eof1018;
+case 1018:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st1019;
+ case 32: goto st1019;
+ case 40: goto tr3306;
+ case 41: goto tr3307;
+ case 1034: goto tr3308;
+ case 1083: goto tr3309;
+ }
+ goto tr71;
+tr3306:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1019;
+tr3307:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1019;
+tr3308:
+ {
+ s->line_counter++;
+ }
+ goto st1019;
+tr3313:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1019;
+st1019:
+ if ( ++p == pe )
+ goto _test_eof1019;
+case 1019:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st1019;
+ case 32: goto st1019;
+ case 40: goto tr3306;
+ case 41: goto tr3307;
+ case 43: goto tr3310;
+ case 1034: goto tr3308;
+ case 1083: goto tr3309;
+ }
+ if ( _widec < 65 ) {
+ if ( 47 <= _widec && _widec <= 57 )
+ goto tr3310;
+ } else if ( _widec > 90 ) {
+ if ( 97 <= _widec && _widec <= 122 )
+ goto tr3310;
+ } else
+ goto tr3310;
+ goto tr71;
+tr3310:
+ { p--; {stack[top++] = 1020;goto st329;} }
+ goto st1020;
+st1020:
+ if ( ++p == pe )
+ goto _test_eof1020;
+case 1020:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1152 + ((*p) - -128));
+ if (
+ !s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1152 + ((*p) - -128));
+ if (
+ !s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 1546: goto tr3311;
+ case 1595: goto tr3311;
+ }
+ goto tr71;
+tr3311:
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1201;
+st1201:
+ if ( ++p == pe )
+ goto _test_eof1201;
+case 1201:
+ goto st0;
+tr3309:
+ {
+ s->buffer_length = 0;
+ }
+ goto st1021;
+tr3312:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st1021;
+st1021:
+ if ( ++p == pe )
+ goto _test_eof1021;
+case 1021:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr3313;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr3312;
+ goto tr71;
+tr3304:
+ {
+ s->buffer_length = 0;
+ }
+ goto st1022;
+tr3314:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st1022;
+tr3298:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st1022;
+st1022:
+ if ( ++p == pe )
+ goto _test_eof1022;
+case 1022:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr3315;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr3314;
+ goto tr71;
+tr3292:
+ {
+ s->buffer_length = 0;
+ }
+ goto st1023;
+tr3316:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st1023;
+tr3286:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st1023;
+st1023:
+ if ( ++p == pe )
+ goto _test_eof1023;
+case 1023:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr3317;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr3316;
+ goto tr71;
+st1024:
+ if ( ++p == pe )
+ goto _test_eof1024;
+case 1024:
+ if ( (*p) == 43 )
+ goto tr3318;
+ if ( (*p) < 65 ) {
+ if ( 47 <= (*p) && (*p) <= 57 )
+ goto tr3318;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr3318;
+ } else
+ goto tr3318;
+ goto tr71;
+tr3318:
+ { p--; {stack[top++] = 1025;goto st329;} }
+ goto st1025;
+st1025:
+ if ( ++p == pe )
+ goto _test_eof1025;
+case 1025:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1152 + ((*p) - -128));
+ if (
+ !s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1152 + ((*p) - -128));
+ if (
+ !s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 1546: goto tr3319;
+ case 1595: goto tr3319;
+ }
+ goto tr71;
+tr3319:
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1202;
+st1202:
+ if ( ++p == pe )
+ goto _test_eof1202;
+case 1202:
+ goto st0;
+st1026:
+ if ( ++p == pe )
+ goto _test_eof1026;
+case 1026:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3320;
+ goto tr1885;
+tr3320:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1027;
+tr3324:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1027;
+st1027:
+ if ( ++p == pe )
+ goto _test_eof1027;
+case 1027:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3321;
+ case 32: goto tr3321;
+ case 40: goto tr3322;
+ case 41: goto tr3323;
+ case 1034: goto tr3325;
+ case 1083: goto tr3326;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3324;
+ goto tr1885;
+tr3328:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1028;
+tr3329:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1028;
+tr3331:
+ {
+ s->line_counter++;
+ }
+ goto st1028;
+tr3395:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1028;
+tr3321:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1028;
+tr3322:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1028;
+tr3323:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1028;
+tr3325:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1028;
+st1028:
+ if ( ++p == pe )
+ goto _test_eof1028;
+case 1028:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st1028;
+ case 32: goto st1028;
+ case 40: goto tr3328;
+ case 41: goto tr3329;
+ case 1034: goto tr3331;
+ case 1083: goto tr3332;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3330;
+ goto tr1885;
+tr3330:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1029;
+tr3336:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1029;
+st1029:
+ if ( ++p == pe )
+ goto _test_eof1029;
+case 1029:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3333;
+ case 32: goto tr3333;
+ case 40: goto tr3334;
+ case 41: goto tr3335;
+ case 1034: goto tr3337;
+ case 1083: goto tr3338;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3336;
+ goto tr1885;
+tr3340:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1030;
+tr3341:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1030;
+tr3343:
+ {
+ s->line_counter++;
+ }
+ goto st1030;
+tr3393:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1030;
+tr3333:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1030;
+tr3334:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1030;
+tr3335:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1030;
+tr3337:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1030;
+st1030:
+ if ( ++p == pe )
+ goto _test_eof1030;
+case 1030:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st1030;
+ case 32: goto st1030;
+ case 40: goto tr3340;
+ case 41: goto tr3341;
+ case 1034: goto tr3343;
+ case 1083: goto tr3344;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3342;
+ goto tr1885;
+tr3342:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1031;
+tr3348:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1031;
+st1031:
+ if ( ++p == pe )
+ goto _test_eof1031;
+case 1031:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3345;
+ case 32: goto tr3345;
+ case 40: goto tr3346;
+ case 41: goto tr3347;
+ case 1034: goto tr3349;
+ case 1083: goto tr3350;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3348;
+ goto tr1885;
+tr3352:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1032;
+tr3353:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1032;
+tr3356:
+ {
+ s->line_counter++;
+ }
+ goto st1032;
+tr3391:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1032;
+tr3345:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1032;
+tr3346:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1032;
+tr3347:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1032;
+tr3349:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1032;
+st1032:
+ if ( ++p == pe )
+ goto _test_eof1032;
+case 1032:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st1032;
+ case 32: goto st1032;
+ case 40: goto tr3352;
+ case 41: goto tr3353;
+ case 45: goto tr3354;
+ case 1034: goto tr3356;
+ case 1083: goto tr3357;
+ }
+ if ( _widec < 65 ) {
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3355;
+ } else if ( _widec > 70 ) {
+ if ( 97 <= _widec && _widec <= 102 )
+ goto tr3355;
+ } else
+ goto tr3355;
+ goto tr2556;
+tr3354:
+ {
+ if (rdata_tail <= rdata_stop) {
+ s->item_length_location = rdata_tail++;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1033;
+st1033:
+ if ( ++p == pe )
+ goto _test_eof1033;
+case 1033:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3358;
+ case 32: goto tr3358;
+ case 40: goto tr3359;
+ case 41: goto tr3360;
+ case 1034: goto tr3361;
+ case 1083: goto tr3362;
+ }
+ goto tr2556;
+tr3365:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1034;
+tr3366:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1034;
+tr3368:
+ {
+ s->line_counter++;
+ }
+ goto st1034;
+tr3387:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1034;
+tr3358:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1034;
+tr3359:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1034;
+tr3360:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1034;
+tr3361:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1034;
+st1034:
+ if ( ++p == pe )
+ goto _test_eof1034;
+case 1034:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st1034;
+ case 32: goto st1034;
+ case 40: goto tr3365;
+ case 41: goto tr3366;
+ case 1034: goto tr3368;
+ case 1083: goto tr3369;
+ }
+ if ( _widec < 65 ) {
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3367;
+ } else if ( _widec > 86 ) {
+ if ( 97 <= _widec && _widec <= 118 )
+ goto tr3367;
+ } else
+ goto tr3367;
+ goto tr3363;
+tr3367:
+ {
+ if (rdata_tail <= rdata_stop) {
+ s->item_length_location = rdata_tail++;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = first_base32hex_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1035;
+tr3382:
+ {
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = first_base32hex_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1035;
+st1035:
+ if ( ++p == pe )
+ goto _test_eof1035;
+case 1035:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3370;
+ } else if ( (*p) > 86 ) {
+ if ( 97 <= (*p) && (*p) <= 118 )
+ goto tr3370;
+ } else
+ goto tr3370;
+ goto tr3363;
+tr3370:
+ {
+ *(rdata_tail++) += second_left_base32hex_to_num[(uint8_t)(*p)];
+
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = second_right_base32hex_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1036;
+st1036:
+ if ( ++p == pe )
+ goto _test_eof1036;
+case 1036:
+ if ( (*p) == 61 )
+ goto st1047;
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3371;
+ } else if ( (*p) > 86 ) {
+ if ( 97 <= (*p) && (*p) <= 118 )
+ goto tr3371;
+ } else
+ goto tr3371;
+ goto tr3363;
+tr3371:
+ {
+ *rdata_tail += third_base32hex_to_num[(uint8_t)(*p)];
+ }
+ goto st1037;
+st1037:
+ if ( ++p == pe )
+ goto _test_eof1037;
+case 1037:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3373;
+ } else if ( (*p) > 86 ) {
+ if ( 97 <= (*p) && (*p) <= 118 )
+ goto tr3373;
+ } else
+ goto tr3373;
+ goto tr3363;
+tr3373:
+ {
+ *(rdata_tail++) += fourth_left_base32hex_to_num[(uint8_t)(*p)];
+
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = fourth_right_base32hex_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1038;
+st1038:
+ if ( ++p == pe )
+ goto _test_eof1038;
+case 1038:
+ if ( (*p) == 61 )
+ goto st1046;
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3374;
+ } else if ( (*p) > 86 ) {
+ if ( 97 <= (*p) && (*p) <= 118 )
+ goto tr3374;
+ } else
+ goto tr3374;
+ goto tr3363;
+tr3374:
+ {
+ *(rdata_tail++) += fifth_left_base32hex_to_num[(uint8_t)(*p)];
+
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = fifth_right_base32hex_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1039;
+st1039:
+ if ( ++p == pe )
+ goto _test_eof1039;
+case 1039:
+ if ( (*p) == 61 )
+ goto st1044;
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3376;
+ } else if ( (*p) > 86 ) {
+ if ( 97 <= (*p) && (*p) <= 118 )
+ goto tr3376;
+ } else
+ goto tr3376;
+ goto tr3363;
+tr3376:
+ {
+ *rdata_tail += sixth_base32hex_to_num[(uint8_t)(*p)];
+ }
+ goto st1040;
+st1040:
+ if ( ++p == pe )
+ goto _test_eof1040;
+case 1040:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3378;
+ } else if ( (*p) > 86 ) {
+ if ( 97 <= (*p) && (*p) <= 118 )
+ goto tr3378;
+ } else
+ goto tr3378;
+ goto tr3363;
+tr3378:
+ {
+ *(rdata_tail++) += seventh_left_base32hex_to_num[(uint8_t)(*p)];
+
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = seventh_right_base32hex_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1041;
+st1041:
+ if ( ++p == pe )
+ goto _test_eof1041;
+case 1041:
+ if ( (*p) == 61 )
+ goto st1042;
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3379;
+ } else if ( (*p) > 86 ) {
+ if ( 97 <= (*p) && (*p) <= 118 )
+ goto tr3379;
+ } else
+ goto tr3379;
+ goto tr3363;
+tr3379:
+ {
+ *(rdata_tail++) += eighth_base32hex_to_num[(uint8_t)(*p)];
+ }
+ goto st1042;
+st1042:
+ if ( ++p == pe )
+ goto _test_eof1042;
+case 1042:
+ switch( (*p) ) {
+ case 32: goto tr3381;
+ case 59: goto tr3381;
+ }
+ if ( (*p) < 48 ) {
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr3381;
+ } else if ( (*p) >= 9 )
+ goto tr3381;
+ } else if ( (*p) > 57 ) {
+ if ( (*p) > 86 ) {
+ if ( 97 <= (*p) && (*p) <= 118 )
+ goto tr3382;
+ } else if ( (*p) >= 65 )
+ goto tr3382;
+ } else
+ goto tr3382;
+ goto tr3363;
+tr3381:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ { p--; {stack[top++] = 1043;goto st336;} }
+ goto st1043;
+st1043:
+ if ( ++p == pe )
+ goto _test_eof1043;
+case 1043:
+ switch( (*p) ) {
+ case 32: goto tr3383;
+ case 59: goto tr3383;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr3383;
+ } else if ( (*p) >= 9 )
+ goto tr3383;
+ goto tr71;
+tr3383:
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1203;
+st1203:
+ if ( ++p == pe )
+ goto _test_eof1203;
+case 1203:
+ goto st0;
+st1044:
+ if ( ++p == pe )
+ goto _test_eof1044;
+case 1044:
+ if ( (*p) == 61 )
+ goto st1045;
+ goto tr3363;
+st1045:
+ if ( ++p == pe )
+ goto _test_eof1045;
+case 1045:
+ if ( (*p) == 61 )
+ goto st1042;
+ goto tr3363;
+st1046:
+ if ( ++p == pe )
+ goto _test_eof1046;
+case 1046:
+ if ( (*p) == 61 )
+ goto st1044;
+ goto tr3363;
+st1047:
+ if ( ++p == pe )
+ goto _test_eof1047;
+case 1047:
+ if ( (*p) == 61 )
+ goto st1048;
+ goto tr3363;
+st1048:
+ if ( ++p == pe )
+ goto _test_eof1048;
+case 1048:
+ if ( (*p) == 61 )
+ goto st1046;
+ goto tr3363;
+tr3369:
+ {
+ s->buffer_length = 0;
+ }
+ goto st1049;
+tr3386:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st1049;
+tr3362:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st1049;
+st1049:
+ if ( ++p == pe )
+ goto _test_eof1049;
+case 1049:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr3387;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr3386;
+ goto tr71;
+tr3389:
+ {
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = first_hex_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1050;
+tr3355:
+ {
+ if (rdata_tail <= rdata_stop) {
+ s->item_length_location = rdata_tail++;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = first_hex_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1050;
+st1050:
+ if ( ++p == pe )
+ goto _test_eof1050;
+case 1050:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3388;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto tr3388;
+ } else
+ goto tr3388;
+ goto tr2556;
+tr3388:
+ {
+ *rdata_tail += second_hex_to_num[(uint8_t)(*p)];
+ rdata_tail++;
+ }
+ goto st1051;
+st1051:
+ if ( ++p == pe )
+ goto _test_eof1051;
+case 1051:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3358;
+ case 32: goto tr3358;
+ case 40: goto tr3359;
+ case 41: goto tr3360;
+ case 1034: goto tr3361;
+ case 1083: goto tr3362;
+ }
+ if ( _widec < 65 ) {
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3389;
+ } else if ( _widec > 70 ) {
+ if ( 97 <= _widec && _widec <= 102 )
+ goto tr3389;
+ } else
+ goto tr3389;
+ goto tr2556;
+tr3357:
+ {
+ s->buffer_length = 0;
+ }
+ goto st1052;
+tr3390:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st1052;
+tr3350:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st1052;
+st1052:
+ if ( ++p == pe )
+ goto _test_eof1052;
+case 1052:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr3391;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr3390;
+ goto tr71;
+tr3344:
+ {
+ s->buffer_length = 0;
+ }
+ goto st1053;
+tr3392:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st1053;
+tr3338:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st1053;
+st1053:
+ if ( ++p == pe )
+ goto _test_eof1053;
+case 1053:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr3393;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr3392;
+ goto tr71;
+tr3332:
+ {
+ s->buffer_length = 0;
+ }
+ goto st1054;
+tr3394:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st1054;
+tr3326:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st1054;
+st1054:
+ if ( ++p == pe )
+ goto _test_eof1054;
+case 1054:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr3395;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr3394;
+ goto tr71;
+st1055:
+ if ( ++p == pe )
+ goto _test_eof1055;
+case 1055:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3396;
+ goto tr1885;
+tr3396:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1056;
+tr3400:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1056;
+st1056:
+ if ( ++p == pe )
+ goto _test_eof1056;
+case 1056:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3397;
+ case 32: goto tr3397;
+ case 40: goto tr3398;
+ case 41: goto tr3399;
+ case 1034: goto tr3401;
+ case 1083: goto tr3402;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3400;
+ goto tr1885;
+tr3404:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1057;
+tr3405:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1057;
+tr3407:
+ {
+ s->line_counter++;
+ }
+ goto st1057;
+tr3442:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1057;
+tr3397:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1057;
+tr3398:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1057;
+tr3399:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1057;
+tr3401:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1057;
+st1057:
+ if ( ++p == pe )
+ goto _test_eof1057;
+case 1057:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st1057;
+ case 32: goto st1057;
+ case 40: goto tr3404;
+ case 41: goto tr3405;
+ case 1034: goto tr3407;
+ case 1083: goto tr3408;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3406;
+ goto tr1885;
+tr3406:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1058;
+tr3412:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1058;
+st1058:
+ if ( ++p == pe )
+ goto _test_eof1058;
+case 1058:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3409;
+ case 32: goto tr3409;
+ case 40: goto tr3410;
+ case 41: goto tr3411;
+ case 1034: goto tr3413;
+ case 1083: goto tr3414;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3412;
+ goto tr1885;
+tr3416:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1059;
+tr3417:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1059;
+tr3419:
+ {
+ s->line_counter++;
+ }
+ goto st1059;
+tr3440:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1059;
+tr3409:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1059;
+tr3410:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1059;
+tr3411:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1059;
+tr3413:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1059;
+st1059:
+ if ( ++p == pe )
+ goto _test_eof1059;
+case 1059:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st1059;
+ case 32: goto st1059;
+ case 40: goto tr3416;
+ case 41: goto tr3417;
+ case 1034: goto tr3419;
+ case 1083: goto tr3420;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3418;
+ goto tr1885;
+tr3418:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1060;
+tr3424:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1060;
+st1060:
+ if ( ++p == pe )
+ goto _test_eof1060;
+case 1060:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3421;
+ case 32: goto tr3421;
+ case 40: goto tr3422;
+ case 41: goto tr3423;
+ case 1034: goto tr3425;
+ case 1083: goto tr3426;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3424;
+ goto tr1885;
+tr3428:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1061;
+tr3429:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1061;
+tr3432:
+ {
+ s->line_counter++;
+ }
+ goto st1061;
+tr3438:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1061;
+tr3421:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1061;
+tr3422:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1061;
+tr3423:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1061;
+tr3425:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1061;
+st1061:
+ if ( ++p == pe )
+ goto _test_eof1061;
+case 1061:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st1061;
+ case 32: goto st1061;
+ case 40: goto tr3428;
+ case 41: goto tr3429;
+ case 45: goto tr3430;
+ case 1034: goto tr3432;
+ case 1083: goto tr3433;
+ }
+ if ( _widec < 65 ) {
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3431;
+ } else if ( _widec > 70 ) {
+ if ( 97 <= _widec && _widec <= 102 )
+ goto tr3431;
+ } else
+ goto tr3431;
+ goto tr2556;
+tr3430:
+ {
+ if (rdata_tail <= rdata_stop) {
+ s->item_length_location = rdata_tail++;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1062;
+st1062:
+ if ( ++p == pe )
+ goto _test_eof1062;
+case 1062:
+ switch( (*p) ) {
+ case 32: goto tr3434;
+ case 59: goto tr3434;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr3434;
+ } else if ( (*p) >= 9 )
+ goto tr3434;
+ goto tr2556;
+tr3434:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1204;
+st1204:
+ if ( ++p == pe )
+ goto _test_eof1204;
+case 1204:
+ goto st0;
+tr3436:
+ {
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = first_hex_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1063;
+tr3431:
+ {
+ if (rdata_tail <= rdata_stop) {
+ s->item_length_location = rdata_tail++;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = first_hex_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1063;
+st1063:
+ if ( ++p == pe )
+ goto _test_eof1063;
+case 1063:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3435;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto tr3435;
+ } else
+ goto tr3435;
+ goto tr2556;
+tr3435:
+ {
+ *rdata_tail += second_hex_to_num[(uint8_t)(*p)];
+ rdata_tail++;
+ }
+ goto st1064;
+st1064:
+ if ( ++p == pe )
+ goto _test_eof1064;
+case 1064:
+ switch( (*p) ) {
+ case 32: goto tr3434;
+ case 59: goto tr3434;
+ }
+ if ( (*p) < 48 ) {
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr3434;
+ } else if ( (*p) >= 9 )
+ goto tr3434;
+ } else if ( (*p) > 57 ) {
+ if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto tr3436;
+ } else if ( (*p) >= 65 )
+ goto tr3436;
+ } else
+ goto tr3436;
+ goto tr2556;
+tr3433:
+ {
+ s->buffer_length = 0;
+ }
+ goto st1065;
+tr3437:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st1065;
+tr3426:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st1065;
+st1065:
+ if ( ++p == pe )
+ goto _test_eof1065;
+case 1065:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr3438;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr3437;
+ goto tr71;
+tr3420:
+ {
+ s->buffer_length = 0;
+ }
+ goto st1066;
+tr3439:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st1066;
+tr3414:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st1066;
+st1066:
+ if ( ++p == pe )
+ goto _test_eof1066;
+case 1066:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr3440;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr3439;
+ goto tr71;
+tr3408:
+ {
+ s->buffer_length = 0;
+ }
+ goto st1067;
+tr3441:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st1067;
+tr3402:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st1067;
+st1067:
+ if ( ++p == pe )
+ goto _test_eof1067;
+case 1067:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr3442;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr3441;
+ goto tr71;
+st1068:
+ if ( ++p == pe )
+ goto _test_eof1068;
+case 1068:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3443;
+ goto tr1885;
+tr3443:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1069;
+tr3447:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1069;
+st1069:
+ if ( ++p == pe )
+ goto _test_eof1069;
+case 1069:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3444;
+ case 32: goto tr3444;
+ case 40: goto tr3445;
+ case 41: goto tr3446;
+ case 1034: goto tr3448;
+ case 1083: goto tr3449;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3447;
+ goto tr1885;
+tr3451:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1070;
+tr3452:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1070;
+tr3454:
+ {
+ s->line_counter++;
+ }
+ goto st1070;
+tr3496:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1070;
+tr3444:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1070;
+tr3445:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1070;
+tr3446:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1070;
+tr3448:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1070;
+st1070:
+ if ( ++p == pe )
+ goto _test_eof1070;
+case 1070:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st1070;
+ case 32: goto st1070;
+ case 40: goto tr3451;
+ case 41: goto tr3452;
+ case 1034: goto tr3454;
+ case 1083: goto tr3455;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3453;
+ goto tr1885;
+tr3453:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1071;
+tr3459:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1071;
+st1071:
+ if ( ++p == pe )
+ goto _test_eof1071;
+case 1071:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3456;
+ case 32: goto tr3456;
+ case 40: goto tr3457;
+ case 41: goto tr3458;
+ case 1034: goto tr3460;
+ case 1083: goto tr3461;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3459;
+ goto tr1885;
+tr3463:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1072;
+tr3464:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1072;
+tr3466:
+ {
+ s->line_counter++;
+ }
+ goto st1072;
+tr3494:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1072;
+tr3456:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1072;
+tr3457:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1072;
+tr3458:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1072;
+tr3460:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1072;
+st1072:
+ if ( ++p == pe )
+ goto _test_eof1072;
+case 1072:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st1072;
+ case 32: goto st1072;
+ case 40: goto tr3463;
+ case 41: goto tr3464;
+ case 1034: goto tr3466;
+ case 1083: goto tr3467;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3465;
+ goto tr1885;
+tr3465:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1073;
+tr3471:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1073;
+st1073:
+ if ( ++p == pe )
+ goto _test_eof1073;
+case 1073:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3468;
+ case 32: goto tr3468;
+ case 40: goto tr3469;
+ case 41: goto tr3470;
+ case 1034: goto tr3472;
+ case 1083: goto tr3473;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3471;
+ goto tr1885;
+tr3475:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1074;
+tr3476:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1074;
+tr3478:
+ {
+ s->line_counter++;
+ }
+ goto st1074;
+tr3492:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1074;
+tr3468:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1074;
+tr3469:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1074;
+tr3470:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1074;
+tr3472:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1074;
+st1074:
+ if ( ++p == pe )
+ goto _test_eof1074;
+case 1074:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st1074;
+ case 32: goto st1074;
+ case 40: goto tr3475;
+ case 41: goto tr3476;
+ case 1034: goto tr3478;
+ case 1083: goto tr3479;
+ }
+ if ( _widec < 65 ) {
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3477;
+ } else if ( _widec > 70 ) {
+ if ( 97 <= _widec && _widec <= 102 )
+ goto tr3477;
+ } else
+ goto tr3477;
+ goto tr2556;
+tr3477:
+ {
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = first_hex_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1075;
+st1075:
+ if ( ++p == pe )
+ goto _test_eof1075;
+case 1075:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3480;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto tr3480;
+ } else
+ goto tr3480;
+ goto tr2556;
+tr3482:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1076;
+tr3483:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1076;
+tr3484:
+ {
+ s->line_counter++;
+ }
+ goto st1076;
+tr3490:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1076;
+tr3480:
+ {
+ *rdata_tail += second_hex_to_num[(uint8_t)(*p)];
+ rdata_tail++;
+ }
+ goto st1076;
+st1076:
+ if ( ++p == pe )
+ goto _test_eof1076;
+case 1076:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st1076;
+ case 32: goto st1076;
+ case 40: goto tr3482;
+ case 41: goto tr3483;
+ case 2058: goto tr3484;
+ case 2107: goto tr3485;
+ case 2314: goto tr3486;
+ case 2363: goto tr3486;
+ case 2570: goto tr3487;
+ case 2619: goto tr3488;
+ }
+ if ( _widec < 65 ) {
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3477;
+ } else if ( _widec > 70 ) {
+ if ( 97 <= _widec && _widec <= 102 )
+ goto tr3477;
+ } else
+ goto tr3477;
+ goto tr2556;
+tr3485:
+ {
+ s->buffer_length = 0;
+ }
+ goto st1077;
+tr3489:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st1077;
+st1077:
+ if ( ++p == pe )
+ goto _test_eof1077;
+case 1077:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr3490;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr3489;
+ goto tr2556;
+tr3486:
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1205;
+st1205:
+ if ( ++p == pe )
+ goto _test_eof1205;
+case 1205:
+ goto st0;
+tr3487:
+ {
+ s->line_counter++;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1206;
+st1206:
+ if ( ++p == pe )
+ goto _test_eof1206;
+case 1206:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ }
+ switch( _widec ) {
+ case 9: goto st1076;
+ case 32: goto st1076;
+ case 40: goto tr3482;
+ case 41: goto tr3483;
+ case 2058: goto tr3484;
+ case 2107: goto tr3485;
+ case 2314: goto tr3486;
+ case 2363: goto tr3486;
+ case 2570: goto tr3487;
+ case 2619: goto tr3488;
+ }
+ if ( _widec < 65 ) {
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3477;
+ } else if ( _widec > 70 ) {
+ if ( 97 <= _widec && _widec <= 102 )
+ goto tr3477;
+ } else
+ goto tr3477;
+ goto tr2556;
+tr3488:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1207;
+st1207:
+ if ( ++p == pe )
+ goto _test_eof1207;
+case 1207:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr3490;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr3489;
+ goto tr2556;
+tr3479:
+ {
+ s->buffer_length = 0;
+ }
+ goto st1078;
+tr3491:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st1078;
+tr3473:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st1078;
+st1078:
+ if ( ++p == pe )
+ goto _test_eof1078;
+case 1078:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr3492;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr3491;
+ goto tr71;
+tr3467:
+ {
+ s->buffer_length = 0;
+ }
+ goto st1079;
+tr3493:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st1079;
+tr3461:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st1079;
+st1079:
+ if ( ++p == pe )
+ goto _test_eof1079;
+case 1079:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr3494;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr3493;
+ goto tr71;
+tr3455:
+ {
+ s->buffer_length = 0;
+ }
+ goto st1080;
+tr3495:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st1080;
+tr3449:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st1080;
+st1080:
+ if ( ++p == pe )
+ goto _test_eof1080;
+case 1080:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr3496;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr3495;
+ goto tr71;
+st1081:
+ if ( ++p == pe )
+ goto _test_eof1081;
+case 1081:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3497;
+ goto tr1885;
+tr3497:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1082;
+tr3501:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1082;
+st1082:
+ if ( ++p == pe )
+ goto _test_eof1082;
+case 1082:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3498;
+ case 32: goto tr3498;
+ case 40: goto tr3499;
+ case 41: goto tr3500;
+ case 1034: goto tr3502;
+ case 1083: goto tr3503;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3501;
+ goto tr1885;
+tr3505:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1083;
+tr3506:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1083;
+tr3508:
+ {
+ s->line_counter++;
+ }
+ goto st1083;
+tr3513:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1083;
+tr3498:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1083;
+tr3499:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1083;
+tr3500:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1083;
+tr3502:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1083;
+st1083:
+ if ( ++p == pe )
+ goto _test_eof1083;
+case 1083:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st1083;
+ case 32: goto st1083;
+ case 40: goto tr3505;
+ case 41: goto tr3506;
+ case 46: goto tr3507;
+ case 1034: goto tr3508;
+ case 1083: goto tr3509;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3507;
+ goto tr1862;
+tr3507:
+ {
+ s->buffer_length = 0;
+ }
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1084;
+tr3511:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1084;
+st1084:
+ if ( ++p == pe )
+ goto _test_eof1084;
+case 1084:
+ switch( (*p) ) {
+ case 32: goto tr3510;
+ case 46: goto tr3511;
+ case 59: goto tr3510;
+ }
+ if ( (*p) < 40 ) {
+ if ( 9 <= (*p) && (*p) <= 10 )
+ goto tr3510;
+ } else if ( (*p) > 41 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3511;
+ } else
+ goto tr3510;
+ goto tr1862;
+tr3510:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV4);
+ p--; {goto st268;}
+ }
+ }
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET4_ADDR_LENGTH);
+ rdata_tail += ZS_INET4_ADDR_LENGTH;
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1208;
+st1208:
+ if ( ++p == pe )
+ goto _test_eof1208;
+case 1208:
+ goto st0;
+tr3509:
+ {
+ s->buffer_length = 0;
+ }
+ goto st1085;
+tr3512:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st1085;
+tr3503:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st1085;
+st1085:
+ if ( ++p == pe )
+ goto _test_eof1085;
+case 1085:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr3513;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr3512;
+ goto tr71;
+st1086:
+ if ( ++p == pe )
+ goto _test_eof1086;
+case 1086:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3514;
+ goto tr1885;
+tr3514:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1087;
+tr3518:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1087;
+st1087:
+ if ( ++p == pe )
+ goto _test_eof1087;
+case 1087:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3515;
+ case 32: goto tr3515;
+ case 40: goto tr3516;
+ case 41: goto tr3517;
+ case 1034: goto tr3519;
+ case 1083: goto tr3520;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3518;
+ goto tr1885;
+tr3522:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1088;
+tr3523:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1088;
+tr3525:
+ {
+ s->line_counter++;
+ }
+ goto st1088;
+tr3539:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1088;
+tr3515:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1088;
+tr3516:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1088;
+tr3517:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1088;
+tr3519:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1088;
+st1088:
+ if ( ++p == pe )
+ goto _test_eof1088;
+case 1088:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st1088;
+ case 32: goto st1088;
+ case 40: goto tr3522;
+ case 41: goto tr3523;
+ case 1034: goto tr3525;
+ case 1083: goto tr3526;
+ }
+ if ( _widec < 65 ) {
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3524;
+ } else if ( _widec > 70 ) {
+ if ( 97 <= _widec && _widec <= 102 )
+ goto tr3524;
+ } else
+ goto tr3524;
+ goto tr2556;
+tr3524:
+ {
+ s->item_length = 0;
+ }
+ {
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = first_hex_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1089;
+st1089:
+ if ( ++p == pe )
+ goto _test_eof1089;
+case 1089:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3527;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto tr3527;
+ } else
+ goto tr3527;
+ goto tr2556;
+tr3527:
+ {
+ *rdata_tail += second_hex_to_num[(uint8_t)(*p)];
+ rdata_tail++;
+ }
+ goto st1090;
+st1090:
+ if ( ++p == pe )
+ goto _test_eof1090;
+case 1090:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3528;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto tr3528;
+ } else
+ goto tr3528;
+ goto tr2556;
+tr3528:
+ {
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = first_hex_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1091;
+st1091:
+ if ( ++p == pe )
+ goto _test_eof1091;
+case 1091:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3529;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto tr3529;
+ } else
+ goto tr3529;
+ goto tr2556;
+tr3529:
+ {
+ *rdata_tail += second_hex_to_num[(uint8_t)(*p)];
+ rdata_tail++;
+ }
+ goto st1092;
+st1092:
+ if ( ++p == pe )
+ goto _test_eof1092;
+case 1092:
+ if ( (*p) == 58 )
+ goto tr3531;
+ goto tr3530;
+tr3531:
+ {
+ s->item_length++;
+ }
+ goto st1093;
+st1093:
+ if ( ++p == pe )
+ goto _test_eof1093;
+case 1093:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3532;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto tr3532;
+ } else
+ goto tr3532;
+ goto tr2556;
+tr3532:
+ {
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = first_hex_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1094;
+st1094:
+ if ( ++p == pe )
+ goto _test_eof1094;
+case 1094:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3533;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto tr3533;
+ } else
+ goto tr3533;
+ goto tr2556;
+tr3533:
+ {
+ *rdata_tail += second_hex_to_num[(uint8_t)(*p)];
+ rdata_tail++;
+ }
+ goto st1095;
+st1095:
+ if ( ++p == pe )
+ goto _test_eof1095;
+case 1095:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3534;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto tr3534;
+ } else
+ goto tr3534;
+ goto tr2556;
+tr3534:
+ {
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = first_hex_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1096;
+st1096:
+ if ( ++p == pe )
+ goto _test_eof1096;
+case 1096:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3535;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto tr3535;
+ } else
+ goto tr3535;
+ goto tr2556;
+tr3535:
+ {
+ *rdata_tail += second_hex_to_num[(uint8_t)(*p)];
+ rdata_tail++;
+ }
+ goto st1097;
+st1097:
+ if ( ++p == pe )
+ goto _test_eof1097;
+case 1097:
+ switch( (*p) ) {
+ case 32: goto tr3537;
+ case 58: goto tr3531;
+ case 59: goto tr3537;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr3537;
+ } else if ( (*p) >= 9 )
+ goto tr3537;
+ goto tr3536;
+tr3537:
+ {
+ s->item_length++;
+ }
+ {
+ if (s->item_length != 4) {
+ WARN(ZS_BAD_L64_LENGTH);
+ p--; {goto st268;}
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1209;
+st1209:
+ if ( ++p == pe )
+ goto _test_eof1209;
+case 1209:
+ goto st0;
+tr3526:
+ {
+ s->buffer_length = 0;
+ }
+ goto st1098;
+tr3538:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st1098;
+tr3520:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st1098;
+st1098:
+ if ( ++p == pe )
+ goto _test_eof1098;
+case 1098:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr3539;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr3538;
+ goto tr71;
+st1099:
+ if ( ++p == pe )
+ goto _test_eof1099;
+case 1099:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3540;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto tr3540;
+ } else
+ goto tr3540;
+ goto tr2556;
+tr3540:
+ {
+ s->item_length = 0;
+ }
+ {
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = first_hex_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1100;
+st1100:
+ if ( ++p == pe )
+ goto _test_eof1100;
+case 1100:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3541;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto tr3541;
+ } else
+ goto tr3541;
+ goto tr2556;
+tr3541:
+ {
+ *rdata_tail += second_hex_to_num[(uint8_t)(*p)];
+ rdata_tail++;
+ }
+ goto st1101;
+st1101:
+ if ( ++p == pe )
+ goto _test_eof1101;
+case 1101:
+ if ( (*p) == 45 )
+ goto tr3543;
+ goto tr3542;
+tr3543:
+ {
+ s->item_length++;
+ }
+ goto st1102;
+st1102:
+ if ( ++p == pe )
+ goto _test_eof1102;
+case 1102:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3544;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto tr3544;
+ } else
+ goto tr3544;
+ goto tr2556;
+tr3544:
+ {
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = first_hex_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1103;
+st1103:
+ if ( ++p == pe )
+ goto _test_eof1103;
+case 1103:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3545;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto tr3545;
+ } else
+ goto tr3545;
+ goto tr2556;
+tr3545:
+ {
+ *rdata_tail += second_hex_to_num[(uint8_t)(*p)];
+ rdata_tail++;
+ }
+ goto st1104;
+st1104:
+ if ( ++p == pe )
+ goto _test_eof1104;
+case 1104:
+ switch( (*p) ) {
+ case 32: goto tr3546;
+ case 45: goto tr3543;
+ case 59: goto tr3546;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr3546;
+ } else if ( (*p) >= 9 )
+ goto tr3546;
+ goto tr3542;
+tr3546:
+ {
+ s->item_length++;
+ }
+ {
+ if (s->item_length != 6) {
+ WARN(ZS_BAD_EUI_LENGTH);
+ p--; {goto st268;}
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1210;
+st1210:
+ if ( ++p == pe )
+ goto _test_eof1210;
+case 1210:
+ goto st0;
+st1105:
+ if ( ++p == pe )
+ goto _test_eof1105;
+case 1105:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3547;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto tr3547;
+ } else
+ goto tr3547;
+ goto tr2556;
+tr3547:
+ {
+ s->item_length = 0;
+ }
+ {
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = first_hex_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1106;
+st1106:
+ if ( ++p == pe )
+ goto _test_eof1106;
+case 1106:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3548;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto tr3548;
+ } else
+ goto tr3548;
+ goto tr2556;
+tr3548:
+ {
+ *rdata_tail += second_hex_to_num[(uint8_t)(*p)];
+ rdata_tail++;
+ }
+ goto st1107;
+st1107:
+ if ( ++p == pe )
+ goto _test_eof1107;
+case 1107:
+ if ( (*p) == 45 )
+ goto tr3549;
+ goto tr3542;
+tr3549:
+ {
+ s->item_length++;
+ }
+ goto st1108;
+st1108:
+ if ( ++p == pe )
+ goto _test_eof1108;
+case 1108:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3550;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto tr3550;
+ } else
+ goto tr3550;
+ goto tr2556;
+tr3550:
+ {
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = first_hex_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1109;
+st1109:
+ if ( ++p == pe )
+ goto _test_eof1109;
+case 1109:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3551;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto tr3551;
+ } else
+ goto tr3551;
+ goto tr2556;
+tr3551:
+ {
+ *rdata_tail += second_hex_to_num[(uint8_t)(*p)];
+ rdata_tail++;
+ }
+ goto st1110;
+st1110:
+ if ( ++p == pe )
+ goto _test_eof1110;
+case 1110:
+ switch( (*p) ) {
+ case 32: goto tr3552;
+ case 45: goto tr3549;
+ case 59: goto tr3552;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr3552;
+ } else if ( (*p) >= 9 )
+ goto tr3552;
+ goto tr3542;
+tr3552:
+ {
+ s->item_length++;
+ }
+ {
+ if (s->item_length != 8) {
+ WARN(ZS_BAD_EUI_LENGTH);
+ p--; {goto st268;}
+ }
+ }
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1211;
+st1211:
+ if ( ++p == pe )
+ goto _test_eof1211;
+case 1211:
+ goto st0;
+st1111:
+ if ( ++p == pe )
+ goto _test_eof1111;
+case 1111:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3553;
+ goto tr1885;
+tr3553:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1112;
+tr3557:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1112;
+st1112:
+ if ( ++p == pe )
+ goto _test_eof1112;
+case 1112:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3554;
+ case 32: goto tr3554;
+ case 40: goto tr3555;
+ case 41: goto tr3556;
+ case 1034: goto tr3558;
+ case 1083: goto tr3559;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3557;
+ goto tr1885;
+tr3561:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1113;
+tr3562:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1113;
+tr3564:
+ {
+ s->line_counter++;
+ }
+ goto st1113;
+tr3582:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1113;
+tr3554:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1113;
+tr3555:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1113;
+tr3556:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1113;
+tr3558:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1113;
+st1113:
+ if ( ++p == pe )
+ goto _test_eof1113;
+case 1113:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st1113;
+ case 32: goto st1113;
+ case 40: goto tr3561;
+ case 41: goto tr3562;
+ case 1034: goto tr3564;
+ case 1083: goto tr3565;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3563;
+ goto tr1885;
+tr3563:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1114;
+tr3569:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1114;
+st1114:
+ if ( ++p == pe )
+ goto _test_eof1114;
+case 1114:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3566;
+ case 32: goto tr3566;
+ case 40: goto tr3567;
+ case 41: goto tr3568;
+ case 1034: goto tr3570;
+ case 1083: goto tr3571;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3569;
+ goto tr1885;
+tr3574:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1115;
+tr3575:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1115;
+tr3576:
+ {
+ s->line_counter++;
+ }
+ goto st1115;
+tr3580:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1115;
+tr3566:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1115;
+tr3567:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1115;
+tr3568:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1115;
+tr3570:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1115;
+st1115:
+ if ( ++p == pe )
+ goto _test_eof1115;
+case 1115:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st1115;
+ case 32: goto st1115;
+ case 40: goto tr3574;
+ case 41: goto tr3575;
+ case 1034: goto tr3576;
+ case 1083: goto tr3577;
+ }
+ if ( _widec < 11 ) {
+ if ( _widec <= 8 )
+ goto tr3572;
+ } else if ( _widec > 58 ) {
+ if ( 60 <= _widec )
+ goto tr3572;
+ } else
+ goto tr3572;
+ goto tr71;
+tr3572:
+ { p--; {stack[top++] = 1116;goto st279;} }
+ goto st1116;
+st1116:
+ if ( ++p == pe )
+ goto _test_eof1116;
+case 1116:
+ switch( (*p) ) {
+ case 32: goto tr3578;
+ case 59: goto tr3578;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr3578;
+ } else if ( (*p) >= 9 )
+ goto tr3578;
+ goto tr71;
+tr3578:
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1212;
+st1212:
+ if ( ++p == pe )
+ goto _test_eof1212;
+case 1212:
+ goto st0;
+tr3577:
+ {
+ s->buffer_length = 0;
+ }
+ goto st1117;
+tr3579:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st1117;
+tr3571:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st1117;
+st1117:
+ if ( ++p == pe )
+ goto _test_eof1117;
+case 1117:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr3580;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr3579;
+ goto tr71;
+tr3565:
+ {
+ s->buffer_length = 0;
+ }
+ goto st1118;
+tr3581:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st1118;
+tr3559:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st1118;
+st1118:
+ if ( ++p == pe )
+ goto _test_eof1118;
+case 1118:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr3582;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr3581;
+ goto tr71;
+st1119:
+ if ( ++p == pe )
+ goto _test_eof1119;
+case 1119:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr3583;
+ goto tr1885;
+tr3583:
+ {
+ s->number64 = 0;
+ }
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1120;
+tr3587:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1120;
+st1120:
+ if ( ++p == pe )
+ goto _test_eof1120;
+case 1120:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3584;
+ case 32: goto tr3584;
+ case 40: goto tr3585;
+ case 41: goto tr3586;
+ case 1034: goto tr3588;
+ case 1083: goto tr3589;
+ }
+ if ( 48 <= _widec && _widec <= 57 )
+ goto tr3587;
+ goto tr1885;
+tr3592:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1121;
+tr3593:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1121;
+tr3594:
+ {
+ s->line_counter++;
+ }
+ goto st1121;
+tr3611:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1121;
+tr3584:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1121;
+tr3585:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1121;
+tr3586:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1121;
+tr3588:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1121;
+st1121:
+ if ( ++p == pe )
+ goto _test_eof1121;
+case 1121:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st1121;
+ case 32: goto st1121;
+ case 40: goto tr3592;
+ case 41: goto tr3593;
+ case 1034: goto tr3594;
+ case 1083: goto tr3595;
+ }
+ if ( _widec < 11 ) {
+ if ( _widec <= 8 )
+ goto tr3590;
+ } else if ( _widec > 58 ) {
+ if ( 60 <= _widec )
+ goto tr3590;
+ } else
+ goto tr3590;
+ goto tr71;
+tr3590:
+ {
+ if (rdata_tail <= rdata_stop) {
+ s->item_length_location = rdata_tail++;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ { p--; {stack[top++] = 1122;goto st279;} }
+ goto st1122;
+st1122:
+ if ( ++p == pe )
+ goto _test_eof1122;
+case 1122:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto tr3596;
+ case 32: goto tr3596;
+ case 40: goto tr3597;
+ case 41: goto tr3598;
+ case 1034: goto tr3599;
+ case 1083: goto tr3600;
+ }
+ goto tr71;
+tr3603:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1123;
+tr3604:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1123;
+tr3605:
+ {
+ s->line_counter++;
+ }
+ goto st1123;
+tr3609:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1123;
+tr3596:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ goto st1123;
+tr3597:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = true;
+ }
+ goto st1123;
+tr3598:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {goto st268;}
+ }
+ s->multiline = false;
+ }
+ goto st1123;
+tr3599:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->line_counter++;
+ }
+ goto st1123;
+st1123:
+ if ( ++p == pe )
+ goto _test_eof1123;
+case 1123:
+ _widec = (*p);
+ if ( (*p) > 10 ) {
+ if ( 59 <= (*p) && (*p) <= 59 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) >= 10 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ switch( _widec ) {
+ case 9: goto st1123;
+ case 32: goto st1123;
+ case 40: goto tr3603;
+ case 41: goto tr3604;
+ case 1034: goto tr3605;
+ case 1083: goto tr3606;
+ }
+ if ( _widec < 11 ) {
+ if ( _widec <= 8 )
+ goto tr3601;
+ } else if ( _widec > 58 ) {
+ if ( 60 <= _widec )
+ goto tr3601;
+ } else
+ goto tr3601;
+ goto tr71;
+tr3601:
+ { p--; {stack[top++] = 1124;goto st279;} }
+ goto st1124;
+st1124:
+ if ( ++p == pe )
+ goto _test_eof1124;
+case 1124:
+ switch( (*p) ) {
+ case 32: goto tr3607;
+ case 59: goto tr3607;
+ }
+ if ( (*p) > 10 ) {
+ if ( 40 <= (*p) && (*p) <= 41 )
+ goto tr3607;
+ } else if ( (*p) >= 9 )
+ goto tr3607;
+ goto tr71;
+tr3607:
+ {
+ p--; {cs = stack[--top];goto _again;}
+ }
+ goto st1213;
+st1213:
+ if ( ++p == pe )
+ goto _test_eof1213;
+case 1213:
+ goto st0;
+tr3606:
+ {
+ s->buffer_length = 0;
+ }
+ goto st1125;
+tr3608:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st1125;
+tr3600:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st1125;
+st1125:
+ if ( ++p == pe )
+ goto _test_eof1125;
+case 1125:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr3609;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr3608;
+ goto tr71;
+tr3595:
+ {
+ s->buffer_length = 0;
+ }
+ goto st1126;
+tr3610:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ goto st1126;
+tr3589:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {goto st268;}
+ }
+ }
+ {
+ s->buffer_length = 0;
+ }
+ goto st1126;
+st1126:
+ if ( ++p == pe )
+ goto _test_eof1126;
+case 1126:
+ _widec = (*p);
+ if ( (*p) < 10 ) {
+ if ( (*p) <= 9 ) {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else if ( (*p) > 10 ) {
+ if ( 11 <= (*p) )
+ { _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ } else {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ }
+ if ( _widec == 1034 )
+ goto tr3611;
+ if ( 896 <= _widec && _widec <= 1151 )
+ goto tr3610;
+ goto tr71;
+ }
+ _test_eof1127: cs = 1127; goto _test_eof;
+ _test_eof1: cs = 1; goto _test_eof;
+ _test_eof2: cs = 2; goto _test_eof;
+ _test_eof3: cs = 3; goto _test_eof;
+ _test_eof4: cs = 4; goto _test_eof;
+ _test_eof5: cs = 5; goto _test_eof;
+ _test_eof6: cs = 6; goto _test_eof;
+ _test_eof7: cs = 7; goto _test_eof;
+ _test_eof8: cs = 8; goto _test_eof;
+ _test_eof9: cs = 9; goto _test_eof;
+ _test_eof10: cs = 10; goto _test_eof;
+ _test_eof11: cs = 11; goto _test_eof;
+ _test_eof12: cs = 12; goto _test_eof;
+ _test_eof13: cs = 13; goto _test_eof;
+ _test_eof1128: cs = 1128; goto _test_eof;
+ _test_eof14: cs = 14; goto _test_eof;
+ _test_eof15: cs = 15; goto _test_eof;
+ _test_eof16: cs = 16; goto _test_eof;
+ _test_eof17: cs = 17; goto _test_eof;
+ _test_eof18: cs = 18; goto _test_eof;
+ _test_eof19: cs = 19; goto _test_eof;
+ _test_eof20: cs = 20; goto _test_eof;
+ _test_eof21: cs = 21; goto _test_eof;
+ _test_eof22: cs = 22; goto _test_eof;
+ _test_eof23: cs = 23; goto _test_eof;
+ _test_eof24: cs = 24; goto _test_eof;
+ _test_eof25: cs = 25; goto _test_eof;
+ _test_eof26: cs = 26; goto _test_eof;
+ _test_eof27: cs = 27; goto _test_eof;
+ _test_eof28: cs = 28; goto _test_eof;
+ _test_eof29: cs = 29; goto _test_eof;
+ _test_eof30: cs = 30; goto _test_eof;
+ _test_eof31: cs = 31; goto _test_eof;
+ _test_eof32: cs = 32; goto _test_eof;
+ _test_eof33: cs = 33; goto _test_eof;
+ _test_eof34: cs = 34; goto _test_eof;
+ _test_eof35: cs = 35; goto _test_eof;
+ _test_eof36: cs = 36; goto _test_eof;
+ _test_eof37: cs = 37; goto _test_eof;
+ _test_eof38: cs = 38; goto _test_eof;
+ _test_eof39: cs = 39; goto _test_eof;
+ _test_eof40: cs = 40; goto _test_eof;
+ _test_eof41: cs = 41; goto _test_eof;
+ _test_eof42: cs = 42; goto _test_eof;
+ _test_eof43: cs = 43; goto _test_eof;
+ _test_eof44: cs = 44; goto _test_eof;
+ _test_eof45: cs = 45; goto _test_eof;
+ _test_eof46: cs = 46; goto _test_eof;
+ _test_eof47: cs = 47; goto _test_eof;
+ _test_eof48: cs = 48; goto _test_eof;
+ _test_eof49: cs = 49; goto _test_eof;
+ _test_eof50: cs = 50; goto _test_eof;
+ _test_eof51: cs = 51; goto _test_eof;
+ _test_eof52: cs = 52; goto _test_eof;
+ _test_eof53: cs = 53; goto _test_eof;
+ _test_eof54: cs = 54; goto _test_eof;
+ _test_eof55: cs = 55; goto _test_eof;
+ _test_eof56: cs = 56; goto _test_eof;
+ _test_eof57: cs = 57; goto _test_eof;
+ _test_eof58: cs = 58; goto _test_eof;
+ _test_eof59: cs = 59; goto _test_eof;
+ _test_eof60: cs = 60; goto _test_eof;
+ _test_eof61: cs = 61; goto _test_eof;
+ _test_eof62: cs = 62; goto _test_eof;
+ _test_eof63: cs = 63; goto _test_eof;
+ _test_eof64: cs = 64; goto _test_eof;
+ _test_eof65: cs = 65; goto _test_eof;
+ _test_eof66: cs = 66; goto _test_eof;
+ _test_eof67: cs = 67; goto _test_eof;
+ _test_eof68: cs = 68; goto _test_eof;
+ _test_eof69: cs = 69; goto _test_eof;
+ _test_eof70: cs = 70; goto _test_eof;
+ _test_eof71: cs = 71; goto _test_eof;
+ _test_eof72: cs = 72; goto _test_eof;
+ _test_eof73: cs = 73; goto _test_eof;
+ _test_eof74: cs = 74; goto _test_eof;
+ _test_eof75: cs = 75; goto _test_eof;
+ _test_eof76: cs = 76; goto _test_eof;
+ _test_eof77: cs = 77; goto _test_eof;
+ _test_eof78: cs = 78; goto _test_eof;
+ _test_eof79: cs = 79; goto _test_eof;
+ _test_eof80: cs = 80; goto _test_eof;
+ _test_eof81: cs = 81; goto _test_eof;
+ _test_eof82: cs = 82; goto _test_eof;
+ _test_eof83: cs = 83; goto _test_eof;
+ _test_eof84: cs = 84; goto _test_eof;
+ _test_eof85: cs = 85; goto _test_eof;
+ _test_eof86: cs = 86; goto _test_eof;
+ _test_eof87: cs = 87; goto _test_eof;
+ _test_eof88: cs = 88; goto _test_eof;
+ _test_eof89: cs = 89; goto _test_eof;
+ _test_eof90: cs = 90; goto _test_eof;
+ _test_eof91: cs = 91; goto _test_eof;
+ _test_eof92: cs = 92; goto _test_eof;
+ _test_eof93: cs = 93; goto _test_eof;
+ _test_eof94: cs = 94; goto _test_eof;
+ _test_eof95: cs = 95; goto _test_eof;
+ _test_eof96: cs = 96; goto _test_eof;
+ _test_eof97: cs = 97; goto _test_eof;
+ _test_eof98: cs = 98; goto _test_eof;
+ _test_eof99: cs = 99; goto _test_eof;
+ _test_eof100: cs = 100; goto _test_eof;
+ _test_eof101: cs = 101; goto _test_eof;
+ _test_eof102: cs = 102; goto _test_eof;
+ _test_eof103: cs = 103; goto _test_eof;
+ _test_eof104: cs = 104; goto _test_eof;
+ _test_eof105: cs = 105; goto _test_eof;
+ _test_eof106: cs = 106; goto _test_eof;
+ _test_eof107: cs = 107; goto _test_eof;
+ _test_eof108: cs = 108; goto _test_eof;
+ _test_eof109: cs = 109; goto _test_eof;
+ _test_eof110: cs = 110; goto _test_eof;
+ _test_eof111: cs = 111; goto _test_eof;
+ _test_eof112: cs = 112; goto _test_eof;
+ _test_eof113: cs = 113; goto _test_eof;
+ _test_eof114: cs = 114; goto _test_eof;
+ _test_eof115: cs = 115; goto _test_eof;
+ _test_eof116: cs = 116; goto _test_eof;
+ _test_eof117: cs = 117; goto _test_eof;
+ _test_eof118: cs = 118; goto _test_eof;
+ _test_eof119: cs = 119; goto _test_eof;
+ _test_eof120: cs = 120; goto _test_eof;
+ _test_eof121: cs = 121; goto _test_eof;
+ _test_eof122: cs = 122; goto _test_eof;
+ _test_eof123: cs = 123; goto _test_eof;
+ _test_eof124: cs = 124; goto _test_eof;
+ _test_eof125: cs = 125; goto _test_eof;
+ _test_eof126: cs = 126; goto _test_eof;
+ _test_eof127: cs = 127; goto _test_eof;
+ _test_eof128: cs = 128; goto _test_eof;
+ _test_eof129: cs = 129; goto _test_eof;
+ _test_eof130: cs = 130; goto _test_eof;
+ _test_eof131: cs = 131; goto _test_eof;
+ _test_eof132: cs = 132; goto _test_eof;
+ _test_eof133: cs = 133; goto _test_eof;
+ _test_eof134: cs = 134; goto _test_eof;
+ _test_eof135: cs = 135; goto _test_eof;
+ _test_eof136: cs = 136; goto _test_eof;
+ _test_eof137: cs = 137; goto _test_eof;
+ _test_eof138: cs = 138; goto _test_eof;
+ _test_eof139: cs = 139; goto _test_eof;
+ _test_eof140: cs = 140; goto _test_eof;
+ _test_eof141: cs = 141; goto _test_eof;
+ _test_eof1129: cs = 1129; goto _test_eof;
+ _test_eof142: cs = 142; goto _test_eof;
+ _test_eof143: cs = 143; goto _test_eof;
+ _test_eof144: cs = 144; goto _test_eof;
+ _test_eof145: cs = 145; goto _test_eof;
+ _test_eof146: cs = 146; goto _test_eof;
+ _test_eof147: cs = 147; goto _test_eof;
+ _test_eof148: cs = 148; goto _test_eof;
+ _test_eof149: cs = 149; goto _test_eof;
+ _test_eof150: cs = 150; goto _test_eof;
+ _test_eof151: cs = 151; goto _test_eof;
+ _test_eof1130: cs = 1130; goto _test_eof;
+ _test_eof152: cs = 152; goto _test_eof;
+ _test_eof153: cs = 153; goto _test_eof;
+ _test_eof154: cs = 154; goto _test_eof;
+ _test_eof155: cs = 155; goto _test_eof;
+ _test_eof156: cs = 156; goto _test_eof;
+ _test_eof157: cs = 157; goto _test_eof;
+ _test_eof158: cs = 158; goto _test_eof;
+ _test_eof159: cs = 159; goto _test_eof;
+ _test_eof1131: cs = 1131; goto _test_eof;
+ _test_eof160: cs = 160; goto _test_eof;
+ _test_eof161: cs = 161; goto _test_eof;
+ _test_eof162: cs = 162; goto _test_eof;
+ _test_eof1132: cs = 1132; goto _test_eof;
+ _test_eof163: cs = 163; goto _test_eof;
+ _test_eof164: cs = 164; goto _test_eof;
+ _test_eof165: cs = 165; goto _test_eof;
+ _test_eof166: cs = 166; goto _test_eof;
+ _test_eof167: cs = 167; goto _test_eof;
+ _test_eof168: cs = 168; goto _test_eof;
+ _test_eof169: cs = 169; goto _test_eof;
+ _test_eof170: cs = 170; goto _test_eof;
+ _test_eof171: cs = 171; goto _test_eof;
+ _test_eof172: cs = 172; goto _test_eof;
+ _test_eof173: cs = 173; goto _test_eof;
+ _test_eof1133: cs = 1133; goto _test_eof;
+ _test_eof174: cs = 174; goto _test_eof;
+ _test_eof175: cs = 175; goto _test_eof;
+ _test_eof176: cs = 176; goto _test_eof;
+ _test_eof177: cs = 177; goto _test_eof;
+ _test_eof1134: cs = 1134; goto _test_eof;
+ _test_eof178: cs = 178; goto _test_eof;
+ _test_eof179: cs = 179; goto _test_eof;
+ _test_eof180: cs = 180; goto _test_eof;
+ _test_eof181: cs = 181; goto _test_eof;
+ _test_eof182: cs = 182; goto _test_eof;
+ _test_eof183: cs = 183; goto _test_eof;
+ _test_eof184: cs = 184; goto _test_eof;
+ _test_eof185: cs = 185; goto _test_eof;
+ _test_eof186: cs = 186; goto _test_eof;
+ _test_eof187: cs = 187; goto _test_eof;
+ _test_eof188: cs = 188; goto _test_eof;
+ _test_eof189: cs = 189; goto _test_eof;
+ _test_eof190: cs = 190; goto _test_eof;
+ _test_eof191: cs = 191; goto _test_eof;
+ _test_eof192: cs = 192; goto _test_eof;
+ _test_eof193: cs = 193; goto _test_eof;
+ _test_eof1135: cs = 1135; goto _test_eof;
+ _test_eof194: cs = 194; goto _test_eof;
+ _test_eof195: cs = 195; goto _test_eof;
+ _test_eof196: cs = 196; goto _test_eof;
+ _test_eof197: cs = 197; goto _test_eof;
+ _test_eof198: cs = 198; goto _test_eof;
+ _test_eof199: cs = 199; goto _test_eof;
+ _test_eof200: cs = 200; goto _test_eof;
+ _test_eof201: cs = 201; goto _test_eof;
+ _test_eof202: cs = 202; goto _test_eof;
+ _test_eof203: cs = 203; goto _test_eof;
+ _test_eof204: cs = 204; goto _test_eof;
+ _test_eof205: cs = 205; goto _test_eof;
+ _test_eof206: cs = 206; goto _test_eof;
+ _test_eof207: cs = 207; goto _test_eof;
+ _test_eof208: cs = 208; goto _test_eof;
+ _test_eof209: cs = 209; goto _test_eof;
+ _test_eof1136: cs = 1136; goto _test_eof;
+ _test_eof210: cs = 210; goto _test_eof;
+ _test_eof211: cs = 211; goto _test_eof;
+ _test_eof212: cs = 212; goto _test_eof;
+ _test_eof213: cs = 213; goto _test_eof;
+ _test_eof214: cs = 214; goto _test_eof;
+ _test_eof215: cs = 215; goto _test_eof;
+ _test_eof216: cs = 216; goto _test_eof;
+ _test_eof217: cs = 217; goto _test_eof;
+ _test_eof218: cs = 218; goto _test_eof;
+ _test_eof219: cs = 219; goto _test_eof;
+ _test_eof220: cs = 220; goto _test_eof;
+ _test_eof221: cs = 221; goto _test_eof;
+ _test_eof222: cs = 222; goto _test_eof;
+ _test_eof223: cs = 223; goto _test_eof;
+ _test_eof224: cs = 224; goto _test_eof;
+ _test_eof225: cs = 225; goto _test_eof;
+ _test_eof226: cs = 226; goto _test_eof;
+ _test_eof227: cs = 227; goto _test_eof;
+ _test_eof228: cs = 228; goto _test_eof;
+ _test_eof229: cs = 229; goto _test_eof;
+ _test_eof230: cs = 230; goto _test_eof;
+ _test_eof231: cs = 231; goto _test_eof;
+ _test_eof232: cs = 232; goto _test_eof;
+ _test_eof233: cs = 233; goto _test_eof;
+ _test_eof234: cs = 234; goto _test_eof;
+ _test_eof235: cs = 235; goto _test_eof;
+ _test_eof236: cs = 236; goto _test_eof;
+ _test_eof237: cs = 237; goto _test_eof;
+ _test_eof238: cs = 238; goto _test_eof;
+ _test_eof239: cs = 239; goto _test_eof;
+ _test_eof240: cs = 240; goto _test_eof;
+ _test_eof241: cs = 241; goto _test_eof;
+ _test_eof242: cs = 242; goto _test_eof;
+ _test_eof243: cs = 243; goto _test_eof;
+ _test_eof244: cs = 244; goto _test_eof;
+ _test_eof245: cs = 245; goto _test_eof;
+ _test_eof246: cs = 246; goto _test_eof;
+ _test_eof247: cs = 247; goto _test_eof;
+ _test_eof248: cs = 248; goto _test_eof;
+ _test_eof249: cs = 249; goto _test_eof;
+ _test_eof250: cs = 250; goto _test_eof;
+ _test_eof251: cs = 251; goto _test_eof;
+ _test_eof252: cs = 252; goto _test_eof;
+ _test_eof253: cs = 253; goto _test_eof;
+ _test_eof254: cs = 254; goto _test_eof;
+ _test_eof255: cs = 255; goto _test_eof;
+ _test_eof256: cs = 256; goto _test_eof;
+ _test_eof257: cs = 257; goto _test_eof;
+ _test_eof258: cs = 258; goto _test_eof;
+ _test_eof259: cs = 259; goto _test_eof;
+ _test_eof260: cs = 260; goto _test_eof;
+ _test_eof261: cs = 261; goto _test_eof;
+ _test_eof262: cs = 262; goto _test_eof;
+ _test_eof263: cs = 263; goto _test_eof;
+ _test_eof264: cs = 264; goto _test_eof;
+ _test_eof265: cs = 265; goto _test_eof;
+ _test_eof266: cs = 266; goto _test_eof;
+ _test_eof267: cs = 267; goto _test_eof;
+ _test_eof268: cs = 268; goto _test_eof;
+ _test_eof269: cs = 269; goto _test_eof;
+ _test_eof1137: cs = 1137; goto _test_eof;
+ _test_eof270: cs = 270; goto _test_eof;
+ _test_eof271: cs = 271; goto _test_eof;
+ _test_eof1138: cs = 1138; goto _test_eof;
+ _test_eof272: cs = 272; goto _test_eof;
+ _test_eof273: cs = 273; goto _test_eof;
+ _test_eof274: cs = 274; goto _test_eof;
+ _test_eof275: cs = 275; goto _test_eof;
+ _test_eof276: cs = 276; goto _test_eof;
+ _test_eof277: cs = 277; goto _test_eof;
+ _test_eof278: cs = 278; goto _test_eof;
+ _test_eof279: cs = 279; goto _test_eof;
+ _test_eof280: cs = 280; goto _test_eof;
+ _test_eof1139: cs = 1139; goto _test_eof;
+ _test_eof1140: cs = 1140; goto _test_eof;
+ _test_eof281: cs = 281; goto _test_eof;
+ _test_eof282: cs = 282; goto _test_eof;
+ _test_eof283: cs = 283; goto _test_eof;
+ _test_eof284: cs = 284; goto _test_eof;
+ _test_eof285: cs = 285; goto _test_eof;
+ _test_eof286: cs = 286; goto _test_eof;
+ _test_eof287: cs = 287; goto _test_eof;
+ _test_eof288: cs = 288; goto _test_eof;
+ _test_eof289: cs = 289; goto _test_eof;
+ _test_eof290: cs = 290; goto _test_eof;
+ _test_eof291: cs = 291; goto _test_eof;
+ _test_eof292: cs = 292; goto _test_eof;
+ _test_eof293: cs = 293; goto _test_eof;
+ _test_eof294: cs = 294; goto _test_eof;
+ _test_eof1141: cs = 1141; goto _test_eof;
+ _test_eof295: cs = 295; goto _test_eof;
+ _test_eof296: cs = 296; goto _test_eof;
+ _test_eof297: cs = 297; goto _test_eof;
+ _test_eof298: cs = 298; goto _test_eof;
+ _test_eof299: cs = 299; goto _test_eof;
+ _test_eof300: cs = 300; goto _test_eof;
+ _test_eof301: cs = 301; goto _test_eof;
+ _test_eof302: cs = 302; goto _test_eof;
+ _test_eof303: cs = 303; goto _test_eof;
+ _test_eof304: cs = 304; goto _test_eof;
+ _test_eof1142: cs = 1142; goto _test_eof;
+ _test_eof305: cs = 305; goto _test_eof;
+ _test_eof306: cs = 306; goto _test_eof;
+ _test_eof307: cs = 307; goto _test_eof;
+ _test_eof308: cs = 308; goto _test_eof;
+ _test_eof309: cs = 309; goto _test_eof;
+ _test_eof310: cs = 310; goto _test_eof;
+ _test_eof311: cs = 311; goto _test_eof;
+ _test_eof312: cs = 312; goto _test_eof;
+ _test_eof313: cs = 313; goto _test_eof;
+ _test_eof314: cs = 314; goto _test_eof;
+ _test_eof315: cs = 315; goto _test_eof;
+ _test_eof316: cs = 316; goto _test_eof;
+ _test_eof317: cs = 317; goto _test_eof;
+ _test_eof318: cs = 318; goto _test_eof;
+ _test_eof1143: cs = 1143; goto _test_eof;
+ _test_eof319: cs = 319; goto _test_eof;
+ _test_eof320: cs = 320; goto _test_eof;
+ _test_eof321: cs = 321; goto _test_eof;
+ _test_eof322: cs = 322; goto _test_eof;
+ _test_eof323: cs = 323; goto _test_eof;
+ _test_eof324: cs = 324; goto _test_eof;
+ _test_eof325: cs = 325; goto _test_eof;
+ _test_eof1144: cs = 1144; goto _test_eof;
+ _test_eof326: cs = 326; goto _test_eof;
+ _test_eof327: cs = 327; goto _test_eof;
+ _test_eof328: cs = 328; goto _test_eof;
+ _test_eof329: cs = 329; goto _test_eof;
+ _test_eof330: cs = 330; goto _test_eof;
+ _test_eof331: cs = 331; goto _test_eof;
+ _test_eof332: cs = 332; goto _test_eof;
+ _test_eof333: cs = 333; goto _test_eof;
+ _test_eof334: cs = 334; goto _test_eof;
+ _test_eof1145: cs = 1145; goto _test_eof;
+ _test_eof1146: cs = 1146; goto _test_eof;
+ _test_eof1147: cs = 1147; goto _test_eof;
+ _test_eof335: cs = 335; goto _test_eof;
+ _test_eof336: cs = 336; goto _test_eof;
+ _test_eof337: cs = 337; goto _test_eof;
+ _test_eof338: cs = 338; goto _test_eof;
+ _test_eof339: cs = 339; goto _test_eof;
+ _test_eof340: cs = 340; goto _test_eof;
+ _test_eof341: cs = 341; goto _test_eof;
+ _test_eof342: cs = 342; goto _test_eof;
+ _test_eof1148: cs = 1148; goto _test_eof;
+ _test_eof1149: cs = 1149; goto _test_eof;
+ _test_eof343: cs = 343; goto _test_eof;
+ _test_eof344: cs = 344; goto _test_eof;
+ _test_eof345: cs = 345; goto _test_eof;
+ _test_eof1150: cs = 1150; goto _test_eof;
+ _test_eof346: cs = 346; goto _test_eof;
+ _test_eof347: cs = 347; goto _test_eof;
+ _test_eof348: cs = 348; goto _test_eof;
+ _test_eof349: cs = 349; goto _test_eof;
+ _test_eof350: cs = 350; goto _test_eof;
+ _test_eof351: cs = 351; goto _test_eof;
+ _test_eof352: cs = 352; goto _test_eof;
+ _test_eof353: cs = 353; goto _test_eof;
+ _test_eof354: cs = 354; goto _test_eof;
+ _test_eof355: cs = 355; goto _test_eof;
+ _test_eof356: cs = 356; goto _test_eof;
+ _test_eof357: cs = 357; goto _test_eof;
+ _test_eof358: cs = 358; goto _test_eof;
+ _test_eof359: cs = 359; goto _test_eof;
+ _test_eof360: cs = 360; goto _test_eof;
+ _test_eof361: cs = 361; goto _test_eof;
+ _test_eof362: cs = 362; goto _test_eof;
+ _test_eof363: cs = 363; goto _test_eof;
+ _test_eof364: cs = 364; goto _test_eof;
+ _test_eof365: cs = 365; goto _test_eof;
+ _test_eof366: cs = 366; goto _test_eof;
+ _test_eof367: cs = 367; goto _test_eof;
+ _test_eof368: cs = 368; goto _test_eof;
+ _test_eof369: cs = 369; goto _test_eof;
+ _test_eof370: cs = 370; goto _test_eof;
+ _test_eof371: cs = 371; goto _test_eof;
+ _test_eof372: cs = 372; goto _test_eof;
+ _test_eof373: cs = 373; goto _test_eof;
+ _test_eof374: cs = 374; goto _test_eof;
+ _test_eof375: cs = 375; goto _test_eof;
+ _test_eof376: cs = 376; goto _test_eof;
+ _test_eof377: cs = 377; goto _test_eof;
+ _test_eof378: cs = 378; goto _test_eof;
+ _test_eof379: cs = 379; goto _test_eof;
+ _test_eof380: cs = 380; goto _test_eof;
+ _test_eof381: cs = 381; goto _test_eof;
+ _test_eof382: cs = 382; goto _test_eof;
+ _test_eof383: cs = 383; goto _test_eof;
+ _test_eof384: cs = 384; goto _test_eof;
+ _test_eof385: cs = 385; goto _test_eof;
+ _test_eof386: cs = 386; goto _test_eof;
+ _test_eof387: cs = 387; goto _test_eof;
+ _test_eof388: cs = 388; goto _test_eof;
+ _test_eof389: cs = 389; goto _test_eof;
+ _test_eof390: cs = 390; goto _test_eof;
+ _test_eof391: cs = 391; goto _test_eof;
+ _test_eof392: cs = 392; goto _test_eof;
+ _test_eof393: cs = 393; goto _test_eof;
+ _test_eof394: cs = 394; goto _test_eof;
+ _test_eof395: cs = 395; goto _test_eof;
+ _test_eof396: cs = 396; goto _test_eof;
+ _test_eof397: cs = 397; goto _test_eof;
+ _test_eof398: cs = 398; goto _test_eof;
+ _test_eof399: cs = 399; goto _test_eof;
+ _test_eof400: cs = 400; goto _test_eof;
+ _test_eof401: cs = 401; goto _test_eof;
+ _test_eof402: cs = 402; goto _test_eof;
+ _test_eof403: cs = 403; goto _test_eof;
+ _test_eof404: cs = 404; goto _test_eof;
+ _test_eof405: cs = 405; goto _test_eof;
+ _test_eof406: cs = 406; goto _test_eof;
+ _test_eof407: cs = 407; goto _test_eof;
+ _test_eof408: cs = 408; goto _test_eof;
+ _test_eof409: cs = 409; goto _test_eof;
+ _test_eof410: cs = 410; goto _test_eof;
+ _test_eof411: cs = 411; goto _test_eof;
+ _test_eof412: cs = 412; goto _test_eof;
+ _test_eof413: cs = 413; goto _test_eof;
+ _test_eof414: cs = 414; goto _test_eof;
+ _test_eof415: cs = 415; goto _test_eof;
+ _test_eof416: cs = 416; goto _test_eof;
+ _test_eof417: cs = 417; goto _test_eof;
+ _test_eof418: cs = 418; goto _test_eof;
+ _test_eof419: cs = 419; goto _test_eof;
+ _test_eof420: cs = 420; goto _test_eof;
+ _test_eof421: cs = 421; goto _test_eof;
+ _test_eof422: cs = 422; goto _test_eof;
+ _test_eof423: cs = 423; goto _test_eof;
+ _test_eof424: cs = 424; goto _test_eof;
+ _test_eof425: cs = 425; goto _test_eof;
+ _test_eof426: cs = 426; goto _test_eof;
+ _test_eof427: cs = 427; goto _test_eof;
+ _test_eof428: cs = 428; goto _test_eof;
+ _test_eof429: cs = 429; goto _test_eof;
+ _test_eof430: cs = 430; goto _test_eof;
+ _test_eof431: cs = 431; goto _test_eof;
+ _test_eof432: cs = 432; goto _test_eof;
+ _test_eof433: cs = 433; goto _test_eof;
+ _test_eof434: cs = 434; goto _test_eof;
+ _test_eof435: cs = 435; goto _test_eof;
+ _test_eof436: cs = 436; goto _test_eof;
+ _test_eof437: cs = 437; goto _test_eof;
+ _test_eof438: cs = 438; goto _test_eof;
+ _test_eof439: cs = 439; goto _test_eof;
+ _test_eof440: cs = 440; goto _test_eof;
+ _test_eof441: cs = 441; goto _test_eof;
+ _test_eof442: cs = 442; goto _test_eof;
+ _test_eof443: cs = 443; goto _test_eof;
+ _test_eof444: cs = 444; goto _test_eof;
+ _test_eof445: cs = 445; goto _test_eof;
+ _test_eof446: cs = 446; goto _test_eof;
+ _test_eof447: cs = 447; goto _test_eof;
+ _test_eof448: cs = 448; goto _test_eof;
+ _test_eof449: cs = 449; goto _test_eof;
+ _test_eof450: cs = 450; goto _test_eof;
+ _test_eof451: cs = 451; goto _test_eof;
+ _test_eof452: cs = 452; goto _test_eof;
+ _test_eof453: cs = 453; goto _test_eof;
+ _test_eof454: cs = 454; goto _test_eof;
+ _test_eof455: cs = 455; goto _test_eof;
+ _test_eof456: cs = 456; goto _test_eof;
+ _test_eof457: cs = 457; goto _test_eof;
+ _test_eof458: cs = 458; goto _test_eof;
+ _test_eof459: cs = 459; goto _test_eof;
+ _test_eof460: cs = 460; goto _test_eof;
+ _test_eof461: cs = 461; goto _test_eof;
+ _test_eof462: cs = 462; goto _test_eof;
+ _test_eof463: cs = 463; goto _test_eof;
+ _test_eof464: cs = 464; goto _test_eof;
+ _test_eof465: cs = 465; goto _test_eof;
+ _test_eof466: cs = 466; goto _test_eof;
+ _test_eof467: cs = 467; goto _test_eof;
+ _test_eof468: cs = 468; goto _test_eof;
+ _test_eof469: cs = 469; goto _test_eof;
+ _test_eof470: cs = 470; goto _test_eof;
+ _test_eof471: cs = 471; goto _test_eof;
+ _test_eof472: cs = 472; goto _test_eof;
+ _test_eof473: cs = 473; goto _test_eof;
+ _test_eof474: cs = 474; goto _test_eof;
+ _test_eof1151: cs = 1151; goto _test_eof;
+ _test_eof1152: cs = 1152; goto _test_eof;
+ _test_eof1153: cs = 1153; goto _test_eof;
+ _test_eof475: cs = 475; goto _test_eof;
+ _test_eof476: cs = 476; goto _test_eof;
+ _test_eof477: cs = 477; goto _test_eof;
+ _test_eof478: cs = 478; goto _test_eof;
+ _test_eof479: cs = 479; goto _test_eof;
+ _test_eof1154: cs = 1154; goto _test_eof;
+ _test_eof480: cs = 480; goto _test_eof;
+ _test_eof481: cs = 481; goto _test_eof;
+ _test_eof482: cs = 482; goto _test_eof;
+ _test_eof483: cs = 483; goto _test_eof;
+ _test_eof1155: cs = 1155; goto _test_eof;
+ _test_eof1156: cs = 1156; goto _test_eof;
+ _test_eof1157: cs = 1157; goto _test_eof;
+ _test_eof484: cs = 484; goto _test_eof;
+ _test_eof485: cs = 485; goto _test_eof;
+ _test_eof1158: cs = 1158; goto _test_eof;
+ _test_eof486: cs = 486; goto _test_eof;
+ _test_eof487: cs = 487; goto _test_eof;
+ _test_eof488: cs = 488; goto _test_eof;
+ _test_eof1159: cs = 1159; goto _test_eof;
+ _test_eof489: cs = 489; goto _test_eof;
+ _test_eof490: cs = 490; goto _test_eof;
+ _test_eof491: cs = 491; goto _test_eof;
+ _test_eof492: cs = 492; goto _test_eof;
+ _test_eof493: cs = 493; goto _test_eof;
+ _test_eof494: cs = 494; goto _test_eof;
+ _test_eof495: cs = 495; goto _test_eof;
+ _test_eof496: cs = 496; goto _test_eof;
+ _test_eof497: cs = 497; goto _test_eof;
+ _test_eof498: cs = 498; goto _test_eof;
+ _test_eof499: cs = 499; goto _test_eof;
+ _test_eof500: cs = 500; goto _test_eof;
+ _test_eof501: cs = 501; goto _test_eof;
+ _test_eof502: cs = 502; goto _test_eof;
+ _test_eof503: cs = 503; goto _test_eof;
+ _test_eof504: cs = 504; goto _test_eof;
+ _test_eof505: cs = 505; goto _test_eof;
+ _test_eof506: cs = 506; goto _test_eof;
+ _test_eof507: cs = 507; goto _test_eof;
+ _test_eof508: cs = 508; goto _test_eof;
+ _test_eof509: cs = 509; goto _test_eof;
+ _test_eof510: cs = 510; goto _test_eof;
+ _test_eof511: cs = 511; goto _test_eof;
+ _test_eof512: cs = 512; goto _test_eof;
+ _test_eof513: cs = 513; goto _test_eof;
+ _test_eof514: cs = 514; goto _test_eof;
+ _test_eof515: cs = 515; goto _test_eof;
+ _test_eof516: cs = 516; goto _test_eof;
+ _test_eof517: cs = 517; goto _test_eof;
+ _test_eof518: cs = 518; goto _test_eof;
+ _test_eof519: cs = 519; goto _test_eof;
+ _test_eof520: cs = 520; goto _test_eof;
+ _test_eof521: cs = 521; goto _test_eof;
+ _test_eof522: cs = 522; goto _test_eof;
+ _test_eof523: cs = 523; goto _test_eof;
+ _test_eof524: cs = 524; goto _test_eof;
+ _test_eof525: cs = 525; goto _test_eof;
+ _test_eof526: cs = 526; goto _test_eof;
+ _test_eof527: cs = 527; goto _test_eof;
+ _test_eof528: cs = 528; goto _test_eof;
+ _test_eof529: cs = 529; goto _test_eof;
+ _test_eof530: cs = 530; goto _test_eof;
+ _test_eof531: cs = 531; goto _test_eof;
+ _test_eof532: cs = 532; goto _test_eof;
+ _test_eof533: cs = 533; goto _test_eof;
+ _test_eof534: cs = 534; goto _test_eof;
+ _test_eof535: cs = 535; goto _test_eof;
+ _test_eof536: cs = 536; goto _test_eof;
+ _test_eof537: cs = 537; goto _test_eof;
+ _test_eof538: cs = 538; goto _test_eof;
+ _test_eof539: cs = 539; goto _test_eof;
+ _test_eof540: cs = 540; goto _test_eof;
+ _test_eof541: cs = 541; goto _test_eof;
+ _test_eof542: cs = 542; goto _test_eof;
+ _test_eof543: cs = 543; goto _test_eof;
+ _test_eof544: cs = 544; goto _test_eof;
+ _test_eof545: cs = 545; goto _test_eof;
+ _test_eof546: cs = 546; goto _test_eof;
+ _test_eof547: cs = 547; goto _test_eof;
+ _test_eof548: cs = 548; goto _test_eof;
+ _test_eof549: cs = 549; goto _test_eof;
+ _test_eof550: cs = 550; goto _test_eof;
+ _test_eof551: cs = 551; goto _test_eof;
+ _test_eof552: cs = 552; goto _test_eof;
+ _test_eof553: cs = 553; goto _test_eof;
+ _test_eof554: cs = 554; goto _test_eof;
+ _test_eof555: cs = 555; goto _test_eof;
+ _test_eof556: cs = 556; goto _test_eof;
+ _test_eof557: cs = 557; goto _test_eof;
+ _test_eof558: cs = 558; goto _test_eof;
+ _test_eof559: cs = 559; goto _test_eof;
+ _test_eof560: cs = 560; goto _test_eof;
+ _test_eof561: cs = 561; goto _test_eof;
+ _test_eof562: cs = 562; goto _test_eof;
+ _test_eof563: cs = 563; goto _test_eof;
+ _test_eof564: cs = 564; goto _test_eof;
+ _test_eof565: cs = 565; goto _test_eof;
+ _test_eof566: cs = 566; goto _test_eof;
+ _test_eof567: cs = 567; goto _test_eof;
+ _test_eof568: cs = 568; goto _test_eof;
+ _test_eof569: cs = 569; goto _test_eof;
+ _test_eof570: cs = 570; goto _test_eof;
+ _test_eof571: cs = 571; goto _test_eof;
+ _test_eof572: cs = 572; goto _test_eof;
+ _test_eof573: cs = 573; goto _test_eof;
+ _test_eof574: cs = 574; goto _test_eof;
+ _test_eof575: cs = 575; goto _test_eof;
+ _test_eof576: cs = 576; goto _test_eof;
+ _test_eof577: cs = 577; goto _test_eof;
+ _test_eof578: cs = 578; goto _test_eof;
+ _test_eof579: cs = 579; goto _test_eof;
+ _test_eof580: cs = 580; goto _test_eof;
+ _test_eof581: cs = 581; goto _test_eof;
+ _test_eof582: cs = 582; goto _test_eof;
+ _test_eof583: cs = 583; goto _test_eof;
+ _test_eof584: cs = 584; goto _test_eof;
+ _test_eof585: cs = 585; goto _test_eof;
+ _test_eof586: cs = 586; goto _test_eof;
+ _test_eof587: cs = 587; goto _test_eof;
+ _test_eof588: cs = 588; goto _test_eof;
+ _test_eof589: cs = 589; goto _test_eof;
+ _test_eof590: cs = 590; goto _test_eof;
+ _test_eof591: cs = 591; goto _test_eof;
+ _test_eof592: cs = 592; goto _test_eof;
+ _test_eof1160: cs = 1160; goto _test_eof;
+ _test_eof593: cs = 593; goto _test_eof;
+ _test_eof594: cs = 594; goto _test_eof;
+ _test_eof595: cs = 595; goto _test_eof;
+ _test_eof596: cs = 596; goto _test_eof;
+ _test_eof597: cs = 597; goto _test_eof;
+ _test_eof598: cs = 598; goto _test_eof;
+ _test_eof599: cs = 599; goto _test_eof;
+ _test_eof600: cs = 600; goto _test_eof;
+ _test_eof601: cs = 601; goto _test_eof;
+ _test_eof602: cs = 602; goto _test_eof;
+ _test_eof603: cs = 603; goto _test_eof;
+ _test_eof604: cs = 604; goto _test_eof;
+ _test_eof605: cs = 605; goto _test_eof;
+ _test_eof606: cs = 606; goto _test_eof;
+ _test_eof607: cs = 607; goto _test_eof;
+ _test_eof608: cs = 608; goto _test_eof;
+ _test_eof609: cs = 609; goto _test_eof;
+ _test_eof610: cs = 610; goto _test_eof;
+ _test_eof611: cs = 611; goto _test_eof;
+ _test_eof612: cs = 612; goto _test_eof;
+ _test_eof613: cs = 613; goto _test_eof;
+ _test_eof614: cs = 614; goto _test_eof;
+ _test_eof615: cs = 615; goto _test_eof;
+ _test_eof616: cs = 616; goto _test_eof;
+ _test_eof617: cs = 617; goto _test_eof;
+ _test_eof618: cs = 618; goto _test_eof;
+ _test_eof619: cs = 619; goto _test_eof;
+ _test_eof620: cs = 620; goto _test_eof;
+ _test_eof621: cs = 621; goto _test_eof;
+ _test_eof622: cs = 622; goto _test_eof;
+ _test_eof623: cs = 623; goto _test_eof;
+ _test_eof624: cs = 624; goto _test_eof;
+ _test_eof625: cs = 625; goto _test_eof;
+ _test_eof626: cs = 626; goto _test_eof;
+ _test_eof627: cs = 627; goto _test_eof;
+ _test_eof628: cs = 628; goto _test_eof;
+ _test_eof629: cs = 629; goto _test_eof;
+ _test_eof630: cs = 630; goto _test_eof;
+ _test_eof631: cs = 631; goto _test_eof;
+ _test_eof632: cs = 632; goto _test_eof;
+ _test_eof633: cs = 633; goto _test_eof;
+ _test_eof1161: cs = 1161; goto _test_eof;
+ _test_eof634: cs = 634; goto _test_eof;
+ _test_eof635: cs = 635; goto _test_eof;
+ _test_eof1162: cs = 1162; goto _test_eof;
+ _test_eof636: cs = 636; goto _test_eof;
+ _test_eof637: cs = 637; goto _test_eof;
+ _test_eof638: cs = 638; goto _test_eof;
+ _test_eof639: cs = 639; goto _test_eof;
+ _test_eof640: cs = 640; goto _test_eof;
+ _test_eof641: cs = 641; goto _test_eof;
+ _test_eof642: cs = 642; goto _test_eof;
+ _test_eof643: cs = 643; goto _test_eof;
+ _test_eof644: cs = 644; goto _test_eof;
+ _test_eof645: cs = 645; goto _test_eof;
+ _test_eof646: cs = 646; goto _test_eof;
+ _test_eof647: cs = 647; goto _test_eof;
+ _test_eof648: cs = 648; goto _test_eof;
+ _test_eof649: cs = 649; goto _test_eof;
+ _test_eof1163: cs = 1163; goto _test_eof;
+ _test_eof650: cs = 650; goto _test_eof;
+ _test_eof651: cs = 651; goto _test_eof;
+ _test_eof652: cs = 652; goto _test_eof;
+ _test_eof653: cs = 653; goto _test_eof;
+ _test_eof654: cs = 654; goto _test_eof;
+ _test_eof655: cs = 655; goto _test_eof;
+ _test_eof656: cs = 656; goto _test_eof;
+ _test_eof657: cs = 657; goto _test_eof;
+ _test_eof658: cs = 658; goto _test_eof;
+ _test_eof659: cs = 659; goto _test_eof;
+ _test_eof660: cs = 660; goto _test_eof;
+ _test_eof661: cs = 661; goto _test_eof;
+ _test_eof662: cs = 662; goto _test_eof;
+ _test_eof663: cs = 663; goto _test_eof;
+ _test_eof664: cs = 664; goto _test_eof;
+ _test_eof665: cs = 665; goto _test_eof;
+ _test_eof666: cs = 666; goto _test_eof;
+ _test_eof667: cs = 667; goto _test_eof;
+ _test_eof668: cs = 668; goto _test_eof;
+ _test_eof669: cs = 669; goto _test_eof;
+ _test_eof670: cs = 670; goto _test_eof;
+ _test_eof671: cs = 671; goto _test_eof;
+ _test_eof1164: cs = 1164; goto _test_eof;
+ _test_eof672: cs = 672; goto _test_eof;
+ _test_eof673: cs = 673; goto _test_eof;
+ _test_eof674: cs = 674; goto _test_eof;
+ _test_eof675: cs = 675; goto _test_eof;
+ _test_eof676: cs = 676; goto _test_eof;
+ _test_eof1165: cs = 1165; goto _test_eof;
+ _test_eof677: cs = 677; goto _test_eof;
+ _test_eof678: cs = 678; goto _test_eof;
+ _test_eof679: cs = 679; goto _test_eof;
+ _test_eof680: cs = 680; goto _test_eof;
+ _test_eof681: cs = 681; goto _test_eof;
+ _test_eof1166: cs = 1166; goto _test_eof;
+ _test_eof682: cs = 682; goto _test_eof;
+ _test_eof683: cs = 683; goto _test_eof;
+ _test_eof684: cs = 684; goto _test_eof;
+ _test_eof685: cs = 685; goto _test_eof;
+ _test_eof686: cs = 686; goto _test_eof;
+ _test_eof1167: cs = 1167; goto _test_eof;
+ _test_eof1168: cs = 1168; goto _test_eof;
+ _test_eof1169: cs = 1169; goto _test_eof;
+ _test_eof687: cs = 687; goto _test_eof;
+ _test_eof688: cs = 688; goto _test_eof;
+ _test_eof1170: cs = 1170; goto _test_eof;
+ _test_eof689: cs = 689; goto _test_eof;
+ _test_eof690: cs = 690; goto _test_eof;
+ _test_eof691: cs = 691; goto _test_eof;
+ _test_eof692: cs = 692; goto _test_eof;
+ _test_eof693: cs = 693; goto _test_eof;
+ _test_eof694: cs = 694; goto _test_eof;
+ _test_eof695: cs = 695; goto _test_eof;
+ _test_eof696: cs = 696; goto _test_eof;
+ _test_eof697: cs = 697; goto _test_eof;
+ _test_eof698: cs = 698; goto _test_eof;
+ _test_eof699: cs = 699; goto _test_eof;
+ _test_eof700: cs = 700; goto _test_eof;
+ _test_eof701: cs = 701; goto _test_eof;
+ _test_eof702: cs = 702; goto _test_eof;
+ _test_eof703: cs = 703; goto _test_eof;
+ _test_eof704: cs = 704; goto _test_eof;
+ _test_eof705: cs = 705; goto _test_eof;
+ _test_eof706: cs = 706; goto _test_eof;
+ _test_eof707: cs = 707; goto _test_eof;
+ _test_eof708: cs = 708; goto _test_eof;
+ _test_eof709: cs = 709; goto _test_eof;
+ _test_eof710: cs = 710; goto _test_eof;
+ _test_eof711: cs = 711; goto _test_eof;
+ _test_eof712: cs = 712; goto _test_eof;
+ _test_eof713: cs = 713; goto _test_eof;
+ _test_eof714: cs = 714; goto _test_eof;
+ _test_eof715: cs = 715; goto _test_eof;
+ _test_eof1171: cs = 1171; goto _test_eof;
+ _test_eof1172: cs = 1172; goto _test_eof;
+ _test_eof1173: cs = 1173; goto _test_eof;
+ _test_eof716: cs = 716; goto _test_eof;
+ _test_eof717: cs = 717; goto _test_eof;
+ _test_eof718: cs = 718; goto _test_eof;
+ _test_eof1174: cs = 1174; goto _test_eof;
+ _test_eof1175: cs = 1175; goto _test_eof;
+ _test_eof719: cs = 719; goto _test_eof;
+ _test_eof720: cs = 720; goto _test_eof;
+ _test_eof721: cs = 721; goto _test_eof;
+ _test_eof722: cs = 722; goto _test_eof;
+ _test_eof1176: cs = 1176; goto _test_eof;
+ _test_eof1177: cs = 1177; goto _test_eof;
+ _test_eof723: cs = 723; goto _test_eof;
+ _test_eof724: cs = 724; goto _test_eof;
+ _test_eof725: cs = 725; goto _test_eof;
+ _test_eof726: cs = 726; goto _test_eof;
+ _test_eof1178: cs = 1178; goto _test_eof;
+ _test_eof1179: cs = 1179; goto _test_eof;
+ _test_eof727: cs = 727; goto _test_eof;
+ _test_eof728: cs = 728; goto _test_eof;
+ _test_eof729: cs = 729; goto _test_eof;
+ _test_eof730: cs = 730; goto _test_eof;
+ _test_eof731: cs = 731; goto _test_eof;
+ _test_eof732: cs = 732; goto _test_eof;
+ _test_eof733: cs = 733; goto _test_eof;
+ _test_eof734: cs = 734; goto _test_eof;
+ _test_eof735: cs = 735; goto _test_eof;
+ _test_eof736: cs = 736; goto _test_eof;
+ _test_eof737: cs = 737; goto _test_eof;
+ _test_eof738: cs = 738; goto _test_eof;
+ _test_eof739: cs = 739; goto _test_eof;
+ _test_eof740: cs = 740; goto _test_eof;
+ _test_eof741: cs = 741; goto _test_eof;
+ _test_eof742: cs = 742; goto _test_eof;
+ _test_eof743: cs = 743; goto _test_eof;
+ _test_eof744: cs = 744; goto _test_eof;
+ _test_eof745: cs = 745; goto _test_eof;
+ _test_eof746: cs = 746; goto _test_eof;
+ _test_eof747: cs = 747; goto _test_eof;
+ _test_eof748: cs = 748; goto _test_eof;
+ _test_eof749: cs = 749; goto _test_eof;
+ _test_eof750: cs = 750; goto _test_eof;
+ _test_eof751: cs = 751; goto _test_eof;
+ _test_eof1180: cs = 1180; goto _test_eof;
+ _test_eof752: cs = 752; goto _test_eof;
+ _test_eof753: cs = 753; goto _test_eof;
+ _test_eof754: cs = 754; goto _test_eof;
+ _test_eof755: cs = 755; goto _test_eof;
+ _test_eof756: cs = 756; goto _test_eof;
+ _test_eof757: cs = 757; goto _test_eof;
+ _test_eof758: cs = 758; goto _test_eof;
+ _test_eof759: cs = 759; goto _test_eof;
+ _test_eof760: cs = 760; goto _test_eof;
+ _test_eof761: cs = 761; goto _test_eof;
+ _test_eof762: cs = 762; goto _test_eof;
+ _test_eof763: cs = 763; goto _test_eof;
+ _test_eof764: cs = 764; goto _test_eof;
+ _test_eof765: cs = 765; goto _test_eof;
+ _test_eof766: cs = 766; goto _test_eof;
+ _test_eof1181: cs = 1181; goto _test_eof;
+ _test_eof767: cs = 767; goto _test_eof;
+ _test_eof768: cs = 768; goto _test_eof;
+ _test_eof769: cs = 769; goto _test_eof;
+ _test_eof770: cs = 770; goto _test_eof;
+ _test_eof771: cs = 771; goto _test_eof;
+ _test_eof772: cs = 772; goto _test_eof;
+ _test_eof773: cs = 773; goto _test_eof;
+ _test_eof774: cs = 774; goto _test_eof;
+ _test_eof775: cs = 775; goto _test_eof;
+ _test_eof776: cs = 776; goto _test_eof;
+ _test_eof777: cs = 777; goto _test_eof;
+ _test_eof778: cs = 778; goto _test_eof;
+ _test_eof779: cs = 779; goto _test_eof;
+ _test_eof1182: cs = 1182; goto _test_eof;
+ _test_eof780: cs = 780; goto _test_eof;
+ _test_eof781: cs = 781; goto _test_eof;
+ _test_eof782: cs = 782; goto _test_eof;
+ _test_eof783: cs = 783; goto _test_eof;
+ _test_eof784: cs = 784; goto _test_eof;
+ _test_eof785: cs = 785; goto _test_eof;
+ _test_eof786: cs = 786; goto _test_eof;
+ _test_eof787: cs = 787; goto _test_eof;
+ _test_eof788: cs = 788; goto _test_eof;
+ _test_eof789: cs = 789; goto _test_eof;
+ _test_eof790: cs = 790; goto _test_eof;
+ _test_eof1183: cs = 1183; goto _test_eof;
+ _test_eof1184: cs = 1184; goto _test_eof;
+ _test_eof791: cs = 791; goto _test_eof;
+ _test_eof792: cs = 792; goto _test_eof;
+ _test_eof793: cs = 793; goto _test_eof;
+ _test_eof1185: cs = 1185; goto _test_eof;
+ _test_eof794: cs = 794; goto _test_eof;
+ _test_eof795: cs = 795; goto _test_eof;
+ _test_eof796: cs = 796; goto _test_eof;
+ _test_eof797: cs = 797; goto _test_eof;
+ _test_eof798: cs = 798; goto _test_eof;
+ _test_eof799: cs = 799; goto _test_eof;
+ _test_eof800: cs = 800; goto _test_eof;
+ _test_eof801: cs = 801; goto _test_eof;
+ _test_eof802: cs = 802; goto _test_eof;
+ _test_eof803: cs = 803; goto _test_eof;
+ _test_eof1186: cs = 1186; goto _test_eof;
+ _test_eof1187: cs = 1187; goto _test_eof;
+ _test_eof1188: cs = 1188; goto _test_eof;
+ _test_eof804: cs = 804; goto _test_eof;
+ _test_eof805: cs = 805; goto _test_eof;
+ _test_eof806: cs = 806; goto _test_eof;
+ _test_eof807: cs = 807; goto _test_eof;
+ _test_eof808: cs = 808; goto _test_eof;
+ _test_eof809: cs = 809; goto _test_eof;
+ _test_eof810: cs = 810; goto _test_eof;
+ _test_eof811: cs = 811; goto _test_eof;
+ _test_eof812: cs = 812; goto _test_eof;
+ _test_eof813: cs = 813; goto _test_eof;
+ _test_eof814: cs = 814; goto _test_eof;
+ _test_eof1189: cs = 1189; goto _test_eof;
+ _test_eof1190: cs = 1190; goto _test_eof;
+ _test_eof1191: cs = 1191; goto _test_eof;
+ _test_eof815: cs = 815; goto _test_eof;
+ _test_eof816: cs = 816; goto _test_eof;
+ _test_eof817: cs = 817; goto _test_eof;
+ _test_eof818: cs = 818; goto _test_eof;
+ _test_eof819: cs = 819; goto _test_eof;
+ _test_eof820: cs = 820; goto _test_eof;
+ _test_eof821: cs = 821; goto _test_eof;
+ _test_eof822: cs = 822; goto _test_eof;
+ _test_eof823: cs = 823; goto _test_eof;
+ _test_eof824: cs = 824; goto _test_eof;
+ _test_eof825: cs = 825; goto _test_eof;
+ _test_eof826: cs = 826; goto _test_eof;
+ _test_eof1192: cs = 1192; goto _test_eof;
+ _test_eof827: cs = 827; goto _test_eof;
+ _test_eof828: cs = 828; goto _test_eof;
+ _test_eof829: cs = 829; goto _test_eof;
+ _test_eof1193: cs = 1193; goto _test_eof;
+ _test_eof1194: cs = 1194; goto _test_eof;
+ _test_eof830: cs = 830; goto _test_eof;
+ _test_eof1195: cs = 1195; goto _test_eof;
+ _test_eof1196: cs = 1196; goto _test_eof;
+ _test_eof831: cs = 831; goto _test_eof;
+ _test_eof1197: cs = 1197; goto _test_eof;
+ _test_eof1198: cs = 1198; goto _test_eof;
+ _test_eof832: cs = 832; goto _test_eof;
+ _test_eof833: cs = 833; goto _test_eof;
+ _test_eof834: cs = 834; goto _test_eof;
+ _test_eof835: cs = 835; goto _test_eof;
+ _test_eof836: cs = 836; goto _test_eof;
+ _test_eof837: cs = 837; goto _test_eof;
+ _test_eof838: cs = 838; goto _test_eof;
+ _test_eof839: cs = 839; goto _test_eof;
+ _test_eof840: cs = 840; goto _test_eof;
+ _test_eof841: cs = 841; goto _test_eof;
+ _test_eof842: cs = 842; goto _test_eof;
+ _test_eof843: cs = 843; goto _test_eof;
+ _test_eof844: cs = 844; goto _test_eof;
+ _test_eof845: cs = 845; goto _test_eof;
+ _test_eof846: cs = 846; goto _test_eof;
+ _test_eof847: cs = 847; goto _test_eof;
+ _test_eof848: cs = 848; goto _test_eof;
+ _test_eof849: cs = 849; goto _test_eof;
+ _test_eof850: cs = 850; goto _test_eof;
+ _test_eof851: cs = 851; goto _test_eof;
+ _test_eof852: cs = 852; goto _test_eof;
+ _test_eof853: cs = 853; goto _test_eof;
+ _test_eof854: cs = 854; goto _test_eof;
+ _test_eof855: cs = 855; goto _test_eof;
+ _test_eof856: cs = 856; goto _test_eof;
+ _test_eof857: cs = 857; goto _test_eof;
+ _test_eof858: cs = 858; goto _test_eof;
+ _test_eof859: cs = 859; goto _test_eof;
+ _test_eof860: cs = 860; goto _test_eof;
+ _test_eof861: cs = 861; goto _test_eof;
+ _test_eof862: cs = 862; goto _test_eof;
+ _test_eof863: cs = 863; goto _test_eof;
+ _test_eof864: cs = 864; goto _test_eof;
+ _test_eof865: cs = 865; goto _test_eof;
+ _test_eof866: cs = 866; goto _test_eof;
+ _test_eof867: cs = 867; goto _test_eof;
+ _test_eof868: cs = 868; goto _test_eof;
+ _test_eof869: cs = 869; goto _test_eof;
+ _test_eof870: cs = 870; goto _test_eof;
+ _test_eof871: cs = 871; goto _test_eof;
+ _test_eof872: cs = 872; goto _test_eof;
+ _test_eof873: cs = 873; goto _test_eof;
+ _test_eof1199: cs = 1199; goto _test_eof;
+ _test_eof874: cs = 874; goto _test_eof;
+ _test_eof875: cs = 875; goto _test_eof;
+ _test_eof876: cs = 876; goto _test_eof;
+ _test_eof877: cs = 877; goto _test_eof;
+ _test_eof878: cs = 878; goto _test_eof;
+ _test_eof879: cs = 879; goto _test_eof;
+ _test_eof880: cs = 880; goto _test_eof;
+ _test_eof881: cs = 881; goto _test_eof;
+ _test_eof882: cs = 882; goto _test_eof;
+ _test_eof883: cs = 883; goto _test_eof;
+ _test_eof884: cs = 884; goto _test_eof;
+ _test_eof885: cs = 885; goto _test_eof;
+ _test_eof886: cs = 886; goto _test_eof;
+ _test_eof887: cs = 887; goto _test_eof;
+ _test_eof888: cs = 888; goto _test_eof;
+ _test_eof889: cs = 889; goto _test_eof;
+ _test_eof890: cs = 890; goto _test_eof;
+ _test_eof891: cs = 891; goto _test_eof;
+ _test_eof892: cs = 892; goto _test_eof;
+ _test_eof893: cs = 893; goto _test_eof;
+ _test_eof894: cs = 894; goto _test_eof;
+ _test_eof895: cs = 895; goto _test_eof;
+ _test_eof896: cs = 896; goto _test_eof;
+ _test_eof897: cs = 897; goto _test_eof;
+ _test_eof898: cs = 898; goto _test_eof;
+ _test_eof899: cs = 899; goto _test_eof;
+ _test_eof900: cs = 900; goto _test_eof;
+ _test_eof901: cs = 901; goto _test_eof;
+ _test_eof902: cs = 902; goto _test_eof;
+ _test_eof903: cs = 903; goto _test_eof;
+ _test_eof904: cs = 904; goto _test_eof;
+ _test_eof905: cs = 905; goto _test_eof;
+ _test_eof906: cs = 906; goto _test_eof;
+ _test_eof907: cs = 907; goto _test_eof;
+ _test_eof908: cs = 908; goto _test_eof;
+ _test_eof909: cs = 909; goto _test_eof;
+ _test_eof910: cs = 910; goto _test_eof;
+ _test_eof911: cs = 911; goto _test_eof;
+ _test_eof912: cs = 912; goto _test_eof;
+ _test_eof913: cs = 913; goto _test_eof;
+ _test_eof914: cs = 914; goto _test_eof;
+ _test_eof915: cs = 915; goto _test_eof;
+ _test_eof916: cs = 916; goto _test_eof;
+ _test_eof917: cs = 917; goto _test_eof;
+ _test_eof918: cs = 918; goto _test_eof;
+ _test_eof919: cs = 919; goto _test_eof;
+ _test_eof920: cs = 920; goto _test_eof;
+ _test_eof921: cs = 921; goto _test_eof;
+ _test_eof922: cs = 922; goto _test_eof;
+ _test_eof923: cs = 923; goto _test_eof;
+ _test_eof924: cs = 924; goto _test_eof;
+ _test_eof925: cs = 925; goto _test_eof;
+ _test_eof926: cs = 926; goto _test_eof;
+ _test_eof927: cs = 927; goto _test_eof;
+ _test_eof928: cs = 928; goto _test_eof;
+ _test_eof929: cs = 929; goto _test_eof;
+ _test_eof930: cs = 930; goto _test_eof;
+ _test_eof931: cs = 931; goto _test_eof;
+ _test_eof932: cs = 932; goto _test_eof;
+ _test_eof933: cs = 933; goto _test_eof;
+ _test_eof934: cs = 934; goto _test_eof;
+ _test_eof935: cs = 935; goto _test_eof;
+ _test_eof936: cs = 936; goto _test_eof;
+ _test_eof937: cs = 937; goto _test_eof;
+ _test_eof938: cs = 938; goto _test_eof;
+ _test_eof939: cs = 939; goto _test_eof;
+ _test_eof940: cs = 940; goto _test_eof;
+ _test_eof941: cs = 941; goto _test_eof;
+ _test_eof942: cs = 942; goto _test_eof;
+ _test_eof943: cs = 943; goto _test_eof;
+ _test_eof944: cs = 944; goto _test_eof;
+ _test_eof945: cs = 945; goto _test_eof;
+ _test_eof946: cs = 946; goto _test_eof;
+ _test_eof947: cs = 947; goto _test_eof;
+ _test_eof948: cs = 948; goto _test_eof;
+ _test_eof949: cs = 949; goto _test_eof;
+ _test_eof950: cs = 950; goto _test_eof;
+ _test_eof951: cs = 951; goto _test_eof;
+ _test_eof952: cs = 952; goto _test_eof;
+ _test_eof953: cs = 953; goto _test_eof;
+ _test_eof954: cs = 954; goto _test_eof;
+ _test_eof955: cs = 955; goto _test_eof;
+ _test_eof956: cs = 956; goto _test_eof;
+ _test_eof957: cs = 957; goto _test_eof;
+ _test_eof958: cs = 958; goto _test_eof;
+ _test_eof959: cs = 959; goto _test_eof;
+ _test_eof960: cs = 960; goto _test_eof;
+ _test_eof961: cs = 961; goto _test_eof;
+ _test_eof962: cs = 962; goto _test_eof;
+ _test_eof963: cs = 963; goto _test_eof;
+ _test_eof964: cs = 964; goto _test_eof;
+ _test_eof965: cs = 965; goto _test_eof;
+ _test_eof966: cs = 966; goto _test_eof;
+ _test_eof967: cs = 967; goto _test_eof;
+ _test_eof968: cs = 968; goto _test_eof;
+ _test_eof969: cs = 969; goto _test_eof;
+ _test_eof970: cs = 970; goto _test_eof;
+ _test_eof971: cs = 971; goto _test_eof;
+ _test_eof972: cs = 972; goto _test_eof;
+ _test_eof973: cs = 973; goto _test_eof;
+ _test_eof974: cs = 974; goto _test_eof;
+ _test_eof975: cs = 975; goto _test_eof;
+ _test_eof976: cs = 976; goto _test_eof;
+ _test_eof977: cs = 977; goto _test_eof;
+ _test_eof978: cs = 978; goto _test_eof;
+ _test_eof979: cs = 979; goto _test_eof;
+ _test_eof980: cs = 980; goto _test_eof;
+ _test_eof981: cs = 981; goto _test_eof;
+ _test_eof982: cs = 982; goto _test_eof;
+ _test_eof983: cs = 983; goto _test_eof;
+ _test_eof984: cs = 984; goto _test_eof;
+ _test_eof985: cs = 985; goto _test_eof;
+ _test_eof986: cs = 986; goto _test_eof;
+ _test_eof987: cs = 987; goto _test_eof;
+ _test_eof988: cs = 988; goto _test_eof;
+ _test_eof989: cs = 989; goto _test_eof;
+ _test_eof990: cs = 990; goto _test_eof;
+ _test_eof991: cs = 991; goto _test_eof;
+ _test_eof992: cs = 992; goto _test_eof;
+ _test_eof993: cs = 993; goto _test_eof;
+ _test_eof994: cs = 994; goto _test_eof;
+ _test_eof995: cs = 995; goto _test_eof;
+ _test_eof996: cs = 996; goto _test_eof;
+ _test_eof997: cs = 997; goto _test_eof;
+ _test_eof998: cs = 998; goto _test_eof;
+ _test_eof999: cs = 999; goto _test_eof;
+ _test_eof1000: cs = 1000; goto _test_eof;
+ _test_eof1001: cs = 1001; goto _test_eof;
+ _test_eof1002: cs = 1002; goto _test_eof;
+ _test_eof1003: cs = 1003; goto _test_eof;
+ _test_eof1004: cs = 1004; goto _test_eof;
+ _test_eof1005: cs = 1005; goto _test_eof;
+ _test_eof1006: cs = 1006; goto _test_eof;
+ _test_eof1007: cs = 1007; goto _test_eof;
+ _test_eof1008: cs = 1008; goto _test_eof;
+ _test_eof1009: cs = 1009; goto _test_eof;
+ _test_eof1010: cs = 1010; goto _test_eof;
+ _test_eof1011: cs = 1011; goto _test_eof;
+ _test_eof1012: cs = 1012; goto _test_eof;
+ _test_eof1200: cs = 1200; goto _test_eof;
+ _test_eof1013: cs = 1013; goto _test_eof;
+ _test_eof1014: cs = 1014; goto _test_eof;
+ _test_eof1015: cs = 1015; goto _test_eof;
+ _test_eof1016: cs = 1016; goto _test_eof;
+ _test_eof1017: cs = 1017; goto _test_eof;
+ _test_eof1018: cs = 1018; goto _test_eof;
+ _test_eof1019: cs = 1019; goto _test_eof;
+ _test_eof1020: cs = 1020; goto _test_eof;
+ _test_eof1201: cs = 1201; goto _test_eof;
+ _test_eof1021: cs = 1021; goto _test_eof;
+ _test_eof1022: cs = 1022; goto _test_eof;
+ _test_eof1023: cs = 1023; goto _test_eof;
+ _test_eof1024: cs = 1024; goto _test_eof;
+ _test_eof1025: cs = 1025; goto _test_eof;
+ _test_eof1202: cs = 1202; goto _test_eof;
+ _test_eof1026: cs = 1026; goto _test_eof;
+ _test_eof1027: cs = 1027; goto _test_eof;
+ _test_eof1028: cs = 1028; goto _test_eof;
+ _test_eof1029: cs = 1029; goto _test_eof;
+ _test_eof1030: cs = 1030; goto _test_eof;
+ _test_eof1031: cs = 1031; goto _test_eof;
+ _test_eof1032: cs = 1032; goto _test_eof;
+ _test_eof1033: cs = 1033; goto _test_eof;
+ _test_eof1034: cs = 1034; goto _test_eof;
+ _test_eof1035: cs = 1035; goto _test_eof;
+ _test_eof1036: cs = 1036; goto _test_eof;
+ _test_eof1037: cs = 1037; goto _test_eof;
+ _test_eof1038: cs = 1038; goto _test_eof;
+ _test_eof1039: cs = 1039; goto _test_eof;
+ _test_eof1040: cs = 1040; goto _test_eof;
+ _test_eof1041: cs = 1041; goto _test_eof;
+ _test_eof1042: cs = 1042; goto _test_eof;
+ _test_eof1043: cs = 1043; goto _test_eof;
+ _test_eof1203: cs = 1203; goto _test_eof;
+ _test_eof1044: cs = 1044; goto _test_eof;
+ _test_eof1045: cs = 1045; goto _test_eof;
+ _test_eof1046: cs = 1046; goto _test_eof;
+ _test_eof1047: cs = 1047; goto _test_eof;
+ _test_eof1048: cs = 1048; goto _test_eof;
+ _test_eof1049: cs = 1049; goto _test_eof;
+ _test_eof1050: cs = 1050; goto _test_eof;
+ _test_eof1051: cs = 1051; goto _test_eof;
+ _test_eof1052: cs = 1052; goto _test_eof;
+ _test_eof1053: cs = 1053; goto _test_eof;
+ _test_eof1054: cs = 1054; goto _test_eof;
+ _test_eof1055: cs = 1055; goto _test_eof;
+ _test_eof1056: cs = 1056; goto _test_eof;
+ _test_eof1057: cs = 1057; goto _test_eof;
+ _test_eof1058: cs = 1058; goto _test_eof;
+ _test_eof1059: cs = 1059; goto _test_eof;
+ _test_eof1060: cs = 1060; goto _test_eof;
+ _test_eof1061: cs = 1061; goto _test_eof;
+ _test_eof1062: cs = 1062; goto _test_eof;
+ _test_eof1204: cs = 1204; goto _test_eof;
+ _test_eof1063: cs = 1063; goto _test_eof;
+ _test_eof1064: cs = 1064; goto _test_eof;
+ _test_eof1065: cs = 1065; goto _test_eof;
+ _test_eof1066: cs = 1066; goto _test_eof;
+ _test_eof1067: cs = 1067; goto _test_eof;
+ _test_eof1068: cs = 1068; goto _test_eof;
+ _test_eof1069: cs = 1069; goto _test_eof;
+ _test_eof1070: cs = 1070; goto _test_eof;
+ _test_eof1071: cs = 1071; goto _test_eof;
+ _test_eof1072: cs = 1072; goto _test_eof;
+ _test_eof1073: cs = 1073; goto _test_eof;
+ _test_eof1074: cs = 1074; goto _test_eof;
+ _test_eof1075: cs = 1075; goto _test_eof;
+ _test_eof1076: cs = 1076; goto _test_eof;
+ _test_eof1077: cs = 1077; goto _test_eof;
+ _test_eof1205: cs = 1205; goto _test_eof;
+ _test_eof1206: cs = 1206; goto _test_eof;
+ _test_eof1207: cs = 1207; goto _test_eof;
+ _test_eof1078: cs = 1078; goto _test_eof;
+ _test_eof1079: cs = 1079; goto _test_eof;
+ _test_eof1080: cs = 1080; goto _test_eof;
+ _test_eof1081: cs = 1081; goto _test_eof;
+ _test_eof1082: cs = 1082; goto _test_eof;
+ _test_eof1083: cs = 1083; goto _test_eof;
+ _test_eof1084: cs = 1084; goto _test_eof;
+ _test_eof1208: cs = 1208; goto _test_eof;
+ _test_eof1085: cs = 1085; goto _test_eof;
+ _test_eof1086: cs = 1086; goto _test_eof;
+ _test_eof1087: cs = 1087; goto _test_eof;
+ _test_eof1088: cs = 1088; goto _test_eof;
+ _test_eof1089: cs = 1089; goto _test_eof;
+ _test_eof1090: cs = 1090; goto _test_eof;
+ _test_eof1091: cs = 1091; goto _test_eof;
+ _test_eof1092: cs = 1092; goto _test_eof;
+ _test_eof1093: cs = 1093; goto _test_eof;
+ _test_eof1094: cs = 1094; goto _test_eof;
+ _test_eof1095: cs = 1095; goto _test_eof;
+ _test_eof1096: cs = 1096; goto _test_eof;
+ _test_eof1097: cs = 1097; goto _test_eof;
+ _test_eof1209: cs = 1209; goto _test_eof;
+ _test_eof1098: cs = 1098; goto _test_eof;
+ _test_eof1099: cs = 1099; goto _test_eof;
+ _test_eof1100: cs = 1100; goto _test_eof;
+ _test_eof1101: cs = 1101; goto _test_eof;
+ _test_eof1102: cs = 1102; goto _test_eof;
+ _test_eof1103: cs = 1103; goto _test_eof;
+ _test_eof1104: cs = 1104; goto _test_eof;
+ _test_eof1210: cs = 1210; goto _test_eof;
+ _test_eof1105: cs = 1105; goto _test_eof;
+ _test_eof1106: cs = 1106; goto _test_eof;
+ _test_eof1107: cs = 1107; goto _test_eof;
+ _test_eof1108: cs = 1108; goto _test_eof;
+ _test_eof1109: cs = 1109; goto _test_eof;
+ _test_eof1110: cs = 1110; goto _test_eof;
+ _test_eof1211: cs = 1211; goto _test_eof;
+ _test_eof1111: cs = 1111; goto _test_eof;
+ _test_eof1112: cs = 1112; goto _test_eof;
+ _test_eof1113: cs = 1113; goto _test_eof;
+ _test_eof1114: cs = 1114; goto _test_eof;
+ _test_eof1115: cs = 1115; goto _test_eof;
+ _test_eof1116: cs = 1116; goto _test_eof;
+ _test_eof1212: cs = 1212; goto _test_eof;
+ _test_eof1117: cs = 1117; goto _test_eof;
+ _test_eof1118: cs = 1118; goto _test_eof;
+ _test_eof1119: cs = 1119; goto _test_eof;
+ _test_eof1120: cs = 1120; goto _test_eof;
+ _test_eof1121: cs = 1121; goto _test_eof;
+ _test_eof1122: cs = 1122; goto _test_eof;
+ _test_eof1123: cs = 1123; goto _test_eof;
+ _test_eof1124: cs = 1124; goto _test_eof;
+ _test_eof1213: cs = 1213; goto _test_eof;
+ _test_eof1125: cs = 1125; goto _test_eof;
+ _test_eof1126: cs = 1126; goto _test_eof;
+
+ _test_eof: {}
+ if ( p == eof )
+ {
+ switch ( cs ) {
+ case 7:
+ case 8:
+ case 151:
+ case 175:
+ case 177:
+ case 227:
+ case 241:
+ case 264:
+ case 318:
+ case 319:
+ case 325:
+ {
+ WARN(ZS_BAD_REST);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 270:
+ case 271:
+ case 272:
+ case 277:
+ case 278:
+ {
+ WARN(ZS_BAD_DNAME_CHAR);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 160:
+ {
+ s->r_owner_length = 0;
+ WARN(ZS_BAD_OWNER);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 286:
+ {
+ WARN(ZS_BAD_TEXT);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 291:
+ case 299:
+ {
+ ERR(ZS_BAD_TTL);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 300:
+ case 301:
+ case 302:
+ case 311:
+ {
+ ERR(ZS_BAD_ORIGIN);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 313:
+ {
+ ERR(ZS_BAD_INCLUDE_FILENAME);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 316:
+ case 326:
+ {
+ ERR(ZS_BAD_INCLUDE_ORIGIN);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 1131:
+ {
+ NOERR;
+ }
+ break;
+ case 152:
+ case 153:
+ case 154:
+ case 155:
+ case 156:
+ case 157:
+ case 158:
+ case 159:
+ case 195:
+ case 196:
+ case 197:
+ case 198:
+ case 199:
+ case 200:
+ case 201:
+ case 202:
+ case 203:
+ {
+ ERR(ZS_BAD_DIRECTIVE);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 329:
+ case 330:
+ case 331:
+ case 332:
+ case 333:
+ case 334:
+ case 335:
+ {
+ WARN(ZS_BAD_BASE64_CHAR);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 336:
+ case 337:
+ case 338:
+ case 339:
+ case 340:
+ case 341:
+ case 342:
+ case 343:
+ case 344:
+ case 345:
+ case 346:
+ case 347:
+ case 348:
+ case 349:
+ case 350:
+ case 351:
+ case 352:
+ case 353:
+ case 354:
+ case 355:
+ case 356:
+ case 357:
+ case 358:
+ case 359:
+ case 360:
+ case 361:
+ case 362:
+ case 363:
+ case 364:
+ case 365:
+ case 366:
+ case 367:
+ case 368:
+ case 369:
+ case 370:
+ case 371:
+ case 372:
+ case 373:
+ case 374:
+ case 375:
+ case 376:
+ case 377:
+ case 378:
+ case 379:
+ case 380:
+ case 381:
+ case 382:
+ case 383:
+ case 384:
+ case 385:
+ case 386:
+ case 387:
+ case 388:
+ case 389:
+ case 390:
+ case 391:
+ case 392:
+ case 393:
+ case 394:
+ case 395:
+ case 396:
+ case 397:
+ case 398:
+ case 399:
+ case 400:
+ case 401:
+ case 402:
+ case 403:
+ case 404:
+ case 405:
+ case 406:
+ case 407:
+ case 408:
+ case 409:
+ case 410:
+ case 411:
+ case 412:
+ case 413:
+ case 414:
+ case 415:
+ case 416:
+ case 417:
+ case 418:
+ case 419:
+ case 420:
+ case 421:
+ case 422:
+ case 423:
+ case 424:
+ case 425:
+ case 426:
+ case 427:
+ case 428:
+ case 429:
+ case 430:
+ case 431:
+ case 432:
+ case 433:
+ case 434:
+ case 435:
+ case 436:
+ case 437:
+ case 438:
+ case 439:
+ case 440:
+ case 441:
+ case 442:
+ case 443:
+ case 444:
+ case 445:
+ case 446:
+ case 447:
+ case 448:
+ case 449:
+ case 450:
+ case 451:
+ case 452:
+ case 453:
+ case 454:
+ case 455:
+ case 456:
+ case 457:
+ case 458:
+ case 459:
+ case 460:
+ case 461:
+ case 462:
+ case 463:
+ case 464:
+ case 465:
+ case 466:
+ case 467:
+ {
+ WARN(ZS_BAD_BITMAP);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 468:
+ case 475:
+ case 476:
+ case 477:
+ case 484:
+ case 486:
+ {
+ WARN(ZS_BAD_HEX_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 487:
+ case 488:
+ case 489:
+ case 490:
+ case 491:
+ case 492:
+ case 493:
+ case 494:
+ case 495:
+ case 496:
+ case 497:
+ case 498:
+ case 499:
+ case 500:
+ case 501:
+ case 502:
+ case 503:
+ case 504:
+ case 505:
+ case 506:
+ case 507:
+ case 508:
+ case 509:
+ case 510:
+ case 511:
+ case 512:
+ case 513:
+ case 514:
+ case 515:
+ case 516:
+ case 517:
+ case 518:
+ case 519:
+ case 520:
+ case 521:
+ case 522:
+ case 523:
+ case 524:
+ case 525:
+ case 526:
+ case 527:
+ case 528:
+ case 529:
+ case 530:
+ case 531:
+ case 532:
+ case 533:
+ case 534:
+ case 535:
+ case 536:
+ case 537:
+ case 538:
+ case 539:
+ case 540:
+ case 541:
+ case 542:
+ case 543:
+ case 544:
+ case 545:
+ case 546:
+ case 547:
+ case 548:
+ case 549:
+ case 550:
+ case 551:
+ case 552:
+ case 553:
+ case 554:
+ case 555:
+ case 556:
+ case 557:
+ case 558:
+ case 559:
+ case 560:
+ case 561:
+ case 562:
+ case 563:
+ case 564:
+ case 565:
+ case 566:
+ case 567:
+ case 568:
+ case 569:
+ case 570:
+ case 571:
+ case 572:
+ case 573:
+ case 574:
+ case 575:
+ case 576:
+ case 577:
+ case 578:
+ case 579:
+ case 580:
+ case 581:
+ case 582:
+ case 583:
+ case 584:
+ case 585:
+ case 586:
+ case 587:
+ case 588:
+ case 589:
+ case 590:
+ {
+ WARN(ZS_BAD_ALGORITHM);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 591:
+ case 592:
+ case 593:
+ case 594:
+ case 595:
+ case 596:
+ case 597:
+ case 598:
+ case 599:
+ case 600:
+ case 601:
+ case 602:
+ case 603:
+ case 604:
+ case 605:
+ case 606:
+ case 607:
+ case 608:
+ case 609:
+ case 610:
+ case 611:
+ case 612:
+ case 613:
+ case 614:
+ case 615:
+ case 616:
+ case 617:
+ case 618:
+ case 619:
+ case 620:
+ case 621:
+ case 622:
+ case 623:
+ case 624:
+ case 625:
+ case 626:
+ case 627:
+ case 628:
+ case 629:
+ case 630:
+ case 631:
+ {
+ WARN(ZS_BAD_CERT_TYPE);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 5:
+ case 9:
+ case 10:
+ case 246:
+ case 634:
+ case 635:
+ case 636:
+ case 637:
+ case 638:
+ case 639:
+ case 653:
+ case 657:
+ case 661:
+ case 665:
+ case 666:
+ case 667:
+ case 668:
+ case 669:
+ case 670:
+ case 671:
+ case 672:
+ case 673:
+ case 674:
+ case 675:
+ case 676:
+ case 677:
+ case 680:
+ case 681:
+ case 682:
+ case 750:
+ case 751:
+ case 752:
+ case 753:
+ case 754:
+ case 759:
+ case 760:
+ case 761:
+ case 762:
+ case 763:
+ case 764:
+ case 765:
+ case 766:
+ case 767:
+ case 768:
+ case 769:
+ case 770:
+ case 771:
+ case 772:
+ case 773:
+ case 776:
+ case 777:
+ case 778:
+ case 779:
+ case 780:
+ case 781:
+ case 782:
+ case 790:
+ case 796:
+ case 797:
+ case 804:
+ case 805:
+ case 806:
+ case 815:
+ case 816:
+ case 855:
+ case 858:
+ case 859:
+ case 870:
+ case 871:
+ case 872:
+ case 873:
+ case 874:
+ case 875:
+ case 876:
+ case 877:
+ case 878:
+ case 879:
+ case 880:
+ case 881:
+ case 1010:
+ case 1011:
+ case 1012:
+ case 1017:
+ case 1018:
+ case 1019:
+ case 1020:
+ case 1021:
+ case 1022:
+ case 1023:
+ case 1024:
+ case 1025:
+ case 1043:
+ case 1049:
+ case 1052:
+ case 1053:
+ case 1054:
+ case 1065:
+ case 1066:
+ case 1067:
+ case 1078:
+ case 1079:
+ case 1080:
+ case 1085:
+ case 1098:
+ case 1115:
+ case 1116:
+ case 1117:
+ case 1118:
+ case 1121:
+ case 1122:
+ case 1123:
+ case 1124:
+ case 1125:
+ case 1126:
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 3:
+ case 17:
+ case 18:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 29:
+ case 30:
+ case 32:
+ case 33:
+ case 34:
+ case 36:
+ case 37:
+ case 38:
+ case 39:
+ case 41:
+ case 42:
+ case 43:
+ case 45:
+ case 46:
+ case 47:
+ case 50:
+ case 51:
+ case 52:
+ case 53:
+ case 55:
+ case 57:
+ case 58:
+ case 59:
+ case 60:
+ case 62:
+ case 63:
+ case 64:
+ case 65:
+ case 66:
+ case 67:
+ case 68:
+ case 69:
+ case 70:
+ case 71:
+ case 73:
+ case 74:
+ case 77:
+ case 78:
+ case 80:
+ case 82:
+ case 85:
+ case 86:
+ case 87:
+ case 88:
+ case 91:
+ case 92:
+ case 93:
+ case 94:
+ case 96:
+ case 99:
+ case 102:
+ case 103:
+ case 104:
+ case 105:
+ case 107:
+ case 108:
+ case 110:
+ case 112:
+ case 113:
+ case 114:
+ case 117:
+ case 118:
+ case 120:
+ case 122:
+ case 124:
+ case 125:
+ case 126:
+ case 128:
+ case 129:
+ case 130:
+ case 132:
+ case 134:
+ case 135:
+ case 138:
+ case 139:
+ case 141:
+ case 143:
+ case 144:
+ case 150:
+ case 165:
+ case 169:
+ case 230:
+ case 231:
+ case 233:
+ case 234:
+ case 235:
+ case 237:
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 294:
+ case 295:
+ {
+ WARN(ZS_BAD_REST);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ ERR(ZS_BAD_TTL);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 303:
+ case 304:
+ case 305:
+ case 310:
+ {
+ WARN(ZS_BAD_REST);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ ERR(ZS_BAD_ORIGIN);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 273:
+ case 274:
+ case 275:
+ case 276:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_DNAME_CHAR);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 306:
+ case 307:
+ case 308:
+ case 309:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ ERR(ZS_BAD_ORIGIN);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 320:
+ case 321:
+ case 322:
+ case 323:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ ERR(ZS_BAD_INCLUDE_ORIGIN);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 224:
+ {
+ s->r_owner_length = 0;
+ WARN(ZS_BAD_OWNER);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 250:
+ case 251:
+ case 252:
+ case 253:
+ case 254:
+ case 255:
+ case 256:
+ case 257:
+ case 258:
+ case 259:
+ case 260:
+ case 261:
+ case 262:
+ case 263:
+ case 266:
+ {
+ s->r_owner_length = 0;
+ WARN(ZS_BAD_OWNER);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 292:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ ERR(ZS_BAD_TTL);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 469:
+ case 470:
+ case 478:
+ case 479:
+ case 485:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_HEX_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 640:
+ case 641:
+ case 642:
+ case 644:
+ case 646:
+ case 648:
+ case 678:
+ case 679:
+ case 744:
+ case 745:
+ case 746:
+ case 747:
+ case 748:
+ case 749:
+ case 755:
+ case 756:
+ case 757:
+ case 758:
+ case 774:
+ case 775:
+ case 794:
+ case 795:
+ case 798:
+ case 799:
+ case 807:
+ case 808:
+ case 809:
+ case 810:
+ case 817:
+ case 818:
+ case 860:
+ case 861:
+ case 862:
+ case 863:
+ case 868:
+ case 869:
+ case 1013:
+ case 1014:
+ case 1015:
+ case 1016:
+ case 1026:
+ case 1027:
+ case 1028:
+ case 1029:
+ case 1030:
+ case 1031:
+ case 1055:
+ case 1056:
+ case 1057:
+ case 1058:
+ case 1059:
+ case 1060:
+ case 1068:
+ case 1069:
+ case 1070:
+ case 1071:
+ case 1072:
+ case 1073:
+ case 1081:
+ case 1082:
+ case 1086:
+ case 1087:
+ case 1111:
+ case 1112:
+ case 1113:
+ case 1114:
+ case 1119:
+ case 1120:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 136:
+ case 145:
+ case 161:
+ case 164:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 864:
+ case 865:
+ case 866:
+ case 867:
+ {
+ WARN(ZS_BAD_TIMESTAMP_CHAR);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 279:
+ case 280:
+ case 285:
+ {
+ WARN(ZS_BAD_TEXT_CHAR);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_TEXT);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 683:
+ case 684:
+ case 685:
+ case 686:
+ {
+ s->long_string = false;
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 314:
+ {
+ ERR(ZS_BAD_INCLUDE_FILENAME);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 315:
+ case 317:
+ case 324:
+ {
+ ERR(ZS_BAD_INCLUDE_ORIGIN);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 632:
+ case 633:
+ case 687:
+ case 688:
+ case 1083:
+ case 1084:
+ {
+ WARN(ZS_BAD_ADDRESS_CHAR);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 783:
+ case 784:
+ case 785:
+ case 788:
+ case 789:
+ case 791:
+ {
+ WARN(ZS_BAD_APL);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 800:
+ case 801:
+ case 802:
+ case 803:
+ case 811:
+ case 812:
+ case 813:
+ case 814:
+ case 1032:
+ case 1033:
+ case 1050:
+ case 1051:
+ case 1061:
+ case 1062:
+ case 1063:
+ case 1064:
+ case 1074:
+ case 1075:
+ case 1076:
+ case 1077:
+ case 1088:
+ case 1089:
+ case 1090:
+ case 1091:
+ case 1093:
+ case 1094:
+ case 1095:
+ case 1096:
+ case 1099:
+ case 1100:
+ case 1102:
+ case 1103:
+ case 1105:
+ case 1106:
+ case 1108:
+ case 1109:
+ {
+ WARN(ZS_BAD_HEX_CHAR);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 1034:
+ case 1035:
+ case 1036:
+ case 1037:
+ case 1038:
+ case 1039:
+ case 1040:
+ case 1041:
+ case 1042:
+ case 1044:
+ case 1045:
+ case 1046:
+ case 1047:
+ case 1048:
+ {
+ WARN(ZS_BAD_BASE32HEX_CHAR);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 819:
+ case 820:
+ case 823:
+ case 832:
+ case 833:
+ case 834:
+ case 839:
+ case 840:
+ case 841:
+ case 846:
+ case 847:
+ case 848:
+ case 851:
+ case 853:
+ case 854:
+ {
+ WARN(ZS_BAD_GATEWAY);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 825:
+ case 826:
+ case 827:
+ case 828:
+ case 829:
+ case 830:
+ case 831:
+ {
+ WARN(ZS_BAD_GATEWAY_KEY);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 856:
+ case 857:
+ case 882:
+ case 883:
+ case 884:
+ case 885:
+ case 886:
+ case 887:
+ case 888:
+ case 889:
+ case 890:
+ case 891:
+ case 892:
+ case 893:
+ case 894:
+ case 895:
+ case 896:
+ case 897:
+ case 898:
+ case 899:
+ case 900:
+ case 901:
+ case 902:
+ case 903:
+ case 904:
+ case 905:
+ case 906:
+ case 907:
+ case 908:
+ case 909:
+ case 910:
+ case 911:
+ case 912:
+ case 913:
+ case 914:
+ case 915:
+ case 916:
+ case 917:
+ case 918:
+ case 919:
+ case 920:
+ case 921:
+ case 922:
+ case 923:
+ case 924:
+ case 925:
+ case 926:
+ case 927:
+ case 928:
+ case 929:
+ case 930:
+ case 931:
+ case 932:
+ case 933:
+ case 934:
+ case 935:
+ case 936:
+ case 937:
+ case 938:
+ case 939:
+ case 940:
+ case 941:
+ case 942:
+ case 943:
+ case 944:
+ case 945:
+ case 946:
+ case 947:
+ case 948:
+ case 949:
+ case 950:
+ case 951:
+ case 952:
+ case 953:
+ case 954:
+ case 955:
+ case 956:
+ case 957:
+ case 958:
+ case 959:
+ case 960:
+ case 961:
+ case 962:
+ case 963:
+ case 964:
+ case 965:
+ case 966:
+ case 967:
+ case 968:
+ case 969:
+ case 970:
+ case 971:
+ case 972:
+ case 973:
+ case 974:
+ case 975:
+ case 976:
+ case 977:
+ case 978:
+ case 979:
+ case 980:
+ case 981:
+ case 982:
+ case 983:
+ case 984:
+ case 985:
+ case 986:
+ case 987:
+ case 988:
+ case 989:
+ case 990:
+ case 991:
+ case 992:
+ case 993:
+ case 994:
+ case 995:
+ case 996:
+ case 997:
+ case 998:
+ case 999:
+ case 1000:
+ case 1001:
+ case 1002:
+ case 1003:
+ case 1004:
+ case 1007:
+ case 1008:
+ case 1009:
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 689:
+ case 690:
+ case 691:
+ case 692:
+ case 693:
+ case 694:
+ case 695:
+ case 696:
+ case 697:
+ case 698:
+ case 699:
+ case 700:
+ case 701:
+ case 702:
+ case 703:
+ case 704:
+ case 705:
+ case 706:
+ case 707:
+ case 708:
+ case 709:
+ case 710:
+ case 711:
+ case 712:
+ case 713:
+ case 714:
+ case 715:
+ case 716:
+ case 717:
+ case 718:
+ case 719:
+ case 720:
+ case 721:
+ case 722:
+ case 723:
+ case 724:
+ case 725:
+ case 726:
+ case 727:
+ case 728:
+ case 729:
+ case 730:
+ case 731:
+ case 732:
+ case 733:
+ case 734:
+ case 735:
+ case 736:
+ case 737:
+ case 738:
+ case 739:
+ case 740:
+ case 741:
+ case 742:
+ case 743:
+ {
+ WARN(ZS_BAD_LOC_DATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 6:
+ case 11:
+ case 12:
+ case 13:
+ case 20:
+ case 21:
+ case 173:
+ case 176:
+ case 193:
+ case 226:
+ case 228:
+ case 229:
+ case 239:
+ case 240:
+ case 242:
+ case 243:
+ case 244:
+ case 245:
+ case 248:
+ case 249:
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 16:
+ case 207:
+ case 265:
+ case 267:
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 4:
+ case 19:
+ case 27:
+ case 28:
+ case 31:
+ case 35:
+ case 40:
+ case 44:
+ case 48:
+ case 49:
+ case 54:
+ case 56:
+ case 61:
+ case 72:
+ case 75:
+ case 76:
+ case 79:
+ case 81:
+ case 83:
+ case 84:
+ case 89:
+ case 90:
+ case 95:
+ case 97:
+ case 98:
+ case 100:
+ case 101:
+ case 106:
+ case 109:
+ case 111:
+ case 115:
+ case 116:
+ case 119:
+ case 121:
+ case 123:
+ case 127:
+ case 131:
+ case 133:
+ case 140:
+ case 232:
+ case 236:
+ case 238:
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 204:
+ {
+ s->r_owner_length = 0;
+ WARN(ZS_BAD_OWNER);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 170:
+ {
+ s->r_owner_length = 0;
+ WARN(ZS_BAD_OWNER);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 821:
+ case 822:
+ case 835:
+ case 836:
+ case 842:
+ case 843:
+ case 849:
+ case 850:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_GATEWAY);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 1005:
+ case 1006:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 1:
+ case 142:
+ case 174:
+ case 206:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 137:
+ case 171:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 297:
+ {
+ WARN(ZS_BAD_TIME_UNIT);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ ERR(ZS_BAD_TTL);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 643:
+ case 645:
+ case 647:
+ case 649:
+ case 650:
+ case 651:
+ case 652:
+ case 654:
+ case 655:
+ case 656:
+ case 658:
+ case 659:
+ case 660:
+ case 662:
+ case 663:
+ case 664:
+ {
+ WARN(ZS_BAD_TIME_UNIT);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 2:
+ case 146:
+ case 147:
+ case 148:
+ case 149:
+ case 166:
+ case 167:
+ case 168:
+ {
+ WARN(ZS_BAD_TIME_UNIT);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 281:
+ case 282:
+ case 283:
+ case 284:
+ case 287:
+ case 288:
+ case 289:
+ case 290:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_TEXT_CHAR);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_TEXT);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 786:
+ case 787:
+ case 792:
+ case 793:
+ {
+ WARN(ZS_BAD_ADDRESS_CHAR);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_APL);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 837:
+ case 844:
+ {
+ WARN(ZS_BAD_ADDRESS_CHAR);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_GATEWAY);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 471:
+ case 472:
+ case 473:
+ case 474:
+ case 480:
+ case 481:
+ case 482:
+ case 483:
+ {
+ WARN(ZS_BAD_HEX_CHAR);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_HEX_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_HEX_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 1092:
+ {
+ WARN(ZS_BAD_HEX_CHAR);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_CHAR_COLON);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 824:
+ case 852:
+ {
+ WARN(ZS_BAD_GATEWAY);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_GATEWAY_KEY);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 1101:
+ case 1104:
+ case 1107:
+ case 1110:
+ {
+ WARN(ZS_BAD_CHAR_DASH);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_HEX_CHAR);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 1097:
+ {
+ WARN(ZS_BAD_CHAR_COLON);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_HEX_CHAR);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 194:
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ ERR(ZS_BAD_DIRECTIVE);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 172:
+ case 179:
+ case 180:
+ case 181:
+ case 182:
+ case 183:
+ case 184:
+ case 185:
+ case 186:
+ case 187:
+ case 188:
+ case 189:
+ case 190:
+ case 191:
+ case 192:
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 163:
+ {
+ s->r_owner_length = 0;
+ WARN(ZS_BAD_OWNER);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_TIME_UNIT);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 208:
+ case 210:
+ case 211:
+ case 212:
+ case 213:
+ case 214:
+ case 215:
+ case 216:
+ case 217:
+ case 218:
+ case 219:
+ case 220:
+ case 221:
+ case 222:
+ case 223:
+ {
+ s->r_owner_length = 0;
+ WARN(ZS_BAD_OWNER);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 14:
+ case 178:
+ case 209:
+ case 225:
+ case 247:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 293:
+ case 296:
+ case 298:
+ {
+ WARN(ZS_BAD_TIME_UNIT);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ ERR(ZS_BAD_TTL);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 838:
+ case 845:
+ {
+ WARN(ZS_BAD_ADDRESS_CHAR);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_GATEWAY);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_GATEWAY_KEY);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 15:
+ {
+ WARN(ZS_BAD_TIME_UNIT);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ case 205:
+ {
+ s->r_owner_length = 0;
+ WARN(ZS_BAD_OWNER);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_TIME_UNIT);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ {
+ WARN(ZS_BAD_REST);
+ p--; { if ( p == pe )
+ goto _test_eof268;
+goto st268;}
+ }
+ break;
+ }
+ }
+
+ _out: {}
+ }
+
+
+ // Check if the scanner state machine is in an uncovered state.
+ bool extra_error = false;
+ if (cs == 0) {
+ ERR(ZS_UNCOVERED_STATE);
+ extra_error = true;
+ // Check for an unclosed multiline record.
+ } else if (s->input.eof && s->multiline) {
+ ERR(ZS_UNCLOSED_MULTILINE);
+ extra_error = true;
+ }
+
+ // Treat the extra error.
+ if (extra_error) {
+ s->error.counter++;
+ s->state = ZS_STATE_ERROR;
+
+ // Copy the error context just for the part of the current line.
+ s->buffer_length = 0;
+ while (p < pe && *p != '\n' && s->buffer_length < 50) {
+ s->buffer[s->buffer_length++] = *p++;
+ }
+ s->buffer[s->buffer_length++] = 0;
+
+ // Execute the error callback.
+ if (s->process.automatic && s->process.error != NULL) {
+ s->process.error(s);
+ }
+
+ return;
+ }
+
+ // Storing scanner states.
+ s->cs = cs;
+ s->top = top;
+ memcpy(s->stack, stack, sizeof(stack));
+
+ // Store the current parser position.
+ s->input.current = p;
+
+ // Storing r_data pointer.
+ s->r_data_tail = rdata_tail - s->r_data;
+
+ if (*wrap == WRAP_DETECTED) {
+ if (set_input_string(s, "\\", 1, true) != 0) {
+ return;
+ }
+
+ *wrap = WRAP_PROCESS;
+ parse(s, wrap);
+ } else {
+ *wrap = WRAP_NONE;
+ }
+}
+
+__attribute__((visibility("default")))
+int zs_parse_record(
+ zs_scanner_t *s)
+{
+ if (s == NULL) {
+ return -1;
+ }
+
+ // Check if parsing is possible.
+ switch (s->state) {
+ case ZS_STATE_NONE:
+ case ZS_STATE_DATA:
+ case ZS_STATE_INCLUDE:
+ break;
+ case ZS_STATE_ERROR:
+ if (s->error.fatal) {
+ return -1;
+ }
+ break;
+ default:
+ // Return if stop or end of file.
+ return 0;
+ }
+
+ // Check for the end of the input.
+ if (s->input.current != s->input.end) {
+ // Try to parse another item.
+ s->state = ZS_STATE_NONE;
+ wrap_t wrap = WRAP_NONE;
+ parse(s, &wrap);
+
+ // Finish if nothing was parsed.
+ if (s->state == ZS_STATE_NONE) {
+ // Parse the final block.
+ if (set_input_string(s, "\n", 1, true) != 0) {
+ return -1;
+ }
+ parse(s, &wrap);
+ if (s->state == ZS_STATE_NONE) {
+ s->state = ZS_STATE_EOF;
+ }
+ }
+ } else {
+ s->state = ZS_STATE_EOF;
+ }
+
+ return 0;
+}
+
+__attribute__((visibility("default")))
+int zs_parse_all(
+ zs_scanner_t *s)
+{
+ if (s == NULL) {
+ return -1;
+ }
+
+ s->process.automatic = true;
+
+ // Parse input block.
+ wrap_t wrap = WRAP_NONE;
+ parse(s, &wrap);
+
+ // Parse trailing newline-char block if it makes sense.
+ if (s->state != ZS_STATE_STOP && !s->error.fatal) {
+ if (set_input_string(s, "\n", 1, true) != 0) {
+ return -1;
+ }
+ parse(s, &wrap);
+ }
+
+ // Check if any errors have occurred.
+ if (s->error.counter > 0) {
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/libzscanner/scanner.c.t0 b/src/libzscanner/scanner.c.t0
new file mode 100644
index 0000000..29205f6
--- /dev/null
+++ b/src/libzscanner/scanner.c.t0
@@ -0,0 +1,8509 @@
+
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libgen.h>
+#include <math.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "libzscanner/scanner.h"
+#include "libzscanner/functions.h"
+#include "libknot/descriptor.h"
+
+/*! \brief Maximal length of rdata item. */
+#define MAX_ITEM_LENGTH 255
+
+/*! \brief Latitude value for equator (2^31). */
+#define LOC_LAT_ZERO (uint32_t)2147483648
+/*! \brief Longitude value for meridian (2^31). */
+#define LOC_LONG_ZERO (uint32_t)2147483648
+/*! \brief Zero level altitude value. */
+#define LOC_ALT_ZERO (uint32_t)10000000
+
+/*! \brief Shorthand for setting warning data. */
+#define WARN(err_code) { s->error.code = err_code; }
+/*! \brief Shorthand for setting error data. */
+#define ERR(err_code) { WARN(err_code); s->error.fatal = true; }
+/*! \brief Shorthand for error reset. */
+#define NOERR { WARN(ZS_OK); s->error.fatal = false; }
+
+/*!
+ * \brief Writes record type number to r_data.
+ *
+ * \param type Type number.
+ * \param rdata_tail Position where to write type number to.
+ */
+static inline void type_num(const uint16_t type, uint8_t **rdata_tail)
+{
+ *((uint16_t *)*rdata_tail) = htons(type);
+ *rdata_tail += 2;
+}
+
+/*!
+ * \brief Sets bit to bitmap window.
+ *
+ * \param type Type number.
+ * \param s Scanner context.
+ */
+static inline void window_add_bit(const uint16_t type, zs_scanner_t *s) {
+ uint8_t win = type / 256;
+ uint8_t bit_pos = type % 256;
+ uint8_t byte_pos = bit_pos / 8;
+
+ ((s->windows[win]).bitmap)[byte_pos] |= 128 >> (bit_pos % 8);
+
+ if ((s->windows[win]).length < byte_pos + 1) {
+ (s->windows[win]).length = byte_pos + 1;
+ }
+
+ if (s->last_window < win) {
+ s->last_window = win;
+ }
+}
+
+// Include scanner file (in Ragel).
+
+static const short _zone_scanner_actions[] = {
+ 0, 1, 0, 1, 1, 1, 2, 1,
+ 3, 1, 4, 1, 5, 1, 7, 1,
+ 8, 1, 10, 1, 12, 1, 13, 1,
+ 14, 1, 16, 1, 17, 1, 22, 1,
+ 23, 1, 25, 1, 26, 1, 28, 1,
+ 30, 1, 32, 1, 33, 1, 42, 1,
+ 43, 1, 44, 1, 46, 1, 48, 1,
+ 49, 1, 50, 1, 51, 1, 55, 1,
+ 56, 1, 58, 1, 60, 1, 62, 1,
+ 63, 1, 65, 1, 69, 1, 70, 1,
+ 73, 1, 74, 1, 77, 1, 80, 1,
+ 82, 1, 83, 1, 84, 1, 85, 1,
+ 86, 1, 87, 1, 88, 1, 89, 1,
+ 91, 1, 93, 1, 95, 1, 99, 1,
+ 100, 1, 104, 1, 105, 1, 109, 1,
+ 110, 1, 111, 1, 112, 1, 113, 1,
+ 114, 1, 115, 1, 116, 1, 117, 1,
+ 118, 1, 119, 1, 120, 1, 121, 1,
+ 122, 1, 124, 1, 125, 1, 126, 1,
+ 127, 1, 154, 1, 155, 1, 156, 1,
+ 157, 1, 158, 1, 159, 1, 160, 1,
+ 161, 1, 162, 1, 163, 1, 164, 1,
+ 165, 1, 166, 1, 167, 1, 168, 1,
+ 169, 1, 170, 1, 171, 1, 172, 1,
+ 173, 1, 174, 1, 175, 1, 176, 1,
+ 177, 1, 178, 1, 179, 1, 180, 1,
+ 181, 1, 182, 1, 183, 1, 184, 1,
+ 185, 1, 186, 1, 187, 1, 188, 1,
+ 189, 1, 190, 1, 191, 1, 192, 1,
+ 193, 1, 194, 1, 195, 1, 196, 1,
+ 197, 1, 198, 1, 199, 1, 200, 1,
+ 201, 1, 202, 1, 203, 1, 204, 1,
+ 205, 1, 206, 1, 207, 1, 208, 1,
+ 209, 1, 210, 1, 211, 1, 212, 1,
+ 213, 1, 214, 1, 215, 1, 216, 1,
+ 217, 1, 218, 1, 219, 1, 220, 1,
+ 221, 1, 222, 1, 223, 1, 224, 1,
+ 225, 1, 226, 1, 227, 1, 228, 1,
+ 229, 1, 230, 1, 231, 1, 232, 1,
+ 233, 1, 234, 1, 235, 1, 236, 1,
+ 237, 1, 238, 1, 239, 1, 241, 1,
+ 243, 1, 244, 1, 245, 1, 246, 1,
+ 253, 1, 254, 1, 259, 1, 261, 1,
+ 266, 1, 269, 1, 270, 1, 271, 1,
+ 272, 1, 274, 1, 275, 1, 276, 1,
+ 277, 1, 279, 2, 0, 46, 2, 1,
+ 0, 2, 1, 275, 2, 1, 322, 2,
+ 2, 5, 2, 2, 7, 2, 3, 5,
+ 2, 3, 7, 2, 4, 0, 2, 4,
+ 5, 2, 4, 7, 2, 4, 275, 2,
+ 5, 2, 2, 5, 3, 2, 5, 4,
+ 2, 5, 7, 2, 6, 1, 2, 7,
+ 1, 2, 7, 2, 2, 7, 3, 2,
+ 7, 4, 2, 7, 5, 2, 7, 29,
+ 2, 8, 69, 2, 8, 73, 2, 9,
+ 10, 2, 11, 1, 2, 12, 13, 2,
+ 15, 16, 2, 17, 13, 2, 17, 14,
+ 2, 18, 23, 2, 18, 73, 2, 18,
+ 80, 2, 19, 0, 2, 19, 7, 2,
+ 21, 0, 2, 22, 12, 2, 25, 65,
+ 2, 25, 104, 2, 25, 115, 2, 26,
+ 0, 2, 26, 1, 2, 26, 2, 2,
+ 26, 3, 2, 26, 4, 2, 26, 242,
+ 2, 27, 24, 2, 28, 1, 2, 28,
+ 2, 2, 28, 3, 2, 28, 4, 2,
+ 28, 7, 2, 28, 89, 2, 29, 7,
+ 2, 30, 8, 2, 30, 274, 2, 30,
+ 279, 2, 31, 24, 2, 32, 0, 2,
+ 32, 1, 2, 32, 2, 2, 32, 3,
+ 2, 32, 4, 2, 32, 242, 2, 33,
+ 38, 2, 34, 33, 2, 35, 69, 2,
+ 35, 259, 2, 35, 274, 2, 35, 279,
+ 2, 39, 247, 2, 39, 248, 2, 39,
+ 249, 2, 39, 250, 2, 39, 251, 2,
+ 39, 252, 2, 42, 0, 2, 42, 1,
+ 2, 42, 2, 2, 42, 3, 2, 42,
+ 4, 2, 43, 0, 2, 43, 1, 2,
+ 43, 2, 2, 43, 3, 2, 43, 4,
+ 2, 44, 0, 2, 44, 1, 2, 44,
+ 2, 2, 44, 3, 2, 44, 4, 2,
+ 45, 273, 2, 46, 1, 2, 46, 2,
+ 2, 46, 3, 2, 46, 4, 2, 53,
+ 7, 2, 53, 44, 2, 53, 89, 2,
+ 54, 55, 2, 56, 1, 2, 56, 2,
+ 2, 56, 3, 2, 56, 4, 2, 57,
+ 274, 2, 58, 0, 2, 59, 60, 2,
+ 61, 62, 2, 63, 0, 2, 63, 58,
+ 2, 67, 0, 2, 67, 274, 2, 71,
+ 22, 2, 75, 65, 2, 76, 7, 2,
+ 77, 8, 2, 78, 22, 2, 80, 8,
+ 2, 86, 87, 2, 88, 1, 2, 88,
+ 2, 2, 88, 3, 2, 88, 4, 2,
+ 89, 1, 2, 89, 2, 2, 89, 3,
+ 2, 89, 4, 2, 89, 7, 2, 90,
+ 91, 2, 92, 274, 2, 93, 94, 2,
+ 95, 96, 2, 97, 98, 2, 97, 99,
+ 2, 97, 100, 2, 101, 102, 2, 103,
+ 274, 2, 106, 274, 2, 107, 0, 2,
+ 123, 274, 2, 125, 0, 2, 126, 0,
+ 2, 127, 0, 2, 128, 0, 2, 129,
+ 0, 2, 130, 0, 2, 131, 0, 2,
+ 132, 0, 2, 133, 0, 2, 134, 0,
+ 2, 135, 0, 2, 136, 0, 2, 137,
+ 0, 2, 138, 0, 2, 139, 0, 2,
+ 140, 0, 2, 141, 0, 2, 142, 0,
+ 2, 143, 0, 2, 144, 0, 2, 145,
+ 0, 2, 146, 0, 2, 147, 0, 2,
+ 148, 0, 2, 149, 0, 2, 150, 0,
+ 2, 151, 274, 2, 152, 274, 2, 153,
+ 274, 2, 154, 1, 2, 154, 2, 2,
+ 154, 3, 2, 154, 4, 2, 155, 1,
+ 2, 155, 2, 2, 155, 3, 2, 155,
+ 4, 2, 156, 1, 2, 156, 2, 2,
+ 156, 3, 2, 156, 4, 2, 157, 1,
+ 2, 157, 2, 2, 157, 3, 2, 157,
+ 4, 2, 158, 1, 2, 158, 2, 2,
+ 158, 3, 2, 158, 4, 2, 159, 1,
+ 2, 159, 2, 2, 159, 3, 2, 159,
+ 4, 2, 160, 1, 2, 160, 2, 2,
+ 160, 3, 2, 160, 4, 2, 161, 1,
+ 2, 161, 2, 2, 161, 3, 2, 161,
+ 4, 2, 162, 1, 2, 162, 2, 2,
+ 162, 3, 2, 162, 4, 2, 163, 1,
+ 2, 163, 2, 2, 163, 3, 2, 163,
+ 4, 2, 164, 1, 2, 164, 2, 2,
+ 164, 3, 2, 164, 4, 2, 165, 1,
+ 2, 165, 2, 2, 165, 3, 2, 165,
+ 4, 2, 166, 1, 2, 166, 2, 2,
+ 166, 3, 2, 166, 4, 2, 167, 1,
+ 2, 167, 2, 2, 167, 3, 2, 167,
+ 4, 2, 168, 1, 2, 168, 2, 2,
+ 168, 3, 2, 168, 4, 2, 169, 1,
+ 2, 169, 2, 2, 169, 3, 2, 169,
+ 4, 2, 170, 1, 2, 170, 2, 2,
+ 170, 3, 2, 170, 4, 2, 171, 1,
+ 2, 171, 2, 2, 171, 3, 2, 171,
+ 4, 2, 172, 1, 2, 172, 2, 2,
+ 172, 3, 2, 172, 4, 2, 173, 1,
+ 2, 173, 2, 2, 173, 3, 2, 173,
+ 4, 2, 174, 1, 2, 174, 2, 2,
+ 174, 3, 2, 174, 4, 2, 175, 1,
+ 2, 175, 2, 2, 175, 3, 2, 175,
+ 4, 2, 176, 1, 2, 176, 2, 2,
+ 176, 3, 2, 176, 4, 2, 177, 1,
+ 2, 177, 2, 2, 177, 3, 2, 177,
+ 4, 2, 178, 1, 2, 178, 2, 2,
+ 178, 3, 2, 178, 4, 2, 179, 1,
+ 2, 179, 2, 2, 179, 3, 2, 179,
+ 4, 2, 180, 1, 2, 180, 2, 2,
+ 180, 3, 2, 180, 4, 2, 181, 1,
+ 2, 181, 2, 2, 181, 3, 2, 181,
+ 4, 2, 182, 1, 2, 182, 2, 2,
+ 182, 3, 2, 182, 4, 2, 183, 1,
+ 2, 183, 2, 2, 183, 3, 2, 183,
+ 4, 2, 184, 1, 2, 184, 2, 2,
+ 184, 3, 2, 184, 4, 2, 185, 1,
+ 2, 185, 2, 2, 185, 3, 2, 185,
+ 4, 2, 186, 1, 2, 186, 2, 2,
+ 186, 3, 2, 186, 4, 2, 187, 1,
+ 2, 187, 2, 2, 187, 3, 2, 187,
+ 4, 2, 188, 1, 2, 188, 2, 2,
+ 188, 3, 2, 188, 4, 2, 189, 1,
+ 2, 189, 2, 2, 189, 3, 2, 189,
+ 4, 2, 190, 1, 2, 190, 2, 2,
+ 190, 3, 2, 190, 4, 2, 191, 1,
+ 2, 191, 2, 2, 191, 3, 2, 191,
+ 4, 2, 192, 1, 2, 192, 2, 2,
+ 192, 3, 2, 192, 4, 2, 193, 1,
+ 2, 193, 2, 2, 193, 3, 2, 193,
+ 4, 2, 194, 1, 2, 194, 2, 2,
+ 194, 3, 2, 194, 4, 2, 195, 1,
+ 2, 195, 2, 2, 195, 3, 2, 195,
+ 4, 2, 196, 1, 2, 196, 2, 2,
+ 196, 3, 2, 196, 4, 2, 197, 1,
+ 2, 197, 2, 2, 197, 3, 2, 197,
+ 4, 2, 198, 1, 2, 198, 2, 2,
+ 198, 3, 2, 198, 4, 2, 199, 1,
+ 2, 199, 2, 2, 199, 3, 2, 199,
+ 4, 2, 200, 1, 2, 200, 2, 2,
+ 200, 3, 2, 200, 4, 2, 201, 1,
+ 2, 201, 2, 2, 201, 3, 2, 201,
+ 4, 2, 202, 1, 2, 202, 2, 2,
+ 202, 3, 2, 202, 4, 2, 203, 1,
+ 2, 203, 2, 2, 203, 3, 2, 203,
+ 4, 2, 204, 1, 2, 204, 2, 2,
+ 204, 3, 2, 204, 4, 2, 205, 1,
+ 2, 205, 2, 2, 205, 3, 2, 205,
+ 4, 2, 206, 1, 2, 206, 2, 2,
+ 206, 3, 2, 206, 4, 2, 207, 1,
+ 2, 207, 2, 2, 207, 3, 2, 207,
+ 4, 2, 208, 1, 2, 208, 2, 2,
+ 208, 3, 2, 208, 4, 2, 209, 1,
+ 2, 209, 2, 2, 209, 3, 2, 209,
+ 4, 2, 210, 1, 2, 210, 2, 2,
+ 210, 3, 2, 210, 4, 2, 211, 1,
+ 2, 211, 2, 2, 211, 3, 2, 211,
+ 4, 2, 212, 1, 2, 212, 2, 2,
+ 212, 3, 2, 212, 4, 2, 213, 1,
+ 2, 213, 2, 2, 213, 3, 2, 213,
+ 4, 2, 214, 1, 2, 214, 2, 2,
+ 214, 3, 2, 214, 4, 2, 215, 1,
+ 2, 215, 2, 2, 215, 3, 2, 215,
+ 4, 2, 216, 1, 2, 216, 2, 2,
+ 216, 3, 2, 216, 4, 2, 217, 1,
+ 2, 217, 2, 2, 217, 3, 2, 217,
+ 4, 2, 218, 1, 2, 218, 2, 2,
+ 218, 3, 2, 218, 4, 2, 219, 1,
+ 2, 219, 2, 2, 219, 3, 2, 219,
+ 4, 2, 220, 1, 2, 220, 2, 2,
+ 220, 3, 2, 220, 4, 2, 221, 1,
+ 2, 221, 2, 2, 221, 3, 2, 221,
+ 4, 2, 222, 1, 2, 222, 2, 2,
+ 222, 3, 2, 222, 4, 2, 223, 1,
+ 2, 223, 2, 2, 223, 3, 2, 223,
+ 4, 2, 224, 1, 2, 224, 2, 2,
+ 224, 3, 2, 224, 4, 2, 225, 1,
+ 2, 225, 2, 2, 225, 3, 2, 225,
+ 4, 2, 226, 1, 2, 226, 2, 2,
+ 226, 3, 2, 226, 4, 2, 227, 1,
+ 2, 227, 2, 2, 227, 3, 2, 227,
+ 4, 2, 228, 1, 2, 228, 2, 2,
+ 228, 3, 2, 228, 4, 2, 229, 1,
+ 2, 229, 2, 2, 229, 3, 2, 229,
+ 4, 2, 230, 1, 2, 230, 2, 2,
+ 230, 3, 2, 230, 4, 2, 231, 1,
+ 2, 231, 2, 2, 231, 3, 2, 231,
+ 4, 2, 232, 1, 2, 232, 2, 2,
+ 232, 3, 2, 232, 4, 2, 233, 1,
+ 2, 233, 2, 2, 233, 3, 2, 233,
+ 4, 2, 234, 1, 2, 234, 2, 2,
+ 234, 3, 2, 234, 4, 2, 235, 1,
+ 2, 235, 2, 2, 235, 3, 2, 235,
+ 4, 2, 236, 1, 2, 236, 2, 2,
+ 236, 3, 2, 236, 4, 2, 237, 1,
+ 2, 237, 2, 2, 237, 3, 2, 237,
+ 4, 2, 238, 1, 2, 238, 2, 2,
+ 238, 3, 2, 238, 4, 2, 239, 1,
+ 2, 239, 2, 2, 239, 3, 2, 239,
+ 4, 2, 240, 0, 2, 243, 1, 2,
+ 243, 2, 2, 243, 3, 2, 243, 4,
+ 2, 244, 1, 2, 244, 2, 2, 244,
+ 3, 2, 244, 4, 2, 245, 1, 2,
+ 245, 2, 2, 245, 3, 2, 245, 4,
+ 2, 246, 1, 2, 246, 2, 2, 246,
+ 3, 2, 246, 4, 2, 253, 1, 2,
+ 253, 2, 2, 253, 3, 2, 253, 4,
+ 2, 254, 1, 2, 254, 2, 2, 254,
+ 3, 2, 254, 4, 2, 257, 0, 2,
+ 258, 274, 2, 260, 104, 2, 265, 104,
+ 2, 274, 8, 2, 275, 1, 2, 275,
+ 4, 2, 278, 275, 2, 279, 8, 2,
+ 279, 274, 2, 280, 273, 2, 281, 273,
+ 2, 282, 273, 2, 283, 273, 2, 284,
+ 273, 2, 285, 273, 2, 286, 273, 2,
+ 287, 273, 2, 288, 273, 2, 289, 273,
+ 2, 290, 273, 2, 291, 273, 2, 292,
+ 273, 2, 293, 273, 2, 294, 273, 2,
+ 295, 273, 2, 296, 273, 2, 297, 273,
+ 2, 298, 273, 2, 299, 273, 2, 300,
+ 273, 2, 301, 273, 2, 302, 273, 2,
+ 303, 273, 2, 304, 273, 2, 305, 273,
+ 2, 306, 273, 2, 307, 273, 2, 308,
+ 273, 2, 309, 273, 2, 310, 273, 2,
+ 311, 273, 2, 312, 273, 2, 313, 273,
+ 2, 314, 273, 2, 315, 273, 2, 316,
+ 273, 2, 317, 273, 2, 318, 273, 2,
+ 319, 273, 2, 320, 273, 2, 321, 273,
+ 2, 322, 1, 3, 0, 46, 1, 3,
+ 0, 46, 2, 3, 0, 46, 3, 3,
+ 0, 46, 4, 3, 1, 7, 322, 3,
+ 1, 29, 7, 3, 1, 67, 0, 3,
+ 1, 107, 0, 3, 1, 240, 0, 3,
+ 1, 257, 0, 3, 1, 275, 322, 3,
+ 2, 7, 29, 3, 2, 29, 7, 3,
+ 3, 7, 29, 3, 3, 29, 7, 3,
+ 4, 7, 29, 3, 4, 29, 7, 3,
+ 4, 67, 0, 3, 4, 107, 0, 3,
+ 4, 240, 0, 3, 4, 257, 0, 3,
+ 4, 275, 7, 3, 5, 7, 2, 3,
+ 5, 7, 3, 3, 5, 7, 4, 3,
+ 6, 1, 322, 3, 6, 322, 1, 3,
+ 7, 2, 5, 3, 7, 2, 29, 3,
+ 7, 3, 5, 3, 7, 3, 29, 3,
+ 7, 4, 5, 3, 7, 4, 29, 3,
+ 7, 322, 1, 3, 9, 11, 1, 3,
+ 14, 20, 0, 3, 19, 7, 2, 3,
+ 19, 7, 3, 3, 19, 7, 4, 3,
+ 19, 79, 7, 3, 22, 12, 13, 3,
+ 26, 67, 0, 3, 28, 1, 89, 3,
+ 28, 2, 7, 3, 28, 2, 89, 3,
+ 28, 3, 7, 3, 28, 3, 89, 3,
+ 28, 4, 7, 3, 28, 4, 89, 3,
+ 28, 89, 7, 3, 28, 278, 275, 3,
+ 28, 280, 273, 3, 29, 1, 7, 3,
+ 29, 2, 7, 3, 29, 3, 7, 3,
+ 29, 4, 7, 3, 30, 85, 8, 3,
+ 30, 274, 8, 3, 30, 279, 8, 3,
+ 30, 279, 274, 3, 32, 1, 0, 3,
+ 32, 4, 0, 3, 34, 33, 275, 3,
+ 35, 151, 274, 3, 35, 153, 274, 3,
+ 35, 279, 8, 3, 35, 279, 274, 3,
+ 37, 39, 247, 3, 37, 39, 248, 3,
+ 37, 39, 249, 3, 37, 39, 250, 3,
+ 37, 39, 251, 3, 37, 39, 252, 3,
+ 39, 247, 1, 3, 39, 247, 2, 3,
+ 39, 247, 3, 3, 39, 247, 4, 3,
+ 39, 248, 1, 3, 39, 248, 2, 3,
+ 39, 248, 3, 3, 39, 248, 4, 3,
+ 39, 249, 1, 3, 39, 249, 2, 3,
+ 39, 249, 3, 3, 39, 249, 4, 3,
+ 39, 250, 1, 3, 39, 250, 2, 3,
+ 39, 250, 3, 3, 39, 250, 4, 3,
+ 39, 251, 1, 3, 39, 251, 2, 3,
+ 39, 251, 3, 3, 39, 251, 4, 3,
+ 39, 252, 1, 3, 39, 252, 2, 3,
+ 39, 252, 3, 3, 39, 252, 4, 3,
+ 45, 273, 1, 3, 45, 273, 2, 3,
+ 45, 273, 3, 3, 45, 273, 4, 3,
+ 45, 273, 275, 3, 47, 35, 69, 3,
+ 47, 35, 274, 3, 47, 35, 279, 3,
+ 52, 34, 33, 3, 53, 7, 2, 3,
+ 53, 7, 3, 3, 53, 7, 4, 3,
+ 53, 44, 0, 3, 53, 44, 1, 3,
+ 53, 44, 2, 3, 53, 44, 3, 3,
+ 53, 44, 4, 3, 53, 89, 1, 3,
+ 53, 89, 2, 3, 53, 89, 3, 3,
+ 53, 89, 4, 3, 63, 58, 0, 3,
+ 64, 59, 60, 3, 66, 25, 65, 3,
+ 68, 0, 1, 3, 71, 22, 12, 3,
+ 72, 0, 1, 3, 76, 2, 7, 3,
+ 76, 3, 7, 3, 76, 4, 7, 3,
+ 76, 7, 4, 3, 78, 22, 12, 3,
+ 81, 0, 1, 3, 84, 7, 1, 3,
+ 84, 7, 4, 3, 84, 27, 24, 3,
+ 84, 29, 7, 3, 86, 27, 24, 3,
+ 86, 87, 275, 3, 89, 2, 7, 3,
+ 89, 3, 7, 3, 89, 4, 7, 3,
+ 92, 103, 274, 3, 92, 151, 274, 3,
+ 93, 94, 0, 3, 93, 94, 1, 3,
+ 93, 94, 2, 3, 93, 94, 3, 3,
+ 93, 94, 4, 3, 95, 96, 0, 3,
+ 95, 96, 1, 3, 95, 96, 2, 3,
+ 95, 96, 3, 3, 95, 96, 4, 3,
+ 101, 102, 0, 3, 101, 102, 1, 3,
+ 101, 102, 2, 3, 101, 102, 3, 3,
+ 101, 102, 4, 3, 106, 108, 259, 3,
+ 106, 268, 274, 3, 151, 152, 274, 3,
+ 196, 240, 0, 3, 197, 240, 0, 3,
+ 198, 240, 0, 3, 199, 240, 0, 3,
+ 200, 240, 0, 3, 201, 240, 0, 3,
+ 202, 240, 0, 3, 203, 240, 0, 3,
+ 204, 240, 0, 3, 205, 240, 0, 3,
+ 206, 240, 0, 3, 207, 240, 0, 3,
+ 208, 240, 0, 3, 209, 240, 0, 3,
+ 210, 240, 0, 3, 211, 240, 0, 3,
+ 212, 240, 0, 3, 213, 240, 0, 3,
+ 214, 240, 0, 3, 215, 240, 0, 3,
+ 216, 240, 0, 3, 217, 240, 0, 3,
+ 218, 240, 0, 3, 219, 240, 0, 3,
+ 220, 240, 0, 3, 221, 240, 0, 3,
+ 222, 240, 0, 3, 223, 240, 0, 3,
+ 224, 240, 0, 3, 225, 240, 0, 3,
+ 226, 240, 0, 3, 227, 240, 0, 3,
+ 228, 240, 0, 3, 229, 240, 0, 3,
+ 230, 240, 0, 3, 231, 240, 0, 3,
+ 232, 240, 0, 3, 233, 240, 0, 3,
+ 234, 240, 0, 3, 235, 240, 0, 3,
+ 236, 240, 0, 3, 237, 240, 0, 3,
+ 238, 240, 0, 3, 239, 240, 0, 3,
+ 256, 34, 33, 3, 261, 262, 0, 3,
+ 261, 263, 0, 3, 264, 106, 274, 3,
+ 266, 267, 0, 3, 268, 106, 274, 3,
+ 274, 8, 85, 3, 275, 7, 1, 3,
+ 275, 7, 4, 3, 275, 27, 24, 3,
+ 275, 322, 1, 3, 277, 27, 24, 3,
+ 279, 274, 8, 3, 280, 273, 1, 3,
+ 280, 273, 2, 3, 280, 273, 3, 3,
+ 280, 273, 4, 3, 280, 273, 7, 3,
+ 280, 273, 275, 3, 281, 273, 1, 3,
+ 281, 273, 2, 3, 281, 273, 3, 3,
+ 281, 273, 4, 3, 281, 273, 275, 3,
+ 282, 273, 1, 3, 282, 273, 2, 3,
+ 282, 273, 3, 3, 282, 273, 4, 3,
+ 282, 273, 275, 3, 283, 273, 1, 3,
+ 283, 273, 2, 3, 283, 273, 3, 3,
+ 283, 273, 4, 3, 283, 273, 275, 3,
+ 284, 273, 1, 3, 284, 273, 2, 3,
+ 284, 273, 3, 3, 284, 273, 4, 3,
+ 284, 273, 275, 3, 285, 273, 1, 3,
+ 285, 273, 2, 3, 285, 273, 3, 3,
+ 285, 273, 4, 3, 285, 273, 275, 3,
+ 286, 273, 1, 3, 286, 273, 2, 3,
+ 286, 273, 3, 3, 286, 273, 4, 3,
+ 286, 273, 275, 3, 287, 273, 1, 3,
+ 287, 273, 2, 3, 287, 273, 3, 3,
+ 287, 273, 4, 3, 287, 273, 275, 3,
+ 288, 273, 1, 3, 288, 273, 2, 3,
+ 288, 273, 3, 3, 288, 273, 4, 3,
+ 288, 273, 275, 3, 289, 273, 1, 3,
+ 289, 273, 2, 3, 289, 273, 3, 3,
+ 289, 273, 4, 3, 289, 273, 275, 3,
+ 290, 273, 1, 3, 290, 273, 2, 3,
+ 290, 273, 3, 3, 290, 273, 4, 3,
+ 290, 273, 275, 3, 291, 273, 1, 3,
+ 291, 273, 2, 3, 291, 273, 3, 3,
+ 291, 273, 4, 3, 291, 273, 275, 3,
+ 292, 273, 1, 3, 292, 273, 2, 3,
+ 292, 273, 3, 3, 292, 273, 4, 3,
+ 292, 273, 275, 3, 293, 273, 1, 3,
+ 293, 273, 2, 3, 293, 273, 3, 3,
+ 293, 273, 4, 3, 293, 273, 275, 3,
+ 294, 273, 1, 3, 294, 273, 2, 3,
+ 294, 273, 3, 3, 294, 273, 4, 3,
+ 294, 273, 275, 3, 295, 273, 1, 3,
+ 295, 273, 2, 3, 295, 273, 3, 3,
+ 295, 273, 4, 3, 295, 273, 275, 3,
+ 296, 273, 1, 3, 296, 273, 2, 3,
+ 296, 273, 3, 3, 296, 273, 4, 3,
+ 296, 273, 275, 3, 297, 273, 1, 3,
+ 297, 273, 2, 3, 297, 273, 3, 3,
+ 297, 273, 4, 3, 297, 273, 275, 3,
+ 298, 273, 1, 3, 298, 273, 2, 3,
+ 298, 273, 3, 3, 298, 273, 4, 3,
+ 298, 273, 275, 3, 299, 273, 1, 3,
+ 299, 273, 2, 3, 299, 273, 3, 3,
+ 299, 273, 4, 3, 299, 273, 275, 3,
+ 300, 273, 1, 3, 300, 273, 2, 3,
+ 300, 273, 3, 3, 300, 273, 4, 3,
+ 300, 273, 275, 3, 301, 273, 1, 3,
+ 301, 273, 2, 3, 301, 273, 3, 3,
+ 301, 273, 4, 3, 301, 273, 275, 3,
+ 302, 273, 1, 3, 302, 273, 2, 3,
+ 302, 273, 3, 3, 302, 273, 4, 3,
+ 302, 273, 275, 3, 303, 273, 1, 3,
+ 303, 273, 2, 3, 303, 273, 3, 3,
+ 303, 273, 4, 3, 303, 273, 275, 3,
+ 304, 273, 1, 3, 304, 273, 2, 3,
+ 304, 273, 3, 3, 304, 273, 4, 3,
+ 304, 273, 275, 3, 305, 273, 1, 3,
+ 305, 273, 2, 3, 305, 273, 3, 3,
+ 305, 273, 4, 3, 305, 273, 275, 3,
+ 306, 273, 1, 3, 306, 273, 2, 3,
+ 306, 273, 3, 3, 306, 273, 4, 3,
+ 306, 273, 275, 3, 307, 273, 1, 3,
+ 307, 273, 2, 3, 307, 273, 3, 3,
+ 307, 273, 4, 3, 307, 273, 275, 3,
+ 308, 273, 1, 3, 308, 273, 2, 3,
+ 308, 273, 3, 3, 308, 273, 4, 3,
+ 308, 273, 275, 3, 309, 273, 1, 3,
+ 309, 273, 2, 3, 309, 273, 3, 3,
+ 309, 273, 4, 3, 309, 273, 275, 3,
+ 310, 273, 1, 3, 310, 273, 2, 3,
+ 310, 273, 3, 3, 310, 273, 4, 3,
+ 310, 273, 275, 3, 311, 273, 1, 3,
+ 311, 273, 2, 3, 311, 273, 3, 3,
+ 311, 273, 4, 3, 311, 273, 275, 3,
+ 312, 273, 1, 3, 312, 273, 2, 3,
+ 312, 273, 3, 3, 312, 273, 4, 3,
+ 312, 273, 275, 3, 313, 273, 1, 3,
+ 313, 273, 2, 3, 313, 273, 3, 3,
+ 313, 273, 4, 3, 313, 273, 275, 3,
+ 314, 273, 1, 3, 314, 273, 2, 3,
+ 314, 273, 3, 3, 314, 273, 4, 3,
+ 314, 273, 275, 3, 315, 273, 1, 3,
+ 315, 273, 2, 3, 315, 273, 3, 3,
+ 315, 273, 4, 3, 315, 273, 275, 3,
+ 316, 273, 1, 3, 316, 273, 2, 3,
+ 316, 273, 3, 3, 316, 273, 4, 3,
+ 316, 273, 275, 3, 317, 273, 1, 3,
+ 317, 273, 2, 3, 317, 273, 3, 3,
+ 317, 273, 4, 3, 317, 273, 275, 3,
+ 318, 273, 1, 3, 318, 273, 2, 3,
+ 318, 273, 3, 3, 318, 273, 4, 3,
+ 318, 273, 275, 3, 319, 273, 1, 3,
+ 319, 273, 2, 3, 319, 273, 3, 3,
+ 319, 273, 4, 3, 319, 273, 275, 3,
+ 320, 273, 1, 3, 320, 273, 2, 3,
+ 320, 273, 3, 3, 320, 273, 4, 3,
+ 320, 273, 275, 3, 321, 273, 1, 3,
+ 321, 273, 2, 3, 321, 273, 3, 3,
+ 321, 273, 4, 3, 321, 273, 275, 3,
+ 322, 1, 6, 4, 1, 7, 322, 29,
+ 4, 1, 275, 29, 7, 4, 4, 275,
+ 7, 29, 4, 4, 275, 29, 7, 4,
+ 6, 1, 7, 322, 4, 6, 1, 81,
+ 0, 4, 6, 68, 0, 1, 4, 6,
+ 72, 0, 1, 4, 6, 81, 0, 1,
+ 4, 7, 6, 322, 1, 4, 7, 68,
+ 0, 1, 4, 7, 322, 1, 6, 4,
+ 7, 322, 1, 29, 4, 17, 14, 20,
+ 0, 4, 19, 79, 7, 2, 4, 19,
+ 79, 7, 3, 4, 19, 79, 7, 4,
+ 4, 26, 1, 67, 0, 4, 26, 4,
+ 67, 0, 4, 28, 1, 7, 322, 4,
+ 28, 1, 278, 275, 4, 28, 1, 280,
+ 273, 4, 28, 2, 89, 7, 4, 28,
+ 2, 278, 275, 4, 28, 2, 280, 273,
+ 4, 28, 3, 89, 7, 4, 28, 3,
+ 278, 275, 4, 28, 3, 280, 273, 4,
+ 28, 4, 89, 7, 4, 28, 4, 278,
+ 275, 4, 28, 4, 280, 273, 4, 28,
+ 280, 273, 7, 4, 30, 35, 279, 8,
+ 4, 30, 47, 35, 279, 4, 30, 279,
+ 274, 8, 4, 34, 33, 27, 24, 4,
+ 35, 279, 274, 8, 4, 37, 34, 33,
+ 38, 4, 37, 39, 247, 1, 4, 37,
+ 39, 247, 2, 4, 37, 39, 247, 3,
+ 4, 37, 39, 247, 4, 4, 37, 39,
+ 248, 1, 4, 37, 39, 248, 2, 4,
+ 37, 39, 248, 3, 4, 37, 39, 248,
+ 4, 4, 37, 39, 249, 1, 4, 37,
+ 39, 249, 2, 4, 37, 39, 249, 3,
+ 4, 37, 39, 249, 4, 4, 37, 39,
+ 250, 1, 4, 37, 39, 250, 2, 4,
+ 37, 39, 250, 3, 4, 37, 39, 250,
+ 4, 4, 37, 39, 251, 1, 4, 37,
+ 39, 251, 2, 4, 37, 39, 251, 3,
+ 4, 37, 39, 251, 4, 4, 37, 39,
+ 252, 1, 4, 37, 39, 252, 2, 4,
+ 37, 39, 252, 3, 4, 37, 39, 252,
+ 4, 4, 39, 249, 257, 0, 4, 39,
+ 250, 257, 0, 4, 39, 251, 257, 0,
+ 4, 39, 252, 257, 0, 4, 40, 36,
+ 34, 33, 4, 41, 36, 34, 33, 4,
+ 45, 273, 1, 275, 4, 45, 273, 4,
+ 275, 4, 47, 35, 8, 69, 4, 53,
+ 52, 34, 33, 4, 71, 22, 12, 13,
+ 4, 78, 22, 12, 13, 4, 84, 29,
+ 1, 7, 4, 84, 29, 2, 7, 4,
+ 84, 29, 3, 7, 4, 84, 29, 4,
+ 7, 4, 86, 87, 27, 24, 4, 89,
+ 1, 7, 322, 4, 92, 151, 152, 274,
+ 4, 93, 94, 1, 0, 4, 93, 94,
+ 4, 0, 4, 95, 96, 1, 0, 4,
+ 95, 96, 4, 0, 4, 101, 102, 1,
+ 0, 4, 101, 102, 4, 0, 4, 196,
+ 1, 240, 0, 4, 196, 4, 240, 0,
+ 4, 197, 1, 240, 0, 4, 197, 4,
+ 240, 0, 4, 198, 1, 240, 0, 4,
+ 198, 4, 240, 0, 4, 199, 1, 240,
+ 0, 4, 199, 4, 240, 0, 4, 200,
+ 1, 240, 0, 4, 200, 4, 240, 0,
+ 4, 201, 1, 240, 0, 4, 201, 4,
+ 240, 0, 4, 202, 1, 240, 0, 4,
+ 202, 4, 240, 0, 4, 203, 1, 240,
+ 0, 4, 203, 4, 240, 0, 4, 204,
+ 1, 240, 0, 4, 204, 4, 240, 0,
+ 4, 205, 1, 240, 0, 4, 205, 4,
+ 240, 0, 4, 206, 1, 240, 0, 4,
+ 206, 4, 240, 0, 4, 207, 1, 240,
+ 0, 4, 207, 4, 240, 0, 4, 208,
+ 1, 240, 0, 4, 208, 4, 240, 0,
+ 4, 209, 1, 240, 0, 4, 209, 4,
+ 240, 0, 4, 210, 1, 240, 0, 4,
+ 210, 4, 240, 0, 4, 211, 1, 240,
+ 0, 4, 211, 4, 240, 0, 4, 212,
+ 1, 240, 0, 4, 212, 4, 240, 0,
+ 4, 213, 1, 240, 0, 4, 213, 4,
+ 240, 0, 4, 214, 1, 240, 0, 4,
+ 214, 4, 240, 0, 4, 215, 1, 240,
+ 0, 4, 215, 4, 240, 0, 4, 216,
+ 1, 240, 0, 4, 216, 4, 240, 0,
+ 4, 217, 1, 240, 0, 4, 217, 4,
+ 240, 0, 4, 218, 1, 240, 0, 4,
+ 218, 4, 240, 0, 4, 219, 1, 240,
+ 0, 4, 219, 4, 240, 0, 4, 220,
+ 1, 240, 0, 4, 220, 4, 240, 0,
+ 4, 221, 1, 240, 0, 4, 221, 4,
+ 240, 0, 4, 222, 1, 240, 0, 4,
+ 222, 4, 240, 0, 4, 223, 1, 240,
+ 0, 4, 223, 4, 240, 0, 4, 224,
+ 1, 240, 0, 4, 224, 4, 240, 0,
+ 4, 225, 1, 240, 0, 4, 225, 4,
+ 240, 0, 4, 226, 1, 240, 0, 4,
+ 226, 4, 240, 0, 4, 227, 1, 240,
+ 0, 4, 227, 4, 240, 0, 4, 228,
+ 1, 240, 0, 4, 228, 4, 240, 0,
+ 4, 229, 1, 240, 0, 4, 229, 4,
+ 240, 0, 4, 230, 1, 240, 0, 4,
+ 230, 4, 240, 0, 4, 231, 1, 240,
+ 0, 4, 231, 4, 240, 0, 4, 232,
+ 1, 240, 0, 4, 232, 4, 240, 0,
+ 4, 233, 1, 240, 0, 4, 233, 4,
+ 240, 0, 4, 234, 1, 240, 0, 4,
+ 234, 4, 240, 0, 4, 235, 1, 240,
+ 0, 4, 235, 4, 240, 0, 4, 236,
+ 1, 240, 0, 4, 236, 4, 240, 0,
+ 4, 237, 1, 240, 0, 4, 237, 4,
+ 240, 0, 4, 238, 1, 240, 0, 4,
+ 238, 4, 240, 0, 4, 239, 1, 240,
+ 0, 4, 239, 4, 240, 0, 4, 275,
+ 7, 322, 1, 4, 280, 273, 1, 275,
+ 4, 280, 273, 2, 7, 4, 280, 273,
+ 3, 7, 4, 280, 273, 4, 7, 4,
+ 280, 273, 4, 275, 4, 281, 273, 1,
+ 275, 4, 281, 273, 4, 275, 4, 282,
+ 273, 1, 275, 4, 282, 273, 4, 275,
+ 4, 283, 273, 1, 275, 4, 283, 273,
+ 4, 275, 4, 284, 273, 1, 275, 4,
+ 284, 273, 4, 275, 4, 285, 273, 1,
+ 275, 4, 285, 273, 4, 275, 4, 286,
+ 273, 1, 275, 4, 286, 273, 4, 275,
+ 4, 287, 273, 1, 275, 4, 287, 273,
+ 4, 275, 4, 288, 273, 1, 275, 4,
+ 288, 273, 4, 275, 4, 289, 273, 1,
+ 275, 4, 289, 273, 4, 275, 4, 290,
+ 273, 1, 275, 4, 290, 273, 4, 275,
+ 4, 291, 273, 1, 275, 4, 291, 273,
+ 4, 275, 4, 292, 273, 1, 275, 4,
+ 292, 273, 4, 275, 4, 293, 273, 1,
+ 275, 4, 293, 273, 4, 275, 4, 294,
+ 273, 1, 275, 4, 294, 273, 4, 275,
+ 4, 295, 273, 1, 275, 4, 295, 273,
+ 4, 275, 4, 296, 273, 1, 275, 4,
+ 296, 273, 4, 275, 4, 297, 273, 1,
+ 275, 4, 297, 273, 4, 275, 4, 298,
+ 273, 1, 275, 4, 298, 273, 4, 275,
+ 4, 299, 273, 1, 275, 4, 299, 273,
+ 4, 275, 4, 300, 273, 1, 275, 4,
+ 300, 273, 4, 275, 4, 301, 273, 1,
+ 275, 4, 301, 273, 4, 275, 4, 302,
+ 273, 1, 275, 4, 302, 273, 4, 275,
+ 4, 303, 273, 1, 275, 4, 303, 273,
+ 4, 275, 4, 304, 273, 1, 275, 4,
+ 304, 273, 4, 275, 4, 305, 273, 1,
+ 275, 4, 305, 273, 4, 275, 4, 306,
+ 273, 1, 275, 4, 306, 273, 4, 275,
+ 4, 307, 273, 1, 275, 4, 307, 273,
+ 4, 275, 4, 308, 273, 1, 275, 4,
+ 308, 273, 4, 275, 4, 309, 273, 1,
+ 275, 4, 309, 273, 4, 275, 4, 310,
+ 273, 1, 275, 4, 310, 273, 4, 275,
+ 4, 311, 273, 1, 275, 4, 311, 273,
+ 4, 275, 4, 312, 273, 1, 275, 4,
+ 312, 273, 4, 275, 4, 313, 273, 1,
+ 275, 4, 313, 273, 4, 275, 4, 314,
+ 273, 1, 275, 4, 314, 273, 4, 275,
+ 4, 315, 273, 1, 275, 4, 315, 273,
+ 4, 275, 4, 316, 273, 1, 275, 4,
+ 316, 273, 4, 275, 4, 317, 273, 1,
+ 275, 4, 317, 273, 4, 275, 4, 318,
+ 273, 1, 275, 4, 318, 273, 4, 275,
+ 4, 319, 273, 1, 275, 4, 319, 273,
+ 4, 275, 4, 320, 273, 1, 275, 4,
+ 320, 273, 4, 275, 4, 321, 273, 1,
+ 275, 4, 321, 273, 4, 275, 5, 19,
+ 7, 72, 0, 1, 5, 28, 1, 89,
+ 7, 322, 5, 28, 1, 280, 273, 275,
+ 5, 28, 2, 280, 273, 7, 5, 28,
+ 3, 280, 273, 7, 5, 28, 4, 280,
+ 273, 7, 5, 28, 4, 280, 273, 275,
+ 5, 30, 35, 279, 274, 8, 5, 34,
+ 33, 275, 27, 24, 5, 37, 39, 249,
+ 257, 0, 5, 37, 39, 250, 257, 0,
+ 5, 37, 39, 251, 257, 0, 5, 37,
+ 39, 252, 257, 0, 5, 39, 249, 1,
+ 257, 0, 5, 39, 249, 4, 257, 0,
+ 5, 39, 250, 1, 257, 0, 5, 39,
+ 250, 4, 257, 0, 5, 39, 251, 1,
+ 257, 0, 5, 39, 251, 4, 257, 0,
+ 5, 39, 252, 1, 257, 0, 5, 39,
+ 252, 4, 257, 0, 5, 47, 35, 279,
+ 274, 8, 5, 53, 7, 68, 0, 1,
+ 5, 76, 7, 81, 0, 1, 5, 86,
+ 87, 275, 27, 24, 5, 255, 40, 36,
+ 34, 33, 5, 280, 273, 1, 7, 322,
+ 5, 280, 273, 4, 275, 7, 5, 280,
+ 273, 275, 7, 4, 6, 19, 79, 7,
+ 81, 0, 1, 6, 28, 1, 280, 273,
+ 7, 322, 6, 28, 4, 280, 273, 275,
+ 7, 6, 30, 47, 35, 279, 274, 8,
+ 6, 37, 39, 249, 1, 257, 0, 6,
+ 37, 39, 249, 4, 257, 0, 6, 37,
+ 39, 250, 1, 257, 0, 6, 37, 39,
+ 250, 4, 257, 0, 6, 37, 39, 251,
+ 1, 257, 0, 6, 37, 39, 251, 4,
+ 257, 0, 6, 37, 39, 252, 1, 257,
+ 0, 6, 37, 39, 252, 4, 257, 0,
+ 6, 280, 273, 1, 275, 7, 322, 6,
+ 280, 273, 275, 7, 322, 1, 7, 28,
+ 1, 280, 273, 275, 7, 322
+};
+
+static const short _zone_scanner_cond_offsets[] = {
+ 0, 0, 2, 4, 6, 8, 10, 12,
+ 14, 14, 14, 17, 19, 21, 24, 26,
+ 28, 30, 30, 30, 32, 37, 42, 42,
+ 42, 42, 42, 42, 44, 46, 46, 46,
+ 48, 48, 48, 48, 50, 50, 50, 50,
+ 50, 52, 52, 52, 52, 54, 54, 54,
+ 54, 56, 58, 58, 58, 58, 58, 60,
+ 60, 62, 62, 62, 62, 62, 64, 64,
+ 66, 68, 68, 68, 68, 68, 68, 68,
+ 68, 70, 70, 70, 72, 74, 74, 74,
+ 76, 76, 78, 78, 80, 82, 82, 82,
+ 82, 82, 84, 86, 86, 86, 86, 86,
+ 88, 88, 90, 92, 92, 94, 96, 96,
+ 96, 96, 96, 98, 98, 98, 100, 100,
+ 102, 102, 102, 102, 104, 106, 106, 106,
+ 108, 108, 110, 110, 112, 112, 112, 112,
+ 114, 114, 114, 114, 116, 116, 118, 118,
+ 118, 118, 120, 120, 120, 122, 125, 127,
+ 127, 129, 131, 133, 135, 135, 137, 140,
+ 140, 140, 140, 140, 140, 140, 140, 140,
+ 140, 142, 144, 147, 149, 151, 154, 156,
+ 156, 158, 161, 163, 165, 167, 169, 171,
+ 174, 176, 178, 180, 182, 184, 186, 188,
+ 190, 192, 194, 196, 198, 200, 202, 204,
+ 206, 208, 211, 213, 213, 213, 213, 213,
+ 213, 213, 213, 213, 213, 215, 217, 219,
+ 222, 224, 226, 228, 230, 232, 234, 236,
+ 238, 240, 242, 244, 246, 248, 250, 252,
+ 254, 256, 258, 263, 268, 273, 278, 278,
+ 278, 280, 280, 280, 280, 282, 282, 284,
+ 287, 289, 291, 296, 301, 306, 311, 314,
+ 316, 321, 326, 328, 330, 332, 334, 336,
+ 338, 340, 342, 344, 346, 348, 350, 352,
+ 354, 357, 360, 362, 365, 365, 365, 365,
+ 365, 365, 365, 365, 365, 365, 365, 365,
+ 365, 365, 365, 365, 365, 365, 366, 366,
+ 366, 366, 366, 367, 369, 371, 373, 375,
+ 375, 377, 377, 379, 382, 384, 386, 386,
+ 388, 390, 390, 390, 390, 390, 390, 392,
+ 395, 397, 399, 401, 403, 403, 405, 407,
+ 407, 407, 407, 407, 407, 409, 412, 414,
+ 417, 420, 420, 420, 420, 420, 422, 425,
+ 425, 427, 429, 431, 431, 431, 433, 436,
+ 436, 436, 438, 438, 438, 438, 438, 438,
+ 440, 442, 442, 442, 444, 444, 444, 444,
+ 446, 446, 446, 446, 446, 448, 448, 448,
+ 448, 450, 450, 450, 450, 452, 454, 454,
+ 454, 454, 454, 456, 456, 458, 458, 458,
+ 458, 458, 460, 460, 460, 460, 460, 460,
+ 460, 460, 462, 462, 462, 464, 466, 466,
+ 466, 468, 468, 470, 470, 472, 474, 474,
+ 474, 474, 474, 476, 478, 478, 478, 478,
+ 478, 480, 480, 482, 484, 484, 486, 488,
+ 488, 488, 488, 488, 490, 490, 490, 492,
+ 492, 494, 494, 494, 494, 496, 498, 498,
+ 498, 500, 500, 502, 502, 504, 504, 504,
+ 504, 506, 506, 506, 506, 508, 508, 510,
+ 510, 510, 510, 512, 512, 512, 514, 514,
+ 514, 514, 516, 516, 518, 520, 522, 524,
+ 526, 526, 528, 531, 534, 537, 539, 541,
+ 543, 545, 545, 547, 550, 553, 555, 558,
+ 558, 558, 558, 558, 558, 558, 558, 558,
+ 558, 558, 558, 558, 558, 558, 558, 558,
+ 558, 558, 558, 558, 558, 558, 558, 558,
+ 558, 558, 558, 558, 558, 558, 558, 558,
+ 558, 558, 558, 558, 558, 558, 558, 558,
+ 558, 558, 558, 558, 558, 558, 558, 558,
+ 558, 558, 558, 558, 558, 558, 558, 558,
+ 558, 558, 558, 558, 558, 558, 558, 558,
+ 558, 558, 558, 558, 558, 558, 558, 558,
+ 558, 558, 558, 558, 558, 558, 558, 558,
+ 558, 558, 558, 558, 558, 558, 558, 558,
+ 558, 558, 558, 558, 558, 558, 558, 558,
+ 558, 558, 558, 558, 558, 558, 558, 558,
+ 558, 558, 558, 558, 558, 558, 558, 558,
+ 558, 558, 558, 558, 558, 558, 558, 558,
+ 558, 558, 558, 558, 558, 558, 558, 558,
+ 558, 558, 558, 558, 558, 558, 558, 558,
+ 558, 558, 558, 558, 558, 558, 558, 558,
+ 558, 558, 558, 558, 558, 558, 560, 562,
+ 564, 566, 568, 570, 572, 574, 576, 578,
+ 580, 582, 582, 582, 582, 582, 585, 587,
+ 587, 589, 592, 594, 594, 596, 599, 601,
+ 601, 603, 606, 609, 612, 612, 614, 616,
+ 616, 619, 619, 621, 623, 623, 626, 626,
+ 628, 630, 630, 633, 633, 635, 637, 640,
+ 640, 640, 640, 642, 644, 646, 648, 650,
+ 652, 654, 656, 658, 660, 662, 664, 666,
+ 668, 670, 672, 672, 674, 676, 678, 680,
+ 682, 684, 686, 688, 691, 693, 695, 698,
+ 700, 702, 704, 707, 709, 711, 713, 716,
+ 718, 720, 722, 725, 727, 730, 732, 734,
+ 737, 740, 743, 745, 748, 750, 752, 755,
+ 758, 758, 760, 762, 764, 766, 768, 770,
+ 770, 773, 776, 779, 779, 781, 783, 785,
+ 787, 789, 791, 793, 795, 797, 799, 799,
+ 802, 805, 808, 811, 814, 814, 816, 818,
+ 820, 822, 824, 826, 828, 831, 834, 837,
+ 839, 839, 839, 839, 839, 839, 841, 844,
+ 844, 844, 844, 844, 846, 848, 850, 852,
+ 854, 856, 856, 858, 861, 864, 867, 870,
+ 870, 872, 874, 876, 878, 878, 880, 883,
+ 886, 889, 889, 891, 893, 895, 897, 899,
+ 901, 907, 918, 920, 923, 929, 932, 943,
+ 946, 949, 952, 954, 956, 958, 960, 966,
+ 969, 972, 974, 976, 978, 980, 986, 989,
+ 992, 994, 996, 998, 1000, 1006, 1009, 1012,
+ 1015, 1015, 1017, 1019, 1021, 1023, 1025, 1027,
+ 1029, 1031, 1033, 1035, 1037, 1039, 1041, 1043,
+ 1045, 1047, 1049, 1052, 1055, 1058, 1061, 1064,
+ 1067, 1070, 1073, 1073, 1073, 1075, 1075, 1075,
+ 1075, 1077, 1077, 1079, 1079, 1079, 1081, 1081,
+ 1081, 1081, 1081, 1081, 1083, 1085, 1085, 1085,
+ 1087, 1087, 1087, 1087, 1089, 1089, 1089, 1089,
+ 1089, 1091, 1091, 1091, 1091, 1093, 1093, 1093,
+ 1093, 1095, 1097, 1097, 1097, 1097, 1097, 1099,
+ 1099, 1101, 1101, 1101, 1101, 1101, 1103, 1103,
+ 1103, 1103, 1103, 1103, 1103, 1103, 1105, 1105,
+ 1105, 1107, 1109, 1109, 1109, 1111, 1111, 1113,
+ 1113, 1115, 1117, 1117, 1117, 1117, 1117, 1119,
+ 1121, 1121, 1121, 1121, 1121, 1123, 1123, 1125,
+ 1127, 1127, 1129, 1131, 1131, 1131, 1131, 1131,
+ 1133, 1133, 1133, 1135, 1135, 1137, 1137, 1137,
+ 1137, 1139, 1141, 1141, 1141, 1143, 1143, 1145,
+ 1145, 1147, 1147, 1147, 1147, 1149, 1149, 1149,
+ 1149, 1151, 1151, 1153, 1153, 1153, 1153, 1155,
+ 1155, 1155, 1157, 1157, 1157, 1157, 1157, 1159,
+ 1161, 1163, 1165, 1167, 1169, 1171, 1174, 1177,
+ 1180, 1180, 1182, 1182, 1184, 1186, 1188, 1190,
+ 1192, 1194, 1196, 1198, 1198, 1198, 1198, 1198,
+ 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198,
+ 1198, 1198, 1201, 1201, 1203, 1206, 1209, 1212,
+ 1212, 1214, 1216, 1218, 1220, 1222, 1224, 1224,
+ 1224, 1224, 1227, 1230, 1233, 1233, 1235, 1237,
+ 1239, 1241, 1243, 1245, 1245, 1247, 1250, 1253,
+ 1256, 1259, 1259, 1261, 1263, 1263, 1266, 1266,
+ 1268, 1270, 1270, 1270, 1270, 1270, 1270, 1270,
+ 1270, 1270, 1270, 1273, 1273, 1273, 1273, 1273,
+ 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273,
+ 1273, 1275, 1277, 1279, 1281, 1281, 1284, 1287,
+ 1287, 1289, 1291, 1293, 1295, 1295, 1298, 1301,
+ 1303, 1305, 1307, 1309, 1311, 1313, 1315, 1317,
+ 1319, 1321, 1321, 1321, 1321, 1321, 1321, 1321,
+ 1321, 1323, 1323, 1325, 1328, 1328, 1330, 1333,
+ 1333, 1335, 1338, 1340, 1340, 1342, 1345, 1348,
+ 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348,
+ 1348, 1350, 1353, 1353, 1353, 1355, 1358, 1360,
+ 1363, 1365, 1368, 1370, 1373, 1373, 1373, 1373,
+ 1373, 1375, 1378, 1378, 1380, 1383, 1383, 1385,
+ 1388, 1388, 1394, 1397, 1408, 1411, 1422, 1425,
+ 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1427,
+ 1430, 1430, 1430, 1430, 1430, 1430
+};
+
+static const char _zone_scanner_cond_lengths[] = {
+ 0, 2, 2, 2, 2, 2, 2, 2,
+ 0, 0, 3, 2, 2, 3, 2, 2,
+ 2, 0, 0, 2, 5, 5, 0, 0,
+ 0, 0, 0, 2, 2, 0, 0, 2,
+ 0, 0, 0, 2, 0, 0, 0, 0,
+ 2, 0, 0, 0, 2, 0, 0, 0,
+ 2, 2, 0, 0, 0, 0, 2, 0,
+ 2, 0, 0, 0, 0, 2, 0, 2,
+ 2, 0, 0, 0, 0, 0, 0, 0,
+ 2, 0, 0, 2, 2, 0, 0, 2,
+ 0, 2, 0, 2, 2, 0, 0, 0,
+ 0, 2, 2, 0, 0, 0, 0, 2,
+ 0, 2, 2, 0, 2, 2, 0, 0,
+ 0, 0, 2, 0, 0, 2, 0, 2,
+ 0, 0, 0, 2, 2, 0, 0, 2,
+ 0, 2, 0, 2, 0, 0, 0, 2,
+ 0, 0, 0, 2, 0, 2, 0, 0,
+ 0, 2, 0, 0, 2, 3, 2, 0,
+ 2, 2, 2, 2, 0, 2, 3, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 2, 2, 3, 2, 2, 3, 2, 0,
+ 2, 3, 2, 2, 2, 2, 2, 3,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 3, 2, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2, 2, 2, 3,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 5, 5, 5, 5, 0, 0,
+ 2, 0, 0, 0, 2, 0, 2, 3,
+ 2, 2, 5, 5, 5, 5, 3, 2,
+ 5, 5, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 2, 3, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 1, 2, 2, 2, 2, 0,
+ 2, 0, 2, 3, 2, 2, 0, 2,
+ 2, 0, 0, 0, 0, 0, 2, 3,
+ 2, 2, 2, 2, 0, 2, 2, 0,
+ 0, 0, 0, 0, 2, 3, 2, 3,
+ 3, 0, 0, 0, 0, 2, 3, 0,
+ 2, 2, 2, 0, 0, 2, 3, 0,
+ 0, 2, 0, 0, 0, 0, 0, 2,
+ 2, 0, 0, 2, 0, 0, 0, 2,
+ 0, 0, 0, 0, 2, 0, 0, 0,
+ 2, 0, 0, 0, 2, 2, 0, 0,
+ 0, 0, 2, 0, 2, 0, 0, 0,
+ 0, 2, 0, 0, 0, 0, 0, 0,
+ 0, 2, 0, 0, 2, 2, 0, 0,
+ 2, 0, 2, 0, 2, 2, 0, 0,
+ 0, 0, 2, 2, 0, 0, 0, 0,
+ 2, 0, 2, 2, 0, 2, 2, 0,
+ 0, 0, 0, 2, 0, 0, 2, 0,
+ 2, 0, 0, 0, 2, 2, 0, 0,
+ 2, 0, 2, 0, 2, 0, 0, 0,
+ 2, 0, 0, 0, 2, 0, 2, 0,
+ 0, 0, 2, 0, 0, 2, 0, 0,
+ 0, 2, 0, 2, 2, 2, 2, 2,
+ 0, 2, 3, 3, 3, 2, 2, 2,
+ 2, 0, 2, 3, 3, 2, 3, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 0, 0, 0, 0, 3, 2, 0,
+ 2, 3, 2, 0, 2, 3, 2, 0,
+ 2, 3, 3, 3, 0, 2, 2, 0,
+ 3, 0, 2, 2, 0, 3, 0, 2,
+ 2, 0, 3, 0, 2, 2, 3, 0,
+ 0, 0, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 0, 2, 2, 2, 2, 2,
+ 2, 2, 2, 3, 2, 2, 3, 2,
+ 2, 2, 3, 2, 2, 2, 3, 2,
+ 2, 2, 3, 2, 3, 2, 2, 3,
+ 3, 3, 2, 3, 2, 2, 3, 3,
+ 0, 2, 2, 2, 2, 2, 2, 0,
+ 3, 3, 3, 0, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 0, 3,
+ 3, 3, 3, 3, 0, 2, 2, 2,
+ 2, 2, 2, 2, 3, 3, 3, 2,
+ 0, 0, 0, 0, 0, 2, 3, 0,
+ 0, 0, 0, 2, 2, 2, 2, 2,
+ 2, 0, 2, 3, 3, 3, 3, 0,
+ 2, 2, 2, 2, 0, 2, 3, 3,
+ 3, 0, 2, 2, 2, 2, 2, 2,
+ 6, 11, 2, 3, 6, 3, 11, 3,
+ 3, 3, 2, 2, 2, 2, 6, 3,
+ 3, 2, 2, 2, 2, 6, 3, 3,
+ 2, 2, 2, 2, 6, 3, 3, 3,
+ 0, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 3, 3, 3, 3, 3, 3,
+ 3, 3, 0, 0, 2, 0, 0, 0,
+ 2, 0, 2, 0, 0, 2, 0, 0,
+ 0, 0, 0, 2, 2, 0, 0, 2,
+ 0, 0, 0, 2, 0, 0, 0, 0,
+ 2, 0, 0, 0, 2, 0, 0, 0,
+ 2, 2, 0, 0, 0, 0, 2, 0,
+ 2, 0, 0, 0, 0, 2, 0, 0,
+ 0, 0, 0, 0, 0, 2, 0, 0,
+ 2, 2, 0, 0, 2, 0, 2, 0,
+ 2, 2, 0, 0, 0, 0, 2, 2,
+ 0, 0, 0, 0, 2, 0, 2, 2,
+ 0, 2, 2, 0, 0, 0, 0, 2,
+ 0, 0, 2, 0, 2, 0, 0, 0,
+ 2, 2, 0, 0, 2, 0, 2, 0,
+ 2, 0, 0, 0, 2, 0, 0, 0,
+ 2, 0, 2, 0, 0, 0, 2, 0,
+ 0, 2, 0, 0, 0, 0, 2, 2,
+ 2, 2, 2, 2, 2, 3, 3, 3,
+ 0, 2, 0, 2, 2, 2, 2, 2,
+ 2, 2, 2, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 3, 0, 2, 3, 3, 3, 0,
+ 2, 2, 2, 2, 2, 2, 0, 0,
+ 0, 3, 3, 3, 0, 2, 2, 2,
+ 2, 2, 2, 0, 2, 3, 3, 3,
+ 3, 0, 2, 2, 0, 3, 0, 2,
+ 2, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 2, 2, 2, 2, 0, 3, 3, 0,
+ 2, 2, 2, 2, 0, 3, 3, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 0, 0, 0, 0, 0, 0, 0,
+ 2, 0, 2, 3, 0, 2, 3, 0,
+ 2, 3, 2, 0, 2, 3, 3, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 2, 3, 0, 0, 2, 3, 2, 3,
+ 2, 3, 2, 3, 0, 0, 0, 0,
+ 2, 3, 0, 2, 3, 0, 2, 3,
+ 0, 6, 3, 11, 3, 11, 3, 0,
+ 0, 0, 0, 0, 0, 0, 2, 3,
+ 0, 0, 0, 0, 0, 0
+};
+
+static const short _zone_scanner_cond_keys[] = {
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, -128, 9, 10, 10,
+ 11, 127, 10, 10, 59, 59, 10, 10,
+ 59, 59, -128, 9, 10, 10, 11, 127,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ -128, 9, 10, 10, 11, 58, 59, 59,
+ 60, 127, -128, 9, 10, 10, 11, 58,
+ 59, 59, 60, 127, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, -128, 9, 10, 10,
+ 11, 127, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, -128, 9, 10, 10, 11, 127,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ -128, 9, 10, 10, 11, 127, 10, 10,
+ 59, 59, 10, 10, 59, 59, -128, 9,
+ 10, 10, 11, 127, 10, 10, 59, 59,
+ 10, 10, 59, 59, -128, 9, 10, 10,
+ 11, 127, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, -128, 9,
+ 10, 10, 11, 127, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ -128, 9, 10, 10, 11, 127, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, -128, 9,
+ 10, 10, 11, 127, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, -128, 9, 10, 10,
+ 11, 58, 59, 59, 60, 127, -128, 9,
+ 10, 10, 11, 58, 59, 59, 60, 127,
+ -128, 9, 10, 10, 11, 58, 59, 59,
+ 60, 127, -128, 9, 10, 10, 11, 58,
+ 59, 59, 60, 127, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ -128, 9, 10, 10, 11, 127, 10, 10,
+ 59, 59, 10, 10, 59, 59, -128, 9,
+ 10, 10, 11, 58, 59, 59, 60, 127,
+ -128, 9, 10, 10, 11, 58, 59, 59,
+ 60, 127, -128, 9, 10, 10, 11, 58,
+ 59, 59, 60, 127, -128, 9, 10, 10,
+ 11, 58, 59, 59, 60, 127, -128, 9,
+ 10, 10, 11, 127, 10, 10, 59, 59,
+ -128, 9, 10, 10, 11, 58, 59, 59,
+ 60, 127, -128, 9, 10, 10, 11, 58,
+ 59, 59, 60, 127, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, -128, 9, 10, 10,
+ 11, 127, -128, 9, 10, 10, 11, 127,
+ 10, 10, 59, 59, -128, 9, 10, 10,
+ 11, 127, 10, 10, 10, 10, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, -128, 9,
+ 10, 10, 11, 127, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ -128, 9, 10, 10, 11, 127, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, -128, 9, 10, 10, 11, 127,
+ 10, 10, 59, 59, -128, 9, 10, 10,
+ 11, 127, -128, 9, 10, 10, 11, 127,
+ 10, 10, 59, 59, -128, 9, 10, 10,
+ 11, 127, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, -128, 9, 10, 10, 11, 127,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ -128, 9, 10, 10, 11, 127, -128, 9,
+ 10, 10, 11, 127, -128, 9, 10, 10,
+ 11, 127, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, -128, 9,
+ 10, 10, 11, 127, -128, 9, 10, 10,
+ 11, 127, 10, 10, 59, 59, -128, 9,
+ 10, 10, 11, 127, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, -128, 9, 10, 10,
+ 11, 127, 10, 10, 59, 59, 10, 10,
+ 59, 59, -128, 9, 10, 10, 11, 127,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ -128, 9, 10, 10, 11, 127, 10, 10,
+ 59, 59, 10, 10, 59, 59, -128, 9,
+ 10, 10, 11, 127, -128, 9, 10, 10,
+ 11, 127, -128, 9, 10, 10, 11, 127,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ -128, 9, 10, 10, 11, 127, 10, 10,
+ 59, 59, 10, 10, 59, 59, -128, 9,
+ 10, 10, 11, 127, 10, 10, 59, 59,
+ 10, 10, 59, 59, -128, 9, 10, 10,
+ 11, 127, 10, 10, 59, 59, 10, 10,
+ 59, 59, -128, 9, 10, 10, 11, 127,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ -128, 9, 10, 10, 11, 127, 10, 10,
+ 59, 59, 10, 10, 59, 59, -128, 9,
+ 10, 10, 11, 127, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ -128, 9, 10, 10, 11, 127, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, -128, 9, 10, 10, 11, 127,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, -128, 9, 10, 10,
+ 11, 127, 10, 10, 59, 59, -128, 9,
+ 10, 10, 11, 127, 10, 10, 59, 59,
+ 10, 10, 59, 59, -128, 9, 10, 10,
+ 11, 127, -128, 9, 10, 10, 11, 127,
+ -128, 9, 10, 10, 11, 127, 10, 10,
+ 59, 59, -128, 9, 10, 10, 11, 127,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ -128, 9, 10, 10, 11, 127, -128, 9,
+ 10, 10, 11, 127, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, -128, 9, 10, 10,
+ 11, 127, -128, 9, 10, 10, 11, 127,
+ -128, 9, 10, 10, 11, 127, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, -128, 9,
+ 10, 10, 11, 127, -128, 9, 10, 10,
+ 11, 127, -128, 9, 10, 10, 11, 127,
+ -128, 9, 10, 10, 11, 127, -128, 9,
+ 10, 10, 11, 127, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ -128, 9, 10, 10, 11, 127, -128, 9,
+ 10, 10, 11, 127, -128, 9, 10, 10,
+ 11, 127, 10, 10, 59, 59, 10, 10,
+ 59, 59, -128, 9, 10, 10, 11, 127,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, -128, 9, 10, 10,
+ 11, 127, -128, 9, 10, 10, 11, 127,
+ -128, 9, 10, 10, 11, 127, -128, 9,
+ 10, 10, 11, 127, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ -128, 9, 10, 10, 11, 127, -128, 9,
+ 10, 10, 11, 127, -128, 9, 10, 10,
+ 11, 127, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 9, 9, 10, 10, 32, 32,
+ 40, 40, 41, 41, 59, 59, 9, 9,
+ 10, 10, 32, 32, 40, 40, 41, 41,
+ 43, 43, 47, 47, 48, 57, 59, 59,
+ 65, 90, 97, 122, 10, 10, 59, 59,
+ -128, 9, 10, 10, 11, 127, 9, 9,
+ 10, 10, 32, 32, 40, 40, 41, 41,
+ 59, 59, -128, 9, 10, 10, 11, 127,
+ 9, 9, 10, 10, 32, 32, 40, 40,
+ 41, 41, 43, 43, 47, 47, 48, 57,
+ 59, 59, 65, 90, 97, 122, -128, 9,
+ 10, 10, 11, 127, -128, 9, 10, 10,
+ 11, 127, -128, 9, 10, 10, 11, 127,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 9, 9, 10, 10, 32, 32, 40, 40,
+ 41, 41, 59, 59, -128, 9, 10, 10,
+ 11, 127, -128, 9, 10, 10, 11, 127,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 9, 9, 10, 10, 32, 32, 40, 40,
+ 41, 41, 59, 59, -128, 9, 10, 10,
+ 11, 127, -128, 9, 10, 10, 11, 127,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 9, 9, 10, 10, 32, 32, 40, 40,
+ 41, 41, 59, 59, -128, 9, 10, 10,
+ 11, 127, -128, 9, 10, 10, 11, 127,
+ -128, 9, 10, 10, 11, 127, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, -128, 9, 10, 10, 11, 127,
+ -128, 9, 10, 10, 11, 127, -128, 9,
+ 10, 10, 11, 127, -128, 9, 10, 10,
+ 11, 127, -128, 9, 10, 10, 11, 127,
+ -128, 9, 10, 10, 11, 127, -128, 9,
+ 10, 10, 11, 127, -128, 9, 10, 10,
+ 11, 127, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, -128, 9,
+ 10, 10, 11, 127, -128, 9, 10, 10,
+ 11, 127, -128, 9, 10, 10, 11, 127,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, -128, 9, 10, 10,
+ 11, 127, 10, 10, 59, 59, -128, 9,
+ 10, 10, 11, 127, -128, 9, 10, 10,
+ 11, 127, -128, 9, 10, 10, 11, 127,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ 10, 10, 59, 59, 10, 10, 59, 59,
+ -128, 9, 10, 10, 11, 127, -128, 9,
+ 10, 10, 11, 127, -128, 9, 10, 10,
+ 11, 127, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, -128, 9,
+ 10, 10, 11, 127, -128, 9, 10, 10,
+ 11, 127, -128, 9, 10, 10, 11, 127,
+ -128, 9, 10, 10, 11, 127, 10, 10,
+ 59, 59, 10, 10, 59, 59, -128, 9,
+ 10, 10, 11, 127, 10, 10, 59, 59,
+ 10, 10, 59, 59, -128, 9, 10, 10,
+ 11, 127, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, -128, 9, 10, 10, 11, 127,
+ -128, 9, 10, 10, 11, 127, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, -128, 9,
+ 10, 10, 11, 127, -128, 9, 10, 10,
+ 11, 127, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, 10, 10, 59, 59, 10, 10,
+ 59, 59, -128, 9, 10, 10, 11, 127,
+ 10, 10, 59, 59, -128, 9, 10, 10,
+ 11, 127, 10, 10, 59, 59, -128, 9,
+ 10, 10, 11, 127, 10, 10, 59, 59,
+ 10, 10, 59, 59, -128, 9, 10, 10,
+ 11, 127, -128, 9, 10, 10, 11, 127,
+ 10, 10, 59, 59, -128, 9, 10, 10,
+ 11, 127, 10, 10, 59, 59, -128, 9,
+ 10, 10, 11, 127, 10, 10, 59, 59,
+ -128, 9, 10, 10, 11, 127, 10, 10,
+ 59, 59, -128, 9, 10, 10, 11, 127,
+ 10, 10, 59, 59, -128, 9, 10, 10,
+ 11, 127, 10, 10, 59, 59, -128, 9,
+ 10, 10, 11, 127, 10, 10, 59, 59,
+ -128, 9, 10, 10, 11, 127, 10, 10,
+ 59, 59, -128, 9, 10, 10, 11, 127,
+ 9, 9, 10, 10, 32, 32, 40, 40,
+ 41, 41, 59, 59, -128, 9, 10, 10,
+ 11, 127, 9, 9, 10, 10, 32, 32,
+ 40, 40, 41, 41, 43, 43, 47, 47,
+ 48, 57, 59, 59, 65, 90, 97, 122,
+ -128, 9, 10, 10, 11, 127, 9, 9,
+ 10, 10, 32, 32, 40, 40, 41, 41,
+ 43, 43, 47, 47, 48, 57, 59, 59,
+ 65, 90, 97, 122, -128, 9, 10, 10,
+ 11, 127, 10, 10, 59, 59, -128, 9,
+ 10, 10, 11, 127, 0
+};
+
+static const char _zone_scanner_cond_spaces[] = {
+ 0, 0, 0, 0, 0, 0, 5, 5,
+ 5, 5, 0, 0, 0, 0, 0, 0,
+ 0, 5, 5, 5, 5, 0, 0, 0,
+ 5, 5, 0, 0, 0, 0, 5, 5,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 0, 0, 0, 0, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 5, 5, 5, 5, 5, 5, 5,
+ 5, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 5, 5, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 5, 5,
+ 5, 5, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 5, 5,
+ 5, 5, 5, 5, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 5, 5, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 2, 2, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 5, 5, 0, 0,
+ 0, 5, 5, 5, 5, 5, 5, 5,
+ 5, 0, 0, 0, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 0, 0,
+ 0, 0, 0, 0, 0, 0, 5, 5,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 5, 5, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 5, 5, 5, 5, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 0, 0, 0, 5, 5, 5, 5, 0,
+ 0, 0, 5, 5, 5, 5, 5, 5,
+ 0, 0, 0, 5, 5, 5, 5, 5,
+ 5, 0, 0, 0, 5, 5, 5, 5,
+ 5, 5, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 5, 5, 5,
+ 5, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 5, 5, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 5, 5,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 8, 11, 8,
+ 8, 8, 11, 3, 6, 3, 3, 3,
+ 3, 3, 3, 6, 3, 3, 1, 1,
+ 6, 6, 6, 4, 9, 4, 4, 4,
+ 9, 7, 7, 7, 8, 11, 8, 8,
+ 8, 3, 3, 3, 11, 3, 3, 10,
+ 10, 10, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 8, 11, 8, 8, 8, 11, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 8, 11, 8, 8,
+ 8, 11, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 8, 11, 8, 8, 8, 11, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1,
+ 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 5, 5, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 5,
+ 5, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 5, 5, 5, 5, 5,
+ 5, 0, 0, 5, 5, 0, 0, 0,
+ 5, 5, 0, 0, 0, 5, 5, 0,
+ 0, 0, 0, 0, 5, 5, 0, 0,
+ 0, 0, 0, 0, 5, 5, 0, 0,
+ 0, 5, 5, 0, 0, 0, 5, 5,
+ 0, 0, 0, 5, 5, 0, 0, 0,
+ 5, 5, 0, 0, 0, 5, 5, 0,
+ 0, 0, 5, 5, 0, 0, 0, 5,
+ 5, 0, 0, 0, 4, 9, 4, 4,
+ 4, 9, 7, 7, 7, 3, 6, 3,
+ 3, 3, 3, 3, 3, 6, 3, 3,
+ 6, 6, 6, 8, 11, 8, 8, 8,
+ 3, 3, 3, 11, 3, 3, 10, 10,
+ 10, 5, 5, 0, 0, 0, 0
+};
+
+static const short _zone_scanner_key_offsets[] = {
+ 0, 0, 40, 58, 94, 110, 127, 135,
+ 143, 144, 145, 148, 167, 186, 192, 244,
+ 264, 302, 310, 312, 322, 336, 350, 354,
+ 356, 358, 360, 362, 372, 382, 384, 386,
+ 396, 398, 400, 402, 412, 418, 420, 422,
+ 424, 434, 438, 440, 442, 452, 454, 456,
+ 458, 468, 478, 480, 482, 484, 485, 495,
+ 496, 506, 508, 510, 512, 514, 524, 528,
+ 534, 570, 572, 574, 576, 578, 580, 582,
+ 584, 594, 598, 600, 610, 620, 626, 627,
+ 637, 638, 648, 650, 660, 670, 674, 676,
+ 678, 680, 690, 700, 706, 708, 710, 712,
+ 722, 724, 734, 746, 748, 759, 771, 773,
+ 775, 777, 779, 789, 791, 793, 803, 809,
+ 819, 821, 823, 825, 835, 845, 853, 855,
+ 865, 867, 877, 879, 889, 891, 893, 895,
+ 905, 911, 913, 915, 925, 927, 937, 939,
+ 941, 943, 955, 957, 959, 969, 972, 1012,
+ 1016, 1022, 1060, 1078, 1086, 1098, 1106, 1109,
+ 1110, 1116, 1118, 1120, 1122, 1124, 1126, 1128,
+ 1134, 1140, 1178, 1181, 1199, 1237, 1240, 1248,
+ 1260, 1268, 1271, 1287, 1337, 1355, 1374, 1414,
+ 1420, 1434, 1448, 1500, 1516, 1530, 1540, 1550,
+ 1562, 1574, 1588, 1600, 1614, 1624, 1638, 1654,
+ 1668, 1678, 1684, 1698, 1700, 1702, 1704, 1706,
+ 1708, 1714, 1716, 1718, 1724, 1732, 1752, 1792,
+ 1798, 1816, 1868, 1884, 1898, 1908, 1918, 1930,
+ 1942, 1956, 1968, 1982, 1992, 2006, 2022, 2036,
+ 2046, 2061, 2101, 2115, 2129, 2145, 2161, 2163,
+ 2165, 2175, 2177, 2179, 2181, 2191, 2193, 2203,
+ 2209, 2223, 2237, 2253, 2269, 2285, 2301, 2304,
+ 2356, 2370, 2384, 2398, 2410, 2418, 2426, 2436,
+ 2446, 2458, 2468, 2480, 2488, 2500, 2514, 2526,
+ 2534, 2540, 2546, 2556, 2562, 2563, 2564, 2575,
+ 2591, 2607, 2609, 2611, 2613, 2629, 2635, 2641,
+ 2647, 2659, 2665, 2667, 2669, 2681, 2687, 2693,
+ 2699, 2701, 2703, 2709, 2715, 2723, 2743, 2751,
+ 2752, 2762, 2774, 2784, 2787, 2793, 2809, 2819,
+ 2837, 2845, 2846, 2848, 2850, 2852, 2862, 2870,
+ 2873, 2879, 2891, 2899, 2917, 2927, 2945, 2953,
+ 2954, 2956, 2958, 2960, 2970, 2978, 2984, 3000,
+ 3003, 3006, 3013, 3020, 3028, 3036, 3053, 3056,
+ 3057, 3067, 3107, 3123, 3125, 3127, 3137, 3140,
+ 3148, 3150, 3160, 3164, 3166, 3168, 3170, 3172,
+ 3182, 3192, 3194, 3196, 3206, 3208, 3210, 3212,
+ 3222, 3228, 3230, 3232, 3234, 3244, 3248, 3250,
+ 3252, 3262, 3264, 3266, 3268, 3278, 3288, 3290,
+ 3292, 3294, 3295, 3305, 3306, 3316, 3318, 3320,
+ 3322, 3324, 3334, 3336, 3338, 3340, 3342, 3344,
+ 3346, 3348, 3358, 3362, 3364, 3374, 3384, 3390,
+ 3391, 3401, 3402, 3412, 3414, 3424, 3434, 3438,
+ 3440, 3442, 3444, 3454, 3464, 3470, 3472, 3474,
+ 3476, 3486, 3488, 3498, 3510, 3512, 3523, 3535,
+ 3537, 3539, 3541, 3543, 3553, 3555, 3557, 3567,
+ 3573, 3583, 3585, 3587, 3589, 3599, 3609, 3617,
+ 3619, 3629, 3631, 3641, 3643, 3653, 3655, 3657,
+ 3659, 3669, 3675, 3677, 3679, 3689, 3691, 3701,
+ 3703, 3705, 3707, 3719, 3721, 3723, 3733, 3735,
+ 3737, 3739, 3749, 3751, 3761, 3767, 3775, 3783,
+ 3795, 3801, 3817, 3820, 3823, 3826, 3832, 3841,
+ 3851, 3863, 3869, 3885, 3888, 3891, 3899, 3902,
+ 3914, 3922, 3926, 3932, 3934, 3941, 3943, 3945,
+ 3947, 3949, 3950, 3951, 3953, 3955, 3957, 3958,
+ 3964, 3968, 3972, 3973, 3975, 3977, 3979, 3981,
+ 3987, 3989, 3991, 3993, 3995, 3996, 3997, 3999,
+ 4001, 4003, 4004, 4005, 4006, 4012, 4013, 4014,
+ 4016, 4018, 4020, 4021, 4022, 4023, 4029, 4031,
+ 4032, 4033, 4034, 4035, 4041, 4042, 4043, 4049,
+ 4051, 4053, 4055, 4057, 4059, 4061, 4063, 4069,
+ 4071, 4073, 4075, 4077, 4079, 4081, 4085, 4087,
+ 4089, 4095, 4097, 4099, 4105, 4107, 4109, 4113,
+ 4115, 4116, 4122, 4124, 4126, 4129, 4136, 4138,
+ 4140, 4142, 4144, 4145, 4146, 4148, 4150, 4152,
+ 4153, 4159, 4160, 4161, 4167, 4168, 4169, 4175,
+ 4189, 4197, 4199, 4201, 4203, 4205, 4207, 4213,
+ 4219, 4221, 4223, 4225, 4227, 4229, 4235, 4239,
+ 4241, 4247, 4249, 4251, 4257, 4259, 4261, 4263,
+ 4269, 4271, 4273, 4279, 4283, 4285, 4291, 4293,
+ 4295, 4301, 4303, 4305, 4307, 4313, 4315, 4317,
+ 4323, 4326, 4335, 4344, 4350, 4359, 4365, 4380,
+ 4386, 4394, 4402, 4410, 4428, 4436, 4454, 4462,
+ 4480, 4488, 4506, 4514, 4526, 4534, 4537, 4545,
+ 4557, 4565, 4568, 4576, 4588, 4596, 4599, 4607,
+ 4619, 4627, 4630, 4633, 4636, 4642, 4648, 4660,
+ 4666, 4669, 4678, 4684, 4699, 4705, 4708, 4710,
+ 4718, 4733, 4739, 4742, 4748, 4758, 4774, 4777,
+ 4784, 4797, 4799, 4807, 4817, 4825, 4835, 4844,
+ 4852, 4858, 4866, 4874, 4884, 4892, 4902, 4911,
+ 4919, 4925, 4934, 4936, 4950, 4962, 4976, 4988,
+ 5002, 5014, 5028, 5038, 5041, 5054, 5067, 5070,
+ 5083, 5096, 5106, 5109, 5122, 5135, 5145, 5148,
+ 5161, 5174, 5184, 5187, 5193, 5196, 5204, 5212,
+ 5215, 5218, 5221, 5227, 5230, 5238, 5246, 5249,
+ 5252, 5254, 5262, 5270, 5278, 5286, 5294, 5309,
+ 5315, 5318, 5321, 5324, 5326, 5334, 5342, 5350,
+ 5362, 5368, 5380, 5386, 5398, 5404, 5419, 5425,
+ 5428, 5431, 5434, 5437, 5440, 5446, 5452, 5460,
+ 5468, 5480, 5486, 5499, 5501, 5504, 5507, 5510,
+ 5523, 5525, 5526, 5529, 5532, 5534, 5546, 5549,
+ 5550, 5557, 5564, 5566, 5574, 5586, 5592, 5600,
+ 5608, 5620, 5626, 5642, 5645, 5648, 5651, 5654,
+ 5656, 5664, 5672, 5680, 5692, 5698, 5714, 5717,
+ 5720, 5723, 5725, 5733, 5743, 5749, 5757, 5765,
+ 5772, 5806, 5819, 5821, 5824, 5838, 5841, 5882,
+ 5891, 5894, 5897, 5903, 5911, 5919, 5928, 5965,
+ 5968, 5971, 5977, 5985, 5993, 6006, 6047, 6050,
+ 6053, 6059, 6067, 6075, 6090, 6124, 6127, 6130,
+ 6133, 6163, 6175, 6187, 6193, 6201, 6209, 6217,
+ 6225, 6233, 6241, 6249, 6257, 6265, 6273, 6288,
+ 6294, 6307, 6309, 6312, 6315, 6318, 6321, 6324,
+ 6327, 6330, 6333, 6335, 6337, 6343, 6345, 6347,
+ 6349, 6355, 6357, 6363, 6371, 6373, 6379, 6383,
+ 6385, 6387, 6389, 6391, 6397, 6403, 6405, 6407,
+ 6413, 6415, 6417, 6419, 6425, 6431, 6433, 6435,
+ 6437, 6443, 6447, 6449, 6451, 6457, 6459, 6461,
+ 6463, 6469, 6475, 6477, 6479, 6481, 6482, 6488,
+ 6489, 6495, 6497, 6499, 6501, 6503, 6509, 6511,
+ 6513, 6515, 6517, 6519, 6521, 6523, 6529, 6533,
+ 6535, 6541, 6547, 6553, 6554, 6560, 6561, 6567,
+ 6569, 6575, 6581, 6585, 6587, 6589, 6591, 6597,
+ 6603, 6609, 6611, 6613, 6615, 6621, 6623, 6629,
+ 6637, 6639, 6646, 6654, 6656, 6658, 6660, 6662,
+ 6668, 6670, 6672, 6678, 6684, 6690, 6692, 6694,
+ 6696, 6702, 6708, 6716, 6718, 6724, 6726, 6732,
+ 6734, 6740, 6742, 6744, 6746, 6752, 6758, 6760,
+ 6762, 6768, 6770, 6776, 6778, 6780, 6782, 6790,
+ 6792, 6794, 6800, 6809, 6815, 6821, 6823, 6831,
+ 6839, 6847, 6859, 6865, 6878, 6880, 6883, 6886,
+ 6889, 6896, 6898, 6900, 6908, 6916, 6924, 6932,
+ 6940, 6953, 6959, 6971, 6977, 6984, 6990, 6997,
+ 7004, 7010, 7017, 7029, 7035, 7036, 7037, 7038,
+ 7039, 7040, 7043, 7049, 7061, 7064, 7067, 7070,
+ 7072, 7080, 7088, 7096, 7104, 7112, 7125, 7131,
+ 7137, 7149, 7152, 7155, 7158, 7160, 7168, 7176,
+ 7184, 7192, 7200, 7212, 7218, 7234, 7237, 7240,
+ 7243, 7246, 7248, 7256, 7265, 7274, 7277, 7279,
+ 7287, 7299, 7305, 7311, 7317, 7318, 7324, 7330,
+ 7336, 7342, 7349, 7352, 7358, 7364, 7365, 7371,
+ 7377, 7384, 7390, 7396, 7397, 7403, 7409, 7416,
+ 7418, 7426, 7434, 7442, 7454, 7460, 7463, 7466,
+ 7468, 7476, 7488, 7494, 7506, 7512, 7515, 7518,
+ 7536, 7569, 7617, 7667, 7685, 7735, 7753, 7786,
+ 7851, 7916, 7916, 7916, 7916, 7928, 7928, 7928,
+ 7928, 7944, 7944, 7961, 7964, 7964, 8004, 8007,
+ 8007, 8023, 8026, 8038, 8038, 8054, 8057, 8060,
+ 8060, 8060, 8060, 8060, 8060, 8060, 8060, 8060,
+ 8060, 8076, 8079, 8079, 8079, 8089, 8092, 8104,
+ 8107, 8119, 8122, 8134, 8137, 8137, 8137, 8137,
+ 8137, 8150, 8153, 8153, 8169, 8172, 8172, 8188,
+ 8191, 8191, 8205, 8208, 8221, 8224, 8265, 8274,
+ 8274, 8274, 8274, 8274, 8274, 8274, 8274, 8290,
+ 8293, 8293, 8293, 8293, 8293, 8293
+};
+
+static const short _zone_scanner_trans_keys[] = {
+ 9, 32, 40, 41, 65, 67, 68, 69,
+ 72, 73, 75, 76, 77, 78, 80, 82,
+ 83, 84, 85, 97, 99, 100, 101, 104,
+ 105, 107, 108, 109, 110, 112, 114, 115,
+ 116, 117, 778, 827, 1034, 1083, 48, 57,
+ 9, 32, 40, 41, 68, 72, 77, 83,
+ 87, 100, 104, 109, 115, 119, 1034, 1083,
+ 48, 57, 9, 32, 40, 41, 65, 67,
+ 68, 69, 72, 73, 75, 76, 77, 78,
+ 80, 82, 83, 84, 85, 97, 99, 100,
+ 101, 104, 105, 107, 108, 109, 110, 112,
+ 114, 115, 116, 117, 1034, 1083, 9, 32,
+ 40, 41, 65, 70, 80, 97, 102, 112,
+ 2058, 2107, 2314, 2363, 2570, 2619, 9, 32,
+ 40, 41, 92, 2058, 2107, 2314, 2363, 2570,
+ 2619, -128, 8, 11, 58, 60, 127, 9,
+ 32, 40, 41, 778, 827, 1034, 1083, 9,
+ 32, 40, 41, 778, 827, 1034, 1083, 10,
+ 35, 1034, 896, 1151, 9, 32, 40, 41,
+ 92, 1802, 1851, 2058, 2107, 2314, 2363, 2570,
+ 2619, -128, 8, 11, 58, 60, 127, 9,
+ 32, 40, 41, 92, 1802, 1851, 2058, 2107,
+ 2314, 2363, 2570, 2619, -128, 8, 11, 58,
+ 60, 127, 778, 1034, 640, 895, 896, 1151,
+ 9, 32, 40, 41, 58, 65, 67, 68,
+ 69, 72, 73, 75, 76, 77, 78, 80,
+ 82, 83, 84, 85, 92, 97, 99, 100,
+ 101, 104, 105, 107, 108, 109, 110, 112,
+ 114, 115, 116, 117, 1802, 1851, 2058, 2107,
+ 2314, 2363, 2570, 2619, -128, 8, 11, 47,
+ 48, 57, 60, 127, 9, 32, 40, 41,
+ 68, 72, 77, 83, 87, 100, 104, 109,
+ 115, 119, 778, 827, 1034, 1083, 48, 57,
+ 9, 32, 40, 41, 65, 67, 68, 69,
+ 72, 73, 75, 76, 77, 78, 80, 82,
+ 83, 84, 85, 97, 99, 100, 101, 104,
+ 105, 107, 108, 109, 110, 112, 114, 115,
+ 116, 117, 778, 827, 1034, 1083, 65, 68,
+ 69, 78, 97, 100, 101, 110, 65, 97,
+ 9, 32, 40, 41, 2058, 2107, 2314, 2363,
+ 2570, 2619, 777, 778, 800, 808, 809, 827,
+ 1033, 1034, 1056, 1064, 1065, 1083, 896, 1151,
+ 777, 778, 800, 808, 809, 827, 1033, 1034,
+ 1056, 1064, 1065, 1083, 896, 1151, 78, 83,
+ 110, 115, 83, 115, 75, 107, 69, 101,
+ 89, 121, 9, 32, 40, 41, 2058, 2107,
+ 2314, 2363, 2570, 2619, 9, 32, 40, 41,
+ 2058, 2107, 2314, 2363, 2570, 2619, 82, 114,
+ 84, 116, 9, 32, 40, 41, 2058, 2107,
+ 2314, 2363, 2570, 2619, 65, 97, 77, 109,
+ 69, 101, 9, 32, 40, 41, 2058, 2107,
+ 2314, 2363, 2570, 2619, 72, 78, 83, 104,
+ 110, 115, 67, 99, 73, 105, 68, 100,
+ 9, 32, 40, 41, 2058, 2107, 2314, 2363,
+ 2570, 2619, 65, 83, 97, 115, 77, 109,
+ 69, 101, 9, 32, 40, 41, 2058, 2107,
+ 2314, 2363, 2570, 2619, 75, 107, 69, 101,
+ 89, 121, 9, 32, 40, 41, 2058, 2107,
+ 2314, 2363, 2570, 2619, 9, 32, 40, 41,
+ 2058, 2107, 2314, 2363, 2570, 2619, 85, 117,
+ 73, 105, 52, 54, 56, 9, 32, 40,
+ 41, 2058, 2107, 2314, 2363, 2570, 2619, 52,
+ 9, 32, 40, 41, 2058, 2107, 2314, 2363,
+ 2570, 2619, 73, 105, 78, 110, 70, 102,
+ 79, 111, 9, 32, 40, 41, 2058, 2107,
+ 2314, 2363, 2570, 2619, 78, 80, 110, 112,
+ 9, 32, 40, 41, 1034, 1083, 9, 32,
+ 40, 41, 65, 67, 68, 69, 72, 73,
+ 75, 76, 77, 78, 80, 82, 83, 84,
+ 85, 97, 99, 100, 101, 104, 105, 107,
+ 108, 109, 110, 112, 114, 115, 116, 117,
+ 1034, 1083, 80, 112, 83, 115, 69, 101,
+ 67, 99, 75, 107, 69, 101, 89, 121,
+ 9, 32, 40, 41, 2058, 2107, 2314, 2363,
+ 2570, 2619, 69, 88, 101, 120, 89, 121,
+ 9, 32, 40, 41, 2058, 2107, 2314, 2363,
+ 2570, 2619, 9, 32, 40, 41, 2058, 2107,
+ 2314, 2363, 2570, 2619, 51, 54, 79, 80,
+ 111, 112, 50, 9, 32, 40, 41, 2058,
+ 2107, 2314, 2363, 2570, 2619, 52, 9, 32,
+ 40, 41, 2058, 2107, 2314, 2363, 2570, 2619,
+ 67, 99, 9, 32, 40, 41, 2058, 2107,
+ 2314, 2363, 2570, 2619, 9, 32, 40, 41,
+ 2058, 2107, 2314, 2363, 2570, 2619, 73, 88,
+ 105, 120, 78, 110, 70, 102, 79, 111,
+ 9, 32, 40, 41, 2058, 2107, 2314, 2363,
+ 2570, 2619, 9, 32, 40, 41, 2058, 2107,
+ 2314, 2363, 2570, 2619, 65, 73, 83, 97,
+ 105, 115, 80, 112, 84, 116, 82, 114,
+ 9, 32, 40, 41, 2058, 2107, 2314, 2363,
+ 2570, 2619, 68, 100, 9, 32, 40, 41,
+ 2058, 2107, 2314, 2363, 2570, 2619, 9, 32,
+ 40, 41, 69, 101, 2058, 2107, 2314, 2363,
+ 2570, 2619, 67, 99, 9, 32, 40, 41,
+ 51, 2058, 2107, 2314, 2363, 2570, 2619, 9,
+ 32, 40, 41, 80, 112, 2058, 2107, 2314,
+ 2363, 2570, 2619, 65, 97, 82, 114, 65,
+ 97, 77, 109, 9, 32, 40, 41, 2058,
+ 2107, 2314, 2363, 2570, 2619, 84, 116, 82,
+ 114, 9, 32, 40, 41, 2058, 2107, 2314,
+ 2363, 2570, 2619, 80, 82, 84, 112, 114,
+ 116, 9, 32, 40, 41, 2058, 2107, 2314,
+ 2363, 2570, 2619, 83, 115, 73, 105, 71,
+ 103, 9, 32, 40, 41, 2058, 2107, 2314,
+ 2363, 2570, 2619, 9, 32, 40, 41, 2058,
+ 2107, 2314, 2363, 2570, 2619, 79, 80, 82,
+ 83, 111, 112, 114, 115, 65, 97, 9,
+ 32, 40, 41, 2058, 2107, 2314, 2363, 2570,
+ 2619, 70, 102, 9, 32, 40, 41, 2058,
+ 2107, 2314, 2363, 2570, 2619, 86, 118, 9,
+ 32, 40, 41, 2058, 2107, 2314, 2363, 2570,
+ 2619, 72, 104, 70, 102, 80, 112, 9,
+ 32, 40, 41, 2058, 2107, 2314, 2363, 2570,
+ 2619, 76, 88, 89, 108, 120, 121, 83,
+ 115, 65, 97, 9, 32, 40, 41, 2058,
+ 2107, 2314, 2363, 2570, 2619, 84, 116, 9,
+ 32, 40, 41, 2058, 2107, 2314, 2363, 2570,
+ 2619, 80, 112, 69, 101, 48, 57, 9,
+ 32, 40, 41, 2058, 2107, 2314, 2363, 2570,
+ 2619, 48, 57, 82, 114, 73, 105, 9,
+ 32, 40, 41, 2058, 2107, 2314, 2363, 2570,
+ 2619, 1034, 896, 1151, 9, 32, 40, 41,
+ 65, 67, 68, 69, 72, 73, 75, 76,
+ 77, 78, 80, 82, 83, 84, 85, 97,
+ 99, 100, 101, 104, 105, 107, 108, 109,
+ 110, 112, 114, 115, 116, 117, 778, 827,
+ 1034, 1083, 48, 57, 78, 80, 110, 112,
+ 9, 32, 40, 41, 1034, 1083, 9, 32,
+ 40, 41, 65, 67, 68, 69, 72, 73,
+ 75, 76, 77, 78, 80, 82, 83, 84,
+ 85, 97, 99, 100, 101, 104, 105, 107,
+ 108, 109, 110, 112, 114, 115, 116, 117,
+ 1034, 1083, 48, 57, 9, 32, 40, 41,
+ 68, 72, 77, 83, 87, 100, 104, 109,
+ 115, 119, 1034, 1083, 48, 57, 9, 32,
+ 40, 41, 1034, 1083, 48, 57, 68, 72,
+ 77, 83, 87, 100, 104, 109, 115, 119,
+ 48, 57, 9, 32, 40, 41, 1034, 1083,
+ 48, 57, 1034, 896, 1151, 10, 73, 79,
+ 84, 105, 111, 116, 78, 110, 67, 99,
+ 76, 108, 85, 117, 68, 100, 69, 101,
+ 32, 59, 9, 10, 40, 41, 9, 32,
+ 40, 41, 1034, 1083, 9, 32, 40, 41,
+ 65, 67, 68, 69, 72, 73, 75, 76,
+ 77, 78, 80, 82, 83, 84, 85, 97,
+ 99, 100, 101, 104, 105, 107, 108, 109,
+ 110, 112, 114, 115, 116, 117, 1034, 1083,
+ 48, 57, 1034, 896, 1151, 9, 32, 40,
+ 41, 68, 72, 77, 83, 87, 100, 104,
+ 109, 115, 119, 1034, 1083, 48, 57, 9,
+ 32, 40, 41, 65, 67, 68, 69, 72,
+ 73, 75, 76, 77, 78, 80, 82, 83,
+ 84, 85, 97, 99, 100, 101, 104, 105,
+ 107, 108, 109, 110, 112, 114, 115, 116,
+ 117, 1034, 1083, 48, 57, 1034, 896, 1151,
+ 9, 32, 40, 41, 1034, 1083, 48, 57,
+ 68, 72, 77, 83, 87, 100, 104, 109,
+ 115, 119, 48, 57, 9, 32, 40, 41,
+ 1034, 1083, 48, 57, 1034, 896, 1151, 9,
+ 32, 40, 41, 65, 70, 80, 97, 102,
+ 112, 2058, 2107, 2314, 2363, 2570, 2619, 9,
+ 32, 40, 41, 58, 65, 67, 68, 69,
+ 72, 73, 75, 76, 77, 78, 80, 82,
+ 83, 84, 85, 92, 97, 99, 100, 101,
+ 104, 105, 107, 108, 109, 110, 112, 114,
+ 115, 116, 117, 2058, 2107, 2314, 2363, 2570,
+ 2619, -128, 8, 11, 47, 48, 57, 60,
+ 127, 9, 32, 40, 41, 65, 70, 80,
+ 97, 102, 112, 1802, 1851, 2058, 2107, 2314,
+ 2363, 2570, 2619, 9, 32, 40, 41, 92,
+ 1802, 1851, 2058, 2107, 2314, 2363, 2570, 2619,
+ -128, 8, 11, 58, 60, 127, 9, 32,
+ 40, 41, 65, 67, 68, 69, 72, 73,
+ 75, 76, 77, 78, 80, 82, 83, 84,
+ 85, 97, 99, 100, 101, 104, 105, 107,
+ 108, 109, 110, 112, 114, 115, 116, 117,
+ 778, 827, 1034, 1083, 48, 57, 778, 1034,
+ 640, 895, 896, 1151, 9, 32, 40, 41,
+ 778, 827, 1034, 1083, -128, 8, 11, 58,
+ 60, 127, 9, 32, 40, 41, 778, 827,
+ 1034, 1083, -128, 8, 11, 58, 60, 127,
+ 9, 32, 40, 41, 58, 65, 67, 68,
+ 69, 72, 73, 75, 76, 77, 78, 80,
+ 82, 83, 84, 85, 92, 97, 99, 100,
+ 101, 104, 105, 107, 108, 109, 110, 112,
+ 114, 115, 116, 117, 1802, 1851, 2058, 2107,
+ 2314, 2363, 2570, 2619, -128, 8, 11, 47,
+ 48, 57, 60, 127, 9, 32, 40, 41,
+ 65, 68, 69, 78, 97, 100, 101, 110,
+ 778, 827, 1034, 1083, 9, 32, 40, 41,
+ 72, 78, 83, 104, 110, 115, 778, 827,
+ 1034, 1083, 9, 32, 40, 41, 85, 117,
+ 778, 827, 1034, 1083, 9, 32, 40, 41,
+ 73, 105, 778, 827, 1034, 1083, 9, 32,
+ 40, 41, 78, 80, 110, 112, 778, 827,
+ 1034, 1083, 9, 32, 40, 41, 69, 88,
+ 101, 120, 778, 827, 1034, 1083, 9, 32,
+ 40, 41, 51, 54, 79, 80, 111, 112,
+ 778, 827, 1034, 1083, 9, 32, 40, 41,
+ 73, 88, 105, 120, 778, 827, 1034, 1083,
+ 9, 32, 40, 41, 65, 73, 83, 97,
+ 105, 115, 778, 827, 1034, 1083, 9, 32,
+ 40, 41, 84, 116, 778, 827, 1034, 1083,
+ 9, 32, 40, 41, 80, 82, 84, 112,
+ 114, 116, 778, 827, 1034, 1083, 9, 32,
+ 40, 41, 79, 80, 82, 83, 111, 112,
+ 114, 115, 778, 827, 1034, 1083, 9, 32,
+ 40, 41, 76, 88, 89, 108, 120, 121,
+ 778, 827, 1034, 1083, 9, 32, 40, 41,
+ 82, 114, 778, 827, 1034, 1083, 778, 1034,
+ 640, 895, 896, 1151, 9, 32, 40, 41,
+ 73, 79, 84, 105, 111, 116, 778, 827,
+ 1034, 1083, 82, 114, 73, 105, 71, 103,
+ 73, 105, 78, 110, 32, 59, 9, 10,
+ 40, 41, 84, 116, 76, 108, 32, 59,
+ 9, 10, 40, 41, 9, 32, 40, 41,
+ 778, 827, 1034, 1083, 9, 32, 40, 41,
+ 68, 72, 77, 83, 87, 100, 104, 109,
+ 115, 119, 778, 827, 1034, 1083, 48, 57,
+ 9, 32, 40, 41, 65, 67, 68, 69,
+ 72, 73, 75, 76, 77, 78, 80, 82,
+ 83, 84, 85, 97, 99, 100, 101, 104,
+ 105, 107, 108, 109, 110, 112, 114, 115,
+ 116, 117, 778, 827, 1034, 1083, 48, 57,
+ 778, 1034, 640, 895, 896, 1151, 9, 32,
+ 40, 41, 65, 70, 80, 97, 102, 112,
+ 1802, 1851, 2058, 2107, 2314, 2363, 2570, 2619,
+ 9, 32, 40, 41, 58, 65, 67, 68,
+ 69, 72, 73, 75, 76, 77, 78, 80,
+ 82, 83, 84, 85, 92, 97, 99, 100,
+ 101, 104, 105, 107, 108, 109, 110, 112,
+ 114, 115, 116, 117, 1802, 1851, 2058, 2107,
+ 2314, 2363, 2570, 2619, -128, 8, 11, 47,
+ 48, 57, 60, 127, 9, 32, 40, 41,
+ 65, 68, 69, 78, 97, 100, 101, 110,
+ 778, 827, 1034, 1083, 9, 32, 40, 41,
+ 72, 78, 83, 104, 110, 115, 778, 827,
+ 1034, 1083, 9, 32, 40, 41, 85, 117,
+ 778, 827, 1034, 1083, 9, 32, 40, 41,
+ 73, 105, 778, 827, 1034, 1083, 9, 32,
+ 40, 41, 78, 80, 110, 112, 778, 827,
+ 1034, 1083, 9, 32, 40, 41, 69, 88,
+ 101, 120, 778, 827, 1034, 1083, 9, 32,
+ 40, 41, 51, 54, 79, 80, 111, 112,
+ 778, 827, 1034, 1083, 9, 32, 40, 41,
+ 73, 88, 105, 120, 778, 827, 1034, 1083,
+ 9, 32, 40, 41, 65, 73, 83, 97,
+ 105, 115, 778, 827, 1034, 1083, 9, 32,
+ 40, 41, 84, 116, 778, 827, 1034, 1083,
+ 9, 32, 40, 41, 80, 82, 84, 112,
+ 114, 116, 778, 827, 1034, 1083, 9, 32,
+ 40, 41, 79, 80, 82, 83, 111, 112,
+ 114, 115, 778, 827, 1034, 1083, 9, 32,
+ 40, 41, 76, 88, 89, 108, 120, 121,
+ 778, 827, 1034, 1083, 9, 32, 40, 41,
+ 82, 114, 778, 827, 1034, 1083, 9, 32,
+ 35, 40, 41, 778, 827, 1034, 1083, -128,
+ 8, 11, 58, 60, 127, 9, 32, 40,
+ 41, 65, 67, 68, 69, 72, 73, 75,
+ 76, 77, 78, 80, 82, 83, 84, 85,
+ 97, 99, 100, 101, 104, 105, 107, 108,
+ 109, 110, 112, 114, 115, 116, 117, 778,
+ 827, 1034, 1083, 48, 57, 777, 778, 800,
+ 808, 809, 827, 1033, 1034, 1056, 1064, 1065,
+ 1083, 896, 1151, 777, 778, 800, 808, 809,
+ 827, 1033, 1034, 1056, 1064, 1065, 1083, 896,
+ 1151, 777, 778, 800, 808, 809, 827, 1033,
+ 1034, 1056, 1064, 1065, 1083, 640, 895, 896,
+ 1151, 777, 778, 800, 808, 809, 827, 1033,
+ 1034, 1056, 1064, 1065, 1083, 640, 895, 896,
+ 1151, 65, 97, 65, 97, 9, 32, 40,
+ 41, 2058, 2107, 2314, 2363, 2570, 2619, 83,
+ 115, 68, 100, 66, 98, 9, 32, 40,
+ 41, 2058, 2107, 2314, 2363, 2570, 2619, 76,
+ 108, 9, 32, 40, 41, 2058, 2107, 2314,
+ 2363, 2570, 2619, 778, 1034, 640, 895, 896,
+ 1151, 9, 32, 40, 41, 778, 827, 1034,
+ 1083, -128, 8, 11, 58, 60, 127, 9,
+ 32, 40, 41, 778, 827, 1034, 1083, -128,
+ 8, 11, 58, 60, 127, 777, 778, 800,
+ 808, 809, 827, 1033, 1034, 1056, 1064, 1065,
+ 1083, 640, 895, 896, 1151, 777, 778, 800,
+ 808, 809, 827, 1033, 1034, 1056, 1064, 1065,
+ 1083, 640, 895, 896, 1151, 777, 778, 800,
+ 808, 809, 827, 1033, 1034, 1056, 1064, 1065,
+ 1083, 640, 895, 896, 1151, 777, 778, 800,
+ 808, 809, 827, 1033, 1034, 1056, 1064, 1065,
+ 1083, 640, 895, 896, 1151, 1034, 896, 1151,
+ 9, 32, 40, 41, 58, 65, 67, 68,
+ 69, 72, 73, 75, 76, 77, 78, 80,
+ 82, 83, 84, 85, 92, 97, 99, 100,
+ 101, 104, 105, 107, 108, 109, 110, 112,
+ 114, 115, 116, 117, 1802, 1851, 2058, 2107,
+ 2314, 2363, 2570, 2619, -128, 8, 11, 47,
+ 48, 57, 60, 127, 777, 778, 800, 808,
+ 809, 827, 1033, 1034, 1056, 1064, 1065, 1083,
+ 896, 1151, 777, 778, 800, 808, 809, 827,
+ 1033, 1034, 1056, 1064, 1065, 1083, 896, 1151,
+ 9, 32, 40, 41, 65, 68, 69, 78,
+ 97, 100, 101, 110, 1034, 1083, 9, 32,
+ 40, 41, 72, 78, 83, 104, 110, 115,
+ 1034, 1083, 9, 32, 40, 41, 85, 117,
+ 1034, 1083, 9, 32, 40, 41, 73, 105,
+ 1034, 1083, 9, 32, 40, 41, 78, 80,
+ 110, 112, 1034, 1083, 9, 32, 40, 41,
+ 69, 88, 101, 120, 1034, 1083, 9, 32,
+ 40, 41, 51, 54, 79, 80, 111, 112,
+ 1034, 1083, 9, 32, 40, 41, 73, 88,
+ 105, 120, 1034, 1083, 9, 32, 40, 41,
+ 65, 73, 83, 97, 105, 115, 1034, 1083,
+ 9, 32, 40, 41, 84, 116, 1034, 1083,
+ 9, 32, 40, 41, 80, 82, 84, 112,
+ 114, 116, 1034, 1083, 9, 32, 40, 41,
+ 79, 80, 82, 83, 111, 112, 114, 115,
+ 1034, 1083, 9, 32, 40, 41, 76, 88,
+ 89, 108, 120, 121, 1034, 1083, 9, 32,
+ 40, 41, 82, 114, 1034, 1083, 778, 1034,
+ 640, 895, 896, 1151, 778, 1034, 640, 895,
+ 896, 1151, 9, 32, 40, 41, 78, 80,
+ 110, 112, 1034, 1083, 778, 1034, 640, 895,
+ 896, 1151, 10, 10, 42, 46, 64, 92,
+ 95, 45, 57, 65, 90, 97, 122, 32,
+ 42, 46, 59, 92, 95, 9, 10, 40,
+ 41, 45, 57, 65, 90, 97, 122, 32,
+ 42, 45, 59, 92, 95, 9, 10, 40,
+ 41, 47, 57, 65, 90, 97, 122, 48,
+ 57, 48, 57, 48, 57, 32, 42, 46,
+ 59, 92, 95, 9, 10, 40, 41, 45,
+ 57, 65, 90, 97, 122, 32, 59, 9,
+ 10, 40, 41, 32, 59, 9, 10, 40,
+ 41, 34, 92, 33, 58, 60, 126, 32,
+ 33, 59, 92, 9, 10, 35, 39, 40,
+ 41, 42, 126, 32, 47, 48, 57, 58,
+ 126, 48, 57, 48, 57, 32, 33, 59,
+ 92, 9, 10, 35, 39, 40, 41, 42,
+ 126, 9, 34, 92, 522, 32, 126, 32,
+ 59, 9, 10, 40, 41, 32, 47, 48,
+ 57, 58, 126, 48, 57, 48, 57, 9,
+ 34, 92, 522, 32, 126, 9, 32, 40,
+ 41, 1034, 1083, 9, 32, 40, 41, 1034,
+ 1083, 48, 57, 9, 32, 40, 41, 68,
+ 72, 77, 83, 87, 100, 104, 109, 115,
+ 119, 778, 827, 1034, 1083, 48, 57, 9,
+ 32, 40, 41, 778, 827, 1034, 1083, 10,
+ 9, 32, 40, 41, 778, 827, 1034, 1083,
+ 48, 57, 68, 72, 77, 83, 87, 100,
+ 104, 109, 115, 119, 48, 57, 9, 32,
+ 40, 41, 778, 827, 1034, 1083, 48, 57,
+ 1034, 896, 1151, 9, 32, 40, 41, 1034,
+ 1083, 9, 32, 40, 41, 42, 46, 92,
+ 95, 1034, 1083, 45, 57, 65, 90, 97,
+ 122, 42, 46, 92, 95, 45, 57, 65,
+ 90, 97, 122, 9, 32, 40, 41, 42,
+ 45, 92, 95, 778, 827, 1034, 1083, 47,
+ 57, 65, 90, 97, 122, 9, 32, 40,
+ 41, 778, 827, 1034, 1083, 10, 48, 57,
+ 48, 57, 48, 57, 42, 46, 92, 95,
+ 45, 57, 65, 90, 97, 122, 9, 32,
+ 40, 41, 778, 827, 1034, 1083, 1034, 896,
+ 1151, 9, 32, 40, 41, 1034, 1083, 9,
+ 32, 40, 41, 1034, 1083, -128, 8, 11,
+ 58, 60, 127, 9, 32, 40, 41, 778,
+ 827, 1034, 1083, 9, 32, 40, 41, 42,
+ 46, 92, 95, 778, 827, 1034, 1083, 45,
+ 57, 65, 90, 97, 122, 42, 46, 92,
+ 95, 45, 57, 65, 90, 97, 122, 9,
+ 32, 40, 41, 42, 45, 92, 95, 778,
+ 827, 1034, 1083, 47, 57, 65, 90, 97,
+ 122, 9, 32, 40, 41, 778, 827, 1034,
+ 1083, 10, 48, 57, 48, 57, 48, 57,
+ 42, 46, 92, 95, 45, 57, 65, 90,
+ 97, 122, 9, 32, 40, 41, 778, 827,
+ 1034, 1083, 778, 1034, 640, 895, 896, 1151,
+ 9, 32, 40, 41, 42, 46, 92, 95,
+ 1034, 1083, 45, 57, 65, 90, 97, 122,
+ 1034, 896, 1151, 1034, 896, 1151, 43, 47,
+ 57, 65, 90, 97, 122, 43, 47, 57,
+ 65, 90, 97, 122, 43, 61, 47, 57,
+ 65, 90, 97, 122, 43, 61, 47, 57,
+ 65, 90, 97, 122, 9, 32, 40, 41,
+ 43, 2058, 2107, 2314, 2363, 2570, 2619, 47,
+ 57, 65, 90, 97, 122, 1034, 896, 1151,
+ 61, 9, 32, 40, 41, 2058, 2107, 2314,
+ 2363, 2570, 2619, 9, 32, 40, 41, 65,
+ 67, 68, 69, 72, 73, 75, 76, 77,
+ 78, 80, 82, 83, 84, 85, 97, 99,
+ 100, 101, 104, 105, 107, 108, 109, 110,
+ 112, 114, 115, 116, 117, 2058, 2107, 2314,
+ 2363, 2570, 2619, 9, 32, 40, 41, 65,
+ 70, 80, 97, 102, 112, 2058, 2107, 2314,
+ 2363, 2570, 2619, 65, 97, 65, 97, 9,
+ 32, 40, 41, 2058, 2107, 2314, 2363, 2570,
+ 2619, 1034, 896, 1151, 65, 68, 69, 78,
+ 97, 100, 101, 110, 65, 97, 9, 32,
+ 40, 41, 2058, 2107, 2314, 2363, 2570, 2619,
+ 78, 83, 110, 115, 83, 115, 75, 107,
+ 69, 101, 89, 121, 9, 32, 40, 41,
+ 2058, 2107, 2314, 2363, 2570, 2619, 9, 32,
+ 40, 41, 2058, 2107, 2314, 2363, 2570, 2619,
+ 82, 114, 84, 116, 9, 32, 40, 41,
+ 2058, 2107, 2314, 2363, 2570, 2619, 65, 97,
+ 77, 109, 69, 101, 9, 32, 40, 41,
+ 2058, 2107, 2314, 2363, 2570, 2619, 72, 78,
+ 83, 104, 110, 115, 67, 99, 73, 105,
+ 68, 100, 9, 32, 40, 41, 2058, 2107,
+ 2314, 2363, 2570, 2619, 65, 83, 97, 115,
+ 77, 109, 69, 101, 9, 32, 40, 41,
+ 2058, 2107, 2314, 2363, 2570, 2619, 75, 107,
+ 69, 101, 89, 121, 9, 32, 40, 41,
+ 2058, 2107, 2314, 2363, 2570, 2619, 9, 32,
+ 40, 41, 2058, 2107, 2314, 2363, 2570, 2619,
+ 85, 117, 73, 105, 52, 54, 56, 9,
+ 32, 40, 41, 2058, 2107, 2314, 2363, 2570,
+ 2619, 52, 9, 32, 40, 41, 2058, 2107,
+ 2314, 2363, 2570, 2619, 73, 105, 78, 110,
+ 70, 102, 79, 111, 9, 32, 40, 41,
+ 2058, 2107, 2314, 2363, 2570, 2619, 80, 112,
+ 83, 115, 69, 101, 67, 99, 75, 107,
+ 69, 101, 89, 121, 9, 32, 40, 41,
+ 2058, 2107, 2314, 2363, 2570, 2619, 69, 88,
+ 101, 120, 89, 121, 9, 32, 40, 41,
+ 2058, 2107, 2314, 2363, 2570, 2619, 9, 32,
+ 40, 41, 2058, 2107, 2314, 2363, 2570, 2619,
+ 51, 54, 79, 80, 111, 112, 50, 9,
+ 32, 40, 41, 2058, 2107, 2314, 2363, 2570,
+ 2619, 52, 9, 32, 40, 41, 2058, 2107,
+ 2314, 2363, 2570, 2619, 67, 99, 9, 32,
+ 40, 41, 2058, 2107, 2314, 2363, 2570, 2619,
+ 9, 32, 40, 41, 2058, 2107, 2314, 2363,
+ 2570, 2619, 73, 88, 105, 120, 78, 110,
+ 70, 102, 79, 111, 9, 32, 40, 41,
+ 2058, 2107, 2314, 2363, 2570, 2619, 9, 32,
+ 40, 41, 2058, 2107, 2314, 2363, 2570, 2619,
+ 65, 73, 83, 97, 105, 115, 80, 112,
+ 84, 116, 82, 114, 9, 32, 40, 41,
+ 2058, 2107, 2314, 2363, 2570, 2619, 68, 100,
+ 9, 32, 40, 41, 2058, 2107, 2314, 2363,
+ 2570, 2619, 9, 32, 40, 41, 69, 101,
+ 2058, 2107, 2314, 2363, 2570, 2619, 67, 99,
+ 9, 32, 40, 41, 51, 2058, 2107, 2314,
+ 2363, 2570, 2619, 9, 32, 40, 41, 80,
+ 112, 2058, 2107, 2314, 2363, 2570, 2619, 65,
+ 97, 82, 114, 65, 97, 77, 109, 9,
+ 32, 40, 41, 2058, 2107, 2314, 2363, 2570,
+ 2619, 84, 116, 82, 114, 9, 32, 40,
+ 41, 2058, 2107, 2314, 2363, 2570, 2619, 80,
+ 82, 84, 112, 114, 116, 9, 32, 40,
+ 41, 2058, 2107, 2314, 2363, 2570, 2619, 83,
+ 115, 73, 105, 71, 103, 9, 32, 40,
+ 41, 2058, 2107, 2314, 2363, 2570, 2619, 9,
+ 32, 40, 41, 2058, 2107, 2314, 2363, 2570,
+ 2619, 79, 80, 82, 83, 111, 112, 114,
+ 115, 65, 97, 9, 32, 40, 41, 2058,
+ 2107, 2314, 2363, 2570, 2619, 70, 102, 9,
+ 32, 40, 41, 2058, 2107, 2314, 2363, 2570,
+ 2619, 86, 118, 9, 32, 40, 41, 2058,
+ 2107, 2314, 2363, 2570, 2619, 72, 104, 70,
+ 102, 80, 112, 9, 32, 40, 41, 2058,
+ 2107, 2314, 2363, 2570, 2619, 76, 88, 89,
+ 108, 120, 121, 83, 115, 65, 97, 9,
+ 32, 40, 41, 2058, 2107, 2314, 2363, 2570,
+ 2619, 84, 116, 9, 32, 40, 41, 2058,
+ 2107, 2314, 2363, 2570, 2619, 80, 112, 69,
+ 101, 48, 57, 9, 32, 40, 41, 2058,
+ 2107, 2314, 2363, 2570, 2619, 48, 57, 82,
+ 114, 73, 105, 9, 32, 40, 41, 2058,
+ 2107, 2314, 2363, 2570, 2619, 83, 115, 68,
+ 100, 66, 98, 9, 32, 40, 41, 2058,
+ 2107, 2314, 2363, 2570, 2619, 76, 108, 9,
+ 32, 40, 41, 2058, 2107, 2314, 2363, 2570,
+ 2619, 9, 32, 40, 41, 1034, 1083, 9,
+ 32, 40, 41, 1034, 1083, 48, 57, 9,
+ 32, 40, 41, 1034, 1083, 48, 57, 9,
+ 32, 40, 41, 1034, 1083, 48, 57, 65,
+ 70, 97, 102, 48, 57, 65, 70, 97,
+ 102, 9, 32, 40, 41, 2058, 2107, 2314,
+ 2363, 2570, 2619, 48, 57, 65, 70, 97,
+ 102, 1034, 896, 1151, 1034, 896, 1151, 1034,
+ 896, 1151, 9, 32, 40, 41, 1034, 1083,
+ 9, 32, 40, 41, 48, 1034, 1083, 49,
+ 57, 9, 32, 40, 41, 778, 827, 1034,
+ 1083, 48, 57, 9, 32, 40, 41, 1034,
+ 1083, 48, 57, 65, 70, 97, 102, 48,
+ 57, 65, 70, 97, 102, 9, 32, 40,
+ 41, 2058, 2107, 2314, 2363, 2570, 2619, 48,
+ 57, 65, 70, 97, 102, 1034, 896, 1151,
+ 1034, 896, 1151, 9, 32, 40, 41, 1034,
+ 1083, 48, 57, 1034, 896, 1151, 68, 69,
+ 73, 80, 82, 100, 101, 105, 112, 114,
+ 48, 57, 32, 59, 9, 10, 40, 41,
+ 48, 57, 72, 83, 104, 115, 32, 59,
+ 9, 10, 40, 41, 65, 97, 32, 45,
+ 59, 9, 10, 40, 41, 78, 110, 83,
+ 115, 69, 101, 67, 99, 51, 45, 83,
+ 115, 72, 104, 65, 97, 49, 32, 59,
+ 9, 10, 40, 41, 67, 68, 99, 100,
+ 67, 68, 99, 100, 45, 71, 103, 79,
+ 111, 83, 115, 84, 116, 32, 59, 9,
+ 10, 40, 41, 83, 115, 65, 97, 80,
+ 112, 50, 51, 53, 54, 83, 115, 72,
+ 104, 65, 97, 50, 53, 54, 32, 59,
+ 9, 10, 40, 41, 56, 52, 83, 115,
+ 72, 104, 65, 97, 51, 56, 52, 32,
+ 59, 9, 10, 40, 41, 50, 52, 53,
+ 53, 49, 57, 32, 59, 9, 10, 40,
+ 41, 52, 56, 32, 59, 9, 10, 40,
+ 41, 78, 110, 68, 100, 73, 105, 82,
+ 114, 69, 101, 67, 99, 84, 116, 32,
+ 59, 9, 10, 40, 41, 82, 114, 73,
+ 105, 86, 118, 65, 97, 84, 116, 69,
+ 101, 68, 79, 100, 111, 78, 110, 83,
+ 115, 32, 59, 9, 10, 40, 41, 73,
+ 105, 68, 100, 32, 59, 9, 10, 40,
+ 41, 83, 115, 65, 97, 77, 83, 109,
+ 115, 68, 100, 53, 32, 59, 9, 10,
+ 40, 41, 72, 104, 65, 97, 49, 50,
+ 53, 32, 45, 59, 9, 10, 40, 41,
+ 78, 110, 83, 115, 69, 101, 67, 99,
+ 51, 45, 83, 115, 72, 104, 65, 97,
+ 49, 32, 59, 9, 10, 40, 41, 53,
+ 54, 32, 59, 9, 10, 40, 41, 49,
+ 50, 32, 59, 9, 10, 40, 41, 65,
+ 73, 79, 80, 83, 85, 97, 105, 111,
+ 112, 115, 117, 48, 57, 32, 59, 9,
+ 10, 40, 41, 48, 57, 67, 99, 80,
+ 112, 75, 107, 73, 105, 88, 120, 32,
+ 59, 9, 10, 40, 41, 65, 80, 83,
+ 97, 112, 115, 67, 99, 80, 112, 75,
+ 107, 73, 105, 88, 120, 32, 59, 9,
+ 10, 40, 41, 71, 75, 103, 107, 80,
+ 112, 32, 59, 9, 10, 40, 41, 73,
+ 105, 88, 120, 32, 59, 9, 10, 40,
+ 41, 80, 112, 75, 107, 73, 105, 32,
+ 59, 9, 10, 40, 41, 73, 105, 68,
+ 100, 32, 59, 9, 10, 40, 41, 71,
+ 75, 103, 107, 80, 112, 32, 59, 9,
+ 10, 40, 41, 73, 105, 88, 120, 32,
+ 59, 9, 10, 40, 41, 80, 112, 75,
+ 107, 73, 105, 32, 59, 9, 10, 40,
+ 41, 82, 114, 73, 105, 32, 59, 9,
+ 10, 40, 41, 46, 48, 57, 32, 46,
+ 59, 9, 10, 40, 41, 48, 57, 42,
+ 92, 95, 45, 57, 64, 90, 97, 122,
+ 32, 59, 9, 10, 40, 41, 42, 92,
+ 95, 45, 57, 64, 90, 97, 122, 9,
+ 32, 40, 41, 1034, 1083, 9, 32, 40,
+ 41, 42, 92, 95, 1034, 1083, 45, 57,
+ 64, 90, 97, 122, 9, 32, 40, 41,
+ 1034, 1083, 9, 32, 40, 41, 1034, 1083,
+ 48, 57, 9, 32, 40, 41, 1034, 1083,
+ 48, 57, 9, 32, 40, 41, 1034, 1083,
+ 48, 57, 9, 32, 40, 41, 68, 72,
+ 77, 83, 87, 100, 104, 109, 115, 119,
+ 1034, 1083, 48, 57, 9, 32, 40, 41,
+ 1034, 1083, 48, 57, 9, 32, 40, 41,
+ 68, 72, 77, 83, 87, 100, 104, 109,
+ 115, 119, 1034, 1083, 48, 57, 9, 32,
+ 40, 41, 1034, 1083, 48, 57, 9, 32,
+ 40, 41, 68, 72, 77, 83, 87, 100,
+ 104, 109, 115, 119, 1034, 1083, 48, 57,
+ 9, 32, 40, 41, 1034, 1083, 48, 57,
+ 32, 59, 68, 72, 77, 83, 87, 100,
+ 104, 109, 115, 119, 9, 10, 40, 41,
+ 48, 57, 32, 59, 9, 10, 40, 41,
+ 48, 57, 68, 72, 77, 83, 87, 100,
+ 104, 109, 115, 119, 48, 57, 32, 59,
+ 9, 10, 40, 41, 48, 57, 1034, 896,
+ 1151, 9, 32, 40, 41, 1034, 1083, 48,
+ 57, 68, 72, 77, 83, 87, 100, 104,
+ 109, 115, 119, 48, 57, 9, 32, 40,
+ 41, 1034, 1083, 48, 57, 1034, 896, 1151,
+ 9, 32, 40, 41, 1034, 1083, 48, 57,
+ 68, 72, 77, 83, 87, 100, 104, 109,
+ 115, 119, 48, 57, 9, 32, 40, 41,
+ 1034, 1083, 48, 57, 1034, 896, 1151, 9,
+ 32, 40, 41, 1034, 1083, 48, 57, 68,
+ 72, 77, 83, 87, 100, 104, 109, 115,
+ 119, 48, 57, 9, 32, 40, 41, 1034,
+ 1083, 48, 57, 1034, 896, 1151, 1034, 896,
+ 1151, 1034, 896, 1151, 32, 59, 9, 10,
+ 40, 41, 9, 32, 40, 41, 1034, 1083,
+ 9, 32, 40, 41, 1034, 1083, -128, 8,
+ 11, 58, 60, 127, 32, 59, 9, 10,
+ 40, 41, 1034, 896, 1151, 42, 92, 95,
+ 45, 57, 64, 90, 97, 122, 9, 32,
+ 40, 41, 1034, 1083, 9, 32, 40, 41,
+ 42, 92, 95, 1034, 1083, 45, 57, 64,
+ 90, 97, 122, 32, 59, 9, 10, 40,
+ 41, 1034, 896, 1151, 48, 57, 9, 32,
+ 40, 41, 1034, 1083, 48, 57, 9, 32,
+ 40, 41, 42, 92, 95, 1034, 1083, 45,
+ 57, 64, 90, 97, 122, 32, 59, 9,
+ 10, 40, 41, 1034, 896, 1151, 32, 59,
+ 9, 10, 40, 41, 9, 32, 40, 41,
+ 2058, 2107, 2314, 2363, 2570, 2619, 9, 32,
+ 40, 41, 2058, 2107, 2314, 2363, 2570, 2619,
+ -128, 8, 11, 58, 60, 127, 1034, 896,
+ 1151, 46, 48, 58, 65, 70, 97, 102,
+ 32, 46, 59, 9, 10, 40, 41, 48,
+ 58, 65, 70, 97, 102, 48, 57, 9,
+ 32, 40, 41, 1034, 1083, 48, 57, 9,
+ 32, 40, 41, 78, 83, 1034, 1083, 48,
+ 57, 9, 32, 40, 41, 1034, 1083, 48,
+ 57, 9, 32, 40, 41, 78, 83, 1034,
+ 1083, 48, 57, 9, 32, 40, 41, 46,
+ 1034, 1083, 48, 57, 9, 32, 40, 41,
+ 78, 83, 1034, 1083, 9, 32, 40, 41,
+ 1034, 1083, 9, 32, 40, 41, 1034, 1083,
+ 48, 57, 9, 32, 40, 41, 1034, 1083,
+ 48, 57, 9, 32, 40, 41, 69, 87,
+ 1034, 1083, 48, 57, 9, 32, 40, 41,
+ 1034, 1083, 48, 57, 9, 32, 40, 41,
+ 69, 87, 1034, 1083, 48, 57, 9, 32,
+ 40, 41, 46, 1034, 1083, 48, 57, 9,
+ 32, 40, 41, 69, 87, 1034, 1083, 9,
+ 32, 40, 41, 1034, 1083, 9, 32, 40,
+ 41, 45, 1034, 1083, 48, 57, 48, 57,
+ 9, 32, 40, 41, 46, 109, 2058, 2107,
+ 2314, 2363, 2570, 2619, 48, 57, 9, 32,
+ 40, 41, 2058, 2107, 2314, 2363, 2570, 2619,
+ 48, 57, 9, 32, 40, 41, 46, 109,
+ 2058, 2107, 2314, 2363, 2570, 2619, 48, 57,
+ 9, 32, 40, 41, 2058, 2107, 2314, 2363,
+ 2570, 2619, 48, 57, 9, 32, 40, 41,
+ 46, 109, 2058, 2107, 2314, 2363, 2570, 2619,
+ 48, 57, 9, 32, 40, 41, 2058, 2107,
+ 2314, 2363, 2570, 2619, 48, 57, 9, 32,
+ 40, 41, 46, 109, 2058, 2107, 2314, 2363,
+ 2570, 2619, 48, 57, 9, 32, 40, 41,
+ 2058, 2107, 2314, 2363, 2570, 2619, 1034, 896,
+ 1151, 9, 32, 40, 41, 109, 2058, 2107,
+ 2314, 2363, 2570, 2619, 48, 57, 9, 32,
+ 40, 41, 109, 2058, 2107, 2314, 2363, 2570,
+ 2619, 48, 57, 1034, 896, 1151, 9, 32,
+ 40, 41, 109, 2058, 2107, 2314, 2363, 2570,
+ 2619, 48, 57, 9, 32, 40, 41, 109,
+ 2058, 2107, 2314, 2363, 2570, 2619, 48, 57,
+ 9, 32, 40, 41, 2058, 2107, 2314, 2363,
+ 2570, 2619, 1034, 896, 1151, 9, 32, 40,
+ 41, 109, 2058, 2107, 2314, 2363, 2570, 2619,
+ 48, 57, 9, 32, 40, 41, 109, 2058,
+ 2107, 2314, 2363, 2570, 2619, 48, 57, 9,
+ 32, 40, 41, 2058, 2107, 2314, 2363, 2570,
+ 2619, 1034, 896, 1151, 9, 32, 40, 41,
+ 109, 2058, 2107, 2314, 2363, 2570, 2619, 48,
+ 57, 9, 32, 40, 41, 109, 2058, 2107,
+ 2314, 2363, 2570, 2619, 48, 57, 9, 32,
+ 40, 41, 2058, 2107, 2314, 2363, 2570, 2619,
+ 1034, 896, 1151, 9, 32, 40, 41, 1034,
+ 1083, 1034, 896, 1151, 9, 32, 40, 41,
+ 1034, 1083, 48, 57, 9, 32, 40, 41,
+ 1034, 1083, 48, 57, 1034, 896, 1151, 1034,
+ 896, 1151, 1034, 896, 1151, 9, 32, 40,
+ 41, 1034, 1083, 1034, 896, 1151, 9, 32,
+ 40, 41, 1034, 1083, 48, 57, 9, 32,
+ 40, 41, 1034, 1083, 48, 57, 1034, 896,
+ 1151, 1034, 896, 1151, 48, 57, 9, 32,
+ 40, 41, 1034, 1083, 48, 57, 9, 32,
+ 40, 41, 1034, 1083, 48, 57, 9, 32,
+ 40, 41, 1034, 1083, 48, 57, 9, 32,
+ 40, 41, 1034, 1083, 48, 57, 9, 32,
+ 40, 41, 1034, 1083, 48, 57, 9, 32,
+ 40, 41, 42, 92, 95, 1034, 1083, 45,
+ 57, 64, 90, 97, 122, 32, 59, 9,
+ 10, 40, 41, 1034, 896, 1151, 1034, 896,
+ 1151, 1034, 896, 1151, 48, 57, 9, 32,
+ 40, 41, 1034, 1083, 48, 57, 9, 32,
+ 40, 41, 1034, 1083, 48, 57, 9, 32,
+ 40, 41, 1034, 1083, 48, 57, 9, 32,
+ 40, 41, 1034, 1083, -128, 8, 11, 58,
+ 60, 127, 9, 32, 40, 41, 1034, 1083,
+ 9, 32, 40, 41, 1034, 1083, -128, 8,
+ 11, 58, 60, 127, 9, 32, 40, 41,
+ 1034, 1083, 9, 32, 40, 41, 1034, 1083,
+ -128, 8, 11, 58, 60, 127, 9, 32,
+ 40, 41, 1034, 1083, 9, 32, 40, 41,
+ 42, 92, 95, 1034, 1083, 45, 57, 64,
+ 90, 97, 122, 32, 59, 9, 10, 40,
+ 41, 1034, 896, 1151, 1034, 896, 1151, 1034,
+ 896, 1151, 1034, 896, 1151, 1034, 896, 1151,
+ 48, 57, 65, 90, 97, 122, 9, 32,
+ 40, 41, 1034, 1083, 9, 32, 40, 41,
+ 1034, 1083, 48, 57, 9, 32, 40, 41,
+ 1034, 1083, 48, 57, 9, 32, 40, 41,
+ 1034, 1083, 48, 57, 65, 90, 97, 122,
+ 9, 32, 40, 41, 1034, 1083, 9, 32,
+ 40, 41, 43, 1034, 1083, 47, 57, 65,
+ 90, 97, 122, 1546, 1595, 1034, 896, 1151,
+ 1034, 896, 1151, 1034, 896, 1151, 9, 32,
+ 33, 40, 41, 49, 50, 2058, 2107, 2314,
+ 2363, 2570, 2619, 49, 50, 58, 46, 48,
+ 57, 47, 46, 57, 48, 57, 9, 32,
+ 40, 41, 2058, 2107, 2314, 2363, 2570, 2619,
+ 48, 57, 1034, 896, 1151, 58, 46, 48,
+ 58, 65, 70, 97, 102, 47, 46, 58,
+ 65, 70, 97, 102, 48, 57, 9, 32,
+ 40, 41, 1034, 1083, 48, 57, 9, 32,
+ 40, 41, 1034, 1083, 48, 57, 65, 90,
+ 97, 122, 9, 32, 40, 41, 1034, 1083,
+ 9, 32, 40, 41, 1034, 1083, 48, 57,
+ 9, 32, 40, 41, 1034, 1083, 48, 57,
+ 9, 32, 40, 41, 1034, 1083, 48, 57,
+ 65, 70, 97, 102, 48, 57, 65, 70,
+ 97, 102, 9, 32, 40, 41, 2058, 2107,
+ 2314, 2363, 2570, 2619, 48, 57, 65, 70,
+ 97, 102, 1034, 896, 1151, 1034, 896, 1151,
+ 1034, 896, 1151, 1034, 896, 1151, 48, 57,
+ 9, 32, 40, 41, 1034, 1083, 48, 57,
+ 9, 32, 40, 41, 1034, 1083, 48, 57,
+ 9, 32, 40, 41, 1034, 1083, 48, 57,
+ 9, 32, 40, 41, 1034, 1083, 48, 57,
+ 65, 70, 97, 102, 48, 57, 65, 70,
+ 97, 102, 9, 32, 40, 41, 2058, 2107,
+ 2314, 2363, 2570, 2619, 48, 57, 65, 70,
+ 97, 102, 1034, 896, 1151, 1034, 896, 1151,
+ 1034, 896, 1151, 48, 57, 9, 32, 40,
+ 41, 1034, 1083, 48, 57, 9, 32, 40,
+ 41, 48, 49, 50, 51, 1034, 1083, 9,
+ 32, 40, 41, 1034, 1083, 9, 32, 40,
+ 41, 1034, 1083, 48, 57, 9, 32, 40,
+ 41, 1034, 1083, 48, 57, 9, 32, 40,
+ 41, 46, 1034, 1083, 6153, 6176, 6184, 6185,
+ 6409, 6432, 6440, 6441, 6665, 6688, 6696, 6697,
+ 9482, 9531, 9738, 9787, 10250, 10299, 10506, 10555,
+ 10762, 10811, 11274, 11323, 11530, 11579, 11786, 11835,
+ 12298, 12347, 12554, 12603, 12810, 12859, 3081, 3104,
+ 3112, 3113, 3115, 4106, 4155, 3119, 3129, 3137,
+ 3162, 3169, 3194, 1546, 1595, 4106, 3968, 4223,
+ 4617, 4640, 4648, 4649, 13578, 13627, 13834, 13883,
+ 14346, 14395, 14602, 14651, 14858, 14907, 5642, 5504,
+ 5759, 3115, 6153, 6176, 6184, 6185, 6409, 6432,
+ 6440, 6441, 6665, 6688, 6696, 6697, 9482, 9531,
+ 9738, 9787, 10250, 10299, 10506, 10555, 10762, 10811,
+ 11274, 11323, 11530, 11579, 11786, 11835, 12298, 12347,
+ 12554, 12603, 12810, 12859, 3119, 3129, 3137, 3162,
+ 3169, 3194, 7690, 8202, 8714, 7552, 7807, 8064,
+ 8319, 8576, 8831, 1034, 896, 1151, 1034, 896,
+ 1151, 9, 32, 40, 41, 1034, 1083, 9,
+ 32, 40, 41, 1034, 1083, 48, 57, 9,
+ 32, 40, 41, 1034, 1083, 48, 57, 9,
+ 32, 40, 41, 46, 1034, 1083, 48, 57,
+ 46, 6153, 6176, 6184, 6185, 6409, 6432, 6440,
+ 6441, 6665, 6688, 6696, 6697, 9482, 9531, 9738,
+ 9787, 10250, 10299, 10506, 10555, 10762, 10811, 11274,
+ 11323, 11530, 11579, 11786, 11835, 12298, 12347, 12554,
+ 12603, 12810, 12859, 48, 57, 1034, 896, 1151,
+ 1034, 896, 1151, 9, 32, 40, 41, 1034,
+ 1083, 9, 32, 40, 41, 1034, 1083, 48,
+ 57, 9, 32, 40, 41, 1034, 1083, 48,
+ 57, 9, 32, 40, 41, 46, 1034, 1083,
+ 48, 58, 65, 70, 97, 102, 46, 6153,
+ 6176, 6184, 6185, 6409, 6432, 6440, 6441, 6665,
+ 6688, 6696, 6697, 9482, 9531, 9738, 9787, 10250,
+ 10299, 10506, 10555, 10762, 10811, 11274, 11323, 11530,
+ 11579, 11786, 11835, 12298, 12347, 12554, 12603, 12810,
+ 12859, 48, 58, 65, 70, 97, 102, 1034,
+ 896, 1151, 1034, 896, 1151, 9, 32, 40,
+ 41, 1034, 1083, 9, 32, 40, 41, 1034,
+ 1083, 48, 57, 9, 32, 40, 41, 1034,
+ 1083, 48, 57, 9, 32, 40, 41, 42,
+ 92, 95, 1034, 1083, 45, 57, 64, 90,
+ 97, 122, 6153, 6176, 6184, 6185, 6409, 6432,
+ 6440, 6441, 6665, 6688, 6696, 6697, 9482, 9531,
+ 9738, 9787, 10250, 10299, 10506, 10555, 10762, 10811,
+ 11274, 11323, 11530, 11579, 11786, 11835, 12298, 12347,
+ 12554, 12603, 12810, 12859, 1034, 896, 1151, 1034,
+ 896, 1151, 1034, 896, 1151, 65, 67, 68,
+ 69, 72, 73, 75, 76, 77, 78, 80,
+ 82, 83, 84, 85, 97, 99, 100, 101,
+ 104, 105, 107, 108, 109, 110, 112, 114,
+ 115, 116, 117, 9, 32, 40, 41, 65,
+ 70, 80, 97, 102, 112, 1034, 1083, 9,
+ 32, 40, 41, 1034, 1083, 48, 57, 65,
+ 90, 97, 122, 9, 32, 40, 41, 1034,
+ 1083, 9, 32, 40, 41, 1034, 1083, 48,
+ 57, 9, 32, 40, 41, 1034, 1083, 48,
+ 57, 9, 32, 40, 41, 1034, 1083, 48,
+ 57, 9, 32, 40, 41, 1034, 1083, 48,
+ 57, 9, 32, 40, 41, 1034, 1083, 48,
+ 57, 9, 32, 40, 41, 1034, 1083, 48,
+ 57, 9, 32, 40, 41, 1034, 1083, 48,
+ 57, 9, 32, 40, 41, 1034, 1083, 48,
+ 57, 9, 32, 40, 41, 1034, 1083, 48,
+ 57, 9, 32, 40, 41, 1034, 1083, 48,
+ 57, 9, 32, 40, 41, 42, 92, 95,
+ 1034, 1083, 45, 57, 64, 90, 97, 122,
+ 9, 32, 40, 41, 1034, 1083, 9, 32,
+ 40, 41, 43, 1034, 1083, 47, 57, 65,
+ 90, 97, 122, 1546, 1595, 1034, 896, 1151,
+ 1034, 896, 1151, 1034, 896, 1151, 1034, 896,
+ 1151, 1034, 896, 1151, 1034, 896, 1151, 1034,
+ 896, 1151, 1034, 896, 1151, 65, 97, 65,
+ 97, 9, 32, 40, 41, 1034, 1083, 83,
+ 115, 68, 100, 66, 98, 9, 32, 40,
+ 41, 1034, 1083, 76, 108, 9, 32, 40,
+ 41, 1034, 1083, 65, 68, 69, 78, 97,
+ 100, 101, 110, 65, 97, 9, 32, 40,
+ 41, 1034, 1083, 78, 83, 110, 115, 83,
+ 115, 75, 107, 69, 101, 89, 121, 9,
+ 32, 40, 41, 1034, 1083, 9, 32, 40,
+ 41, 1034, 1083, 82, 114, 84, 116, 9,
+ 32, 40, 41, 1034, 1083, 65, 97, 77,
+ 109, 69, 101, 9, 32, 40, 41, 1034,
+ 1083, 72, 78, 83, 104, 110, 115, 67,
+ 99, 73, 105, 68, 100, 9, 32, 40,
+ 41, 1034, 1083, 65, 83, 97, 115, 77,
+ 109, 69, 101, 9, 32, 40, 41, 1034,
+ 1083, 75, 107, 69, 101, 89, 121, 9,
+ 32, 40, 41, 1034, 1083, 9, 32, 40,
+ 41, 1034, 1083, 85, 117, 73, 105, 52,
+ 54, 56, 9, 32, 40, 41, 1034, 1083,
+ 52, 9, 32, 40, 41, 1034, 1083, 73,
+ 105, 78, 110, 70, 102, 79, 111, 9,
+ 32, 40, 41, 1034, 1083, 80, 112, 83,
+ 115, 69, 101, 67, 99, 75, 107, 69,
+ 101, 89, 121, 9, 32, 40, 41, 1034,
+ 1083, 69, 88, 101, 120, 89, 121, 9,
+ 32, 40, 41, 1034, 1083, 9, 32, 40,
+ 41, 1034, 1083, 51, 54, 79, 80, 111,
+ 112, 50, 9, 32, 40, 41, 1034, 1083,
+ 52, 9, 32, 40, 41, 1034, 1083, 67,
+ 99, 9, 32, 40, 41, 1034, 1083, 9,
+ 32, 40, 41, 1034, 1083, 73, 88, 105,
+ 120, 78, 110, 70, 102, 79, 111, 9,
+ 32, 40, 41, 1034, 1083, 9, 32, 40,
+ 41, 1034, 1083, 65, 73, 83, 97, 105,
+ 115, 80, 112, 84, 116, 82, 114, 9,
+ 32, 40, 41, 1034, 1083, 68, 100, 9,
+ 32, 40, 41, 1034, 1083, 9, 32, 40,
+ 41, 69, 101, 1034, 1083, 67, 99, 9,
+ 32, 40, 41, 51, 1034, 1083, 9, 32,
+ 40, 41, 80, 112, 1034, 1083, 65, 97,
+ 82, 114, 65, 97, 77, 109, 9, 32,
+ 40, 41, 1034, 1083, 84, 116, 82, 114,
+ 9, 32, 40, 41, 1034, 1083, 80, 82,
+ 84, 112, 114, 116, 9, 32, 40, 41,
+ 1034, 1083, 83, 115, 73, 105, 71, 103,
+ 9, 32, 40, 41, 1034, 1083, 9, 32,
+ 40, 41, 1034, 1083, 79, 80, 82, 83,
+ 111, 112, 114, 115, 65, 97, 9, 32,
+ 40, 41, 1034, 1083, 70, 102, 9, 32,
+ 40, 41, 1034, 1083, 86, 118, 9, 32,
+ 40, 41, 1034, 1083, 72, 104, 70, 102,
+ 80, 112, 9, 32, 40, 41, 1034, 1083,
+ 76, 88, 89, 108, 120, 121, 83, 115,
+ 65, 97, 9, 32, 40, 41, 1034, 1083,
+ 84, 116, 9, 32, 40, 41, 1034, 1083,
+ 80, 112, 69, 101, 48, 57, 9, 32,
+ 40, 41, 1034, 1083, 48, 57, 82, 114,
+ 73, 105, 9, 32, 40, 41, 1034, 1083,
+ 42, 92, 95, 45, 57, 64, 90, 97,
+ 122, 32, 59, 9, 10, 40, 41, 32,
+ 59, 9, 10, 40, 41, 48, 57, 9,
+ 32, 40, 41, 1034, 1083, 48, 57, 9,
+ 32, 40, 41, 1034, 1083, 48, 57, 9,
+ 32, 40, 41, 1034, 1083, 48, 57, 9,
+ 32, 40, 41, 1034, 1083, 48, 57, 65,
+ 90, 97, 122, 9, 32, 40, 41, 1034,
+ 1083, 9, 32, 40, 41, 43, 1034, 1083,
+ 47, 57, 65, 90, 97, 122, 1546, 1595,
+ 1034, 896, 1151, 1034, 896, 1151, 1034, 896,
+ 1151, 43, 47, 57, 65, 90, 97, 122,
+ 1546, 1595, 48, 57, 9, 32, 40, 41,
+ 1034, 1083, 48, 57, 9, 32, 40, 41,
+ 1034, 1083, 48, 57, 9, 32, 40, 41,
+ 1034, 1083, 48, 57, 9, 32, 40, 41,
+ 1034, 1083, 48, 57, 9, 32, 40, 41,
+ 1034, 1083, 48, 57, 9, 32, 40, 41,
+ 45, 1034, 1083, 48, 57, 65, 70, 97,
+ 102, 9, 32, 40, 41, 1034, 1083, 9,
+ 32, 40, 41, 1034, 1083, 48, 57, 65,
+ 86, 97, 118, 48, 57, 65, 86, 97,
+ 118, 61, 48, 57, 65, 86, 97, 118,
+ 48, 57, 65, 86, 97, 118, 61, 48,
+ 57, 65, 86, 97, 118, 61, 48, 57,
+ 65, 86, 97, 118, 48, 57, 65, 86,
+ 97, 118, 61, 48, 57, 65, 86, 97,
+ 118, 32, 59, 9, 10, 40, 41, 48,
+ 57, 65, 86, 97, 118, 32, 59, 9,
+ 10, 40, 41, 61, 61, 61, 61, 61,
+ 1034, 896, 1151, 48, 57, 65, 70, 97,
+ 102, 9, 32, 40, 41, 1034, 1083, 48,
+ 57, 65, 70, 97, 102, 1034, 896, 1151,
+ 1034, 896, 1151, 1034, 896, 1151, 48, 57,
+ 9, 32, 40, 41, 1034, 1083, 48, 57,
+ 9, 32, 40, 41, 1034, 1083, 48, 57,
+ 9, 32, 40, 41, 1034, 1083, 48, 57,
+ 9, 32, 40, 41, 1034, 1083, 48, 57,
+ 9, 32, 40, 41, 1034, 1083, 48, 57,
+ 9, 32, 40, 41, 45, 1034, 1083, 48,
+ 57, 65, 70, 97, 102, 32, 59, 9,
+ 10, 40, 41, 48, 57, 65, 70, 97,
+ 102, 32, 59, 9, 10, 40, 41, 48,
+ 57, 65, 70, 97, 102, 1034, 896, 1151,
+ 1034, 896, 1151, 1034, 896, 1151, 48, 57,
+ 9, 32, 40, 41, 1034, 1083, 48, 57,
+ 9, 32, 40, 41, 1034, 1083, 48, 57,
+ 9, 32, 40, 41, 1034, 1083, 48, 57,
+ 9, 32, 40, 41, 1034, 1083, 48, 57,
+ 9, 32, 40, 41, 1034, 1083, 48, 57,
+ 9, 32, 40, 41, 1034, 1083, 48, 57,
+ 65, 70, 97, 102, 48, 57, 65, 70,
+ 97, 102, 9, 32, 40, 41, 2058, 2107,
+ 2314, 2363, 2570, 2619, 48, 57, 65, 70,
+ 97, 102, 1034, 896, 1151, 1034, 896, 1151,
+ 1034, 896, 1151, 1034, 896, 1151, 48, 57,
+ 9, 32, 40, 41, 1034, 1083, 48, 57,
+ 9, 32, 40, 41, 46, 1034, 1083, 48,
+ 57, 32, 46, 59, 9, 10, 40, 41,
+ 48, 57, 1034, 896, 1151, 48, 57, 9,
+ 32, 40, 41, 1034, 1083, 48, 57, 9,
+ 32, 40, 41, 1034, 1083, 48, 57, 65,
+ 70, 97, 102, 48, 57, 65, 70, 97,
+ 102, 48, 57, 65, 70, 97, 102, 48,
+ 57, 65, 70, 97, 102, 58, 48, 57,
+ 65, 70, 97, 102, 48, 57, 65, 70,
+ 97, 102, 48, 57, 65, 70, 97, 102,
+ 48, 57, 65, 70, 97, 102, 32, 58,
+ 59, 9, 10, 40, 41, 1034, 896, 1151,
+ 48, 57, 65, 70, 97, 102, 48, 57,
+ 65, 70, 97, 102, 45, 48, 57, 65,
+ 70, 97, 102, 48, 57, 65, 70, 97,
+ 102, 32, 45, 59, 9, 10, 40, 41,
+ 48, 57, 65, 70, 97, 102, 48, 57,
+ 65, 70, 97, 102, 45, 48, 57, 65,
+ 70, 97, 102, 48, 57, 65, 70, 97,
+ 102, 32, 45, 59, 9, 10, 40, 41,
+ 48, 57, 9, 32, 40, 41, 1034, 1083,
+ 48, 57, 9, 32, 40, 41, 1034, 1083,
+ 48, 57, 9, 32, 40, 41, 1034, 1083,
+ 48, 57, 9, 32, 40, 41, 1034, 1083,
+ -128, 8, 11, 58, 60, 127, 32, 59,
+ 9, 10, 40, 41, 1034, 896, 1151, 1034,
+ 896, 1151, 48, 57, 9, 32, 40, 41,
+ 1034, 1083, 48, 57, 9, 32, 40, 41,
+ 1034, 1083, -128, 8, 11, 58, 60, 127,
+ 9, 32, 40, 41, 1034, 1083, 9, 32,
+ 40, 41, 1034, 1083, -128, 8, 11, 58,
+ 60, 127, 32, 59, 9, 10, 40, 41,
+ 1034, 896, 1151, 1034, 896, 1151, 9, 32,
+ 36, 40, 41, 42, 92, 95, 778, 827,
+ 1034, 1083, 45, 57, 64, 90, 97, 122,
+ 9, 32, 36, 40, 41, 42, 58, 92,
+ 95, 1802, 1851, 2058, 2107, 2314, 2363, 2570,
+ 2619, -128, 8, 11, 44, 45, 57, 60,
+ 63, 64, 90, 91, 96, 97, 122, 123,
+ 127, 9, 32, 36, 40, 41, 42, 65,
+ 67, 68, 69, 72, 73, 75, 76, 77,
+ 78, 80, 82, 83, 84, 85, 92, 95,
+ 97, 99, 100, 101, 104, 105, 107, 108,
+ 109, 110, 112, 114, 115, 116, 117, 778,
+ 827, 1034, 1083, 45, 57, 64, 90, 98,
+ 122, 9, 32, 36, 40, 41, 42, 65,
+ 67, 68, 69, 72, 73, 75, 76, 77,
+ 78, 80, 82, 83, 84, 85, 92, 95,
+ 97, 99, 100, 101, 104, 105, 107, 108,
+ 109, 110, 112, 114, 115, 116, 117, 778,
+ 827, 1034, 1083, 45, 47, 48, 57, 64,
+ 90, 98, 122, 9, 32, 36, 40, 41,
+ 42, 92, 95, 778, 827, 1034, 1083, 45,
+ 57, 64, 90, 97, 122, 9, 32, 36,
+ 40, 41, 42, 65, 67, 68, 69, 72,
+ 73, 75, 76, 77, 78, 80, 82, 83,
+ 84, 85, 92, 95, 97, 99, 100, 101,
+ 104, 105, 107, 108, 109, 110, 112, 114,
+ 115, 116, 117, 778, 827, 1034, 1083, 45,
+ 47, 48, 57, 64, 90, 98, 122, 9,
+ 32, 36, 40, 41, 42, 92, 95, 778,
+ 827, 1034, 1083, 45, 57, 64, 90, 97,
+ 122, 9, 32, 36, 40, 41, 42, 58,
+ 92, 95, 1802, 1851, 2058, 2107, 2314, 2363,
+ 2570, 2619, -128, 8, 11, 44, 45, 57,
+ 60, 63, 64, 90, 91, 96, 97, 122,
+ 123, 127, 9, 32, 36, 40, 41, 42,
+ 58, 65, 67, 68, 69, 72, 73, 75,
+ 76, 77, 78, 80, 82, 83, 84, 85,
+ 92, 95, 97, 99, 100, 101, 104, 105,
+ 107, 108, 109, 110, 112, 114, 115, 116,
+ 117, 1802, 1851, 2058, 2107, 2314, 2363, 2570,
+ 2619, -128, 8, 11, 44, 45, 47, 48,
+ 57, 60, 63, 64, 90, 91, 96, 98,
+ 122, 123, 127, 9, 32, 36, 40, 41,
+ 42, 58, 65, 67, 68, 69, 72, 73,
+ 75, 76, 77, 78, 80, 82, 83, 84,
+ 85, 92, 95, 97, 99, 100, 101, 104,
+ 105, 107, 108, 109, 110, 112, 114, 115,
+ 116, 117, 1802, 1851, 2058, 2107, 2314, 2363,
+ 2570, 2619, -128, 8, 11, 44, 45, 47,
+ 48, 57, 60, 63, 64, 90, 91, 96,
+ 98, 122, 123, 127, 32, 33, 59, 92,
+ 9, 10, 35, 39, 40, 41, 42, 126,
+ 9, 32, 40, 41, 42, 46, 92, 95,
+ 1034, 1083, 45, 57, 65, 90, 97, 122,
+ 9, 32, 40, 41, 43, 2058, 2107, 2314,
+ 2363, 2570, 2619, 47, 57, 65, 90, 97,
+ 122, 1034, 896, 1151, 9, 32, 40, 41,
+ 65, 67, 68, 69, 72, 73, 75, 76,
+ 77, 78, 80, 82, 83, 84, 85, 97,
+ 99, 100, 101, 104, 105, 107, 108, 109,
+ 110, 112, 114, 115, 116, 117, 2058, 2107,
+ 2314, 2363, 2570, 2619, 1034, 896, 1151, 9,
+ 32, 40, 41, 2058, 2107, 2314, 2363, 2570,
+ 2619, 48, 57, 65, 70, 97, 102, 1034,
+ 896, 1151, 9, 32, 40, 41, 1034, 1083,
+ 48, 57, 65, 70, 97, 102, 9, 32,
+ 40, 41, 2058, 2107, 2314, 2363, 2570, 2619,
+ 48, 57, 65, 70, 97, 102, 1034, 896,
+ 1151, 1034, 896, 1151, 9, 32, 40, 41,
+ 2058, 2107, 2314, 2363, 2570, 2619, -128, 8,
+ 11, 58, 60, 127, 1034, 896, 1151, 9,
+ 32, 40, 41, 2058, 2107, 2314, 2363, 2570,
+ 2619, 1034, 896, 1151, 9, 32, 40, 41,
+ 2058, 2107, 2314, 2363, 2570, 2619, 48, 57,
+ 1034, 896, 1151, 9, 32, 40, 41, 2058,
+ 2107, 2314, 2363, 2570, 2619, 48, 57, 1034,
+ 896, 1151, 9, 32, 40, 41, 2058, 2107,
+ 2314, 2363, 2570, 2619, 48, 57, 1034, 896,
+ 1151, 9, 32, 33, 40, 41, 49, 50,
+ 2058, 2107, 2314, 2363, 2570, 2619, 1034, 896,
+ 1151, 9, 32, 40, 41, 2058, 2107, 2314,
+ 2363, 2570, 2619, 48, 57, 65, 70, 97,
+ 102, 1034, 896, 1151, 9, 32, 40, 41,
+ 2058, 2107, 2314, 2363, 2570, 2619, 48, 57,
+ 65, 70, 97, 102, 1034, 896, 1151, 4617,
+ 4640, 4648, 4649, 13578, 13627, 13834, 13883, 14346,
+ 14395, 14602, 14651, 14858, 14907, 5642, 5504, 5759,
+ 3081, 3104, 3112, 3113, 3115, 4106, 4155, 3119,
+ 3129, 3137, 3162, 3169, 3194, 4106, 3968, 4223,
+ 3115, 6153, 6176, 6184, 6185, 6409, 6432, 6440,
+ 6441, 6665, 6688, 6696, 6697, 9482, 9531, 9738,
+ 9787, 10250, 10299, 10506, 10555, 10762, 10811, 11274,
+ 11323, 11530, 11579, 11786, 11835, 12298, 12347, 12554,
+ 12603, 12810, 12859, 3119, 3129, 3137, 3162, 3169,
+ 3194, 7690, 8202, 8714, 7552, 7807, 8064, 8319,
+ 8576, 8831, 9, 32, 40, 41, 2058, 2107,
+ 2314, 2363, 2570, 2619, 48, 57, 65, 70,
+ 97, 102, 1034, 896, 1151, 0
+};
+
+static const char _zone_scanner_single_lengths[] = {
+ 0, 38, 16, 36, 16, 11, 8, 8,
+ 1, 1, 1, 13, 13, 2, 44, 18,
+ 38, 8, 2, 10, 12, 12, 4, 2,
+ 2, 2, 2, 10, 10, 2, 2, 10,
+ 2, 2, 2, 10, 6, 2, 2, 2,
+ 10, 4, 2, 2, 10, 2, 2, 2,
+ 10, 10, 2, 2, 2, 1, 10, 1,
+ 10, 2, 2, 2, 2, 10, 4, 6,
+ 36, 2, 2, 2, 2, 2, 2, 2,
+ 10, 4, 2, 10, 10, 6, 1, 10,
+ 1, 10, 2, 10, 10, 4, 2, 2,
+ 2, 10, 10, 6, 2, 2, 2, 10,
+ 2, 10, 12, 2, 11, 12, 2, 2,
+ 2, 2, 10, 2, 2, 10, 6, 10,
+ 2, 2, 2, 10, 10, 8, 2, 10,
+ 2, 10, 2, 10, 2, 2, 2, 10,
+ 6, 2, 2, 10, 2, 10, 2, 2,
+ 0, 10, 2, 2, 10, 1, 38, 4,
+ 6, 36, 16, 6, 10, 6, 1, 1,
+ 6, 2, 2, 2, 2, 2, 2, 2,
+ 6, 36, 1, 16, 36, 1, 6, 10,
+ 6, 1, 16, 42, 18, 13, 38, 2,
+ 8, 8, 44, 16, 14, 10, 10, 12,
+ 12, 14, 12, 14, 10, 14, 16, 14,
+ 10, 2, 14, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 8, 18, 38, 2,
+ 18, 44, 16, 14, 10, 10, 12, 12,
+ 14, 12, 14, 10, 14, 16, 14, 10,
+ 9, 38, 12, 12, 12, 12, 2, 2,
+ 10, 2, 2, 2, 10, 2, 10, 2,
+ 8, 8, 12, 12, 12, 12, 1, 44,
+ 12, 12, 14, 12, 8, 8, 10, 10,
+ 12, 10, 12, 8, 12, 14, 12, 8,
+ 2, 2, 10, 2, 1, 1, 5, 6,
+ 6, 0, 0, 0, 6, 2, 2, 2,
+ 4, 0, 0, 0, 4, 4, 2, 0,
+ 0, 0, 4, 6, 6, 18, 8, 1,
+ 8, 10, 8, 1, 6, 10, 4, 12,
+ 8, 1, 0, 0, 0, 4, 8, 1,
+ 6, 6, 8, 12, 4, 12, 8, 1,
+ 0, 0, 0, 4, 8, 2, 10, 1,
+ 1, 1, 1, 2, 2, 11, 1, 1,
+ 10, 40, 16, 2, 2, 10, 1, 8,
+ 2, 10, 4, 2, 2, 2, 2, 10,
+ 10, 2, 2, 10, 2, 2, 2, 10,
+ 6, 2, 2, 2, 10, 4, 2, 2,
+ 10, 2, 2, 2, 10, 10, 2, 2,
+ 2, 1, 10, 1, 10, 2, 2, 2,
+ 2, 10, 2, 2, 2, 2, 2, 2,
+ 2, 10, 4, 2, 10, 10, 6, 1,
+ 10, 1, 10, 2, 10, 10, 4, 2,
+ 2, 2, 10, 10, 6, 2, 2, 2,
+ 10, 2, 10, 12, 2, 11, 12, 2,
+ 2, 2, 2, 10, 2, 2, 10, 6,
+ 10, 2, 2, 2, 10, 10, 8, 2,
+ 10, 2, 10, 2, 10, 2, 2, 2,
+ 10, 6, 2, 2, 10, 2, 10, 2,
+ 2, 0, 10, 2, 2, 10, 2, 2,
+ 2, 10, 2, 10, 6, 6, 6, 6,
+ 0, 10, 1, 1, 1, 6, 7, 8,
+ 6, 0, 10, 1, 1, 6, 1, 10,
+ 2, 4, 2, 2, 3, 2, 2, 2,
+ 2, 1, 1, 2, 2, 2, 1, 2,
+ 4, 4, 1, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 1, 1, 2, 2,
+ 2, 1, 1, 1, 2, 1, 1, 2,
+ 2, 2, 1, 1, 1, 2, 2, 1,
+ 1, 1, 1, 2, 1, 1, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 4, 2, 2,
+ 2, 2, 2, 2, 2, 2, 4, 2,
+ 1, 2, 2, 2, 3, 3, 2, 2,
+ 2, 2, 1, 1, 2, 2, 2, 1,
+ 2, 1, 1, 2, 1, 1, 2, 12,
+ 2, 2, 2, 2, 2, 2, 2, 6,
+ 2, 2, 2, 2, 2, 2, 4, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 4, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 3, 3, 2, 3, 6, 9, 6,
+ 6, 6, 6, 16, 6, 16, 6, 16,
+ 6, 12, 2, 10, 2, 1, 6, 10,
+ 6, 1, 6, 10, 6, 1, 6, 10,
+ 6, 1, 1, 1, 2, 6, 6, 2,
+ 1, 3, 6, 9, 2, 1, 0, 6,
+ 9, 2, 1, 2, 10, 10, 1, 1,
+ 3, 0, 6, 8, 6, 8, 7, 8,
+ 6, 6, 6, 8, 6, 8, 7, 8,
+ 6, 7, 0, 12, 10, 12, 10, 12,
+ 10, 12, 10, 1, 11, 11, 1, 11,
+ 11, 10, 1, 11, 11, 10, 1, 11,
+ 11, 10, 1, 6, 1, 6, 6, 1,
+ 1, 1, 6, 1, 6, 6, 1, 1,
+ 0, 6, 6, 6, 6, 6, 9, 2,
+ 1, 1, 1, 0, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 9, 2, 1,
+ 1, 1, 1, 1, 0, 6, 6, 6,
+ 6, 6, 7, 2, 1, 1, 1, 13,
+ 2, 1, 1, 1, 0, 10, 1, 1,
+ 1, 1, 0, 6, 6, 6, 6, 6,
+ 6, 0, 10, 1, 1, 1, 1, 0,
+ 6, 6, 6, 6, 0, 10, 1, 1,
+ 1, 0, 6, 10, 6, 6, 6, 7,
+ 34, 7, 2, 1, 14, 1, 35, 3,
+ 1, 1, 6, 6, 6, 7, 35, 1,
+ 1, 6, 6, 6, 7, 35, 1, 1,
+ 6, 6, 6, 9, 34, 1, 1, 1,
+ 30, 12, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 9, 6,
+ 7, 2, 1, 1, 1, 1, 1, 1,
+ 1, 1, 2, 2, 6, 2, 2, 2,
+ 6, 2, 6, 8, 2, 6, 4, 2,
+ 2, 2, 2, 6, 6, 2, 2, 6,
+ 2, 2, 2, 6, 6, 2, 2, 2,
+ 6, 4, 2, 2, 6, 2, 2, 2,
+ 6, 6, 2, 2, 2, 1, 6, 1,
+ 6, 2, 2, 2, 2, 6, 2, 2,
+ 2, 2, 2, 2, 2, 6, 4, 2,
+ 6, 6, 6, 1, 6, 1, 6, 2,
+ 6, 6, 4, 2, 2, 2, 6, 6,
+ 6, 2, 2, 2, 6, 2, 6, 8,
+ 2, 7, 8, 2, 2, 2, 2, 6,
+ 2, 2, 6, 6, 6, 2, 2, 2,
+ 6, 6, 8, 2, 6, 2, 6, 2,
+ 6, 2, 2, 2, 6, 6, 2, 2,
+ 6, 2, 6, 2, 2, 0, 6, 2,
+ 2, 6, 3, 2, 2, 0, 6, 6,
+ 6, 6, 6, 7, 2, 1, 1, 1,
+ 1, 2, 0, 6, 6, 6, 6, 6,
+ 7, 6, 6, 0, 1, 0, 1, 1,
+ 0, 1, 2, 2, 1, 1, 1, 1,
+ 1, 1, 0, 6, 1, 1, 1, 0,
+ 6, 6, 6, 6, 6, 7, 2, 0,
+ 2, 1, 1, 1, 0, 6, 6, 6,
+ 6, 6, 6, 0, 10, 1, 1, 1,
+ 1, 0, 6, 7, 3, 1, 0, 6,
+ 6, 0, 0, 0, 1, 0, 0, 0,
+ 0, 3, 1, 0, 0, 1, 0, 0,
+ 3, 0, 0, 1, 0, 0, 3, 0,
+ 6, 6, 6, 6, 2, 1, 1, 0,
+ 6, 6, 6, 6, 2, 1, 1, 12,
+ 17, 42, 42, 12, 42, 12, 17, 47,
+ 47, 0, 0, 0, 4, 0, 0, 0,
+ 10, 0, 11, 1, 0, 40, 1, 0,
+ 10, 1, 6, 0, 10, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 10, 1, 0, 0, 10, 1, 10, 1,
+ 10, 1, 10, 1, 0, 0, 0, 0,
+ 13, 1, 0, 10, 1, 0, 10, 1,
+ 0, 14, 1, 7, 1, 35, 3, 0,
+ 0, 0, 0, 0, 0, 0, 10, 1,
+ 0, 0, 0, 0, 0, 0
+};
+
+static const char _zone_scanner_range_lengths[] = {
+ 0, 1, 1, 0, 0, 3, 0, 0,
+ 0, 0, 1, 3, 3, 2, 4, 1,
+ 0, 0, 0, 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 0, 0, 0, 1, 1, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 2,
+ 0, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 0, 4, 0, 3, 1, 2,
+ 3, 3, 4, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 2, 0, 0, 0, 0, 0, 0,
+ 2, 0, 0, 2, 0, 1, 1, 2,
+ 0, 4, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 3, 1, 1, 1, 2, 2, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 2,
+ 3, 3, 2, 2, 2, 2, 1, 4,
+ 1, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 2, 2, 0, 2, 0, 0, 3, 5,
+ 5, 1, 1, 1, 5, 2, 2, 2,
+ 4, 3, 1, 1, 4, 1, 2, 3,
+ 1, 1, 1, 0, 1, 1, 0, 0,
+ 1, 1, 1, 1, 0, 3, 3, 3,
+ 0, 0, 1, 1, 1, 3, 0, 1,
+ 0, 3, 0, 3, 3, 3, 0, 0,
+ 1, 1, 1, 3, 0, 2, 3, 1,
+ 1, 3, 3, 3, 3, 3, 1, 0,
+ 0, 0, 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 1, 3,
+ 3, 3, 1, 1, 1, 0, 1, 1,
+ 3, 3, 3, 1, 1, 1, 1, 1,
+ 3, 0, 2, 0, 2, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 2,
+ 0, 0, 0, 0, 0, 0, 0, 2,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2, 0, 0, 0,
+ 0, 0, 0, 0, 0, 2, 0, 0,
+ 0, 0, 0, 2, 0, 0, 2, 0,
+ 0, 0, 0, 0, 0, 0, 2, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 2, 0, 0, 2, 0, 0, 0, 0,
+ 0, 2, 0, 0, 0, 2, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 2, 0, 0, 2, 0, 0, 2, 1,
+ 3, 0, 0, 0, 0, 0, 2, 0,
+ 0, 0, 0, 0, 0, 2, 0, 0,
+ 2, 0, 0, 2, 0, 0, 0, 2,
+ 0, 0, 2, 0, 0, 2, 0, 0,
+ 2, 0, 0, 0, 2, 0, 0, 2,
+ 1, 3, 3, 2, 3, 0, 3, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 3, 3, 1, 3, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 2, 0, 3, 2,
+ 1, 3, 0, 3, 2, 1, 1, 1,
+ 3, 2, 1, 2, 0, 3, 1, 3,
+ 5, 1, 1, 1, 1, 1, 1, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 0, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 1, 0, 1, 1,
+ 1, 0, 1, 0, 1, 1, 1, 1,
+ 1, 1, 0, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 3, 2,
+ 1, 1, 1, 1, 1, 1, 1, 3,
+ 0, 3, 0, 3, 0, 3, 2, 1,
+ 1, 1, 1, 1, 3, 0, 1, 1,
+ 3, 0, 3, 0, 1, 1, 1, 0,
+ 0, 0, 1, 1, 1, 1, 1, 0,
+ 3, 3, 1, 1, 3, 0, 1, 1,
+ 3, 3, 3, 1, 1, 1, 1, 1,
+ 1, 1, 1, 3, 3, 3, 1, 1,
+ 1, 1, 1, 0, 0, 1, 1, 0,
+ 0, 3, 0, 1, 0, 1, 3, 3,
+ 1, 1, 0, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 3, 3, 1, 1,
+ 0, 1, 1, 3, 0, 1, 1, 1,
+ 0, 0, 3, 0, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 3, 0,
+ 3, 0, 1, 1, 1, 1, 1, 1,
+ 1, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 1, 0,
+ 0, 0, 3, 2, 2, 1, 1, 1,
+ 1, 3, 0, 3, 0, 1, 1, 1,
+ 3, 0, 1, 1, 1, 1, 1, 1,
+ 3, 0, 3, 3, 3, 3, 3, 3,
+ 3, 3, 5, 2, 0, 0, 0, 0,
+ 0, 1, 3, 3, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 3, 2, 3,
+ 5, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 3, 3, 3, 1, 1, 1,
+ 1, 1, 1, 1, 3, 1, 1, 1,
+ 3, 3, 3, 3, 0, 3, 3, 3,
+ 3, 2, 1, 3, 3, 0, 3, 3,
+ 2, 3, 3, 0, 3, 3, 2, 1,
+ 1, 1, 1, 3, 2, 1, 1, 1,
+ 1, 3, 0, 3, 2, 1, 1, 3,
+ 8, 3, 4, 3, 4, 3, 8, 9,
+ 9, 0, 0, 0, 4, 0, 0, 0,
+ 3, 0, 3, 1, 0, 0, 1, 0,
+ 3, 1, 3, 0, 3, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 3, 1, 0, 0, 0, 1, 1, 1,
+ 1, 1, 1, 1, 0, 0, 0, 0,
+ 0, 1, 0, 3, 1, 0, 3, 1,
+ 0, 0, 1, 3, 1, 3, 3, 0,
+ 0, 0, 0, 0, 0, 0, 3, 1,
+ 0, 0, 0, 0, 0, 0
+};
+
+static const short _zone_scanner_index_offsets[] = {
+ 0, 0, 40, 58, 95, 112, 127, 136,
+ 145, 147, 149, 152, 169, 186, 191, 240,
+ 260, 299, 308, 311, 322, 336, 350, 355,
+ 358, 361, 364, 367, 378, 389, 392, 395,
+ 406, 409, 412, 415, 426, 433, 436, 439,
+ 442, 453, 458, 461, 464, 475, 478, 481,
+ 484, 495, 506, 509, 512, 515, 517, 528,
+ 530, 541, 544, 547, 550, 553, 564, 569,
+ 576, 613, 616, 619, 622, 625, 628, 631,
+ 634, 645, 650, 653, 664, 675, 682, 684,
+ 695, 697, 708, 711, 722, 733, 738, 741,
+ 744, 747, 758, 769, 776, 779, 782, 785,
+ 796, 799, 810, 823, 826, 838, 851, 854,
+ 857, 860, 863, 874, 877, 880, 891, 898,
+ 909, 912, 915, 918, 929, 940, 949, 952,
+ 963, 966, 977, 980, 991, 994, 997, 1000,
+ 1011, 1018, 1021, 1024, 1035, 1038, 1049, 1052,
+ 1055, 1057, 1069, 1072, 1075, 1086, 1089, 1129,
+ 1134, 1141, 1179, 1197, 1205, 1217, 1225, 1228,
+ 1230, 1237, 1240, 1243, 1246, 1249, 1252, 1255,
+ 1260, 1267, 1305, 1308, 1326, 1364, 1367, 1375,
+ 1387, 1395, 1398, 1415, 1462, 1481, 1498, 1538,
+ 1543, 1555, 1567, 1616, 1633, 1648, 1659, 1670,
+ 1683, 1696, 1711, 1724, 1739, 1750, 1765, 1782,
+ 1797, 1808, 1813, 1828, 1831, 1834, 1837, 1840,
+ 1843, 1848, 1851, 1854, 1859, 1868, 1888, 1928,
+ 1933, 1952, 2001, 2018, 2033, 2044, 2055, 2068,
+ 2081, 2096, 2109, 2124, 2135, 2150, 2167, 2182,
+ 2193, 2206, 2246, 2260, 2274, 2289, 2304, 2307,
+ 2310, 2321, 2324, 2327, 2330, 2341, 2344, 2355,
+ 2360, 2372, 2384, 2399, 2414, 2429, 2444, 2447,
+ 2496, 2510, 2524, 2539, 2552, 2561, 2570, 2581,
+ 2592, 2605, 2616, 2629, 2638, 2651, 2666, 2679,
+ 2688, 2693, 2698, 2709, 2714, 2716, 2718, 2727,
+ 2739, 2751, 2753, 2755, 2757, 2769, 2774, 2779,
+ 2784, 2793, 2797, 2799, 2801, 2810, 2816, 2821,
+ 2825, 2827, 2829, 2835, 2842, 2850, 2870, 2879,
+ 2881, 2891, 2903, 2913, 2916, 2923, 2937, 2945,
+ 2961, 2970, 2972, 2974, 2976, 2978, 2986, 2995,
+ 2998, 3005, 3015, 3024, 3040, 3048, 3064, 3073,
+ 3075, 3077, 3079, 3081, 3089, 3098, 3103, 3117,
+ 3120, 3123, 3128, 3133, 3139, 3145, 3160, 3163,
+ 3165, 3176, 3217, 3234, 3237, 3240, 3251, 3254,
+ 3263, 3266, 3277, 3282, 3285, 3288, 3291, 3294,
+ 3305, 3316, 3319, 3322, 3333, 3336, 3339, 3342,
+ 3353, 3360, 3363, 3366, 3369, 3380, 3385, 3388,
+ 3391, 3402, 3405, 3408, 3411, 3422, 3433, 3436,
+ 3439, 3442, 3444, 3455, 3457, 3468, 3471, 3474,
+ 3477, 3480, 3491, 3494, 3497, 3500, 3503, 3506,
+ 3509, 3512, 3523, 3528, 3531, 3542, 3553, 3560,
+ 3562, 3573, 3575, 3586, 3589, 3600, 3611, 3616,
+ 3619, 3622, 3625, 3636, 3647, 3654, 3657, 3660,
+ 3663, 3674, 3677, 3688, 3701, 3704, 3716, 3729,
+ 3732, 3735, 3738, 3741, 3752, 3755, 3758, 3769,
+ 3776, 3787, 3790, 3793, 3796, 3807, 3818, 3827,
+ 3830, 3841, 3844, 3855, 3858, 3869, 3872, 3875,
+ 3878, 3889, 3896, 3899, 3902, 3913, 3916, 3927,
+ 3930, 3933, 3935, 3947, 3950, 3953, 3964, 3967,
+ 3970, 3973, 3984, 3987, 3998, 4005, 4013, 4021,
+ 4031, 4035, 4049, 4052, 4055, 4058, 4065, 4074,
+ 4084, 4094, 4098, 4112, 4115, 4118, 4126, 4129,
+ 4141, 4147, 4152, 4157, 4160, 4166, 4169, 4172,
+ 4175, 4178, 4180, 4182, 4185, 4188, 4191, 4193,
+ 4198, 4203, 4208, 4210, 4213, 4216, 4219, 4222,
+ 4227, 4230, 4233, 4236, 4239, 4241, 4243, 4246,
+ 4249, 4252, 4254, 4256, 4258, 4263, 4265, 4267,
+ 4270, 4273, 4276, 4278, 4280, 4282, 4287, 4290,
+ 4292, 4294, 4296, 4298, 4303, 4305, 4307, 4312,
+ 4315, 4318, 4321, 4324, 4327, 4330, 4333, 4338,
+ 4341, 4344, 4347, 4350, 4353, 4356, 4361, 4364,
+ 4367, 4372, 4375, 4378, 4383, 4386, 4389, 4394,
+ 4397, 4399, 4404, 4407, 4410, 4414, 4420, 4423,
+ 4426, 4429, 4432, 4434, 4436, 4439, 4442, 4445,
+ 4447, 4452, 4454, 4456, 4461, 4463, 4465, 4470,
+ 4484, 4490, 4493, 4496, 4499, 4502, 4505, 4510,
+ 4517, 4520, 4523, 4526, 4529, 4532, 4537, 4542,
+ 4545, 4550, 4553, 4556, 4561, 4564, 4567, 4570,
+ 4575, 4578, 4581, 4586, 4591, 4594, 4599, 4602,
+ 4605, 4610, 4613, 4616, 4619, 4624, 4627, 4630,
+ 4635, 4638, 4645, 4652, 4657, 4664, 4671, 4684,
+ 4691, 4699, 4707, 4715, 4733, 4741, 4759, 4767,
+ 4785, 4793, 4809, 4815, 4827, 4833, 4836, 4844,
+ 4856, 4864, 4867, 4875, 4887, 4895, 4898, 4906,
+ 4918, 4926, 4929, 4932, 4935, 4940, 4947, 4957,
+ 4962, 4965, 4972, 4979, 4992, 4997, 5000, 5002,
+ 5010, 5023, 5028, 5031, 5036, 5047, 5061, 5064,
+ 5069, 5078, 5080, 5088, 5098, 5106, 5116, 5125,
+ 5134, 5141, 5149, 5157, 5167, 5175, 5185, 5194,
+ 5203, 5210, 5219, 5221, 5235, 5247, 5261, 5273,
+ 5287, 5299, 5313, 5324, 5327, 5340, 5353, 5356,
+ 5369, 5382, 5393, 5396, 5409, 5422, 5433, 5436,
+ 5449, 5462, 5473, 5476, 5483, 5486, 5494, 5502,
+ 5505, 5508, 5511, 5518, 5521, 5529, 5537, 5540,
+ 5543, 5545, 5553, 5561, 5569, 5577, 5585, 5598,
+ 5603, 5606, 5609, 5612, 5614, 5622, 5630, 5638,
+ 5648, 5655, 5665, 5672, 5682, 5689, 5702, 5707,
+ 5710, 5713, 5716, 5719, 5722, 5726, 5733, 5741,
+ 5749, 5759, 5766, 5777, 5780, 5783, 5786, 5789,
+ 5803, 5806, 5808, 5811, 5814, 5816, 5828, 5831,
+ 5833, 5838, 5843, 5845, 5853, 5863, 5870, 5878,
+ 5886, 5896, 5900, 5914, 5917, 5920, 5923, 5926,
+ 5928, 5936, 5944, 5952, 5962, 5966, 5980, 5983,
+ 5986, 5989, 5991, 5999, 6010, 6017, 6025, 6033,
+ 6041, 6076, 6087, 6090, 6093, 6108, 6111, 6150,
+ 6157, 6160, 6163, 6170, 6178, 6186, 6195, 6232,
+ 6235, 6238, 6245, 6253, 6261, 6272, 6311, 6314,
+ 6317, 6324, 6332, 6340, 6353, 6388, 6391, 6394,
+ 6397, 6428, 6441, 6451, 6458, 6466, 6474, 6482,
+ 6490, 6498, 6506, 6514, 6522, 6530, 6538, 6551,
+ 6558, 6569, 6572, 6575, 6578, 6581, 6584, 6587,
+ 6590, 6593, 6596, 6599, 6602, 6609, 6612, 6615,
+ 6618, 6625, 6628, 6635, 6644, 6647, 6654, 6659,
+ 6662, 6665, 6668, 6671, 6678, 6685, 6688, 6691,
+ 6698, 6701, 6704, 6707, 6714, 6721, 6724, 6727,
+ 6730, 6737, 6742, 6745, 6748, 6755, 6758, 6761,
+ 6764, 6771, 6778, 6781, 6784, 6787, 6789, 6796,
+ 6798, 6805, 6808, 6811, 6814, 6817, 6824, 6827,
+ 6830, 6833, 6836, 6839, 6842, 6845, 6852, 6857,
+ 6860, 6867, 6874, 6881, 6883, 6890, 6892, 6899,
+ 6902, 6909, 6916, 6921, 6924, 6927, 6930, 6937,
+ 6944, 6951, 6954, 6957, 6960, 6967, 6970, 6977,
+ 6986, 6989, 6997, 7006, 7009, 7012, 7015, 7018,
+ 7025, 7028, 7031, 7038, 7045, 7052, 7055, 7058,
+ 7061, 7068, 7075, 7084, 7087, 7094, 7097, 7104,
+ 7107, 7114, 7117, 7120, 7123, 7130, 7137, 7140,
+ 7143, 7150, 7153, 7160, 7163, 7166, 7168, 7176,
+ 7179, 7182, 7189, 7196, 7201, 7206, 7208, 7216,
+ 7224, 7232, 7242, 7249, 7260, 7263, 7266, 7269,
+ 7272, 7277, 7280, 7282, 7290, 7298, 7306, 7314,
+ 7322, 7333, 7340, 7350, 7354, 7359, 7363, 7368,
+ 7373, 7377, 7382, 7390, 7395, 7397, 7399, 7401,
+ 7403, 7405, 7408, 7412, 7422, 7425, 7428, 7431,
+ 7433, 7441, 7449, 7457, 7465, 7473, 7484, 7489,
+ 7493, 7501, 7504, 7507, 7510, 7512, 7520, 7528,
+ 7536, 7544, 7552, 7562, 7566, 7580, 7583, 7586,
+ 7589, 7592, 7594, 7602, 7611, 7618, 7621, 7623,
+ 7631, 7641, 7645, 7649, 7653, 7655, 7659, 7663,
+ 7667, 7671, 7677, 7680, 7684, 7688, 7690, 7694,
+ 7698, 7704, 7708, 7712, 7714, 7718, 7722, 7728,
+ 7730, 7738, 7746, 7754, 7764, 7769, 7772, 7775,
+ 7777, 7785, 7795, 7802, 7812, 7817, 7820, 7823,
+ 7839, 7865, 7911, 7958, 7974, 8021, 8037, 8063,
+ 8120, 8177, 8178, 8179, 8180, 8189, 8190, 8191,
+ 8192, 8206, 8207, 8222, 8225, 8226, 8267, 8270,
+ 8271, 8285, 8288, 8298, 8299, 8313, 8316, 8319,
+ 8320, 8321, 8322, 8323, 8324, 8325, 8326, 8327,
+ 8328, 8342, 8345, 8346, 8347, 8358, 8361, 8373,
+ 8376, 8388, 8391, 8403, 8406, 8407, 8408, 8409,
+ 8410, 8424, 8427, 8428, 8442, 8445, 8446, 8460,
+ 8463, 8464, 8479, 8482, 8493, 8496, 8535, 8542,
+ 8543, 8544, 8545, 8546, 8547, 8548, 8549, 8563,
+ 8566, 8567, 8568, 8569, 8570, 8571
+};
+
+static const short _zone_scanner_indicies[] = {
+ 1, 1, 2, 3, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 4, 0,
+ 25, 25, 26, 27, 29, 30, 31, 32,
+ 33, 29, 30, 31, 32, 33, 34, 35,
+ 28, 24, 37, 37, 38, 39, 40, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 53, 54, 55, 56, 36, 58,
+ 58, 59, 60, 61, 62, 63, 61, 62,
+ 63, 64, 65, 66, 66, 67, 68, 57,
+ 70, 70, 72, 73, 74, 75, 76, 69,
+ 69, 77, 78, 69, 69, 69, 71, 80,
+ 80, 81, 82, 83, 84, 83, 84, 79,
+ 86, 86, 87, 88, 89, 90, 89, 90,
+ 85, 92, 91, 94, 93, 96, 95, 71,
+ 97, 97, 98, 99, 74, 83, 84, 83,
+ 100, 101, 102, 83, 103, 69, 69, 69,
+ 79, 104, 104, 105, 106, 74, 89, 90,
+ 89, 107, 108, 109, 89, 110, 69, 69,
+ 69, 79, 92, 112, 91, 111, 79, 113,
+ 113, 115, 116, 69, 118, 119, 120, 121,
+ 122, 123, 124, 125, 126, 127, 128, 129,
+ 130, 131, 132, 74, 118, 119, 120, 121,
+ 122, 123, 124, 125, 126, 127, 128, 129,
+ 130, 131, 132, 20, 21, 133, 134, 135,
+ 136, 137, 138, 69, 69, 117, 69, 114,
+ 140, 140, 141, 142, 29, 30, 31, 32,
+ 33, 29, 30, 31, 32, 33, 83, 84,
+ 143, 144, 28, 139, 146, 146, 147, 148,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 52, 53, 54, 89, 90,
+ 149, 150, 145, 151, 152, 153, 154, 151,
+ 152, 153, 154, 36, 155, 155, 36, 156,
+ 156, 157, 158, 159, 160, 161, 161, 162,
+ 163, 57, 80, 83, 80, 81, 82, 84,
+ 164, 83, 164, 165, 166, 167, 95, 79,
+ 86, 89, 86, 87, 88, 90, 168, 89,
+ 168, 169, 170, 171, 95, 79, 172, 173,
+ 172, 173, 36, 174, 174, 36, 175, 175,
+ 36, 176, 176, 36, 177, 177, 36, 178,
+ 178, 179, 180, 181, 182, 183, 183, 184,
+ 185, 57, 186, 186, 187, 188, 189, 190,
+ 191, 191, 192, 193, 57, 194, 194, 36,
+ 195, 195, 36, 196, 196, 197, 198, 199,
+ 200, 201, 201, 202, 203, 57, 204, 204,
+ 36, 205, 205, 36, 206, 206, 36, 207,
+ 207, 208, 209, 210, 211, 212, 212, 213,
+ 214, 57, 215, 216, 217, 215, 216, 217,
+ 36, 218, 218, 36, 219, 219, 36, 220,
+ 220, 36, 221, 221, 222, 223, 224, 225,
+ 226, 226, 227, 228, 57, 229, 230, 229,
+ 230, 36, 231, 231, 36, 232, 232, 36,
+ 233, 233, 234, 235, 236, 237, 238, 238,
+ 239, 240, 57, 241, 241, 36, 242, 242,
+ 36, 243, 243, 36, 244, 244, 245, 246,
+ 247, 248, 249, 249, 250, 251, 57, 252,
+ 252, 253, 254, 255, 256, 257, 257, 258,
+ 259, 57, 260, 260, 36, 261, 261, 36,
+ 262, 263, 36, 264, 36, 265, 265, 266,
+ 267, 268, 269, 270, 270, 271, 272, 57,
+ 273, 36, 274, 274, 275, 276, 277, 278,
+ 279, 279, 280, 281, 57, 282, 282, 36,
+ 283, 283, 36, 284, 284, 36, 285, 285,
+ 36, 286, 286, 287, 288, 289, 290, 291,
+ 291, 292, 293, 57, 294, 295, 294, 295,
+ 36, 296, 296, 297, 298, 299, 300, 36,
+ 301, 301, 302, 303, 304, 305, 306, 307,
+ 308, 309, 310, 311, 312, 313, 314, 315,
+ 316, 317, 318, 304, 305, 306, 307, 308,
+ 309, 310, 311, 312, 313, 314, 315, 316,
+ 317, 318, 319, 320, 36, 295, 295, 36,
+ 321, 321, 36, 322, 322, 36, 323, 323,
+ 36, 324, 324, 36, 325, 325, 36, 326,
+ 326, 36, 327, 327, 328, 329, 330, 331,
+ 332, 332, 333, 334, 57, 335, 336, 335,
+ 336, 36, 337, 337, 36, 338, 338, 339,
+ 340, 341, 342, 343, 343, 344, 345, 57,
+ 346, 346, 347, 348, 349, 350, 351, 351,
+ 352, 353, 57, 354, 355, 356, 357, 356,
+ 357, 36, 358, 36, 359, 359, 360, 361,
+ 362, 363, 364, 364, 365, 366, 57, 367,
+ 36, 368, 368, 369, 370, 371, 372, 373,
+ 373, 374, 375, 57, 376, 376, 36, 377,
+ 377, 378, 379, 380, 381, 382, 382, 383,
+ 384, 57, 385, 385, 386, 387, 388, 389,
+ 390, 390, 391, 392, 57, 393, 394, 393,
+ 394, 36, 395, 395, 36, 396, 396, 36,
+ 397, 397, 36, 398, 398, 399, 400, 401,
+ 402, 403, 403, 404, 405, 57, 406, 406,
+ 407, 408, 409, 410, 411, 411, 412, 413,
+ 57, 414, 415, 416, 414, 415, 416, 36,
+ 417, 417, 36, 418, 418, 36, 419, 419,
+ 36, 420, 420, 421, 422, 423, 424, 425,
+ 425, 426, 427, 57, 428, 428, 36, 429,
+ 429, 430, 431, 432, 433, 434, 434, 435,
+ 436, 57, 437, 437, 438, 439, 440, 440,
+ 441, 442, 443, 443, 444, 445, 57, 446,
+ 446, 36, 447, 447, 448, 449, 450, 451,
+ 452, 453, 453, 454, 455, 57, 456, 456,
+ 457, 458, 459, 459, 460, 461, 462, 462,
+ 463, 464, 57, 465, 465, 36, 466, 466,
+ 36, 467, 467, 36, 468, 468, 36, 469,
+ 469, 470, 471, 472, 473, 474, 474, 475,
+ 476, 57, 477, 477, 36, 478, 478, 36,
+ 479, 479, 480, 481, 482, 483, 484, 484,
+ 485, 486, 57, 487, 488, 489, 487, 488,
+ 489, 36, 490, 490, 491, 492, 493, 494,
+ 495, 495, 496, 497, 57, 498, 498, 36,
+ 499, 499, 36, 500, 500, 36, 501, 501,
+ 502, 503, 504, 505, 506, 506, 507, 508,
+ 57, 509, 509, 510, 511, 512, 513, 514,
+ 514, 515, 516, 57, 517, 518, 519, 520,
+ 517, 518, 519, 520, 36, 521, 521, 36,
+ 522, 522, 523, 524, 525, 526, 527, 527,
+ 528, 529, 57, 530, 530, 36, 531, 531,
+ 532, 533, 534, 535, 536, 536, 537, 538,
+ 57, 539, 539, 36, 540, 540, 541, 542,
+ 543, 544, 545, 545, 546, 547, 57, 548,
+ 548, 36, 549, 549, 36, 550, 550, 36,
+ 551, 551, 552, 553, 554, 555, 556, 556,
+ 557, 558, 57, 559, 560, 561, 559, 560,
+ 561, 36, 562, 562, 36, 563, 563, 36,
+ 564, 564, 565, 566, 567, 568, 569, 569,
+ 570, 571, 57, 572, 572, 36, 573, 573,
+ 574, 575, 576, 577, 578, 578, 579, 580,
+ 57, 581, 581, 36, 582, 582, 36, 584,
+ 583, 586, 586, 587, 588, 590, 591, 592,
+ 592, 593, 594, 589, 585, 595, 595, 36,
+ 596, 596, 36, 597, 597, 598, 599, 600,
+ 601, 602, 602, 603, 604, 57, 606, 605,
+ 36, 607, 607, 608, 609, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 610, 611, 4,
+ 0, 612, 295, 612, 295, 36, 613, 613,
+ 614, 615, 616, 617, 36, 618, 618, 619,
+ 620, 622, 623, 624, 625, 626, 627, 628,
+ 629, 630, 631, 632, 633, 634, 635, 636,
+ 622, 623, 624, 625, 626, 627, 628, 629,
+ 630, 631, 632, 633, 634, 635, 636, 637,
+ 638, 621, 583, 639, 639, 640, 641, 643,
+ 644, 645, 646, 647, 643, 644, 645, 646,
+ 647, 648, 649, 642, 24, 639, 639, 640,
+ 641, 648, 649, 650, 24, 652, 653, 654,
+ 655, 656, 652, 653, 654, 655, 656, 651,
+ 24, 657, 657, 658, 659, 661, 662, 660,
+ 24, 664, 663, 36, 666, 665, 668, 669,
+ 670, 668, 669, 670, 667, 671, 671, 667,
+ 672, 672, 667, 673, 673, 667, 674, 674,
+ 667, 675, 675, 667, 676, 676, 667, 677,
+ 677, 677, 677, 667, 679, 679, 680, 681,
+ 682, 683, 678, 684, 684, 685, 686, 5,
+ 6, 7, 8, 9, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 687, 688, 4,
+ 583, 691, 689, 690, 693, 693, 694, 695,
+ 29, 30, 31, 32, 33, 29, 30, 31,
+ 32, 33, 696, 697, 28, 692, 698, 698,
+ 699, 700, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19,
+ 701, 702, 4, 583, 704, 703, 36, 25,
+ 25, 26, 27, 34, 35, 705, 24, 707,
+ 708, 709, 710, 711, 707, 708, 709, 710,
+ 711, 706, 24, 712, 712, 713, 714, 716,
+ 717, 715, 24, 719, 718, 36, 721, 721,
+ 722, 723, 61, 62, 63, 61, 62, 63,
+ 724, 725, 66, 66, 726, 727, 720, 728,
+ 728, 729, 730, 69, 118, 119, 120, 121,
+ 122, 123, 124, 125, 126, 127, 128, 129,
+ 130, 131, 132, 74, 118, 119, 120, 121,
+ 122, 123, 124, 125, 126, 127, 128, 129,
+ 130, 131, 132, 731, 732, 69, 69, 733,
+ 734, 69, 69, 117, 69, 585, 736, 736,
+ 737, 738, 61, 62, 63, 61, 62, 63,
+ 83, 84, 739, 740, 741, 742, 743, 744,
+ 735, 745, 745, 746, 747, 74, 89, 90,
+ 748, 107, 108, 109, 749, 110, 69, 69,
+ 69, 79, 750, 750, 751, 752, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 89, 90, 753, 754,
+ 4, 0, 92, 756, 91, 755, 85, 757,
+ 757, 758, 759, 760, 761, 760, 761, 91,
+ 91, 91, 79, 762, 762, 763, 764, 92,
+ 765, 92, 765, 91, 91, 91, 85, 766,
+ 766, 767, 768, 69, 118, 119, 120, 121,
+ 122, 123, 124, 125, 126, 127, 128, 129,
+ 130, 131, 132, 74, 118, 119, 120, 121,
+ 122, 123, 124, 125, 126, 127, 128, 129,
+ 130, 131, 132, 89, 90, 753, 769, 108,
+ 109, 753, 770, 69, 69, 117, 69, 114,
+ 80, 80, 81, 82, 151, 152, 153, 154,
+ 151, 152, 153, 154, 83, 84, 83, 84,
+ 735, 80, 80, 81, 82, 215, 216, 217,
+ 215, 216, 217, 83, 84, 83, 84, 735,
+ 80, 80, 81, 82, 260, 260, 83, 84,
+ 83, 84, 735, 80, 80, 81, 82, 282,
+ 282, 83, 84, 83, 84, 735, 80, 80,
+ 81, 82, 612, 295, 612, 295, 83, 84,
+ 83, 84, 735, 80, 80, 81, 82, 335,
+ 336, 335, 336, 83, 84, 83, 84, 735,
+ 80, 80, 81, 82, 354, 355, 356, 357,
+ 356, 357, 83, 84, 83, 84, 735, 80,
+ 80, 81, 82, 393, 394, 393, 394, 83,
+ 84, 83, 84, 735, 80, 80, 81, 82,
+ 414, 415, 416, 414, 415, 416, 83, 84,
+ 83, 84, 735, 80, 80, 81, 82, 477,
+ 477, 83, 84, 83, 84, 735, 80, 80,
+ 81, 82, 487, 488, 489, 487, 488, 489,
+ 83, 84, 83, 84, 735, 80, 80, 81,
+ 82, 517, 518, 519, 520, 517, 518, 519,
+ 520, 83, 84, 83, 84, 735, 80, 80,
+ 81, 82, 559, 560, 561, 559, 560, 561,
+ 83, 84, 83, 84, 735, 80, 80, 81,
+ 82, 595, 595, 83, 84, 83, 84, 735,
+ 92, 772, 91, 771, 79, 80, 80, 81,
+ 82, 668, 669, 670, 668, 669, 670, 83,
+ 84, 83, 84, 773, 774, 774, 667, 775,
+ 775, 667, 776, 776, 667, 777, 777, 667,
+ 778, 778, 667, 779, 779, 779, 779, 667,
+ 780, 780, 667, 781, 781, 667, 782, 782,
+ 782, 782, 667, 784, 784, 785, 786, 83,
+ 84, 787, 788, 783, 790, 790, 791, 792,
+ 29, 30, 31, 32, 33, 29, 30, 31,
+ 32, 33, 83, 84, 793, 794, 28, 789,
+ 795, 795, 796, 797, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 89, 90, 798, 799, 4, 0,
+ 92, 801, 91, 800, 145, 803, 803, 804,
+ 805, 61, 62, 63, 61, 62, 63, 83,
+ 84, 806, 807, 741, 742, 808, 809, 802,
+ 810, 810, 811, 812, 69, 118, 119, 120,
+ 121, 122, 123, 124, 125, 126, 127, 128,
+ 129, 130, 131, 132, 74, 118, 119, 120,
+ 121, 122, 123, 124, 125, 126, 127, 128,
+ 129, 130, 131, 132, 89, 90, 813, 769,
+ 108, 109, 814, 770, 69, 69, 117, 69,
+ 114, 784, 784, 785, 786, 151, 152, 153,
+ 154, 151, 152, 153, 154, 83, 84, 787,
+ 788, 802, 784, 784, 785, 786, 215, 216,
+ 217, 215, 216, 217, 83, 84, 787, 788,
+ 802, 784, 784, 785, 786, 260, 260, 83,
+ 84, 787, 788, 802, 784, 784, 785, 786,
+ 282, 282, 83, 84, 787, 788, 802, 784,
+ 784, 785, 786, 612, 295, 612, 295, 83,
+ 84, 787, 788, 802, 784, 784, 785, 786,
+ 335, 336, 335, 336, 83, 84, 787, 788,
+ 802, 784, 784, 785, 786, 354, 355, 356,
+ 357, 356, 357, 83, 84, 787, 788, 802,
+ 784, 784, 785, 786, 393, 394, 393, 394,
+ 83, 84, 787, 788, 802, 784, 784, 785,
+ 786, 414, 415, 416, 414, 415, 416, 83,
+ 84, 787, 788, 802, 784, 784, 785, 786,
+ 477, 477, 83, 84, 787, 788, 802, 784,
+ 784, 785, 786, 487, 488, 489, 487, 488,
+ 489, 83, 84, 787, 788, 802, 784, 784,
+ 785, 786, 517, 518, 519, 520, 517, 518,
+ 519, 520, 83, 84, 787, 788, 802, 784,
+ 784, 785, 786, 559, 560, 561, 559, 560,
+ 561, 83, 84, 787, 788, 802, 784, 784,
+ 785, 786, 595, 595, 83, 84, 787, 788,
+ 802, 815, 815, 94, 817, 818, 93, 93,
+ 819, 820, 93, 93, 93, 816, 821, 821,
+ 822, 823, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19,
+ 83, 84, 824, 825, 4, 114, 80, 83,
+ 80, 81, 82, 84, 826, 827, 826, 828,
+ 829, 830, 689, 79, 86, 89, 86, 87,
+ 88, 90, 831, 756, 831, 832, 833, 834,
+ 689, 85, 757, 760, 757, 758, 759, 761,
+ 835, 827, 835, 836, 837, 838, 91, 771,
+ 79, 762, 92, 762, 763, 764, 765, 839,
+ 756, 839, 840, 841, 842, 91, 771, 79,
+ 843, 843, 36, 844, 844, 36, 845, 845,
+ 846, 847, 848, 849, 850, 850, 851, 852,
+ 57, 853, 853, 36, 854, 854, 36, 855,
+ 855, 36, 856, 856, 857, 858, 859, 860,
+ 861, 861, 862, 863, 57, 864, 864, 36,
+ 865, 865, 866, 867, 868, 869, 870, 870,
+ 871, 872, 57, 666, 874, 665, 873, 79,
+ 875, 875, 876, 877, 878, 761, 878, 761,
+ 665, 665, 665, 79, 879, 879, 880, 881,
+ 882, 765, 882, 765, 665, 665, 665, 85,
+ 875, 878, 875, 876, 877, 761, 883, 827,
+ 883, 884, 885, 838, 665, 873, 79, 879,
+ 882, 879, 880, 881, 765, 886, 756, 886,
+ 887, 888, 842, 665, 873, 79, 757, 760,
+ 757, 758, 759, 761, 889, 760, 889, 890,
+ 891, 167, 91, 111, 79, 762, 92, 762,
+ 763, 764, 765, 892, 92, 892, 893, 894,
+ 171, 91, 111, 79, 896, 895, 71, 897,
+ 897, 898, 899, 69, 118, 119, 120, 121,
+ 122, 123, 124, 125, 126, 127, 128, 129,
+ 130, 131, 132, 74, 118, 119, 120, 121,
+ 122, 123, 124, 125, 126, 127, 128, 129,
+ 130, 131, 132, 83, 84, 824, 900, 101,
+ 102, 824, 901, 69, 69, 117, 69, 114,
+ 80, 83, 80, 81, 82, 84, 902, 827,
+ 902, 903, 904, 838, 895, 79, 86, 89,
+ 86, 87, 88, 90, 905, 756, 905, 906,
+ 907, 842, 895, 79, 679, 679, 680, 681,
+ 151, 152, 153, 154, 151, 152, 153, 154,
+ 682, 683, 908, 679, 679, 680, 681, 215,
+ 216, 217, 215, 216, 217, 682, 683, 908,
+ 679, 679, 680, 681, 260, 260, 682, 683,
+ 908, 679, 679, 680, 681, 282, 282, 682,
+ 683, 908, 679, 679, 680, 681, 612, 295,
+ 612, 295, 682, 683, 908, 679, 679, 680,
+ 681, 335, 336, 335, 336, 682, 683, 908,
+ 679, 679, 680, 681, 354, 355, 356, 357,
+ 356, 357, 682, 683, 908, 679, 679, 680,
+ 681, 393, 394, 393, 394, 682, 683, 908,
+ 679, 679, 680, 681, 414, 415, 416, 414,
+ 415, 416, 682, 683, 908, 679, 679, 680,
+ 681, 477, 477, 682, 683, 908, 679, 679,
+ 680, 681, 487, 488, 489, 487, 488, 489,
+ 682, 683, 908, 679, 679, 680, 681, 517,
+ 518, 519, 520, 517, 518, 519, 520, 682,
+ 683, 908, 679, 679, 680, 681, 559, 560,
+ 561, 559, 560, 561, 682, 683, 908, 679,
+ 679, 680, 681, 595, 595, 682, 683, 908,
+ 666, 910, 665, 909, 85, 666, 912, 665,
+ 911, 145, 679, 679, 680, 681, 294, 295,
+ 294, 295, 682, 683, 908, 92, 914, 91,
+ 913, 145, 916, 915, 918, 917, 920, 921,
+ 922, 923, 920, 920, 920, 920, 919, 924,
+ 925, 926, 924, 927, 925, 924, 924, 925,
+ 925, 925, 919, 928, 929, 929, 928, 930,
+ 929, 928, 928, 929, 929, 929, 919, 931,
+ 925, 933, 932, 934, 932, 935, 936, 937,
+ 935, 938, 936, 935, 935, 936, 936, 936,
+ 932, 928, 928, 928, 928, 919, 939, 939,
+ 939, 939, 919, 942, 943, 941, 941, 940,
+ 944, 941, 944, 943, 944, 941, 945, 941,
+ 940, 941, 947, 941, 946, 948, 946, 949,
+ 946, 950, 951, 950, 953, 950, 951, 952,
+ 951, 946, 954, 955, 956, 954, 954, 940,
+ 944, 944, 944, 944, 957, 954, 958, 954,
+ 946, 959, 946, 960, 946, 961, 962, 963,
+ 961, 961, 946, 965, 965, 966, 967, 968,
+ 969, 964, 965, 965, 966, 967, 968, 969,
+ 971, 970, 973, 973, 974, 975, 977, 978,
+ 979, 980, 981, 977, 978, 979, 980, 981,
+ 982, 983, 982, 983, 976, 972, 985, 985,
+ 986, 987, 988, 989, 988, 989, 984, 991,
+ 990, 973, 973, 974, 975, 982, 983, 982,
+ 983, 992, 972, 995, 996, 997, 998, 999,
+ 995, 996, 997, 998, 999, 994, 993, 1000,
+ 1000, 1001, 1002, 1004, 1005, 1004, 1005, 1003,
+ 972, 1007, 1006, 964, 1009, 1009, 1010, 1011,
+ 1012, 1013, 1008, 1009, 1009, 1010, 1011, 1014,
+ 1015, 1016, 1014, 1012, 1013, 1014, 1014, 1014,
+ 1008, 1017, 1018, 1019, 1017, 1017, 1017, 1017,
+ 1008, 1021, 1021, 1022, 1023, 1024, 1024, 1025,
+ 1024, 1026, 1027, 1026, 1027, 1024, 1024, 1024,
+ 1020, 1028, 1028, 1029, 1030, 1031, 1032, 1031,
+ 1032, 1020, 1034, 1033, 1035, 1017, 1037, 1036,
+ 1038, 1036, 1039, 1040, 1041, 1039, 1039, 1039,
+ 1039, 1036, 1021, 1021, 1022, 1023, 1026, 1027,
+ 1026, 1027, 1020, 1043, 1042, 1008, 1044, 1044,
+ 1045, 1046, 1047, 1048, 690, 1044, 1044, 1045,
+ 1046, 1047, 1048, 1049, 1049, 1049, 1050, 1052,
+ 1052, 1053, 1054, 1055, 1056, 1055, 1057, 1051,
+ 1059, 1059, 1060, 1061, 1062, 1063, 1064, 1062,
+ 1065, 1066, 1065, 1067, 1062, 1062, 1062, 1058,
+ 1069, 1070, 1071, 1069, 1069, 1069, 1069, 1068,
+ 1072, 1072, 1073, 1074, 1075, 1075, 1076, 1075,
+ 1077, 1078, 1077, 1078, 1075, 1075, 1075, 1058,
+ 1079, 1079, 1080, 1081, 1065, 1066, 1065, 1066,
+ 85, 1083, 1082, 1084, 1069, 1086, 1085, 1087,
+ 1085, 1088, 1089, 1090, 1088, 1088, 1088, 1088,
+ 1085, 1072, 1072, 1073, 1074, 1077, 1078, 1077,
+ 1078, 1058, 1083, 1092, 1082, 1091, 85, 1093,
+ 1093, 1094, 1095, 1062, 1063, 1064, 1062, 1096,
+ 1097, 1062, 1062, 1062, 1068, 1099, 1098, 690,
+ 1101, 1100, 690, 1103, 1103, 1103, 1103, 1102,
+ 1104, 1104, 1104, 1104, 1102, 1105, 1106, 1105,
+ 1105, 1105, 1102, 1107, 1108, 1107, 1107, 1107,
+ 1102, 1108, 1108, 1109, 1110, 1103, 1111, 1112,
+ 1113, 1113, 1114, 1115, 1103, 1103, 1103, 1102,
+ 1117, 1116, 1102, 1108, 1102, 1119, 1119, 1120,
+ 1121, 1122, 1123, 1124, 1124, 1125, 1126, 1118,
+ 1127, 1127, 1128, 1129, 1130, 1131, 1132, 1133,
+ 1134, 1135, 1136, 1137, 1138, 1139, 1140, 1141,
+ 1142, 1143, 1144, 1130, 1131, 1132, 1133, 1134,
+ 1135, 1136, 1137, 1138, 1139, 1140, 1141, 1142,
+ 1143, 1144, 1145, 1146, 1147, 1147, 1148, 1149,
+ 1118, 1150, 1150, 1151, 1152, 1153, 1154, 1155,
+ 1153, 1154, 1155, 1156, 1157, 1158, 1158, 1159,
+ 1160, 1118, 1161, 1161, 1118, 1162, 1162, 1118,
+ 1163, 1163, 1164, 1165, 1166, 1167, 1168, 1168,
+ 1169, 1170, 1118, 1172, 1171, 1118, 1173, 1174,
+ 1175, 1176, 1173, 1174, 1175, 1176, 1118, 1177,
+ 1177, 1118, 1178, 1178, 1179, 1180, 1181, 1182,
+ 1183, 1183, 1184, 1185, 1118, 1186, 1187, 1186,
+ 1187, 1118, 1188, 1188, 1118, 1189, 1189, 1118,
+ 1190, 1190, 1118, 1191, 1191, 1118, 1192, 1192,
+ 1193, 1194, 1195, 1196, 1197, 1197, 1198, 1199,
+ 1118, 1200, 1200, 1201, 1202, 1203, 1204, 1205,
+ 1205, 1206, 1207, 1118, 1208, 1208, 1118, 1209,
+ 1209, 1118, 1210, 1210, 1211, 1212, 1213, 1214,
+ 1215, 1215, 1216, 1217, 1118, 1218, 1218, 1118,
+ 1219, 1219, 1118, 1220, 1220, 1118, 1221, 1221,
+ 1222, 1223, 1224, 1225, 1226, 1226, 1227, 1228,
+ 1118, 1229, 1230, 1231, 1229, 1230, 1231, 1118,
+ 1232, 1232, 1118, 1233, 1233, 1118, 1234, 1234,
+ 1118, 1235, 1235, 1236, 1237, 1238, 1239, 1240,
+ 1240, 1241, 1242, 1118, 1243, 1244, 1243, 1244,
+ 1118, 1245, 1245, 1118, 1246, 1246, 1118, 1247,
+ 1247, 1248, 1249, 1250, 1251, 1252, 1252, 1253,
+ 1254, 1118, 1255, 1255, 1118, 1256, 1256, 1118,
+ 1257, 1257, 1118, 1258, 1258, 1259, 1260, 1261,
+ 1262, 1263, 1263, 1264, 1265, 1118, 1266, 1266,
+ 1267, 1268, 1269, 1270, 1271, 1271, 1272, 1273,
+ 1118, 1274, 1274, 1118, 1275, 1275, 1118, 1276,
+ 1277, 1118, 1278, 1118, 1279, 1279, 1280, 1281,
+ 1282, 1283, 1284, 1284, 1285, 1286, 1118, 1287,
+ 1118, 1288, 1288, 1289, 1290, 1291, 1292, 1293,
+ 1293, 1294, 1295, 1118, 1296, 1296, 1118, 1297,
+ 1297, 1118, 1298, 1298, 1118, 1299, 1299, 1118,
+ 1300, 1300, 1301, 1302, 1303, 1304, 1305, 1305,
+ 1306, 1307, 1118, 1308, 1308, 1118, 1309, 1309,
+ 1118, 1310, 1310, 1118, 1311, 1311, 1118, 1312,
+ 1312, 1118, 1313, 1313, 1118, 1314, 1314, 1118,
+ 1315, 1315, 1316, 1317, 1318, 1319, 1320, 1320,
+ 1321, 1322, 1118, 1323, 1324, 1323, 1324, 1118,
+ 1325, 1325, 1118, 1326, 1326, 1327, 1328, 1329,
+ 1330, 1331, 1331, 1332, 1333, 1118, 1334, 1334,
+ 1335, 1336, 1337, 1338, 1339, 1339, 1340, 1341,
+ 1118, 1342, 1343, 1344, 1345, 1344, 1345, 1118,
+ 1346, 1118, 1347, 1347, 1348, 1349, 1350, 1351,
+ 1352, 1352, 1353, 1354, 1118, 1355, 1118, 1356,
+ 1356, 1357, 1358, 1359, 1360, 1361, 1361, 1362,
+ 1363, 1118, 1364, 1364, 1118, 1365, 1365, 1366,
+ 1367, 1368, 1369, 1370, 1370, 1371, 1372, 1118,
+ 1373, 1373, 1374, 1375, 1376, 1377, 1378, 1378,
+ 1379, 1380, 1118, 1381, 1382, 1381, 1382, 1118,
+ 1383, 1383, 1118, 1384, 1384, 1118, 1385, 1385,
+ 1118, 1386, 1386, 1387, 1388, 1389, 1390, 1391,
+ 1391, 1392, 1393, 1118, 1394, 1394, 1395, 1396,
+ 1397, 1398, 1399, 1399, 1400, 1401, 1118, 1402,
+ 1403, 1404, 1402, 1403, 1404, 1118, 1405, 1405,
+ 1118, 1406, 1406, 1118, 1407, 1407, 1118, 1408,
+ 1408, 1409, 1410, 1411, 1412, 1413, 1413, 1414,
+ 1415, 1118, 1416, 1416, 1118, 1417, 1417, 1418,
+ 1419, 1420, 1421, 1422, 1422, 1423, 1424, 1118,
+ 1425, 1425, 1426, 1427, 1428, 1428, 1429, 1430,
+ 1431, 1431, 1432, 1433, 1118, 1434, 1434, 1118,
+ 1435, 1435, 1436, 1437, 1438, 1439, 1440, 1441,
+ 1441, 1442, 1443, 1118, 1444, 1444, 1445, 1446,
+ 1447, 1447, 1448, 1449, 1450, 1450, 1451, 1452,
+ 1118, 1453, 1453, 1118, 1454, 1454, 1118, 1455,
+ 1455, 1118, 1456, 1456, 1118, 1457, 1457, 1458,
+ 1459, 1460, 1461, 1462, 1462, 1463, 1464, 1118,
+ 1465, 1465, 1118, 1466, 1466, 1118, 1467, 1467,
+ 1468, 1469, 1470, 1471, 1472, 1472, 1473, 1474,
+ 1118, 1475, 1476, 1477, 1475, 1476, 1477, 1118,
+ 1478, 1478, 1479, 1480, 1481, 1482, 1483, 1483,
+ 1484, 1485, 1118, 1486, 1486, 1118, 1487, 1487,
+ 1118, 1488, 1488, 1118, 1489, 1489, 1490, 1491,
+ 1492, 1493, 1494, 1494, 1495, 1496, 1118, 1497,
+ 1497, 1498, 1499, 1500, 1501, 1502, 1502, 1503,
+ 1504, 1118, 1505, 1506, 1507, 1508, 1505, 1506,
+ 1507, 1508, 1118, 1509, 1509, 1118, 1510, 1510,
+ 1511, 1512, 1513, 1514, 1515, 1515, 1516, 1517,
+ 1118, 1518, 1518, 1118, 1519, 1519, 1520, 1521,
+ 1522, 1523, 1524, 1524, 1525, 1526, 1118, 1527,
+ 1527, 1118, 1528, 1528, 1529, 1530, 1531, 1532,
+ 1533, 1533, 1534, 1535, 1118, 1536, 1536, 1118,
+ 1537, 1537, 1118, 1538, 1538, 1118, 1539, 1539,
+ 1540, 1541, 1542, 1543, 1544, 1544, 1545, 1546,
+ 1118, 1547, 1548, 1549, 1547, 1548, 1549, 1118,
+ 1550, 1550, 1118, 1551, 1551, 1118, 1552, 1552,
+ 1553, 1554, 1555, 1556, 1557, 1557, 1558, 1559,
+ 1118, 1560, 1560, 1118, 1561, 1561, 1562, 1563,
+ 1564, 1565, 1566, 1566, 1567, 1568, 1118, 1569,
+ 1569, 1118, 1570, 1570, 1118, 1571, 1118, 1572,
+ 1572, 1573, 1574, 1576, 1577, 1578, 1578, 1579,
+ 1580, 1575, 1118, 1581, 1581, 1118, 1582, 1582,
+ 1118, 1583, 1583, 1584, 1585, 1586, 1587, 1588,
+ 1588, 1589, 1590, 1118, 1591, 1591, 1118, 1592,
+ 1592, 1118, 1593, 1593, 1118, 1594, 1594, 1595,
+ 1596, 1597, 1598, 1599, 1599, 1600, 1601, 1118,
+ 1602, 1602, 1118, 1603, 1603, 1604, 1605, 1606,
+ 1607, 1608, 1608, 1609, 1610, 1118, 1612, 1612,
+ 1613, 1614, 1615, 1616, 1611, 1612, 1612, 1613,
+ 1614, 1615, 1616, 1618, 1617, 1619, 1619, 1620,
+ 1621, 1623, 1624, 1622, 1617, 1626, 1626, 1627,
+ 1628, 1630, 1631, 1629, 1629, 1629, 1625, 1632,
+ 1632, 1632, 1625, 1633, 1633, 1634, 1635, 1636,
+ 1637, 1638, 1638, 1639, 1640, 1629, 1629, 1629,
+ 1625, 1642, 1641, 1625, 1644, 1643, 1611, 1646,
+ 1645, 1611, 1647, 1647, 1648, 1649, 1650, 1651,
+ 1611, 1647, 1647, 1648, 1649, 1652, 1650, 1651,
+ 1653, 1617, 1654, 1654, 1655, 1656, 1658, 1658,
+ 1659, 1660, 1657, 1617, 1661, 1661, 1662, 1663,
+ 1665, 1666, 1664, 1664, 1664, 1625, 1667, 1667,
+ 1667, 1625, 1668, 1668, 1669, 1670, 1671, 1672,
+ 1673, 1673, 1674, 1675, 1664, 1664, 1664, 1625,
+ 1677, 1676, 1625, 1679, 1678, 1611, 1680, 1680,
+ 1681, 1682, 1683, 1684, 1657, 1617, 1686, 1685,
+ 1611, 1689, 1690, 1691, 1692, 1693, 1689, 1690,
+ 1691, 1692, 1693, 1688, 1687, 1694, 1694, 1694,
+ 1694, 1695, 1687, 1696, 1697, 1696, 1697, 1687,
+ 1698, 1698, 1698, 1698, 1687, 1699, 1699, 1687,
+ 1700, 1701, 1700, 1700, 1700, 1687, 1702, 1702,
+ 1687, 1703, 1703, 1687, 1704, 1704, 1687, 1705,
+ 1705, 1687, 1706, 1687, 1707, 1687, 1708, 1708,
+ 1687, 1709, 1709, 1687, 1710, 1710, 1687, 1711,
+ 1687, 1712, 1712, 1712, 1712, 1687, 1713, 1714,
+ 1713, 1714, 1687, 1715, 1716, 1715, 1716, 1687,
+ 1717, 1687, 1718, 1718, 1687, 1719, 1719, 1687,
+ 1720, 1720, 1687, 1721, 1721, 1687, 1722, 1722,
+ 1722, 1722, 1687, 1723, 1723, 1687, 1724, 1724,
+ 1687, 1725, 1725, 1687, 1726, 1727, 1687, 1728,
+ 1687, 1729, 1687, 1730, 1730, 1687, 1731, 1731,
+ 1687, 1732, 1732, 1687, 1733, 1687, 1734, 1687,
+ 1735, 1687, 1736, 1736, 1736, 1736, 1687, 1737,
+ 1687, 1738, 1687, 1739, 1739, 1687, 1740, 1740,
+ 1687, 1741, 1741, 1687, 1742, 1687, 1743, 1687,
+ 1744, 1687, 1745, 1745, 1745, 1745, 1687, 1746,
+ 1747, 1687, 1748, 1687, 1749, 1687, 1750, 1687,
+ 1751, 1687, 1752, 1752, 1752, 1752, 1687, 1753,
+ 1687, 1754, 1687, 1755, 1755, 1755, 1755, 1687,
+ 1756, 1756, 1687, 1757, 1757, 1687, 1758, 1758,
+ 1687, 1759, 1759, 1687, 1760, 1760, 1687, 1761,
+ 1761, 1687, 1762, 1762, 1687, 1763, 1763, 1763,
+ 1763, 1687, 1764, 1764, 1687, 1765, 1765, 1687,
+ 1766, 1766, 1687, 1767, 1767, 1687, 1768, 1768,
+ 1687, 1769, 1769, 1687, 1770, 1771, 1770, 1771,
+ 1687, 1772, 1772, 1687, 1773, 1773, 1687, 1774,
+ 1774, 1774, 1774, 1687, 1775, 1775, 1687, 1776,
+ 1776, 1687, 1777, 1777, 1777, 1777, 1687, 1778,
+ 1778, 1687, 1779, 1779, 1687, 1780, 1781, 1780,
+ 1781, 1687, 1782, 1782, 1687, 1783, 1687, 1784,
+ 1784, 1784, 1784, 1687, 1785, 1785, 1687, 1786,
+ 1786, 1687, 1787, 1788, 1789, 1687, 1790, 1791,
+ 1790, 1790, 1790, 1687, 1792, 1792, 1687, 1793,
+ 1793, 1687, 1794, 1794, 1687, 1795, 1795, 1687,
+ 1796, 1687, 1797, 1687, 1798, 1798, 1687, 1799,
+ 1799, 1687, 1800, 1800, 1687, 1801, 1687, 1802,
+ 1802, 1802, 1802, 1687, 1803, 1687, 1804, 1687,
+ 1805, 1805, 1805, 1805, 1687, 1806, 1687, 1807,
+ 1687, 1808, 1808, 1808, 1808, 1687, 1811, 1812,
+ 1813, 1814, 1815, 1816, 1811, 1812, 1813, 1814,
+ 1815, 1816, 1810, 1809, 1817, 1817, 1817, 1817,
+ 1818, 1809, 1819, 1819, 1809, 1820, 1820, 1809,
+ 1821, 1821, 1809, 1822, 1822, 1809, 1823, 1823,
+ 1809, 1824, 1824, 1824, 1824, 1809, 1825, 1826,
+ 1827, 1825, 1826, 1827, 1809, 1828, 1828, 1809,
+ 1829, 1829, 1809, 1830, 1830, 1809, 1831, 1831,
+ 1809, 1832, 1832, 1809, 1833, 1833, 1833, 1833,
+ 1809, 1834, 1835, 1834, 1835, 1809, 1836, 1836,
+ 1809, 1837, 1837, 1837, 1837, 1809, 1838, 1838,
+ 1809, 1839, 1839, 1809, 1840, 1840, 1840, 1840,
+ 1809, 1841, 1841, 1809, 1842, 1842, 1809, 1843,
+ 1843, 1809, 1844, 1844, 1844, 1844, 1809, 1845,
+ 1845, 1809, 1846, 1846, 1809, 1847, 1847, 1847,
+ 1847, 1809, 1848, 1849, 1848, 1849, 1809, 1850,
+ 1850, 1809, 1851, 1851, 1851, 1851, 1809, 1852,
+ 1852, 1809, 1853, 1853, 1809, 1854, 1854, 1854,
+ 1854, 1809, 1855, 1855, 1809, 1856, 1856, 1809,
+ 1857, 1857, 1809, 1858, 1858, 1858, 1858, 1809,
+ 1859, 1859, 1809, 1860, 1860, 1809, 1861, 1861,
+ 1861, 1861, 1809, 1863, 1863, 1862, 1864, 1865,
+ 1864, 1864, 1864, 1865, 1862, 1866, 1866, 1866,
+ 1866, 1866, 1866, 71, 1867, 1867, 1867, 1867,
+ 71, 1868, 1868, 1868, 1868, 1868, 1868, 71,
+ 1869, 1869, 1870, 1871, 1872, 1873, 71, 1874,
+ 1874, 1875, 1876, 1877, 1877, 1877, 1878, 1879,
+ 1877, 1877, 1877, 71, 1880, 1880, 1881, 1882,
+ 1883, 1884, 71, 1886, 1886, 1887, 1888, 1890,
+ 1891, 1889, 1885, 1892, 1892, 1893, 1894, 1896,
+ 1897, 1895, 1885, 1898, 1898, 1899, 1900, 1902,
+ 1903, 1901, 1885, 1905, 1905, 1906, 1907, 1909,
+ 1910, 1911, 1912, 1913, 1909, 1910, 1911, 1912,
+ 1913, 1914, 1915, 1908, 1904, 1916, 1916, 1917,
+ 1918, 1920, 1921, 1919, 1885, 1922, 1922, 1923,
+ 1924, 1926, 1927, 1928, 1929, 1930, 1926, 1927,
+ 1928, 1929, 1930, 1931, 1932, 1925, 1904, 1933,
+ 1933, 1934, 1935, 1937, 1938, 1936, 1885, 1939,
+ 1939, 1940, 1941, 1943, 1944, 1945, 1946, 1947,
+ 1943, 1944, 1945, 1946, 1947, 1948, 1949, 1942,
+ 1904, 1950, 1950, 1951, 1952, 1954, 1955, 1953,
+ 1885, 1956, 1956, 1958, 1959, 1960, 1961, 1962,
+ 1958, 1959, 1960, 1961, 1962, 1956, 1956, 1957,
+ 1904, 1956, 1956, 1956, 1956, 1963, 1904, 1965,
+ 1966, 1967, 1968, 1969, 1965, 1966, 1967, 1968,
+ 1969, 1964, 1904, 1970, 1970, 1970, 1970, 1971,
+ 1904, 1973, 1972, 71, 1939, 1939, 1940, 1941,
+ 1948, 1949, 1974, 1904, 1976, 1977, 1978, 1979,
+ 1980, 1976, 1977, 1978, 1979, 1980, 1975, 1904,
+ 1981, 1981, 1982, 1983, 1985, 1986, 1984, 1904,
+ 1988, 1987, 71, 1922, 1922, 1923, 1924, 1931,
+ 1932, 1989, 1904, 1991, 1992, 1993, 1994, 1995,
+ 1991, 1992, 1993, 1994, 1995, 1990, 1904, 1996,
+ 1996, 1997, 1998, 2000, 2001, 1999, 1904, 2003,
+ 2002, 71, 1905, 1905, 1906, 1907, 1914, 1915,
+ 2004, 1904, 2006, 2007, 2008, 2009, 2010, 2006,
+ 2007, 2008, 2009, 2010, 2005, 1904, 2011, 2011,
+ 2012, 2013, 2015, 2016, 2014, 1904, 2018, 2017,
+ 71, 2020, 2019, 71, 2022, 2021, 71, 71,
+ 71, 71, 71, 2023, 2024, 2024, 2025, 2026,
+ 2027, 2028, 71, 2030, 2030, 2031, 2032, 2033,
+ 2034, 2029, 2029, 2029, 71, 2035, 2035, 2035,
+ 2035, 71, 2037, 2036, 71, 2038, 2038, 2038,
+ 2038, 2038, 2038, 71, 2039, 2039, 2040, 2041,
+ 2042, 2043, 71, 2044, 2044, 2045, 2046, 2047,
+ 2047, 2047, 2048, 2049, 2047, 2047, 2047, 71,
+ 2050, 2050, 2050, 2050, 71, 2052, 2051, 71,
+ 2053, 1885, 2054, 2054, 2055, 2056, 2058, 2059,
+ 2057, 1885, 2060, 2060, 2061, 2062, 2063, 2063,
+ 2063, 2064, 2065, 2063, 2063, 2063, 71, 2066,
+ 2066, 2066, 2066, 71, 2068, 2067, 71, 2070,
+ 2070, 2070, 2070, 2069, 2071, 2071, 2072, 2073,
+ 2074, 2075, 2076, 2076, 2077, 2078, 2070, 2080,
+ 2080, 2081, 2082, 2083, 2084, 2085, 2085, 2086,
+ 2087, 2079, 2079, 2079, 2070, 2089, 2088, 2070,
+ 2090, 2090, 2090, 2090, 1862, 2091, 2092, 2091,
+ 2091, 2091, 2092, 2092, 2092, 1862, 2094, 2093,
+ 2095, 2095, 2096, 2097, 2099, 2100, 2098, 2093,
+ 2101, 2101, 2102, 2103, 2105, 2106, 2107, 2108,
+ 2104, 2093, 2109, 2109, 2110, 2111, 2113, 2114,
+ 2112, 2093, 2115, 2115, 2116, 2117, 2105, 2106,
+ 2119, 2120, 2118, 2093, 2121, 2121, 2122, 2123,
+ 2124, 2126, 2127, 2125, 2093, 2128, 2128, 2129,
+ 2130, 2105, 2106, 2131, 2132, 2093, 2133, 2133,
+ 2134, 2135, 2136, 2137, 2093, 2133, 2133, 2134,
+ 2135, 2136, 2137, 2138, 2093, 2139, 2139, 2140,
+ 2141, 2143, 2144, 2142, 2093, 2145, 2145, 2146,
+ 2147, 2149, 2150, 2151, 2152, 2148, 2093, 2153,
+ 2153, 2154, 2155, 2157, 2158, 2156, 2093, 2159,
+ 2159, 2160, 2161, 2149, 2150, 2163, 2164, 2162,
+ 2093, 2165, 2165, 2166, 2167, 2168, 2170, 2171,
+ 2169, 2093, 2172, 2172, 2173, 2174, 2149, 2150,
+ 2175, 2176, 2093, 2177, 2177, 2178, 2179, 2180,
+ 2181, 2093, 2177, 2177, 2178, 2179, 2182, 2180,
+ 2181, 2183, 2093, 2184, 2093, 2185, 2185, 2186,
+ 2187, 2188, 2190, 2191, 2192, 2193, 2193, 2194,
+ 2195, 2189, 2093, 2196, 2196, 2197, 2198, 2200,
+ 2201, 2202, 2202, 2203, 2204, 2199, 2093, 2205,
+ 2205, 2206, 2207, 2208, 2210, 2211, 2212, 2213,
+ 2213, 2214, 2215, 2209, 2093, 2216, 2216, 2217,
+ 2218, 2220, 2221, 2202, 2202, 2222, 2223, 2219,
+ 2093, 2224, 2224, 2225, 2226, 2227, 2229, 2230,
+ 2231, 2232, 2232, 2233, 2234, 2228, 2093, 2235,
+ 2235, 2236, 2237, 2239, 2240, 2202, 2202, 2241,
+ 2242, 2238, 2093, 2243, 2243, 2244, 2245, 2246,
+ 2243, 2248, 2249, 2250, 2250, 2251, 2252, 2247,
+ 2093, 2253, 2253, 2254, 2255, 2256, 2257, 2202,
+ 2202, 2258, 2259, 2093, 2261, 2260, 2093, 2262,
+ 2262, 2263, 2264, 2262, 2266, 2267, 2268, 2268,
+ 2269, 2270, 2265, 2093, 2243, 2243, 2244, 2245,
+ 2243, 2248, 2249, 2250, 2250, 2251, 2252, 2271,
+ 2093, 2273, 2272, 2093, 2274, 2274, 2275, 2276,
+ 2278, 2279, 2280, 2281, 2281, 2282, 2283, 2277,
+ 2093, 2224, 2224, 2225, 2226, 2229, 2230, 2231,
+ 2232, 2232, 2233, 2234, 2284, 2093, 2235, 2235,
+ 2236, 2237, 2239, 2240, 2202, 2202, 2241, 2242,
+ 2093, 2286, 2285, 2093, 2287, 2287, 2288, 2289,
+ 2291, 2292, 2293, 2294, 2294, 2295, 2296, 2290,
+ 2093, 2205, 2205, 2206, 2207, 2210, 2211, 2212,
+ 2213, 2213, 2214, 2215, 2297, 2093, 2216, 2216,
+ 2217, 2218, 2220, 2221, 2202, 2202, 2222, 2223,
+ 2093, 2299, 2298, 2093, 2300, 2300, 2301, 2302,
+ 2304, 2305, 2306, 2307, 2307, 2308, 2309, 2303,
+ 2093, 2185, 2185, 2186, 2187, 2190, 2191, 2192,
+ 2193, 2193, 2194, 2195, 2310, 2093, 2196, 2196,
+ 2197, 2198, 2200, 2201, 2202, 2202, 2203, 2204,
+ 2093, 2312, 2311, 2093, 2313, 2313, 2314, 2315,
+ 2316, 2317, 2093, 2319, 2318, 2093, 2320, 2320,
+ 2321, 2322, 2324, 2325, 2323, 2093, 2165, 2165,
+ 2166, 2167, 2170, 2171, 2326, 2093, 2328, 2327,
+ 2093, 2330, 2329, 2093, 2332, 2331, 2093, 2333,
+ 2333, 2334, 2335, 2336, 2337, 2093, 2339, 2338,
+ 2093, 2340, 2340, 2341, 2342, 2344, 2345, 2343,
+ 2093, 2121, 2121, 2122, 2123, 2126, 2127, 2346,
+ 2093, 2348, 2347, 2093, 2350, 2349, 2093, 2351,
+ 1885, 2352, 2352, 2353, 2354, 2356, 2357, 2355,
+ 1885, 2358, 2358, 2359, 2360, 2362, 2363, 2361,
+ 1885, 2364, 2364, 2365, 2366, 2368, 2369, 2367,
+ 1885, 2370, 2370, 2371, 2372, 2374, 2375, 2373,
+ 1885, 2376, 2376, 2377, 2378, 2380, 2381, 2379,
+ 1885, 2382, 2382, 2383, 2384, 2385, 2385, 2385,
+ 2386, 2387, 2385, 2385, 2385, 71, 2388, 2388,
+ 2388, 2388, 71, 2390, 2389, 71, 2392, 2391,
+ 71, 2394, 2393, 71, 2395, 1885, 2396, 2396,
+ 2397, 2398, 2400, 2401, 2399, 1885, 2402, 2402,
+ 2403, 2404, 2406, 2407, 2405, 1885, 2408, 2408,
+ 2409, 2410, 2412, 2413, 2411, 1885, 2415, 2415,
+ 2416, 2417, 2418, 2419, 2414, 2414, 2414, 71,
+ 2420, 2420, 2421, 2422, 2423, 2424, 71, 2426,
+ 2426, 2427, 2428, 2429, 2430, 2425, 2425, 2425,
+ 71, 2431, 2431, 2432, 2433, 2434, 2435, 71,
+ 2437, 2437, 2438, 2439, 2440, 2441, 2436, 2436,
+ 2436, 71, 2442, 2442, 2443, 2444, 2445, 2446,
+ 71, 2447, 2447, 2448, 2449, 2450, 2450, 2450,
+ 2451, 2452, 2450, 2450, 2450, 71, 2453, 2453,
+ 2453, 2453, 71, 2455, 2454, 71, 2457, 2456,
+ 71, 2459, 2458, 71, 2461, 2460, 71, 2463,
+ 2462, 71, 2464, 2464, 2464, 71, 2465, 2465,
+ 2466, 2467, 2468, 2469, 71, 2465, 2465, 2466,
+ 2467, 2468, 2469, 2470, 1885, 2471, 2471, 2472,
+ 2473, 2475, 2476, 2474, 1885, 2477, 2477, 2478,
+ 2479, 2481, 2482, 2480, 2480, 2480, 71, 2483,
+ 2483, 2484, 2485, 2486, 2487, 71, 2483, 2483,
+ 2484, 2485, 2488, 2486, 2487, 2488, 2488, 2488,
+ 71, 2489, 2489, 71, 2491, 2490, 71, 2493,
+ 2492, 71, 2495, 2494, 71, 2497, 2497, 2498,
+ 2499, 2500, 2501, 2502, 2503, 2504, 2505, 2505,
+ 2506, 2507, 2496, 2508, 2509, 2496, 2510, 2496,
+ 2512, 2512, 2511, 2514, 2513, 2511, 2515, 2496,
+ 2516, 2516, 2517, 2518, 2520, 2521, 2522, 2522,
+ 2523, 2524, 2519, 2496, 2526, 2525, 71, 2527,
+ 2496, 2528, 2528, 2528, 2528, 2511, 2530, 2529,
+ 2529, 2529, 2511, 2531, 1885, 2532, 2532, 2533,
+ 2534, 2536, 2537, 2535, 1885, 2538, 2538, 2539,
+ 2540, 2542, 2543, 2541, 2541, 2541, 71, 2544,
+ 2544, 2545, 2546, 2547, 2548, 71, 2544, 2544,
+ 2545, 2546, 2547, 2548, 2549, 1885, 2550, 2550,
+ 2551, 2552, 2554, 2555, 2553, 1885, 2557, 2557,
+ 2558, 2559, 2561, 2562, 2560, 2560, 2560, 2556,
+ 2563, 2563, 2563, 2556, 2564, 2564, 2565, 2566,
+ 2567, 2568, 2569, 2569, 2570, 2571, 2560, 2560,
+ 2560, 2556, 2573, 2572, 2556, 2575, 2574, 71,
+ 2577, 2576, 71, 2579, 2578, 71, 2580, 1885,
+ 2581, 2581, 2582, 2583, 2585, 2586, 2584, 1885,
+ 2587, 2587, 2588, 2589, 2591, 2592, 2590, 1885,
+ 2593, 2593, 2594, 2595, 2597, 2598, 2596, 1885,
+ 2599, 2599, 2600, 2601, 2603, 2604, 2602, 2602,
+ 2602, 2556, 2605, 2605, 2605, 2556, 2606, 2606,
+ 2607, 2608, 2609, 2610, 2611, 2611, 2612, 2613,
+ 2602, 2602, 2602, 2556, 2615, 2614, 2556, 2617,
+ 2616, 71, 2619, 2618, 71, 2620, 1885, 2621,
+ 2621, 2622, 2623, 2625, 2626, 2624, 1885, 2628,
+ 2628, 2629, 2630, 2631, 2632, 2633, 2634, 2635,
+ 2636, 2627, 2637, 2637, 2638, 2639, 2640, 2641,
+ 2627, 2637, 2637, 2638, 2639, 2640, 2641, 2643,
+ 2642, 2644, 2644, 2645, 2646, 2648, 2649, 2647,
+ 2642, 2650, 2650, 2651, 2652, 2653, 2654, 2655,
+ 2627, 2657, 2657, 2658, 2659, 2660, 2660, 2661,
+ 2662, 2663, 2663, 2664, 2665, 2666, 2666, 2666,
+ 2666, 2667, 2668, 2666, 2666, 2669, 2670, 2671,
+ 2672, 2666, 2666, 2673, 2674, 2675, 2676, 2666,
+ 2666, 2677, 2678, 2656, 2657, 2657, 2658, 2659,
+ 2680, 2667, 2668, 2680, 2680, 2680, 2679, 2666,
+ 2666, 2679, 2682, 2681, 2679, 2660, 2660, 2661,
+ 2662, 2666, 2666, 2666, 2666, 2671, 2672, 2666,
+ 2666, 2673, 2674, 2679, 2684, 2683, 2679, 2680,
+ 2657, 2657, 2658, 2659, 2660, 2660, 2661, 2662,
+ 2663, 2663, 2664, 2665, 2666, 2666, 2666, 2666,
+ 2667, 2668, 2666, 2666, 2669, 2670, 2671, 2672,
+ 2666, 2666, 2673, 2674, 2675, 2676, 2666, 2666,
+ 2677, 2678, 2680, 2680, 2680, 2679, 2682, 2684,
+ 2686, 2681, 2683, 2685, 2679, 2688, 2687, 2627,
+ 2690, 2689, 2627, 2691, 2691, 2692, 2693, 2694,
+ 2695, 2627, 2691, 2691, 2692, 2693, 2694, 2695,
+ 2696, 2642, 2697, 2697, 2698, 2699, 2701, 2702,
+ 2700, 2642, 2704, 2704, 2705, 2706, 2707, 2708,
+ 2709, 2707, 2703, 2711, 2712, 2712, 2713, 2714,
+ 2715, 2715, 2716, 2717, 2718, 2718, 2719, 2720,
+ 2721, 2721, 2721, 2721, 2722, 2723, 2721, 2721,
+ 2724, 2725, 2726, 2727, 2721, 2721, 2728, 2729,
+ 2730, 2731, 2721, 2721, 2732, 2733, 2711, 2710,
+ 2735, 2734, 2627, 2737, 2736, 2627, 2738, 2738,
+ 2739, 2740, 2741, 2742, 2627, 2738, 2738, 2739,
+ 2740, 2741, 2742, 2743, 2642, 2744, 2744, 2745,
+ 2746, 2748, 2749, 2747, 2642, 2750, 2750, 2751,
+ 2752, 2753, 2754, 2755, 2753, 2753, 2753, 2703,
+ 2756, 2757, 2757, 2758, 2759, 2760, 2760, 2761,
+ 2762, 2763, 2763, 2764, 2765, 2766, 2766, 2766,
+ 2766, 2767, 2768, 2766, 2766, 2769, 2770, 2771,
+ 2772, 2766, 2766, 2773, 2774, 2775, 2776, 2766,
+ 2766, 2777, 2778, 2756, 2756, 2756, 2710, 2780,
+ 2779, 2627, 2782, 2781, 2627, 2783, 2783, 2784,
+ 2785, 2786, 2787, 2627, 2783, 2783, 2784, 2785,
+ 2786, 2787, 2788, 2642, 2789, 2789, 2790, 2791,
+ 2793, 2794, 2792, 2642, 2795, 2795, 2796, 2797,
+ 2798, 2798, 2798, 2799, 2800, 2798, 2798, 2798,
+ 2627, 2801, 2801, 2802, 2803, 2804, 2804, 2805,
+ 2806, 2807, 2807, 2808, 2809, 2810, 2810, 2810,
+ 2810, 2811, 2812, 2810, 2810, 2813, 2814, 2815,
+ 2816, 2810, 2810, 2817, 2818, 2819, 2820, 2810,
+ 2810, 2821, 2822, 2656, 2824, 2823, 2627, 2826,
+ 2825, 2627, 2828, 2827, 71, 2830, 2831, 2832,
+ 2833, 2834, 2835, 2836, 2837, 2838, 2839, 2840,
+ 2841, 2842, 2843, 2844, 2830, 2831, 2832, 2833,
+ 2834, 2835, 2836, 2837, 2838, 2839, 2840, 2841,
+ 2842, 2843, 2844, 2829, 2845, 2845, 2846, 2847,
+ 2848, 2849, 2850, 2848, 2849, 2850, 2851, 2852,
+ 2829, 2853, 2853, 2854, 2855, 2857, 2858, 2856,
+ 2856, 2856, 71, 2859, 2859, 2860, 2861, 2862,
+ 2863, 71, 2859, 2859, 2860, 2861, 2862, 2863,
+ 2864, 1885, 2865, 2865, 2866, 2867, 2869, 2870,
+ 2868, 1885, 2871, 2871, 2872, 2873, 2875, 2876,
+ 2874, 1885, 2877, 2877, 2878, 2879, 2881, 2882,
+ 2880, 1885, 2884, 2884, 2885, 2886, 2888, 2889,
+ 2887, 2883, 2890, 2890, 2891, 2892, 2894, 2895,
+ 2893, 2883, 2896, 2896, 2897, 2898, 2900, 2901,
+ 2899, 2883, 2902, 2902, 2903, 2904, 2906, 2907,
+ 2905, 2883, 2908, 2908, 2909, 2910, 2912, 2913,
+ 2911, 1885, 2914, 2914, 2915, 2916, 2918, 2919,
+ 2917, 1885, 2920, 2920, 2921, 2922, 2923, 2923,
+ 2923, 2924, 2925, 2923, 2923, 2923, 71, 2926,
+ 2926, 2927, 2928, 2929, 2930, 71, 2931, 2931,
+ 2932, 2933, 2934, 2935, 2936, 2934, 2934, 2934,
+ 71, 2937, 2937, 71, 2939, 2938, 71, 2941,
+ 2940, 71, 2943, 2942, 71, 2945, 2944, 71,
+ 2947, 2946, 71, 2949, 2948, 71, 2951, 2950,
+ 71, 2953, 2952, 71, 2954, 2954, 2829, 2955,
+ 2955, 2829, 2956, 2956, 2957, 2958, 2959, 2960,
+ 2829, 2961, 2961, 2829, 2962, 2962, 2829, 2963,
+ 2963, 2829, 2964, 2964, 2965, 2966, 2967, 2968,
+ 2829, 2969, 2969, 2829, 2970, 2970, 2971, 2972,
+ 2973, 2974, 2829, 2975, 2976, 2977, 2978, 2975,
+ 2976, 2977, 2978, 2829, 2979, 2979, 2829, 2980,
+ 2980, 2981, 2982, 2983, 2984, 2829, 2985, 2986,
+ 2985, 2986, 2829, 2987, 2987, 2829, 2988, 2988,
+ 2829, 2989, 2989, 2829, 2990, 2990, 2829, 2991,
+ 2991, 2992, 2993, 2994, 2995, 2829, 2996, 2996,
+ 2997, 2998, 2999, 3000, 2829, 3001, 3001, 2829,
+ 3002, 3002, 2829, 3003, 3003, 3004, 3005, 3006,
+ 3007, 2829, 3008, 3008, 2829, 3009, 3009, 2829,
+ 3010, 3010, 2829, 3011, 3011, 3012, 3013, 3014,
+ 3015, 2829, 3016, 3017, 3018, 3016, 3017, 3018,
+ 2829, 3019, 3019, 2829, 3020, 3020, 2829, 3021,
+ 3021, 2829, 3022, 3022, 3023, 3024, 3025, 3026,
+ 2829, 3027, 3028, 3027, 3028, 2829, 3029, 3029,
+ 2829, 3030, 3030, 2829, 3031, 3031, 3032, 3033,
+ 3034, 3035, 2829, 3036, 3036, 2829, 3037, 3037,
+ 2829, 3038, 3038, 2829, 3039, 3039, 3040, 3041,
+ 3042, 3043, 2829, 3044, 3044, 3045, 3046, 3047,
+ 3048, 2829, 3049, 3049, 2829, 3050, 3050, 2829,
+ 3051, 3052, 2829, 3053, 2829, 3054, 3054, 3055,
+ 3056, 3057, 3058, 2829, 3059, 2829, 3060, 3060,
+ 3061, 3062, 3063, 3064, 2829, 3065, 3065, 2829,
+ 3066, 3066, 2829, 3067, 3067, 2829, 3068, 3068,
+ 2829, 3069, 3069, 3070, 3071, 3072, 3073, 2829,
+ 3074, 3074, 2829, 3075, 3075, 2829, 3076, 3076,
+ 2829, 3077, 3077, 2829, 3078, 3078, 2829, 3079,
+ 3079, 2829, 3080, 3080, 2829, 3081, 3081, 3082,
+ 3083, 3084, 3085, 2829, 3086, 3087, 3086, 3087,
+ 2829, 3088, 3088, 2829, 3089, 3089, 3090, 3091,
+ 3092, 3093, 2829, 3094, 3094, 3095, 3096, 3097,
+ 3098, 2829, 3099, 3100, 3101, 3102, 3101, 3102,
+ 2829, 3103, 2829, 3104, 3104, 3105, 3106, 3107,
+ 3108, 2829, 3109, 2829, 3110, 3110, 3111, 3112,
+ 3113, 3114, 2829, 3115, 3115, 2829, 3116, 3116,
+ 3117, 3118, 3119, 3120, 2829, 3121, 3121, 3122,
+ 3123, 3124, 3125, 2829, 3126, 3127, 3126, 3127,
+ 2829, 3128, 3128, 2829, 3129, 3129, 2829, 3130,
+ 3130, 2829, 3131, 3131, 3132, 3133, 3134, 3135,
+ 2829, 3136, 3136, 3137, 3138, 3139, 3140, 2829,
+ 3141, 3142, 3143, 3141, 3142, 3143, 2829, 3144,
+ 3144, 2829, 3145, 3145, 2829, 3146, 3146, 2829,
+ 3147, 3147, 3148, 3149, 3150, 3151, 2829, 3152,
+ 3152, 2829, 3153, 3153, 3154, 3155, 3156, 3157,
+ 2829, 3158, 3158, 3159, 3160, 3161, 3161, 3162,
+ 3163, 2829, 3164, 3164, 2829, 3165, 3165, 3166,
+ 3167, 3168, 3169, 3170, 2829, 3171, 3171, 3172,
+ 3173, 3174, 3174, 3175, 3176, 2829, 3177, 3177,
+ 2829, 3178, 3178, 2829, 3179, 3179, 2829, 3180,
+ 3180, 2829, 3181, 3181, 3182, 3183, 3184, 3185,
+ 2829, 3186, 3186, 2829, 3187, 3187, 2829, 3188,
+ 3188, 3189, 3190, 3191, 3192, 2829, 3193, 3194,
+ 3195, 3193, 3194, 3195, 2829, 3196, 3196, 3197,
+ 3198, 3199, 3200, 2829, 3201, 3201, 2829, 3202,
+ 3202, 2829, 3203, 3203, 2829, 3204, 3204, 3205,
+ 3206, 3207, 3208, 2829, 3209, 3209, 3210, 3211,
+ 3212, 3213, 2829, 3214, 3215, 3216, 3217, 3214,
+ 3215, 3216, 3217, 2829, 3218, 3218, 2829, 3219,
+ 3219, 3220, 3221, 3222, 3223, 2829, 3224, 3224,
+ 2829, 3225, 3225, 3226, 3227, 3228, 3229, 2829,
+ 3230, 3230, 2829, 3231, 3231, 3232, 3233, 3234,
+ 3235, 2829, 3236, 3236, 2829, 3237, 3237, 2829,
+ 3238, 3238, 2829, 3239, 3239, 3240, 3241, 3242,
+ 3243, 2829, 3244, 3245, 3246, 3244, 3245, 3246,
+ 2829, 3247, 3247, 2829, 3248, 3248, 2829, 3249,
+ 3249, 3250, 3251, 3252, 3253, 2829, 3254, 3254,
+ 2829, 3255, 3255, 3256, 3257, 3258, 3259, 2829,
+ 3260, 3260, 2829, 3261, 3261, 2829, 3263, 3262,
+ 3264, 3264, 3265, 3266, 3268, 3269, 3267, 3262,
+ 3270, 3270, 2829, 3271, 3271, 2829, 3272, 3272,
+ 3273, 3274, 3275, 3276, 2829, 3277, 3277, 3277,
+ 3277, 3277, 3277, 71, 3278, 3278, 3278, 3278,
+ 71, 3279, 3279, 3279, 3279, 71, 3280, 1885,
+ 3281, 3281, 3282, 3283, 3285, 3286, 3284, 1885,
+ 3287, 3287, 3288, 3289, 3291, 3292, 3290, 1885,
+ 3293, 3293, 3294, 3295, 3297, 3298, 3296, 1885,
+ 3299, 3299, 3300, 3301, 3303, 3304, 3302, 3302,
+ 3302, 71, 3305, 3305, 3306, 3307, 3308, 3309,
+ 71, 3305, 3305, 3306, 3307, 3310, 3308, 3309,
+ 3310, 3310, 3310, 71, 3311, 3311, 71, 3313,
+ 3312, 71, 3315, 3314, 71, 3317, 3316, 71,
+ 3318, 3318, 3318, 3318, 71, 3319, 3319, 71,
+ 3320, 1885, 3321, 3321, 3322, 3323, 3325, 3326,
+ 3324, 1885, 3327, 3327, 3328, 3329, 3331, 3332,
+ 3330, 1885, 3333, 3333, 3334, 3335, 3337, 3338,
+ 3336, 1885, 3339, 3339, 3340, 3341, 3343, 3344,
+ 3342, 1885, 3345, 3345, 3346, 3347, 3349, 3350,
+ 3348, 1885, 3351, 3351, 3352, 3353, 3354, 3356,
+ 3357, 3355, 3355, 3355, 2556, 3358, 3358, 3359,
+ 3360, 3361, 3362, 2556, 3364, 3364, 3365, 3366,
+ 3368, 3369, 3367, 3367, 3367, 3363, 3370, 3370,
+ 3370, 3363, 3372, 3371, 3371, 3371, 3363, 3373,
+ 3373, 3373, 3363, 3375, 3374, 3374, 3374, 3363,
+ 3377, 3376, 3376, 3376, 3363, 3378, 3378, 3378,
+ 3363, 3380, 3379, 3379, 3379, 3363, 3381, 3381,
+ 3381, 3381, 3382, 3382, 3382, 3363, 3383, 3383,
+ 3383, 3383, 71, 3384, 3363, 3380, 3363, 3377,
+ 3363, 3385, 3363, 3375, 3363, 3387, 3386, 71,
+ 3388, 3388, 3388, 2556, 3358, 3358, 3359, 3360,
+ 3361, 3362, 3389, 3389, 3389, 2556, 3391, 3390,
+ 71, 3393, 3392, 71, 3395, 3394, 71, 3396,
+ 1885, 3397, 3397, 3398, 3399, 3401, 3402, 3400,
+ 1885, 3403, 3403, 3404, 3405, 3407, 3408, 3406,
+ 1885, 3409, 3409, 3410, 3411, 3413, 3414, 3412,
+ 1885, 3415, 3415, 3416, 3417, 3419, 3420, 3418,
+ 1885, 3421, 3421, 3422, 3423, 3425, 3426, 3424,
+ 1885, 3427, 3427, 3428, 3429, 3430, 3432, 3433,
+ 3431, 3431, 3431, 2556, 3434, 3434, 3434, 3434,
+ 2556, 3435, 3435, 3435, 2556, 3434, 3434, 3434,
+ 3434, 3436, 3436, 3436, 2556, 3438, 3437, 71,
+ 3440, 3439, 71, 3442, 3441, 71, 3443, 1885,
+ 3444, 3444, 3445, 3446, 3448, 3449, 3447, 1885,
+ 3450, 3450, 3451, 3452, 3454, 3455, 3453, 1885,
+ 3456, 3456, 3457, 3458, 3460, 3461, 3459, 1885,
+ 3462, 3462, 3463, 3464, 3466, 3467, 3465, 1885,
+ 3468, 3468, 3469, 3470, 3472, 3473, 3471, 1885,
+ 3474, 3474, 3475, 3476, 3478, 3479, 3477, 3477,
+ 3477, 2556, 3480, 3480, 3480, 2556, 3481, 3481,
+ 3482, 3483, 3484, 3485, 3486, 3486, 3487, 3488,
+ 3477, 3477, 3477, 2556, 3490, 3489, 2556, 3492,
+ 3491, 71, 3494, 3493, 71, 3496, 3495, 71,
+ 3497, 1885, 3498, 3498, 3499, 3500, 3502, 3503,
+ 3501, 1885, 3504, 3504, 3505, 3506, 3507, 3508,
+ 3509, 3507, 1862, 3510, 3511, 3510, 3510, 3510,
+ 3511, 1862, 3513, 3512, 71, 3514, 1885, 3515,
+ 3515, 3516, 3517, 3519, 3520, 3518, 1885, 3521,
+ 3521, 3522, 3523, 3525, 3526, 3524, 3524, 3524,
+ 2556, 3527, 3527, 3527, 2556, 3528, 3528, 3528,
+ 2556, 3529, 3529, 3529, 2556, 3531, 3530, 3532,
+ 3532, 3532, 2556, 3533, 3533, 3533, 2556, 3534,
+ 3534, 3534, 2556, 3535, 3535, 3535, 2556, 3537,
+ 3531, 3537, 3537, 3537, 3536, 3539, 3538, 71,
+ 3540, 3540, 3540, 2556, 3541, 3541, 3541, 2556,
+ 3543, 3542, 3544, 3544, 3544, 2556, 3545, 3545,
+ 3545, 2556, 3546, 3543, 3546, 3546, 3546, 3542,
+ 3547, 3547, 3547, 2556, 3548, 3548, 3548, 2556,
+ 3549, 3542, 3550, 3550, 3550, 2556, 3551, 3551,
+ 3551, 2556, 3552, 3549, 3552, 3552, 3552, 3542,
+ 3553, 1885, 3554, 3554, 3555, 3556, 3558, 3559,
+ 3557, 1885, 3560, 3560, 3561, 3562, 3564, 3565,
+ 3563, 1885, 3566, 3566, 3567, 3568, 3570, 3571,
+ 3569, 1885, 3573, 3573, 3574, 3575, 3576, 3577,
+ 3572, 3572, 3572, 71, 3578, 3578, 3578, 3578,
+ 71, 3580, 3579, 71, 3582, 3581, 71, 3583,
+ 1885, 3584, 3584, 3585, 3586, 3588, 3589, 3587,
+ 1885, 3591, 3591, 3592, 3593, 3594, 3595, 3590,
+ 3590, 3590, 71, 3596, 3596, 3597, 3598, 3599,
+ 3600, 71, 3602, 3602, 3603, 3604, 3605, 3606,
+ 3601, 3601, 3601, 71, 3607, 3607, 3607, 3607,
+ 71, 3609, 3608, 71, 3611, 3610, 71, 3613,
+ 3613, 3614, 3615, 3616, 3617, 3617, 3617, 3618,
+ 3619, 3620, 3621, 3617, 3617, 3617, 3612, 3622,
+ 3622, 3623, 3624, 3625, 3626, 69, 3627, 3626,
+ 3618, 3619, 3628, 3629, 3630, 3631, 3632, 3633,
+ 69, 69, 3626, 69, 3626, 69, 3626, 69,
+ 783, 3635, 3635, 3614, 3636, 3637, 3617, 3638,
+ 3639, 3640, 3641, 3642, 3643, 3644, 3645, 3646,
+ 3647, 3648, 3649, 3650, 3651, 3652, 3617, 3617,
+ 3638, 3639, 3640, 3641, 3642, 3643, 3644, 3645,
+ 3646, 3647, 3648, 3649, 3650, 3651, 3652, 3618,
+ 3619, 3653, 3654, 3617, 3617, 3617, 3634, 3635,
+ 3635, 3614, 3636, 3637, 3617, 3657, 3658, 3659,
+ 3660, 3661, 3662, 3663, 3664, 3665, 3666, 3667,
+ 3668, 3669, 3670, 3671, 3617, 3617, 3657, 3658,
+ 3659, 3660, 3661, 3662, 3663, 3664, 3665, 3666,
+ 3667, 3668, 3669, 3670, 3671, 3618, 3619, 3653,
+ 3654, 3617, 3656, 3617, 3617, 3655, 3673, 3673,
+ 3674, 3675, 3676, 3677, 3677, 3677, 3678, 3679,
+ 3680, 3681, 3677, 3677, 3677, 3672, 3613, 3613,
+ 3614, 3682, 3683, 3617, 3657, 3658, 3659, 3660,
+ 3661, 3662, 3663, 3664, 3665, 3666, 3667, 3668,
+ 3669, 3670, 3671, 3617, 3617, 3657, 3658, 3659,
+ 3660, 3661, 3662, 3663, 3664, 3665, 3666, 3667,
+ 3668, 3669, 3670, 3671, 3618, 3619, 3684, 3685,
+ 3617, 3656, 3617, 3617, 3655, 3686, 3686, 3614,
+ 3687, 3688, 3617, 3617, 3617, 83, 84, 3689,
+ 3690, 3617, 3617, 3617, 783, 3691, 3691, 3623,
+ 3692, 3693, 3626, 69, 3627, 3626, 83, 84,
+ 3689, 3694, 101, 102, 3689, 3695, 69, 69,
+ 3626, 69, 3626, 69, 3626, 69, 783, 3622,
+ 3622, 3623, 3624, 3625, 3626, 69, 3698, 3699,
+ 3700, 3701, 3702, 3703, 3704, 3705, 3706, 3707,
+ 3708, 3709, 3710, 3711, 3712, 3627, 3626, 3698,
+ 3699, 3700, 3701, 3702, 3703, 3704, 3705, 3706,
+ 3707, 3708, 3709, 3710, 3711, 3712, 3618, 3619,
+ 3628, 3629, 3630, 3631, 3632, 3633, 69, 69,
+ 3626, 3697, 69, 3626, 69, 3626, 69, 3696,
+ 3691, 3691, 3623, 3692, 3693, 3626, 69, 3698,
+ 3699, 3700, 3701, 3702, 3703, 3704, 3705, 3706,
+ 3707, 3708, 3709, 3710, 3711, 3712, 3627, 3626,
+ 3698, 3699, 3700, 3701, 3702, 3703, 3704, 3705,
+ 3706, 3707, 3708, 3709, 3710, 3711, 3712, 83,
+ 84, 3713, 3694, 101, 102, 3713, 3695, 69,
+ 69, 3626, 3697, 69, 3626, 69, 3626, 69,
+ 3696, 690, 690, 690, 944, 941, 944, 943,
+ 944, 941, 945, 941, 940, 690, 690, 690,
+ 1093, 1093, 1094, 1095, 1062, 1063, 1064, 1062,
+ 1096, 1097, 1062, 1062, 1062, 1068, 690, 1108,
+ 1108, 1109, 1110, 1103, 1111, 1112, 1113, 1113,
+ 1114, 1115, 1103, 1103, 1103, 1102, 1117, 1116,
+ 1102, 690, 1127, 1127, 1128, 1129, 1130, 1131,
+ 1132, 1133, 1134, 1135, 1136, 1137, 1138, 1139,
+ 1140, 1141, 1142, 1143, 1144, 1130, 1131, 1132,
+ 1133, 1134, 1135, 1136, 1137, 1138, 1139, 1140,
+ 1141, 1142, 1143, 1144, 1145, 1146, 1147, 1147,
+ 1148, 1149, 1118, 1172, 1171, 1118, 690, 1633,
+ 1633, 1634, 1635, 1636, 1637, 1638, 1638, 1639,
+ 1640, 1629, 1629, 1629, 1625, 1642, 1641, 1625,
+ 1661, 1661, 1662, 1663, 1665, 1666, 1664, 1664,
+ 1664, 1625, 1611, 1668, 1668, 1669, 1670, 1671,
+ 1672, 1673, 1673, 1674, 1675, 1664, 1664, 1664,
+ 1625, 1677, 1676, 1625, 1679, 1678, 1611, 690,
+ 690, 690, 690, 690, 690, 690, 690, 690,
+ 2080, 2080, 2081, 2082, 2083, 2084, 2085, 2085,
+ 2086, 2087, 2079, 2079, 2079, 2070, 2089, 2088,
+ 2070, 690, 690, 2253, 2253, 2254, 2255, 2256,
+ 2257, 2202, 2202, 2258, 2259, 2093, 2261, 2260,
+ 2093, 2235, 2235, 2236, 2237, 2239, 2240, 2202,
+ 2202, 2241, 2242, 2238, 2093, 2273, 2272, 2093,
+ 2216, 2216, 2217, 2218, 2220, 2221, 2202, 2202,
+ 2222, 2223, 2219, 2093, 2286, 2285, 2093, 2196,
+ 2196, 2197, 2198, 2200, 2201, 2202, 2202, 2203,
+ 2204, 2199, 2093, 2299, 2298, 2093, 690, 690,
+ 690, 690, 2497, 2497, 2498, 2499, 2500, 2501,
+ 2502, 2503, 2504, 2505, 2505, 2506, 2507, 2496,
+ 2526, 2525, 71, 690, 2564, 2564, 2565, 2566,
+ 2567, 2568, 2569, 2569, 2570, 2571, 2560, 2560,
+ 2560, 2556, 2573, 2572, 2556, 690, 2606, 2606,
+ 2607, 2608, 2609, 2610, 2611, 2611, 2612, 2613,
+ 2602, 2602, 2602, 2556, 2615, 2614, 2556, 690,
+ 2660, 2660, 2661, 2662, 2666, 2666, 2666, 2666,
+ 2671, 2672, 2666, 2666, 2673, 2674, 2679, 2684,
+ 2683, 2679, 2657, 2657, 2658, 2659, 2680, 2667,
+ 2668, 2680, 2680, 2680, 2679, 2682, 2681, 2679,
+ 2680, 2657, 2657, 2658, 2659, 2660, 2660, 2661,
+ 2662, 2663, 2663, 2664, 2665, 2666, 2666, 2666,
+ 2666, 2667, 2668, 2666, 2666, 2669, 2670, 2671,
+ 2672, 2666, 2666, 2673, 2674, 2675, 2676, 2666,
+ 2666, 2677, 2678, 2680, 2680, 2680, 2679, 2682,
+ 2684, 2686, 2681, 2683, 2685, 2679, 690, 690,
+ 690, 690, 690, 690, 690, 3481, 3481, 3482,
+ 3483, 3484, 3485, 3486, 3486, 3487, 3488, 3477,
+ 3477, 3477, 2556, 3490, 3489, 2556, 690, 690,
+ 690, 690, 690, 690, 0
+};
+
+static const short _zone_scanner_trans_targs[] = {
+ 0, 1, 1, 1, 2, 4, 17, 36,
+ 50, 57, 143, 73, 77, 85, 91, 107,
+ 110, 117, 128, 138, 1127, 151, 1132, 264,
+ 0, 3, 3, 3, 2, 166, 166, 166,
+ 166, 166, 3, 169, 0, 3, 3, 3,
+ 4, 17, 36, 50, 57, 62, 73, 77,
+ 85, 91, 107, 110, 117, 128, 138, 3,
+ 169, 0, 5, 5, 5, 230, 233, 237,
+ 5, 10, 6, 11, 20, 6, 5, 0,
+ 5, 5, 9, 5, 10, 11, 20, 0,
+ 7, 7, 7, 1127, 8, 0, 7, 7,
+ 7, 1127, 8, 8, 1127, 6, 6, 10,
+ 5, 12, 12, 12, 13, 1133, 176, 244,
+ 12, 12, 12, 13, 1133, 176, 244, 13,
+ 1128, 14, 0, 14, 14, 15, 172, 179,
+ 180, 181, 182, 183, 184, 185, 186, 187,
+ 188, 189, 190, 191, 192, 1135, 239, 1133,
+ 240, 1136, 242, 0, 16, 16, 16, 1129,
+ 267, 0, 16, 16, 16, 1129, 267, 18,
+ 22, 29, 32, 19, 5, 5, 5, 5,
+ 10, 6, 11, 20, 21, 21, 21, 13,
+ 21, 21, 21, 13, 23, 28, 24, 25,
+ 26, 27, 5, 5, 5, 5, 10, 6,
+ 11, 20, 5, 5, 5, 5, 10, 6,
+ 11, 20, 30, 31, 5, 5, 5, 5,
+ 10, 6, 11, 20, 33, 34, 35, 5,
+ 5, 5, 5, 10, 6, 11, 20, 37,
+ 41, 49, 38, 39, 40, 5, 5, 5,
+ 5, 10, 6, 11, 20, 42, 45, 43,
+ 44, 5, 5, 5, 5, 10, 6, 11,
+ 20, 46, 47, 48, 5, 5, 5, 5,
+ 10, 6, 11, 20, 5, 5, 5, 5,
+ 10, 6, 11, 20, 51, 52, 53, 55,
+ 54, 5, 5, 5, 5, 10, 6, 11,
+ 20, 56, 5, 5, 5, 5, 10, 6,
+ 11, 20, 58, 59, 60, 61, 5, 5,
+ 5, 5, 10, 6, 11, 20, 63, 66,
+ 64, 64, 64, 64, 141, 64, 64, 64,
+ 4, 17, 36, 50, 57, 65, 73, 77,
+ 85, 91, 107, 110, 117, 128, 138, 64,
+ 141, 67, 68, 69, 70, 71, 72, 5,
+ 5, 5, 5, 10, 6, 11, 20, 74,
+ 76, 75, 5, 5, 5, 5, 10, 6,
+ 11, 20, 5, 5, 5, 5, 10, 6,
+ 11, 20, 78, 80, 82, 84, 79, 5,
+ 5, 5, 5, 10, 6, 11, 20, 81,
+ 5, 5, 5, 5, 10, 6, 11, 20,
+ 83, 5, 5, 5, 5, 10, 6, 11,
+ 20, 5, 5, 5, 5, 10, 6, 11,
+ 20, 86, 90, 87, 88, 89, 5, 5,
+ 5, 5, 10, 6, 11, 20, 5, 5,
+ 5, 5, 10, 6, 11, 20, 92, 96,
+ 98, 93, 94, 95, 5, 5, 5, 5,
+ 10, 6, 11, 20, 97, 5, 5, 5,
+ 5, 10, 6, 11, 20, 5, 5, 5,
+ 99, 5, 10, 6, 11, 20, 100, 5,
+ 5, 5, 101, 5, 10, 6, 11, 20,
+ 5, 5, 5, 102, 5, 10, 6, 11,
+ 20, 103, 104, 105, 106, 5, 5, 5,
+ 5, 10, 6, 11, 20, 108, 109, 5,
+ 5, 5, 5, 10, 6, 11, 20, 111,
+ 112, 116, 5, 5, 5, 5, 10, 6,
+ 11, 20, 113, 114, 115, 5, 5, 5,
+ 5, 10, 6, 11, 20, 5, 5, 5,
+ 5, 10, 6, 11, 20, 118, 120, 122,
+ 124, 119, 5, 5, 5, 5, 10, 6,
+ 11, 20, 121, 5, 5, 5, 5, 10,
+ 6, 11, 20, 123, 5, 5, 5, 5,
+ 10, 6, 11, 20, 125, 126, 127, 5,
+ 5, 5, 5, 10, 6, 11, 20, 129,
+ 132, 134, 130, 131, 5, 5, 5, 5,
+ 10, 6, 11, 20, 133, 5, 5, 5,
+ 5, 10, 6, 11, 20, 135, 136, 0,
+ 137, 0, 5, 5, 5, 137, 5, 10,
+ 6, 11, 20, 139, 140, 5, 5, 5,
+ 5, 10, 6, 11, 20, 141, 64, 142,
+ 142, 142, 1130, 265, 144, 145, 145, 145,
+ 145, 150, 145, 145, 145, 146, 4, 17,
+ 36, 50, 57, 65, 73, 77, 85, 91,
+ 107, 110, 117, 128, 138, 145, 150, 64,
+ 64, 64, 146, 147, 147, 147, 147, 147,
+ 64, 141, 148, 148, 149, 149, 149, 149,
+ 149, 64, 64, 64, 148, 64, 141, 150,
+ 145, 151, 1127, 0, 153, 195, 201, 154,
+ 155, 156, 157, 158, 159, 1131, 0, 161,
+ 161, 161, 161, 162, 161, 161, 161, 161,
+ 162, 162, 0, 161, 0, 164, 164, 164,
+ 164, 165, 164, 164, 164, 164, 165, 165,
+ 164, 167, 167, 168, 168, 168, 168, 168,
+ 3, 3, 3, 167, 3, 169, 169, 3,
+ 0, 171, 171, 171, 171, 246, 247, 248,
+ 171, 171, 171, 171, 246, 247, 248, 0,
+ 173, 173, 173, 1128, 13, 1133, 176, 1134,
+ 244, 173, 173, 173, 1128, 1134, 174, 174,
+ 174, 1132, 175, 175, 1132, 177, 177, 177,
+ 1127, 8, 177, 177, 177, 8, 178, 178,
+ 178, 193, 228, 193, 1135, 0, 196, 197,
+ 198, 199, 200, 1131, 202, 203, 1131, 0,
+ 174, 174, 174, 1132, 175, 0, 206, 206,
+ 206, 1130, 207, 206, 206, 206, 1130, 207,
+ 207, 1130, 0, 209, 209, 209, 1135, 193,
+ 1136, 228, 209, 209, 209, 1135, 1136, 225,
+ 0, 225, 225, 225, 226, 174, 174, 174,
+ 1132, 175, 227, 1132, 227, 227, 175, 227,
+ 227, 227, 175, 229, 229, 229, 193, 229,
+ 229, 229, 193, 231, 232, 5, 5, 5,
+ 5, 10, 6, 11, 20, 234, 235, 236,
+ 5, 5, 5, 5, 10, 6, 11, 20,
+ 238, 5, 5, 5, 5, 10, 6, 11,
+ 20, 239, 1135, 241, 241, 241, 1127, 241,
+ 241, 241, 1127, 243, 243, 243, 243, 243,
+ 243, 245, 245, 245, 245, 245, 245, 246,
+ 171, 178, 178, 178, 193, 228, 249, 249,
+ 249, 249, 249, 249, 0, 264, 1132, 265,
+ 1130, 267, 1129, 269, 1137, 269, 1137, 0,
+ 271, 277, 278, 273, 1138, 271, 272, 273,
+ 1138, 271, 273, 274, 0, 275, 276, 1138,
+ 271, 272, 273, 1138, 0, 280, 285, 281,
+ 1139, 1140, 0, 282, 283, 284, 1139, 280,
+ 1140, 281, 285, 286, 287, 0, 288, 289,
+ 290, 285, 286, 287, 0, 292, 292, 292,
+ 292, 299, 0, 293, 0, 294, 294, 294,
+ 293, 296, 296, 296, 296, 296, 1141, 295,
+ 0, 294, 294, 294, 1141, 295, 295, 1141,
+ 297, 0, 297, 298, 298, 298, 298, 298,
+ 294, 294, 294, 297, 1141, 295, 299, 292,
+ 0, 301, 301, 301, 301, 311, 302, 310,
+ 306, 302, 303, 306, 0, 304, 304, 304,
+ 302, 306, 1142, 305, 304, 304, 304, 1142,
+ 305, 305, 1142, 307, 0, 308, 309, 302,
+ 303, 306, 311, 301, 313, 313, 313, 313,
+ 328, 314, 0, 0, 315, 315, 315, 1143,
+ 319, 325, 0, 315, 315, 315, 316, 324,
+ 320, 1143, 319, 325, 0, 316, 317, 320,
+ 318, 318, 318, 316, 320, 1143, 319, 318,
+ 318, 318, 319, 1143, 321, 0, 322, 323,
+ 316, 317, 320, 325, 1144, 326, 326, 326,
+ 326, 327, 327, 326, 328, 313, 0, 330,
+ 331, 332, 335, 333, 333, 333, 333, 333,
+ 334, 1145, 1146, 1147, 334, 333, 0, 337,
+ 337, 337, 337, 342, 1148, 1149, 1150, 337,
+ 337, 337, 338, 343, 360, 374, 381, 386,
+ 394, 398, 406, 412, 428, 431, 438, 449,
+ 459, 337, 342, 1148, 1149, 1150, 337, 337,
+ 337, 339, 462, 466, 337, 342, 1148, 1149,
+ 1150, 340, 341, 337, 337, 337, 337, 342,
+ 1148, 1149, 1150, 342, 337, 344, 346, 353,
+ 356, 345, 337, 337, 337, 337, 342, 1148,
+ 1149, 1150, 347, 352, 348, 349, 350, 351,
+ 337, 337, 337, 337, 342, 1148, 1149, 1150,
+ 337, 337, 337, 337, 342, 1148, 1149, 1150,
+ 354, 355, 337, 337, 337, 337, 342, 1148,
+ 1149, 1150, 357, 358, 359, 337, 337, 337,
+ 337, 342, 1148, 1149, 1150, 361, 365, 373,
+ 362, 363, 364, 337, 337, 337, 337, 342,
+ 1148, 1149, 1150, 366, 369, 367, 368, 337,
+ 337, 337, 337, 342, 1148, 1149, 1150, 370,
+ 371, 372, 337, 337, 337, 337, 342, 1148,
+ 1149, 1150, 337, 337, 337, 337, 342, 1148,
+ 1149, 1150, 375, 376, 377, 379, 378, 337,
+ 337, 337, 337, 342, 1148, 1149, 1150, 380,
+ 337, 337, 337, 337, 342, 1148, 1149, 1150,
+ 382, 383, 384, 385, 337, 337, 337, 337,
+ 342, 1148, 1149, 1150, 387, 388, 389, 390,
+ 391, 392, 393, 337, 337, 337, 337, 342,
+ 1148, 1149, 1150, 395, 397, 396, 337, 337,
+ 337, 337, 342, 1148, 1149, 1150, 337, 337,
+ 337, 337, 342, 1148, 1149, 1150, 399, 401,
+ 403, 405, 400, 337, 337, 337, 337, 342,
+ 1148, 1149, 1150, 402, 337, 337, 337, 337,
+ 342, 1148, 1149, 1150, 404, 337, 337, 337,
+ 337, 342, 1148, 1149, 1150, 337, 337, 337,
+ 337, 342, 1148, 1149, 1150, 407, 411, 408,
+ 409, 410, 337, 337, 337, 337, 342, 1148,
+ 1149, 1150, 337, 337, 337, 337, 342, 1148,
+ 1149, 1150, 413, 417, 419, 414, 415, 416,
+ 337, 337, 337, 337, 342, 1148, 1149, 1150,
+ 418, 337, 337, 337, 337, 342, 1148, 1149,
+ 1150, 337, 337, 337, 420, 337, 342, 1148,
+ 1149, 1150, 421, 337, 337, 337, 422, 337,
+ 342, 1148, 1149, 1150, 337, 337, 337, 423,
+ 337, 342, 1148, 1149, 1150, 424, 425, 426,
+ 427, 337, 337, 337, 337, 342, 1148, 1149,
+ 1150, 429, 430, 337, 337, 337, 337, 342,
+ 1148, 1149, 1150, 432, 433, 437, 337, 337,
+ 337, 337, 342, 1148, 1149, 1150, 434, 435,
+ 436, 337, 337, 337, 337, 342, 1148, 1149,
+ 1150, 337, 337, 337, 337, 342, 1148, 1149,
+ 1150, 439, 441, 443, 445, 440, 337, 337,
+ 337, 337, 342, 1148, 1149, 1150, 442, 337,
+ 337, 337, 337, 342, 1148, 1149, 1150, 444,
+ 337, 337, 337, 337, 342, 1148, 1149, 1150,
+ 446, 447, 448, 337, 337, 337, 337, 342,
+ 1148, 1149, 1150, 450, 453, 455, 451, 452,
+ 337, 337, 337, 337, 342, 1148, 1149, 1150,
+ 454, 337, 337, 337, 337, 342, 1148, 1149,
+ 1150, 456, 457, 458, 337, 337, 337, 458,
+ 337, 342, 1148, 1149, 1150, 460, 461, 337,
+ 337, 337, 337, 342, 1148, 1149, 1150, 463,
+ 464, 465, 337, 337, 337, 337, 342, 1148,
+ 1149, 1150, 467, 337, 337, 337, 337, 342,
+ 1148, 1149, 1150, 0, 469, 469, 469, 469,
+ 476, 0, 470, 471, 471, 471, 470, 471,
+ 475, 0, 471, 471, 471, 472, 471, 475,
+ 473, 473, 473, 473, 473, 474, 1151, 1152,
+ 1153, 474, 473, 475, 471, 476, 469, 478,
+ 478, 478, 478, 486, 479, 485, 1154, 1154,
+ 1154, 485, 1155, 1154, 1158, 480, 480, 480,
+ 481, 480, 484, 482, 482, 482, 482, 482,
+ 483, 1155, 1156, 1157, 483, 482, 484, 480,
+ 480, 480, 480, 480, 484, 486, 478, 0,
+ 488, 489, 504, 543, 551, 564, 1159, 488,
+ 490, 491, 1159, 492, 1159, 493, 494, 495,
+ 496, 497, 498, 499, 500, 501, 502, 503,
+ 1159, 505, 534, 506, 512, 507, 508, 509,
+ 510, 511, 1159, 513, 514, 515, 516, 525,
+ 517, 518, 519, 520, 521, 522, 523, 524,
+ 1159, 526, 527, 528, 529, 530, 531, 532,
+ 533, 1159, 535, 540, 536, 537, 538, 539,
+ 1159, 541, 542, 1159, 544, 545, 546, 547,
+ 548, 549, 550, 1159, 552, 553, 554, 555,
+ 556, 557, 558, 561, 559, 560, 1159, 562,
+ 563, 1159, 565, 566, 567, 570, 568, 569,
+ 1159, 571, 572, 573, 585, 588, 1159, 574,
+ 575, 576, 577, 578, 579, 580, 581, 582,
+ 583, 584, 1159, 586, 587, 1159, 589, 590,
+ 1159, 0, 592, 593, 599, 616, 619, 625,
+ 629, 1160, 592, 594, 595, 596, 597, 598,
+ 1160, 600, 606, 612, 601, 602, 603, 604,
+ 605, 1160, 607, 609, 608, 1160, 610, 611,
+ 1160, 613, 614, 615, 1160, 617, 618, 1160,
+ 620, 622, 621, 1160, 623, 624, 1160, 626,
+ 627, 628, 1160, 630, 631, 1160, 0, 633,
+ 1161, 633, 635, 1162, 637, 638, 638, 638,
+ 638, 667, 638, 638, 638, 639, 638, 667,
+ 640, 640, 640, 640, 666, 0, 640, 640,
+ 640, 641, 640, 666, 642, 642, 642, 641,
+ 642, 665, 642, 642, 642, 643, 642, 665,
+ 0, 644, 644, 644, 643, 662, 662, 662,
+ 662, 662, 644, 661, 644, 644, 644, 645,
+ 644, 661, 646, 646, 646, 645, 658, 658,
+ 658, 658, 658, 646, 657, 646, 646, 646,
+ 647, 646, 657, 648, 648, 648, 647, 654,
+ 654, 654, 654, 654, 648, 653, 648, 648,
+ 648, 649, 648, 653, 1163, 649, 650, 650,
+ 650, 650, 650, 651, 651, 652, 652, 652,
+ 652, 652, 1163, 651, 653, 648, 655, 655,
+ 656, 656, 656, 656, 656, 648, 648, 648,
+ 655, 648, 653, 657, 646, 659, 659, 660,
+ 660, 660, 660, 660, 646, 646, 646, 659,
+ 646, 657, 661, 644, 663, 663, 664, 664,
+ 664, 664, 664, 644, 644, 644, 663, 644,
+ 661, 665, 642, 666, 640, 667, 638, 669,
+ 670, 670, 670, 670, 672, 671, 670, 670,
+ 670, 670, 672, 1164, 672, 670, 674, 675,
+ 675, 675, 675, 677, 675, 675, 675, 676,
+ 675, 677, 1165, 677, 675, 679, 680, 680,
+ 680, 679, 680, 682, 680, 680, 680, 681,
+ 680, 682, 1166, 682, 680, 684, 0, 685,
+ 685, 685, 685, 686, 1167, 1168, 1169, 684,
+ 685, 685, 685, 685, 686, 1167, 1168, 1169,
+ 686, 685, 688, 1170, 688, 0, 690, 691,
+ 691, 691, 690, 691, 743, 691, 691, 691,
+ 692, 696, 738, 691, 743, 693, 693, 693,
+ 692, 693, 742, 693, 693, 693, 694, 693,
+ 742, 695, 695, 695, 740, 694, 695, 739,
+ 695, 695, 695, 695, 739, 697, 697, 697,
+ 697, 737, 698, 699, 699, 699, 698, 699,
+ 736, 699, 699, 699, 700, 704, 731, 699,
+ 736, 701, 701, 701, 700, 701, 735, 701,
+ 701, 701, 702, 701, 735, 703, 703, 703,
+ 733, 702, 703, 732, 703, 703, 703, 703,
+ 732, 705, 705, 705, 705, 730, 706, 707,
+ 707, 708, 708, 708, 727, 707, 729, 708,
+ 726, 1171, 1178, 1179, 708, 708, 708, 709,
+ 708, 726, 1171, 1178, 1179, 710, 710, 710,
+ 723, 709, 725, 710, 722, 1171, 1176, 1177,
+ 710, 710, 710, 711, 710, 722, 1176, 1177,
+ 712, 712, 712, 719, 711, 721, 712, 718,
+ 1171, 1174, 1175, 712, 712, 712, 713, 712,
+ 718, 1174, 1175, 714, 714, 714, 716, 713,
+ 714, 715, 1171, 1172, 1173, 714, 714, 714,
+ 714, 715, 1172, 1173, 715, 714, 714, 714,
+ 714, 717, 714, 715, 1171, 1172, 1173, 717,
+ 718, 712, 712, 712, 712, 720, 721, 712,
+ 718, 1171, 1174, 1175, 720, 722, 710, 710,
+ 710, 710, 724, 725, 710, 722, 1171, 1176,
+ 1177, 724, 726, 708, 708, 708, 708, 728,
+ 729, 708, 726, 1171, 1178, 1179, 728, 730,
+ 705, 705, 705, 705, 705, 730, 732, 703,
+ 703, 703, 703, 734, 703, 732, 734, 735,
+ 701, 736, 699, 737, 697, 697, 697, 697,
+ 697, 737, 739, 695, 695, 695, 695, 741,
+ 695, 739, 741, 742, 693, 743, 691, 745,
+ 746, 746, 746, 745, 746, 754, 746, 746,
+ 746, 747, 746, 754, 748, 748, 748, 747,
+ 748, 753, 748, 748, 748, 749, 748, 753,
+ 750, 750, 750, 749, 750, 752, 750, 750,
+ 750, 751, 750, 752, 1180, 752, 750, 753,
+ 748, 754, 746, 756, 757, 757, 757, 756,
+ 757, 771, 757, 757, 757, 758, 757, 771,
+ 759, 759, 759, 758, 759, 770, 760, 759,
+ 759, 759, 759, 770, 761, 761, 761, 761,
+ 769, 762, 761, 761, 761, 761, 769, 763,
+ 763, 763, 763, 768, 764, 763, 763, 763,
+ 763, 768, 765, 765, 765, 765, 767, 765,
+ 765, 765, 766, 765, 767, 1181, 767, 765,
+ 768, 763, 769, 761, 770, 759, 771, 757,
+ 773, 774, 774, 774, 774, 782, 775, 776,
+ 776, 776, 775, 776, 781, 776, 776, 776,
+ 777, 776, 781, 778, 778, 778, 778, 780,
+ 779, 1182, 780, 778, 781, 776, 782, 774,
+ 0, 783, 784, 783, 783, 785, 791, 783,
+ 790, 1183, 1184, 1185, 785, 791, 786, 0,
+ 787, 787, 788, 789, 783, 783, 783, 789,
+ 783, 790, 1183, 1184, 1185, 790, 783, 792,
+ 793, 793, 788, 795, 796, 796, 796, 795,
+ 796, 806, 796, 796, 796, 797, 796, 806,
+ 798, 798, 798, 798, 805, 799, 800, 800,
+ 800, 799, 800, 804, 0, 800, 800, 800,
+ 801, 800, 804, 802, 802, 802, 802, 802,
+ 803, 1186, 1187, 1188, 803, 802, 804, 800,
+ 805, 798, 806, 796, 808, 809, 809, 809,
+ 808, 809, 816, 809, 809, 809, 810, 809,
+ 816, 811, 811, 811, 810, 811, 815, 811,
+ 811, 811, 812, 811, 815, 813, 813, 813,
+ 813, 813, 814, 1189, 1190, 1191, 814, 813,
+ 815, 811, 816, 809, 818, 819, 819, 819,
+ 818, 819, 855, 0, 819, 819, 819, 820,
+ 834, 841, 848, 819, 855, 821, 821, 821,
+ 821, 833, 0, 822, 823, 823, 823, 822,
+ 823, 832, 823, 823, 823, 824, 823, 832,
+ 0, 825, 825, 825, 828, 828, 828, 830,
+ 830, 830, 1192, 825, 827, 1195, 1196, 828,
+ 829, 1193, 1194, 830, 831, 1197, 1198, 0,
+ 826, 827, 825, 829, 828, 831, 830, 832,
+ 823, 833, 821, 835, 835, 835, 835, 840,
+ 836, 837, 837, 837, 836, 837, 839, 0,
+ 837, 837, 837, 838, 837, 839, 0, 838,
+ 825, 825, 825, 828, 828, 828, 830, 830,
+ 830, 1192, 825, 827, 1195, 1196, 828, 829,
+ 1193, 1194, 830, 831, 1197, 1198, 839, 837,
+ 840, 835, 842, 842, 842, 842, 847, 843,
+ 844, 844, 844, 843, 844, 846, 844, 844,
+ 844, 845, 844, 846, 845, 825, 825, 825,
+ 828, 828, 828, 830, 830, 830, 1192, 825,
+ 827, 1195, 1196, 828, 829, 1193, 1194, 830,
+ 831, 1197, 1198, 846, 844, 847, 842, 849,
+ 849, 849, 849, 854, 850, 851, 851, 851,
+ 850, 851, 853, 851, 851, 851, 852, 851,
+ 853, 825, 825, 825, 828, 828, 828, 830,
+ 830, 830, 1192, 825, 827, 1195, 1196, 828,
+ 829, 1193, 1194, 830, 831, 1197, 1198, 853,
+ 851, 854, 849, 855, 819, 0, 857, 891,
+ 908, 922, 929, 934, 942, 946, 954, 960,
+ 976, 979, 986, 997, 1007, 858, 858, 858,
+ 882, 885, 889, 858, 881, 858, 858, 858,
+ 859, 858, 881, 860, 860, 860, 860, 880,
+ 861, 862, 862, 862, 861, 862, 879, 862,
+ 862, 862, 863, 862, 879, 864, 864, 864,
+ 863, 864, 878, 0, 864, 864, 864, 865,
+ 864, 878, 866, 866, 866, 865, 866, 877,
+ 866, 866, 866, 867, 866, 877, 868, 868,
+ 868, 867, 868, 876, 868, 868, 868, 869,
+ 868, 876, 870, 870, 870, 869, 870, 875,
+ 870, 870, 870, 871, 870, 875, 872, 872,
+ 872, 872, 874, 872, 872, 872, 873, 872,
+ 874, 1199, 874, 872, 875, 870, 876, 868,
+ 877, 866, 878, 864, 879, 862, 880, 860,
+ 881, 858, 883, 884, 858, 858, 858, 858,
+ 881, 886, 887, 888, 858, 858, 858, 858,
+ 881, 890, 858, 858, 858, 858, 881, 892,
+ 894, 901, 904, 893, 858, 858, 858, 858,
+ 881, 895, 900, 896, 897, 898, 899, 858,
+ 858, 858, 858, 881, 858, 858, 858, 858,
+ 881, 902, 903, 858, 858, 858, 858, 881,
+ 905, 906, 907, 858, 858, 858, 858, 881,
+ 909, 913, 921, 910, 911, 912, 858, 858,
+ 858, 858, 881, 914, 917, 915, 916, 858,
+ 858, 858, 858, 881, 918, 919, 920, 858,
+ 858, 858, 858, 881, 858, 858, 858, 858,
+ 881, 923, 924, 925, 927, 926, 858, 858,
+ 858, 858, 881, 928, 858, 858, 858, 858,
+ 881, 930, 931, 932, 933, 858, 858, 858,
+ 858, 881, 935, 936, 937, 938, 939, 940,
+ 941, 858, 858, 858, 858, 881, 943, 945,
+ 944, 858, 858, 858, 858, 881, 858, 858,
+ 858, 858, 881, 947, 949, 951, 953, 948,
+ 858, 858, 858, 858, 881, 950, 858, 858,
+ 858, 858, 881, 952, 858, 858, 858, 858,
+ 881, 858, 858, 858, 858, 881, 955, 959,
+ 956, 957, 958, 858, 858, 858, 858, 881,
+ 858, 858, 858, 858, 881, 961, 965, 967,
+ 962, 963, 964, 858, 858, 858, 858, 881,
+ 966, 858, 858, 858, 858, 881, 858, 858,
+ 858, 968, 858, 881, 969, 858, 858, 858,
+ 970, 858, 881, 858, 858, 858, 971, 858,
+ 881, 972, 973, 974, 975, 858, 858, 858,
+ 858, 881, 977, 978, 858, 858, 858, 858,
+ 881, 980, 981, 985, 858, 858, 858, 858,
+ 881, 982, 983, 984, 858, 858, 858, 858,
+ 881, 858, 858, 858, 858, 881, 987, 989,
+ 991, 993, 988, 858, 858, 858, 858, 881,
+ 990, 858, 858, 858, 858, 881, 992, 858,
+ 858, 858, 858, 881, 994, 995, 996, 858,
+ 858, 858, 858, 881, 998, 1001, 1003, 999,
+ 1000, 858, 858, 858, 858, 881, 1002, 858,
+ 858, 858, 858, 881, 1004, 1005, 0, 1006,
+ 858, 858, 858, 1006, 858, 881, 1008, 1009,
+ 858, 858, 858, 858, 881, 1011, 1012, 1200,
+ 1014, 1015, 1015, 1015, 1014, 1015, 1023, 1015,
+ 1015, 1015, 1016, 1015, 1023, 1017, 1017, 1017,
+ 1016, 1017, 1022, 1017, 1017, 1017, 1018, 1017,
+ 1022, 1019, 1019, 1019, 1019, 1021, 1020, 1201,
+ 1021, 1019, 1022, 1017, 1023, 1015, 1025, 1202,
+ 1027, 1028, 1028, 1028, 1027, 1028, 1054, 1028,
+ 1028, 1028, 1029, 1028, 1054, 1030, 1030, 1030,
+ 1029, 1030, 1053, 1030, 1030, 1030, 1031, 1030,
+ 1053, 1032, 1032, 1032, 1031, 1032, 1052, 1032,
+ 1032, 1032, 1033, 1050, 1032, 1052, 1034, 1034,
+ 1034, 1034, 1049, 0, 1034, 1034, 1034, 1035,
+ 1034, 1049, 1036, 1037, 1047, 1038, 1039, 1046,
+ 1040, 1044, 1041, 1042, 1042, 1043, 1035, 1203,
+ 1045, 1048, 1049, 1034, 1051, 1050, 1052, 1032,
+ 1053, 1030, 1054, 1028, 1056, 1057, 1057, 1057,
+ 1056, 1057, 1067, 1057, 1057, 1057, 1058, 1057,
+ 1067, 1059, 1059, 1059, 1058, 1059, 1066, 1059,
+ 1059, 1059, 1060, 1059, 1066, 1061, 1061, 1061,
+ 1060, 1061, 1065, 1061, 1061, 1061, 1062, 1063,
+ 1061, 1065, 1204, 1064, 1063, 1065, 1061, 1066,
+ 1059, 1067, 1057, 1069, 1070, 1070, 1070, 1069,
+ 1070, 1080, 1070, 1070, 1070, 1071, 1070, 1080,
+ 1072, 1072, 1072, 1071, 1072, 1079, 1072, 1072,
+ 1072, 1073, 1072, 1079, 1074, 1074, 1074, 1073,
+ 1074, 1078, 1074, 1074, 1074, 1075, 1074, 1078,
+ 1076, 1076, 1076, 1076, 1076, 1077, 1205, 1206,
+ 1207, 1077, 1076, 1078, 1074, 1079, 1072, 1080,
+ 1070, 1082, 1083, 1083, 1083, 1082, 1083, 1085,
+ 1083, 1083, 1083, 1084, 1083, 1085, 1208, 1084,
+ 1085, 1083, 1087, 1088, 1088, 1088, 1087, 1088,
+ 1098, 1088, 1088, 1088, 1089, 1088, 1098, 1090,
+ 1091, 1092, 0, 1093, 1094, 1095, 1096, 1097,
+ 0, 1209, 1098, 1088, 1100, 1101, 0, 1102,
+ 1103, 1104, 1210, 1106, 1107, 1108, 1109, 1110,
+ 1211, 1112, 1113, 1113, 1113, 1112, 1113, 1118,
+ 1113, 1113, 1113, 1114, 1113, 1118, 1115, 1115,
+ 1115, 1114, 1115, 1117, 1116, 1115, 1115, 1115,
+ 1115, 1117, 1212, 1117, 1115, 1118, 1113, 1120,
+ 1121, 1121, 1121, 1120, 1121, 1126, 1122, 1121,
+ 1121, 1121, 1121, 1126, 1123, 1123, 1123, 1123,
+ 1125, 1124, 1123, 1123, 1123, 1123, 1125, 1213,
+ 1125, 1123, 1126, 1121, 0, 1, 152, 1,
+ 1, 160, 1127, 151, 1132, 264, 14, 194,
+ 14, 14, 204, 224, 1135, 239, 1133, 240,
+ 1136, 242, 0, 142, 142, 142, 170, 250,
+ 251, 252, 253, 266, 255, 256, 257, 258,
+ 259, 260, 261, 262, 263, 1130, 265, 0,
+ 163, 170, 250, 251, 252, 253, 254, 255,
+ 256, 257, 258, 259, 260, 261, 262, 263,
+ 0, 1, 152, 1, 1, 160, 1127, 151,
+ 1132, 264, 1, 1, 1132, 264, 174, 174,
+ 174, 1132, 175, 178, 178, 178, 193, 228,
+ 0, 205, 208, 210, 211, 212, 213, 214,
+ 215, 216, 217, 218, 219, 220, 221, 222,
+ 223, 1132
+};
+
+static const short _zone_scanner_trans_actions[] = {
+ 2399, 0, 5, 7, 561, 720, 720, 720,
+ 720, 720, 720, 720, 720, 720, 720, 720,
+ 720, 720, 720, 720, 3, 9, 3, 9,
+ 2555, 101, 738, 741, 43, 57, 55, 53,
+ 0, 59, 735, 744, 361, 0, 5, 7,
+ 95, 95, 95, 95, 95, 95, 95, 95,
+ 95, 95, 95, 95, 95, 95, 95, 3,
+ 9, 2007, 2010, 3007, 3011, 0, 0, 0,
+ 3003, 3015, 3023, 4731, 4751, 355, 0, 353,
+ 5, 7, 359, 3, 9, 369, 396, 1992,
+ 13, 417, 420, 2271, 423, 15, 0, 5,
+ 7, 2136, 9, 11, 2243, 2001, 357, 11,
+ 411, 13, 378, 384, 393, 4726, 2983, 2223,
+ 0, 5, 7, 9, 2991, 1998, 396, 11,
+ 2239, 0, 4031, 5, 7, 2387, 2679, 2679,
+ 2679, 2679, 2679, 2679, 2679, 2679, 2679, 2679,
+ 2679, 2679, 2679, 2679, 2679, 3, 9, 1995,
+ 1998, 369, 396, 5292, 747, 2683, 2687, 4246,
+ 2691, 2004, 0, 5, 7, 372, 9, 0,
+ 0, 0, 0, 0, 2133, 3831, 3835, 3827,
+ 3839, 3843, 5156, 5161, 408, 2227, 2231, 2235,
+ 11, 399, 402, 405, 0, 0, 0, 0,
+ 0, 0, 2106, 3651, 3655, 3647, 3659, 3663,
+ 5066, 5071, 2103, 3631, 3635, 3627, 3639, 3643,
+ 5056, 5061, 0, 0, 2064, 3371, 3375, 3367,
+ 3379, 3383, 4926, 4931, 0, 0, 0, 2016,
+ 3051, 3055, 3047, 3059, 3063, 4766, 4771, 0,
+ 0, 0, 0, 0, 0, 2091, 3551, 3555,
+ 3547, 3559, 3563, 5016, 5021, 0, 0, 0,
+ 0, 2067, 3391, 3395, 3387, 3399, 3403, 4936,
+ 4941, 0, 0, 0, 2088, 3531, 3535, 3527,
+ 3539, 3543, 5006, 5011, 2073, 3431, 3435, 3427,
+ 3439, 3443, 4956, 4961, 0, 0, 0, 0,
+ 0, 2124, 3771, 3775, 3767, 3779, 3783, 5126,
+ 5131, 0, 2127, 3791, 3795, 3787, 3799, 3803,
+ 5136, 5141, 0, 0, 0, 0, 2025, 3111,
+ 3115, 3107, 3119, 3123, 4796, 4801, 0, 0,
+ 99, 726, 729, 723, 732, 0, 5, 7,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 3,
+ 9, 0, 0, 0, 0, 0, 0, 2079,
+ 3471, 3475, 3467, 3479, 3483, 4976, 4981, 0,
+ 0, 0, 2046, 3251, 3255, 3247, 3259, 3263,
+ 4866, 4871, 2061, 3351, 3355, 3347, 3359, 3363,
+ 4916, 4921, 0, 0, 0, 0, 0, 2115,
+ 3711, 3715, 3707, 3719, 3723, 5096, 5101, 0,
+ 2118, 3731, 3735, 3727, 3739, 3743, 5106, 5111,
+ 0, 2052, 3291, 3295, 3287, 3299, 3303, 4886,
+ 4891, 2121, 3751, 3755, 3747, 3759, 3763, 5116,
+ 5121, 0, 0, 0, 0, 0, 2028, 3131,
+ 3135, 3127, 3139, 3143, 4806, 4811, 2031, 3151,
+ 3155, 3147, 3159, 3163, 4816, 4821, 0, 0,
+ 0, 0, 0, 0, 2058, 3331, 3335, 3327,
+ 3339, 3343, 4906, 4911, 0, 2112, 3691, 3695,
+ 3687, 3699, 3703, 5086, 5091, 2013, 3031, 3035,
+ 0, 3027, 3039, 3043, 4756, 4761, 0, 2085,
+ 3511, 3515, 0, 3507, 3519, 3523, 4996, 5001,
+ 2094, 3571, 3575, 0, 3567, 3579, 3583, 5026,
+ 5031, 0, 0, 0, 0, 2097, 3591, 3595,
+ 3587, 3599, 3603, 5036, 5041, 0, 0, 2022,
+ 3091, 3095, 3087, 3099, 3103, 4786, 4791, 0,
+ 0, 0, 2037, 3191, 3195, 3187, 3199, 3203,
+ 4836, 4841, 0, 0, 0, 2082, 3491, 3495,
+ 3487, 3499, 3503, 4986, 4991, 2043, 3231, 3235,
+ 3227, 3239, 3243, 4856, 4861, 0, 0, 0,
+ 0, 0, 2019, 3071, 3075, 3067, 3079, 3083,
+ 4776, 4781, 0, 2109, 3671, 3675, 3667, 3679,
+ 3683, 5076, 5081, 0, 2055, 3311, 3315, 3307,
+ 3319, 3323, 4896, 4901, 0, 0, 0, 2076,
+ 3451, 3455, 3447, 3459, 3463, 4966, 4971, 0,
+ 0, 0, 0, 0, 2100, 3611, 3615, 3607,
+ 3619, 3623, 5046, 5051, 0, 2034, 3171, 3175,
+ 3167, 3179, 3183, 4826, 4831, 0, 0, 573,
+ 561, 2403, 639, 2531, 2535, 43, 2527, 2539,
+ 2543, 4191, 4196, 0, 0, 2130, 3811, 3815,
+ 3807, 3819, 3823, 5146, 5151, 11, 411, 0,
+ 5, 7, 3, 9, 0, 99, 726, 729,
+ 723, 732, 0, 5, 7, 561, 97, 97,
+ 97, 97, 97, 97, 97, 97, 97, 97,
+ 97, 97, 97, 97, 97, 3, 9, 101,
+ 738, 741, 43, 57, 55, 53, 0, 59,
+ 735, 744, 2559, 43, 57, 55, 53, 0,
+ 59, 660, 2599, 2603, 4206, 2595, 2607, 11,
+ 411, 11, 411, 93, 89, 89, 89, 0,
+ 0, 0, 0, 0, 0, 87, 39, 37,
+ 510, 513, 507, 516, 0, 5, 7, 3,
+ 9, 11, 0, 411, 4016, 522, 2315, 2323,
+ 2307, 2331, 0, 5, 7, 3, 9, 11,
+ 411, 2559, 43, 57, 55, 53, 0, 59,
+ 660, 2599, 2603, 4206, 2595, 2607, 11, 411,
+ 2375, 2343, 3971, 3986, 3956, 4001, 5178, 5202,
+ 0, 5, 7, 3, 9, 369, 396, 2999,
+ 3019, 4736, 4741, 5322, 4746, 5431, 5334, 5424,
+ 5328, 0, 5, 7, 372, 2179, 0, 5,
+ 7, 372, 9, 11, 2239, 426, 2247, 2255,
+ 3896, 2263, 11, 375, 381, 390, 0, 5,
+ 7, 9, 396, 11, 2239, 2975, 0, 0,
+ 0, 0, 0, 81, 0, 0, 77, 2367,
+ 519, 2311, 2319, 3946, 2327, 5361, 2335, 3961,
+ 3976, 5172, 3991, 0, 5, 7, 372, 9,
+ 11, 2239, 4021, 4006, 5184, 5190, 5347, 5196,
+ 5438, 5354, 0, 5, 7, 372, 2179, 2339,
+ 531, 3966, 3981, 3951, 3996, 13, 378, 384,
+ 2155, 393, 408, 3871, 2227, 2231, 2235, 11,
+ 399, 402, 405, 408, 2227, 2231, 2235, 11,
+ 399, 402, 405, 0, 0, 2049, 3271, 3275,
+ 3267, 3279, 3283, 4876, 4881, 0, 0, 0,
+ 2040, 3211, 3215, 3207, 3219, 3223, 4846, 4851,
+ 0, 2070, 3411, 3415, 3407, 3419, 3423, 4946,
+ 4951, 11, 411, 426, 2247, 2255, 3906, 11,
+ 375, 381, 3847, 408, 2227, 2231, 11, 399,
+ 402, 408, 2227, 2231, 11, 399, 402, 11,
+ 411, 13, 378, 384, 393, 2223, 408, 2227,
+ 2231, 11, 399, 402, 534, 11, 411, 11,
+ 411, 11, 2239, 438, 2275, 17, 441, 31,
+ 2299, 29, 0, 474, 2279, 21, 23, 0,
+ 465, 444, 19, 447, 456, 25, 25, 3916,
+ 450, 453, 27, 471, 684, 65, 0, 0,
+ 1, 681, 2615, 687, 69, 69, 690, 693,
+ 2611, 71, 65, 0, 0, 67, 687, 69,
+ 69, 693, 71, 71, 75, 0, 5, 7,
+ 3, 9, 564, 561, 4201, 13, 417, 420,
+ 43, 57, 55, 53, 0, 59, 3901, 423,
+ 432, 0, 5, 7, 2623, 9, 11, 3881,
+ 2559, 2547, 43, 57, 55, 53, 0, 59,
+ 654, 2563, 2567, 4206, 5298, 2571, 11, 411,
+ 79, 0, 5, 7, 3, 9, 4211, 702,
+ 2627, 21, 23, 0, 435, 468, 2283, 2287,
+ 444, 19, 5166, 2291, 0, 5, 7, 2631,
+ 9, 11, 3886, 447, 459, 25, 25, 450,
+ 453, 27, 11, 411, 0, 5, 7, 3,
+ 9, 705, 83, 711, 708, 2635, 2639, 5304,
+ 2647, 2643, 717, 0, 5, 7, 4216, 714,
+ 2651, 2655, 9, 9, 85, 21, 23, 0,
+ 2295, 3921, 3926, 444, 19, 5340, 3931, 0,
+ 5, 7, 11, 3891, 447, 462, 25, 25,
+ 450, 453, 27, 11, 3876, 0, 5, 7,
+ 3, 9, 11, 411, 11, 411, 125, 117,
+ 119, 121, 0, 123, 0, 5, 7, 3,
+ 9, 1, 366, 387, 11, 411, 325, 323,
+ 1896, 1899, 1893, 1902, 2947, 4716, 4721, 0,
+ 5, 7, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 3, 9, 1905, 2171, 2215, 239, 1392,
+ 1395, 0, 0, 0, 1389, 1398, 2779, 4296,
+ 4301, 0, 0, 265, 1548, 1551, 1545, 1554,
+ 2831, 4426, 4431, 11, 411, 0, 0, 0,
+ 0, 0, 321, 1884, 1887, 1881, 1890, 2943,
+ 4706, 4711, 0, 0, 0, 0, 0, 0,
+ 303, 1776, 1779, 1773, 1782, 2907, 4616, 4621,
+ 301, 1764, 1767, 1761, 1770, 2903, 4606, 4611,
+ 0, 0, 275, 1608, 1611, 1605, 1614, 2851,
+ 4476, 4481, 0, 0, 0, 243, 1416, 1419,
+ 1413, 1422, 2787, 4316, 4321, 0, 0, 0,
+ 0, 0, 0, 293, 1716, 1719, 1713, 1722,
+ 2887, 4566, 4571, 0, 0, 0, 0, 277,
+ 1620, 1623, 1617, 1626, 2855, 4486, 4491, 0,
+ 0, 0, 291, 1704, 1707, 1701, 1710, 2883,
+ 4556, 4561, 281, 1644, 1647, 1641, 1650, 2863,
+ 4506, 4511, 0, 0, 0, 0, 0, 315,
+ 1848, 1851, 1845, 1854, 2931, 4676, 4681, 0,
+ 317, 1860, 1863, 1857, 1866, 2935, 4686, 4691,
+ 0, 0, 0, 0, 249, 1452, 1455, 1449,
+ 1458, 2799, 4346, 4351, 0, 0, 0, 0,
+ 0, 0, 0, 285, 1668, 1671, 1665, 1674,
+ 2871, 4526, 4531, 0, 0, 0, 263, 1536,
+ 1539, 1533, 1542, 2827, 4416, 4421, 273, 1596,
+ 1599, 1593, 1602, 2847, 4466, 4471, 0, 0,
+ 0, 0, 0, 309, 1812, 1815, 1809, 1818,
+ 2919, 4646, 4651, 0, 311, 1824, 1827, 1821,
+ 1830, 2923, 4656, 4661, 0, 267, 1560, 1563,
+ 1557, 1566, 2835, 4436, 4441, 313, 1836, 1839,
+ 1833, 1842, 2927, 4666, 4671, 0, 0, 0,
+ 0, 0, 251, 1464, 1467, 1461, 1470, 2803,
+ 4356, 4361, 253, 1476, 1479, 1473, 1482, 2807,
+ 4366, 4371, 0, 0, 0, 0, 0, 0,
+ 271, 1584, 1587, 1581, 1590, 2843, 4456, 4461,
+ 0, 307, 1800, 1803, 1797, 1806, 2915, 4636,
+ 4641, 241, 1404, 1407, 0, 1401, 1410, 2783,
+ 4306, 4311, 0, 289, 1692, 1695, 0, 1689,
+ 1698, 2879, 4546, 4551, 295, 1728, 1731, 0,
+ 1725, 1734, 2891, 4576, 4581, 0, 0, 0,
+ 0, 297, 1740, 1743, 1737, 1746, 2895, 4586,
+ 4591, 0, 0, 247, 1440, 1443, 1437, 1446,
+ 2795, 4336, 4341, 0, 0, 0, 257, 1500,
+ 1503, 1497, 1506, 2815, 4386, 4391, 0, 0,
+ 0, 287, 1680, 1683, 1677, 1686, 2875, 4536,
+ 4541, 261, 1524, 1527, 1521, 1530, 2823, 4406,
+ 4411, 0, 0, 0, 0, 0, 245, 1428,
+ 1431, 1425, 1434, 2791, 4326, 4331, 0, 305,
+ 1788, 1791, 1785, 1794, 2911, 4626, 4631, 0,
+ 269, 1572, 1575, 1569, 1578, 2839, 4446, 4451,
+ 0, 0, 0, 283, 1656, 1659, 1653, 1662,
+ 2867, 4516, 4521, 0, 0, 0, 0, 0,
+ 299, 1752, 1755, 1749, 1758, 2899, 4596, 4601,
+ 0, 255, 1488, 1491, 1485, 1494, 2811, 4376,
+ 4381, 0, 0, 561, 237, 1380, 1383, 43,
+ 1377, 1386, 2775, 4286, 4291, 0, 0, 319,
+ 1872, 1875, 1869, 1878, 2939, 4696, 4701, 0,
+ 0, 0, 259, 1512, 1515, 1509, 1518, 2819,
+ 4396, 4401, 0, 279, 1632, 1635, 1629, 1638,
+ 2859, 4496, 4501, 339, 0, 5, 7, 3,
+ 9, 567, 561, 51, 645, 648, 43, 642,
+ 651, 2763, 0, 5, 7, 113, 3, 9,
+ 115, 0, 5, 7, 3, 9, 780, 2167,
+ 2211, 11, 411, 11, 411, 11, 411, 0,
+ 5, 7, 3, 9, 561, 561, 363, 2143,
+ 2147, 43, 1, 2139, 2151, 0, 5, 7,
+ 113, 3, 9, 115, 0, 5, 7, 3,
+ 9, 780, 2167, 2211, 11, 411, 11, 411,
+ 51, 645, 648, 642, 651, 11, 411, 345,
+ 561, 0, 0, 0, 0, 0, 594, 43,
+ 0, 0, 789, 0, 792, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 798, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 810, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 813, 0, 0, 0, 0, 0, 0, 0,
+ 0, 816, 0, 0, 0, 0, 0, 0,
+ 819, 0, 0, 822, 0, 0, 0, 0,
+ 0, 0, 0, 825, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 828, 0,
+ 0, 831, 0, 0, 0, 0, 0, 0,
+ 786, 0, 0, 0, 0, 0, 795, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 801, 0, 0, 804, 0, 0,
+ 807, 347, 561, 0, 0, 0, 0, 0,
+ 0, 609, 43, 0, 0, 0, 0, 0,
+ 852, 0, 0, 0, 0, 0, 0, 0,
+ 0, 855, 0, 0, 0, 849, 0, 0,
+ 843, 0, 0, 0, 846, 0, 0, 861,
+ 0, 0, 0, 840, 0, 0, 834, 0,
+ 0, 0, 837, 0, 0, 858, 753, 750,
+ 2703, 103, 537, 540, 537, 41, 546, 549,
+ 543, 552, 0, 5, 7, 537, 3, 9,
+ 41, 546, 549, 543, 552, 570, 0, 5,
+ 7, 561, 3, 9, 49, 630, 633, 43,
+ 627, 636, 0, 5, 7, 561, 3, 9,
+ 2551, 49, 630, 633, 43, 57, 55, 53,
+ 0, 59, 627, 636, 0, 5, 7, 561,
+ 3, 9, 49, 630, 633, 43, 57, 55,
+ 53, 0, 59, 627, 636, 0, 5, 7,
+ 561, 3, 9, 49, 630, 633, 43, 57,
+ 55, 53, 0, 59, 627, 636, 0, 5,
+ 7, 561, 3, 9, 624, 43, 57, 55,
+ 53, 0, 59, 2559, 43, 57, 55, 53,
+ 0, 59, 2575, 4206, 11, 411, 2559, 43,
+ 57, 55, 53, 0, 59, 657, 2583, 2587,
+ 4206, 2579, 2591, 11, 411, 2559, 43, 57,
+ 55, 53, 0, 59, 657, 2583, 2587, 4206,
+ 2579, 2591, 11, 411, 2559, 43, 57, 55,
+ 53, 0, 59, 657, 2583, 2587, 4206, 2579,
+ 2591, 11, 411, 11, 411, 11, 411, 477,
+ 35, 492, 495, 489, 498, 477, 0, 5,
+ 7, 3, 9, 486, 11, 411, 537, 41,
+ 546, 549, 543, 552, 0, 5, 7, 537,
+ 3, 9, 540, 11, 411, 561, 47, 615,
+ 618, 43, 612, 621, 0, 5, 7, 537,
+ 3, 9, 540, 11, 411, 2619, 699, 35,
+ 492, 495, 489, 498, 2303, 3936, 3941, 477,
+ 0, 5, 7, 3, 9, 696, 2163, 2207,
+ 11, 411, 750, 2723, 103, 1983, 2951, 327,
+ 1911, 1914, 43, 1908, 1917, 0, 5, 7,
+ 561, 0, 0, 3, 9, 331, 1935, 1938,
+ 43, 1932, 1941, 0, 5, 7, 4186, 3,
+ 9, 576, 2435, 2439, 0, 43, 2431, 2443,
+ 0, 5, 7, 3, 9, 0, 5, 7,
+ 3, 9, 561, 329, 1923, 1926, 43, 1920,
+ 1929, 0, 5, 7, 561, 0, 0, 3,
+ 9, 333, 1947, 1950, 43, 1944, 1953, 0,
+ 5, 7, 4186, 3, 9, 579, 2451, 2455,
+ 0, 43, 2447, 2459, 0, 5, 7, 3,
+ 9, 0, 5, 7, 3, 9, 0, 4181,
+ 5316, 582, 2467, 2471, 0, 43, 582, 2463,
+ 2475, 4161, 5244, 5250, 0, 5, 7, 4181,
+ 3, 9, 1980, 2175, 2219, 585, 2483, 2487,
+ 0, 43, 585, 2479, 2491, 4166, 5256, 5262,
+ 0, 5, 7, 4181, 3, 9, 2175, 2219,
+ 588, 2499, 2503, 0, 43, 588, 2495, 2507,
+ 4171, 5268, 5274, 0, 5, 7, 4181, 3,
+ 9, 2175, 2219, 591, 2515, 2519, 0, 43,
+ 2511, 2523, 4176, 5280, 5286, 0, 5, 7,
+ 3, 9, 2175, 2219, 11, 411, 2427, 4146,
+ 4151, 4036, 4141, 4156, 5238, 5410, 5417, 558,
+ 11, 411, 2423, 4126, 4131, 4036, 2423, 4121,
+ 4136, 5232, 5396, 5403, 558, 11, 411, 2419,
+ 4106, 4111, 4036, 2419, 4101, 4116, 5226, 5382,
+ 5389, 558, 11, 411, 2415, 4086, 4091, 4036,
+ 2415, 4081, 4096, 5220, 5368, 5375, 558, 11,
+ 411, 337, 1971, 1974, 1968, 1977, 11, 411,
+ 2411, 4066, 4071, 4036, 4061, 4076, 558, 11,
+ 411, 11, 411, 11, 411, 335, 1959, 1962,
+ 1956, 1965, 11, 411, 2407, 4046, 4051, 4036,
+ 4041, 4056, 558, 11, 411, 11, 411, 561,
+ 47, 615, 618, 43, 612, 621, 0, 5,
+ 7, 561, 3, 9, 47, 615, 618, 43,
+ 612, 621, 0, 5, 7, 561, 3, 9,
+ 47, 615, 618, 43, 612, 621, 0, 5,
+ 7, 537, 3, 9, 540, 11, 411, 11,
+ 411, 11, 411, 561, 47, 615, 618, 43,
+ 612, 621, 0, 5, 7, 561, 3, 9,
+ 47, 615, 618, 43, 612, 621, 477, 0,
+ 5, 7, 3, 9, 35, 492, 495, 489,
+ 498, 477, 0, 5, 7, 3, 9, 35,
+ 492, 495, 489, 498, 477, 0, 5, 7,
+ 3, 9, 35, 492, 495, 489, 498, 0,
+ 5, 7, 537, 3, 9, 540, 11, 411,
+ 11, 411, 11, 411, 11, 411, 11, 411,
+ 351, 0, 5, 7, 3, 9, 561, 47,
+ 615, 618, 43, 612, 621, 0, 5, 7,
+ 349, 3, 9, 0, 5, 7, 3, 9,
+ 127, 1, 11, 411, 11, 411, 11, 411,
+ 774, 0, 762, 5, 7, 765, 768, 3,
+ 9, 1, 366, 387, 109, 111, 0, 2695,
+ 750, 103, 105, 561, 771, 2751, 2755, 43,
+ 2747, 2759, 2743, 4276, 4281, 11, 411, 0,
+ 750, 103, 107, 561, 47, 615, 618, 43,
+ 612, 621, 0, 5, 7, 349, 3, 9,
+ 0, 5, 7, 3, 9, 561, 45, 600,
+ 603, 43, 597, 606, 777, 0, 5, 7,
+ 113, 3, 9, 115, 0, 5, 7, 3,
+ 9, 1, 366, 387, 11, 411, 11, 411,
+ 11, 411, 11, 411, 561, 45, 600, 603,
+ 43, 597, 606, 0, 5, 7, 561, 3,
+ 9, 45, 600, 603, 43, 597, 606, 0,
+ 5, 7, 113, 3, 9, 115, 0, 5,
+ 7, 3, 9, 1, 366, 387, 11, 411,
+ 11, 411, 11, 411, 561, 45, 600, 603,
+ 43, 597, 606, 864, 0, 5, 7, 145,
+ 147, 149, 151, 3, 9, 0, 5, 7,
+ 3, 9, 2391, 561, 45, 600, 603, 43,
+ 597, 606, 0, 5, 7, 0, 3, 9,
+ 2771, 0, 5, 7, 0, 5, 7, 0,
+ 5, 7, 1, 3, 9, 366, 387, 3,
+ 9, 366, 387, 3, 9, 366, 387, 867,
+ 127, 11, 411, 11, 411, 11, 411, 11,
+ 411, 11, 411, 0, 5, 7, 3, 9,
+ 561, 45, 600, 603, 43, 597, 606, 2699,
+ 0, 5, 7, 750, 3, 9, 4251, 103,
+ 756, 2711, 2715, 756, 2711, 2715, 756, 2711,
+ 2715, 2703, 2707, 2719, 4256, 4261, 2707, 2719,
+ 4256, 4261, 2707, 2719, 4256, 4261, 11, 411,
+ 11, 411, 0, 5, 7, 3, 9, 561,
+ 45, 600, 603, 43, 597, 606, 0, 5,
+ 7, 750, 3, 9, 103, 759, 2731, 2735,
+ 759, 2731, 2735, 759, 2731, 2735, 2723, 2727,
+ 2739, 4266, 4271, 2727, 2739, 4266, 4271, 2727,
+ 2739, 4266, 4271, 11, 411, 11, 411, 0,
+ 5, 7, 3, 9, 561, 45, 600, 603,
+ 43, 597, 606, 0, 5, 7, 537, 3,
+ 9, 41, 546, 549, 41, 546, 549, 41,
+ 546, 549, 540, 543, 552, 2379, 2383, 543,
+ 552, 2379, 2383, 543, 552, 2379, 2383, 11,
+ 411, 11, 411, 11, 411, 870, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 153, 876, 879,
+ 0, 0, 0, 873, 882, 0, 5, 7,
+ 349, 3, 9, 0, 5, 7, 3, 9,
+ 561, 45, 600, 603, 43, 597, 606, 0,
+ 5, 7, 561, 3, 9, 49, 630, 633,
+ 43, 627, 636, 678, 0, 5, 7, 663,
+ 3, 9, 63, 669, 672, 61, 666, 675,
+ 0, 5, 7, 663, 3, 9, 63, 669,
+ 672, 61, 666, 675, 0, 5, 7, 561,
+ 3, 9, 47, 615, 618, 43, 612, 621,
+ 0, 5, 7, 537, 3, 9, 41, 546,
+ 549, 543, 552, 0, 5, 7, 127, 3,
+ 9, 1, 11, 411, 11, 411, 11, 411,
+ 11, 411, 11, 411, 11, 411, 11, 411,
+ 11, 411, 0, 0, 179, 1032, 1035, 1029,
+ 1038, 0, 0, 0, 173, 996, 999, 993,
+ 1002, 0, 193, 1116, 1119, 1113, 1122, 0,
+ 0, 0, 0, 0, 235, 1368, 1371, 1365,
+ 1374, 0, 0, 0, 0, 0, 0, 217,
+ 1260, 1263, 1257, 1266, 215, 1248, 1251, 1245,
+ 1254, 0, 0, 189, 1092, 1095, 1089, 1098,
+ 0, 0, 0, 157, 900, 903, 897, 906,
+ 0, 0, 0, 0, 0, 0, 207, 1200,
+ 1203, 1197, 1206, 0, 0, 0, 0, 191,
+ 1104, 1107, 1101, 1110, 0, 0, 0, 205,
+ 1188, 1191, 1185, 1194, 195, 1128, 1131, 1125,
+ 1134, 0, 0, 0, 0, 0, 229, 1332,
+ 1335, 1329, 1338, 0, 231, 1344, 1347, 1341,
+ 1350, 0, 0, 0, 0, 163, 936, 939,
+ 933, 942, 0, 0, 0, 0, 0, 0,
+ 0, 199, 1152, 1155, 1149, 1158, 0, 0,
+ 0, 177, 1020, 1023, 1017, 1026, 187, 1080,
+ 1083, 1077, 1086, 0, 0, 0, 0, 0,
+ 223, 1296, 1299, 1293, 1302, 0, 225, 1308,
+ 1311, 1305, 1314, 0, 181, 1044, 1047, 1041,
+ 1050, 227, 1320, 1323, 1317, 1326, 0, 0,
+ 0, 0, 0, 165, 948, 951, 945, 954,
+ 167, 960, 963, 957, 966, 0, 0, 0,
+ 0, 0, 0, 185, 1068, 1071, 1065, 1074,
+ 0, 221, 1284, 1287, 1281, 1290, 155, 888,
+ 891, 0, 885, 894, 0, 203, 1176, 1179,
+ 0, 1173, 1182, 209, 1212, 1215, 0, 1209,
+ 1218, 0, 0, 0, 0, 211, 1224, 1227,
+ 1221, 1230, 0, 0, 161, 924, 927, 921,
+ 930, 0, 0, 0, 171, 984, 987, 981,
+ 990, 0, 0, 0, 201, 1164, 1167, 1161,
+ 1170, 175, 1008, 1011, 1005, 1014, 0, 0,
+ 0, 0, 0, 159, 912, 915, 909, 918,
+ 0, 219, 1272, 1275, 1269, 1278, 0, 183,
+ 1056, 1059, 1053, 1062, 0, 0, 0, 197,
+ 1140, 1143, 1137, 1146, 0, 0, 0, 0,
+ 0, 213, 1236, 1239, 1233, 1242, 0, 169,
+ 972, 975, 969, 978, 0, 0, 2395, 561,
+ 47, 615, 618, 43, 612, 621, 0, 0,
+ 233, 1356, 1359, 1353, 1362, 537, 555, 1,
+ 561, 47, 615, 618, 43, 612, 621, 0,
+ 5, 7, 561, 3, 9, 45, 600, 603,
+ 43, 597, 606, 0, 5, 7, 349, 3,
+ 9, 0, 5, 7, 3, 9, 127, 1,
+ 11, 411, 11, 411, 11, 411, 127, 1,
+ 561, 45, 600, 603, 43, 597, 606, 0,
+ 5, 7, 561, 3, 9, 45, 600, 603,
+ 43, 597, 606, 0, 5, 7, 561, 3,
+ 9, 47, 615, 618, 43, 612, 621, 0,
+ 5, 7, 33, 480, 3, 9, 35, 492,
+ 495, 489, 498, 783, 0, 5, 7, 483,
+ 3, 9, 131, 133, 0, 135, 137, 0,
+ 139, 0, 141, 143, 0, 501, 129, 1,
+ 0, 0, 11, 411, 115, 113, 11, 411,
+ 11, 411, 11, 411, 561, 45, 600, 603,
+ 43, 597, 606, 0, 5, 7, 561, 3,
+ 9, 45, 600, 603, 43, 597, 606, 0,
+ 5, 7, 561, 3, 9, 47, 615, 618,
+ 43, 612, 621, 0, 5, 7, 33, 480,
+ 3, 9, 486, 115, 113, 11, 411, 11,
+ 411, 11, 411, 561, 45, 600, 603, 43,
+ 597, 606, 0, 5, 7, 561, 3, 9,
+ 45, 600, 603, 43, 597, 606, 0, 5,
+ 7, 561, 3, 9, 45, 600, 603, 43,
+ 597, 606, 0, 5, 7, 113, 3, 9,
+ 115, 0, 5, 7, 3, 9, 1, 366,
+ 387, 11, 411, 11, 411, 11, 411, 11,
+ 411, 561, 47, 615, 618, 43, 612, 621,
+ 0, 5, 7, 750, 3, 9, 2703, 103,
+ 11, 411, 561, 47, 615, 618, 43, 612,
+ 621, 0, 5, 7, 1989, 3, 9, 115,
+ 113, 115, 2767, 343, 113, 115, 113, 115,
+ 2971, 2967, 11, 411, 1986, 115, 2963, 341,
+ 113, 115, 2955, 1986, 115, 341, 113, 115,
+ 2959, 561, 47, 615, 618, 43, 612, 621,
+ 0, 5, 7, 561, 3, 9, 47, 615,
+ 618, 43, 612, 621, 73, 0, 5, 7,
+ 3, 9, 1, 11, 411, 11, 411, 561,
+ 45, 600, 603, 43, 597, 606, 477, 0,
+ 5, 7, 3, 9, 35, 492, 495, 489,
+ 498, 73, 0, 5, 7, 3, 9, 1,
+ 11, 411, 11, 411, 528, 525, 0, 2351,
+ 2355, 504, 414, 423, 2347, 2359, 525, 355,
+ 2187, 2195, 2987, 2995, 2159, 2203, 2979, 2983,
+ 3856, 3866, 2371, 525, 2187, 2195, 2675, 2675,
+ 2675, 2675, 2675, 2675, 2675, 2675, 2675, 2675,
+ 2675, 2675, 2675, 2675, 2675, 2159, 2203, 4011,
+ 4026, 4241, 4241, 4241, 4241, 4241, 4241, 4241,
+ 4241, 4241, 4241, 4241, 4241, 4241, 4241, 4241,
+ 2363, 2671, 91, 4226, 4231, 2667, 2659, 2663,
+ 4221, 4236, 2187, 2195, 2159, 2203, 429, 2251,
+ 2259, 3911, 2267, 429, 2183, 2191, 2199, 3861,
+ 5208, 5214, 5310, 5310, 5310, 5310, 5310, 5310,
+ 5310, 5310, 5310, 5310, 5310, 5310, 5310, 5310,
+ 5310, 3851
+};
+
+static const short _zone_scanner_eof_actions[] = {
+ 0, 2399, 2555, 361, 2007, 353, 1992, 15,
+ 15, 353, 353, 1992, 1992, 1992, 4031, 5292,
+ 2004, 361, 361, 2007, 1992, 1992, 361, 361,
+ 361, 361, 361, 2007, 2007, 361, 361, 2007,
+ 361, 361, 361, 2007, 361, 361, 361, 361,
+ 2007, 361, 361, 361, 2007, 361, 361, 361,
+ 2007, 2007, 361, 361, 361, 361, 2007, 361,
+ 2007, 361, 361, 361, 361, 2007, 361, 361,
+ 361, 361, 361, 361, 361, 361, 361, 361,
+ 2007, 361, 361, 2007, 2007, 361, 361, 2007,
+ 361, 2007, 361, 2007, 2007, 361, 361, 361,
+ 361, 2007, 2007, 361, 361, 361, 361, 2007,
+ 361, 2007, 2007, 361, 2007, 2007, 361, 361,
+ 361, 361, 2007, 361, 361, 2007, 361, 2007,
+ 361, 361, 361, 2007, 2007, 361, 361, 2007,
+ 361, 2007, 361, 2007, 361, 361, 361, 2007,
+ 361, 361, 361, 2007, 361, 2007, 361, 361,
+ 573, 2403, 361, 361, 2007, 361, 2399, 361,
+ 361, 573, 2555, 2555, 2555, 2555, 361, 15,
+ 93, 93, 93, 93, 93, 93, 93, 93,
+ 39, 573, 0, 4016, 573, 361, 2555, 2555,
+ 2555, 361, 2375, 2403, 2999, 1992, 2399, 15,
+ 1992, 15, 4031, 2999, 2999, 2999, 2999, 2999,
+ 2999, 2999, 2999, 2999, 2999, 2999, 2999, 2999,
+ 2999, 1992, 2975, 93, 93, 93, 93, 93,
+ 93, 93, 93, 93, 2367, 5361, 2399, 2004,
+ 4021, 4031, 4021, 4021, 4021, 4021, 4021, 4021,
+ 4021, 4021, 4021, 4021, 4021, 4021, 4021, 4021,
+ 531, 4031, 1992, 15, 1992, 1992, 361, 361,
+ 2007, 361, 361, 361, 2007, 361, 2007, 1992,
+ 1992, 15, 1992, 1992, 1992, 1992, 353, 4031,
+ 1992, 1992, 534, 534, 534, 534, 534, 534,
+ 534, 534, 534, 534, 534, 534, 534, 534,
+ 15, 2004, 534, 2004, 0, 0, 31, 31,
+ 31, 456, 456, 456, 456, 31, 31, 684,
+ 684, 2615, 2615, 2615, 2615, 684, 67, 2615,
+ 2615, 2615, 2615, 75, 564, 4201, 432, 432,
+ 4201, 2547, 4201, 75, 79, 79, 79, 435,
+ 435, 435, 459, 459, 459, 459, 435, 79,
+ 0, 83, 711, 717, 85, 717, 15, 15,
+ 462, 462, 462, 462, 717, 15, 85, 0,
+ 0, 125, 125, 125, 125, 125, 125, 125,
+ 325, 325, 325, 325, 325, 325, 325, 325,
+ 325, 325, 325, 325, 325, 325, 325, 325,
+ 325, 325, 325, 325, 325, 325, 325, 325,
+ 325, 325, 325, 325, 325, 325, 325, 325,
+ 325, 325, 325, 325, 325, 325, 325, 325,
+ 325, 325, 325, 325, 325, 325, 325, 325,
+ 325, 325, 325, 325, 325, 325, 325, 325,
+ 325, 325, 325, 325, 325, 325, 325, 325,
+ 325, 325, 325, 325, 325, 325, 325, 325,
+ 325, 325, 325, 325, 325, 325, 325, 325,
+ 325, 325, 325, 325, 325, 325, 325, 325,
+ 325, 325, 325, 325, 325, 325, 325, 325,
+ 325, 325, 325, 325, 325, 325, 325, 325,
+ 325, 325, 325, 325, 325, 325, 325, 325,
+ 325, 325, 325, 325, 325, 325, 325, 325,
+ 325, 325, 325, 325, 325, 325, 325, 325,
+ 325, 325, 325, 325, 339, 567, 567, 2763,
+ 2763, 2763, 2763, 339, 339, 339, 567, 567,
+ 2763, 2763, 2763, 2763, 339, 567, 339, 345,
+ 345, 345, 345, 345, 345, 345, 345, 345,
+ 345, 345, 345, 345, 345, 345, 345, 345,
+ 345, 345, 345, 345, 345, 345, 345, 345,
+ 345, 345, 345, 345, 345, 345, 345, 345,
+ 345, 345, 345, 345, 345, 345, 345, 345,
+ 345, 345, 345, 345, 345, 345, 345, 345,
+ 345, 345, 345, 345, 345, 345, 345, 345,
+ 345, 345, 345, 345, 345, 345, 345, 345,
+ 345, 345, 345, 345, 345, 345, 345, 345,
+ 345, 345, 345, 345, 345, 345, 345, 345,
+ 345, 345, 345, 345, 345, 345, 345, 345,
+ 345, 345, 345, 345, 345, 345, 345, 345,
+ 345, 345, 345, 345, 345, 345, 345, 347,
+ 347, 347, 347, 347, 347, 347, 347, 347,
+ 347, 347, 347, 347, 347, 347, 347, 347,
+ 347, 347, 347, 347, 347, 347, 347, 347,
+ 347, 347, 347, 347, 347, 347, 347, 347,
+ 347, 347, 347, 347, 347, 347, 347, 347,
+ 753, 753, 353, 353, 353, 353, 353, 353,
+ 570, 570, 570, 2551, 570, 2551, 570, 2551,
+ 570, 2551, 2551, 2551, 2551, 353, 2551, 2551,
+ 2551, 353, 2551, 2551, 2551, 353, 2551, 2551,
+ 2551, 353, 353, 353, 353, 353, 353, 353,
+ 353, 353, 353, 353, 353, 353, 570, 570,
+ 353, 353, 353, 699, 699, 699, 699, 753,
+ 753, 1983, 1983, 1983, 1983, 1983, 1983, 1983,
+ 1983, 1983, 1983, 1983, 1983, 1983, 1983, 1983,
+ 1983, 1983, 1983, 1983, 1983, 1983, 1983, 1983,
+ 1983, 1983, 1983, 1983, 1983, 1983, 1983, 1983,
+ 1983, 1983, 1983, 1983, 1983, 1983, 1983, 1983,
+ 1983, 1983, 1983, 1983, 1983, 1983, 1983, 1983,
+ 1983, 1983, 1983, 1983, 1983, 1983, 1983, 1983,
+ 570, 570, 570, 570, 570, 570, 353, 353,
+ 353, 353, 353, 570, 570, 570, 570, 353,
+ 353, 353, 353, 353, 353, 353, 353, 353,
+ 353, 353, 353, 353, 353, 353, 570, 570,
+ 353, 353, 353, 353, 353, 353, 353, 774,
+ 774, 774, 2695, 2695, 774, 774, 353, 774,
+ 2695, 2695, 570, 570, 353, 353, 570, 570,
+ 777, 777, 777, 777, 353, 353, 353, 570,
+ 570, 570, 570, 777, 777, 777, 777, 353,
+ 353, 570, 570, 864, 864, 2391, 2391, 864,
+ 2771, 867, 867, 867, 867, 867, 867, 867,
+ 864, 864, 864, 2391, 2391, 2699, 4251, 864,
+ 864, 864, 2391, 2391, 2699, 4251, 864, 864,
+ 864, 2391, 2391, 864, 2771, 864, 864, 353,
+ 870, 870, 353, 353, 570, 570, 570, 570,
+ 678, 678, 678, 678, 570, 570, 353, 353,
+ 353, 353, 353, 353, 353, 353, 353, 353,
+ 353, 353, 870, 870, 870, 870, 870, 870,
+ 870, 870, 870, 870, 870, 870, 870, 870,
+ 870, 870, 870, 870, 870, 870, 870, 870,
+ 870, 870, 870, 870, 870, 870, 870, 870,
+ 870, 870, 870, 870, 870, 870, 870, 870,
+ 870, 870, 870, 870, 870, 870, 870, 870,
+ 870, 870, 870, 870, 870, 870, 870, 870,
+ 870, 870, 870, 870, 870, 870, 870, 870,
+ 870, 870, 870, 870, 870, 870, 870, 870,
+ 870, 870, 870, 870, 870, 870, 870, 870,
+ 870, 870, 870, 870, 870, 870, 870, 870,
+ 870, 870, 870, 870, 870, 870, 870, 870,
+ 870, 870, 870, 870, 870, 870, 870, 870,
+ 870, 870, 870, 870, 870, 870, 870, 870,
+ 870, 870, 870, 870, 870, 870, 870, 870,
+ 870, 870, 870, 870, 870, 2395, 2395, 870,
+ 870, 870, 353, 353, 353, 570, 570, 570,
+ 570, 353, 353, 353, 353, 353, 353, 353,
+ 353, 353, 570, 570, 570, 570, 570, 570,
+ 777, 777, 783, 783, 783, 783, 783, 783,
+ 783, 783, 783, 353, 783, 783, 783, 783,
+ 783, 353, 777, 777, 353, 353, 353, 570,
+ 570, 570, 570, 570, 570, 777, 777, 777,
+ 777, 353, 353, 353, 570, 570, 570, 570,
+ 570, 570, 777, 777, 777, 777, 353, 353,
+ 353, 570, 570, 753, 753, 353, 570, 570,
+ 777, 777, 777, 777, 2767, 777, 777, 777,
+ 777, 2971, 353, 777, 777, 2963, 777, 777,
+ 2963, 777, 777, 2963, 777, 777, 2963, 570,
+ 570, 570, 570, 353, 353, 353, 353, 570,
+ 570, 353, 353, 353, 353, 353, 353, 0,
+ 0, 0, 0, 91, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0
+};
+
+
+
+
+
+
+__attribute__((visibility("default")))
+int zs_init(
+ zs_scanner_t *s,
+ const char *origin,
+ const uint16_t rclass,
+ const uint32_t ttl)
+{
+ if (s == NULL) {
+ return -1;
+ }
+
+ memset(s, 0, sizeof(*s));
+
+ // Nonzero initial scanner state.
+ s->cs = 1127;
+
+ // Reset the file descriptor.
+ s->file.descriptor = -1;
+
+ // Use the root zone as origin if not specified.
+ if (origin == NULL || strlen(origin) == 0) {
+ origin = ".";
+ }
+ size_t origin_len = strlen(origin);
+
+ // Prepare a zone settings header.
+ const char *format;
+ if (origin[origin_len - 1] != '.') {
+ format = "$ORIGIN %s.\n";
+ } else {
+ format = "$ORIGIN %s\n";
+ }
+
+ char settings[1024];
+ int ret = snprintf(settings, sizeof(settings), format, origin);
+ if (ret <= 0 || ret >= sizeof(settings)) {
+ ERR(ZS_ENOMEM);
+ return -1;
+ }
+
+ // Parse the settings to set up the scanner origin.
+ if (zs_set_input_string(s, settings, ret) != 0 ||
+ zs_parse_all(s) != 0) {
+ return -1;
+ }
+
+ // Set scanner defaults.
+ s->path = strdup(".");
+ if (s->path == NULL) {
+ ERR(ZS_ENOMEM);
+ return -1;
+ }
+ s->default_class = rclass;
+ s->default_ttl = ttl;
+ s->line_counter = 1;
+
+ s->state = ZS_STATE_NONE;
+ s->process.automatic = false;
+
+ return 0;
+}
+
+static void input_deinit(
+ zs_scanner_t *s,
+ bool keep_filename)
+{
+ // Deinit the file input.
+ if (s->file.descriptor != -1) {
+ // Unmap the file content.
+ if (s->input.start != NULL) {
+ if (s->input.mmaped) {
+ munmap((void *)s->input.start,
+ s->input.end - s->input.start);
+ } else {
+ free((void *)s->input.start);
+ }
+ }
+
+ // Close the opened file.
+ close(s->file.descriptor);
+ s->file.descriptor = -1;
+ }
+
+ // Keep file name for possible trailing error report.
+ if (!keep_filename) {
+ free(s->file.name);
+ s->file.name = NULL;
+ }
+
+ // Unset the input limits.
+ s->input.start = NULL;
+ s->input.current = NULL;
+ s->input.end = NULL;
+ s->input.eof = false;
+}
+
+__attribute__((visibility("default")))
+void zs_deinit(
+ zs_scanner_t *s)
+{
+ if (s == NULL) {
+ return;
+ }
+
+ input_deinit(s, false);
+ free(s->path);
+}
+
+static int set_input_string(
+ zs_scanner_t *s,
+ const char *input,
+ size_t size,
+ bool final_block)
+{
+ if (s == NULL) {
+ return -1;
+ }
+
+ if (input == NULL) {
+ ERR(ZS_EINVAL);
+ return -1;
+ }
+
+ // Deinit possibly opened file.
+ input_deinit(s, final_block);
+
+ // Set the scanner input limits.
+ s->input.start = input;
+ s->input.current = input;
+ s->input.end = input + size;
+ s->input.eof = final_block;
+
+ return 0;
+}
+
+static char *read_file_to_buf(
+ int fd,
+ size_t *bufsize)
+{
+ size_t bufs = 0, newbufs = 8192;
+ char *buf = malloc(bufs + newbufs);
+ int ret = 0;
+
+ while (buf != NULL && (ret = read(fd, buf + bufs, newbufs)) == newbufs) {
+ bufs += newbufs;
+ newbufs = bufs;
+ char *newbuf = realloc(buf, bufs + newbufs);
+ if (newbuf == NULL) {
+ free(buf);
+ }
+ buf = newbuf;
+ }
+ if (ret < 0) {
+ free(buf);
+ return NULL;
+ }
+
+ *bufsize = bufs + ret;
+ return buf;
+}
+
+__attribute__((visibility("default")))
+int zs_set_input_string(
+ zs_scanner_t *s,
+ const char *input,
+ size_t size)
+{
+ s->state = ZS_STATE_NONE;
+
+ return set_input_string(s, input, size, false);
+}
+
+__attribute__((visibility("default")))
+int zs_set_input_file(
+ zs_scanner_t *s,
+ const char *file_name)
+{
+ if (s == NULL) {
+ return -1;
+ }
+
+ if (file_name == NULL) {
+ ERR(ZS_EINVAL);
+ return -1;
+ }
+
+ // Deinit possibly opened file.
+ input_deinit(s, false);
+
+ // Try to open the file.
+ s->file.descriptor = open(file_name, O_RDONLY);
+ if (s->file.descriptor == -1) {
+ ERR(ZS_FILE_OPEN);
+ return -1;
+ }
+
+ char *start = NULL;
+ size_t size = 0;
+
+ // Check the input.
+ struct stat file_stat;
+ if (fstat(s->file.descriptor, &file_stat) == -1) {
+ ERR(ZS_FILE_INVALID);
+ input_deinit(s, false);
+ return -1;
+ } else if (S_ISCHR(file_stat.st_mode) ||
+ S_ISBLK(file_stat.st_mode) ||
+ S_ISFIFO(file_stat.st_mode)) {
+ // Workaround if cannot mmap, read to memory.
+ start = read_file_to_buf(s->file.descriptor, &size);
+ if (start == NULL) {
+ ERR(ZS_FILE_INVALID);
+ input_deinit(s, false);
+ return -1;
+ }
+ } else if (!S_ISREG(file_stat.st_mode)) { // Require regular file.
+ ERR(ZS_FILE_INVALID);
+ input_deinit(s, false);
+ return -1;
+ } else if (file_stat.st_size > 0) { // Mmap non-emtpy file.
+ start = mmap(0, file_stat.st_size, PROT_READ, MAP_SHARED,
+ s->file.descriptor, 0);
+ if (start == MAP_FAILED) {
+ ERR(ZS_FILE_INVALID);
+ input_deinit(s, false);
+ return -1;
+ }
+
+ size = file_stat.st_size;
+ s->input.mmaped = true;
+
+ // Try to set the mapped memory advise to sequential.
+ (void)madvise(start, size, MADV_SEQUENTIAL);
+ }
+
+ // Set the scanner input limits.
+ s->input.start = start;
+ s->input.current = start;
+ s->input.end = start + size;
+
+ // Get absolute path of the zone file if possible.
+ char *full_name = realpath(file_name, NULL);
+ if (full_name != NULL) {
+ free(s->path);
+ s->path = strdup(dirname(full_name));
+ free(full_name);
+ if (s->path == NULL) {
+ ERR(ZS_ENOMEM);
+ input_deinit(s, false);
+ return -1;
+ }
+ }
+
+ s->file.name = strdup(file_name);
+ if (s->file.name == NULL) {
+ ERR(ZS_ENOMEM);
+ input_deinit(s, false);
+ return -1;
+ }
+
+ s->state = ZS_STATE_NONE;
+
+ return 0;
+}
+
+__attribute__((visibility("default")))
+int zs_set_processing(
+ zs_scanner_t *s,
+ void (*process_record)(zs_scanner_t *),
+ void (*process_error)(zs_scanner_t *),
+ void *data)
+{
+ if (s == NULL) {
+ return -1;
+ }
+
+ s->process.record = process_record;
+ s->process.error = process_error;
+ s->process.data = data;
+
+ return 0;
+}
+
+typedef enum {
+ WRAP_NONE, // Initial state.
+ WRAP_DETECTED, // Input block end is a first '\' in rdata.
+ WRAP_PROCESS // Parsing of auxiliary block = "\".
+} wrap_t;
+
+static void parse(
+ zs_scanner_t *s,
+ wrap_t *wrap)
+{
+ // Restore scanner input limits (Ragel internals).
+ const char *p = s->input.current;
+ const char *pe = s->input.end;
+ const char *eof = s->input.eof ? pe : NULL;
+
+ // Restore state variables (Ragel internals).
+ int cs = s->cs;
+ int top = s->top;
+ int stack[ZS_RAGEL_STACK_SIZE];
+ memcpy(stack, s->stack, sizeof(stack));
+
+ // Next 2 variables are for better performance.
+ // Restoring r_data pointer to next free space.
+ uint8_t *rdata_tail = s->r_data + s->r_data_tail;
+ // Initialization of the last r_data byte.
+ uint8_t *rdata_stop = s->r_data + ZS_MAX_RDATA_LENGTH - 1;
+
+ // Write scanner body (in C).
+
+ {
+ int _klen;
+ unsigned int _trans;
+ short _widec;
+ const short *_acts;
+ unsigned int _nacts;
+ const short *_keys;
+
+ if ( p == pe )
+ goto _test_eof;
+ if ( cs == 0 )
+ goto _out;
+_resume:
+ _widec = (*p);
+ _klen = _zone_scanner_cond_lengths[cs];
+ _keys = _zone_scanner_cond_keys + (_zone_scanner_cond_offsets[cs]*2);
+ if ( _klen > 0 ) {
+ const short *_lower = _keys;
+ const short *_mid;
+ const short *_upper = _keys + (_klen<<1) - 2;
+ while (1) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + (((_upper-_lower) >> 1) & ~1);
+ if ( _widec < _mid[0] )
+ _upper = _mid - 2;
+ else if ( _widec > _mid[1] )
+ _lower = _mid + 2;
+ else {
+ switch ( _zone_scanner_cond_spaces[_zone_scanner_cond_offsets[cs] + ((_mid - _keys)>>1)] ) {
+ case 0: {
+ _widec = (short)(640 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ break;
+ }
+ case 1: {
+ _widec = (short)(1152 + ((*p) - -128));
+ if (
+ !s->multiline ) _widec += 256;
+ break;
+ }
+ case 2: {
+ _widec = (short)(128 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ break;
+ }
+ case 3: {
+ _widec = (short)(2688 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ break;
+ }
+ case 4: {
+ _widec = (short)(4224 + ((*p) - -128));
+ if (
+ s->number64 == 0 ) _widec += 256;
+ break;
+ }
+ case 5: {
+ _widec = (short)(1664 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ break;
+ }
+ case 6: {
+ _widec = (short)(3200 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ s->number64 != 0 ) _widec += 512;
+ break;
+ }
+ case 7: {
+ _widec = (short)(4736 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ break;
+ }
+ case 8: {
+ _widec = (short)(5760 + ((*p) - -128));
+ if (
+ s->number64 != 0 ) _widec += 256;
+ if (
+ s->number64 == 0 ) _widec += 512;
+ break;
+ }
+ case 9: {
+ _widec = (short)(12928 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ if (
+ s->number64 == 0 ) _widec += 1024;
+ break;
+ }
+ case 10: {
+ _widec = (short)(6784 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ s->number64 != 0 ) _widec += 512;
+ if (
+ s->number64 == 0 ) _widec += 1024;
+ break;
+ }
+ case 11: {
+ _widec = (short)(8832 + ((*p) - -128));
+ if (
+ s->multiline ) _widec += 256;
+ if (
+ !s->multiline ) _widec += 512;
+ if (
+ s->number64 != 0 ) _widec += 1024;
+ if (
+ s->number64 == 0 ) _widec += 2048;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ _keys = _zone_scanner_trans_keys + _zone_scanner_key_offsets[cs];
+ _trans = _zone_scanner_index_offsets[cs];
+
+ _klen = _zone_scanner_single_lengths[cs];
+ if ( _klen > 0 ) {
+ const short *_lower = _keys;
+ const short *_mid;
+ const short *_upper = _keys + _klen - 1;
+ while (1) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + ((_upper-_lower) >> 1);
+ if ( _widec < *_mid )
+ _upper = _mid - 1;
+ else if ( _widec > *_mid )
+ _lower = _mid + 1;
+ else {
+ _trans += (unsigned int)(_mid - _keys);
+ goto _match;
+ }
+ }
+ _keys += _klen;
+ _trans += _klen;
+ }
+
+ _klen = _zone_scanner_range_lengths[cs];
+ if ( _klen > 0 ) {
+ const short *_lower = _keys;
+ const short *_mid;
+ const short *_upper = _keys + (_klen<<1) - 2;
+ while (1) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + (((_upper-_lower) >> 1) & ~1);
+ if ( _widec < _mid[0] )
+ _upper = _mid - 2;
+ else if ( _widec > _mid[1] )
+ _lower = _mid + 2;
+ else {
+ _trans += (unsigned int)((_mid - _keys)>>1);
+ goto _match;
+ }
+ }
+ _trans += _klen;
+ }
+
+_match:
+ _trans = _zone_scanner_indicies[_trans];
+ cs = _zone_scanner_trans_targs[_trans];
+
+ if ( _zone_scanner_trans_actions[_trans] == 0 )
+ goto _again;
+
+ _acts = _zone_scanner_actions + _zone_scanner_trans_actions[_trans];
+ _nacts = (unsigned int) *_acts++;
+ while ( _nacts-- > 0 )
+ {
+ switch ( *_acts++ )
+ {
+ case 0:
+ {
+ p--; {cs = stack[--top]; goto _again;}
+ }
+ break;
+ case 1:
+ {
+ s->line_counter++;
+ }
+ break;
+ case 2:
+ {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ p--; {cs = 268;goto _again;}
+ }
+ s->multiline = true;
+ }
+ break;
+ case 3:
+ {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ p--; {cs = 268;goto _again;}
+ }
+ s->multiline = false;
+ }
+ break;
+ case 4:
+ {
+ s->buffer_length = 0;
+ }
+ break;
+ case 5:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ break;
+ case 6:
+ {
+ s->buffer[s->buffer_length++] = 0;
+ }
+ break;
+ case 7:
+ {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ break;
+ case 8:
+ {
+ WARN(ZS_BAD_REST);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 9:
+ {
+ s->buffer_length = 0;
+ }
+ break;
+ case 10:
+ {
+ if ((*p) == '\r') {
+ ERR(ZS_DOS_NEWLINE);
+ }
+
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ }
+ }
+ break;
+ case 11:
+ {
+ // Terminate the error context string.
+ s->buffer[s->buffer_length++] = 0;
+
+ // Error counter incrementation.
+ s->error.counter++;
+
+ // Initialize the fcall stack.
+ top = 0;
+
+ // Reset the multiline context.
+ s->multiline = false;
+
+ s->state = ZS_STATE_ERROR;
+
+ // Execute the error callback.
+ if (s->process.automatic) {
+ if (s->process.error != NULL) {
+ s->process.error(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; goto _out; }
+ }
+ }
+
+ // Stop the scanner if fatal error.
+ if (s->error.fatal) {
+ {p++; goto _out; }
+ }
+ {cs = 1127;goto _again;}
+ } else {
+ // Return if external processing.
+ p--; cs = 1127; {p++; goto _out; }
+ }
+ }
+ break;
+ case 12:
+ {
+ s->item_length = 0;
+ s->item_length_position = s->dname_tmp_length++;
+ }
+ break;
+ case 13:
+ {
+ // Check for maximum dname label length.
+ if (s->item_length < ZS_MAX_LABEL_LENGTH) {
+ (s->dname)[s->dname_tmp_length++] = (*p);
+ s->item_length++;
+ } else {
+ WARN(ZS_LABEL_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 14:
+ {
+ // Check for maximum dname length overflow after each label.
+ // (at least the next label length must follow).
+ if (s->dname_tmp_length < ZS_MAX_DNAME_LENGTH) {
+ (s->dname)[s->item_length_position] =
+ (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_DNAME_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 15:
+ {
+ if (s->item_length < ZS_MAX_LABEL_LENGTH) {
+ (s->dname)[s->dname_tmp_length] = 0;
+ s->item_length++;
+ } else {
+ WARN(ZS_LABEL_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 16:
+ {
+ (s->dname)[s->dname_tmp_length] *= 10;
+ (s->dname)[s->dname_tmp_length] += digit_to_num[(uint8_t)(*p)];
+ }
+ break;
+ case 17:
+ {
+ s->dname_tmp_length++;
+ }
+ break;
+ case 18:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 19:
+ {
+ // Enough room for the terminal label is guaranteed (_label_exit).
+ (s->dname)[s->dname_tmp_length++] = 0;
+ }
+ break;
+ case 20:
+ {
+ // Check for (relative + origin) dname length overflow.
+ if (s->dname_tmp_length + s->zone_origin_length <= ZS_MAX_DNAME_LENGTH) {
+ memcpy(s->dname + s->dname_tmp_length,
+ s->zone_origin,
+ s->zone_origin_length);
+
+ s->dname_tmp_length += s->zone_origin_length;
+ } else {
+ WARN(ZS_DNAME_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 21:
+ {
+ // Copy already verified zone origin.
+ memcpy(s->dname,
+ s->zone_origin,
+ s->zone_origin_length);
+
+ s->dname_tmp_length = s->zone_origin_length;
+ }
+ break;
+ case 22:
+ {
+ s->item_length_position = 0;
+ s->dname_tmp_length = 0;
+ }
+ break;
+ case 23:
+ {
+ WARN(ZS_BAD_DNAME_CHAR);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 24:
+ { p--; {stack[top++] = cs; cs = 270;goto _again;} }
+ break;
+ case 25:
+ {
+ if (rdata_tail <= rdata_stop) {
+ s->item_length_location = rdata_tail++;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 26:
+ {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 27:
+ {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ break;
+ case 28:
+ {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ break;
+ case 29:
+ {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 30:
+ {
+ s->r_owner_length = 0;
+ WARN(ZS_BAD_OWNER);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 31:
+ {
+ s->dname = rdata_tail;
+ }
+ break;
+ case 32:
+ {
+ rdata_tail += s->dname_tmp_length;
+ }
+ break;
+ case 33:
+ {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)(*p) <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 34:
+ {
+ s->number64 = 0;
+ }
+ break;
+ case 35:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 36:
+ {
+ s->decimal_counter = 0;
+ }
+ break;
+ case 37:
+ {
+ s->number64_tmp = s->number64;
+ }
+ break;
+ case 38:
+ {
+ s->decimal_counter++;
+ }
+ break;
+ case 39:
+ {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 40:
+ {
+ s->decimals = 2;
+ }
+ break;
+ case 41:
+ {
+ s->decimals = 3;
+ }
+ break;
+ case 42:
+ {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 43:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 44:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 45:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ s->r_type = (uint16_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 46:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ s->r_data_length = (uint16_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 47:
+ {
+ WARN(ZS_BAD_TIME_UNIT);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 48:
+ { if (s->number64 <= (UINT32_MAX / 60)) {
+ s->number64 *= 60;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 49:
+ { if (s->number64 <= (UINT32_MAX / 3600)) {
+ s->number64 *= 3600;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 50:
+ { if (s->number64 <= (UINT32_MAX / 86400)) {
+ s->number64 *= 86400;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 51:
+ { if (s->number64 <= (UINT32_MAX / 604800)) {
+ s->number64 *= 604800;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 52:
+ {
+ s->number64_tmp = s->number64;
+ }
+ break;
+ case 53:
+ {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 54:
+ {
+ s->buffer_length = 0;
+ }
+ break;
+ case 55:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 56:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (s->buffer_length == 14) { // Date; 14 = len("YYYYMMDDHHmmSS").
+ uint32_t timestamp;
+ int ret = date_to_timestamp(s->buffer, &timestamp);
+
+ if (ret == ZS_OK) {
+ *((uint32_t *)rdata_tail) = htonl(timestamp);
+ rdata_tail += 4;
+ } else {
+ WARN(ret);
+ p--; {cs = 268;goto _again;}
+ }
+ } else if (s->buffer_length <= 10) { // Timestamp format.
+ char *end;
+
+ s->number64 = strtoull((char *)(s->buffer), &end, 10);
+
+ if (end == (char *)(s->buffer) || *end != '\0') {
+ WARN(ZS_BAD_TIMESTAMP);
+ p--; {cs = 268;goto _again;}
+ }
+
+ if (s->number64 <= UINT32_MAX) {
+ *((uint32_t *)rdata_tail) = htonl((uint32_t)s->number64);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ } else {
+ WARN(ZS_BAD_TIMESTAMP_LENGTH);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 57:
+ {
+ WARN(ZS_BAD_TIMESTAMP_CHAR);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 58:
+ {
+ if (rdata_tail <= rdata_stop) {
+ // Split long string.
+ if (s->long_string &&
+ rdata_tail - s->item_length_location == 1 + MAX_ITEM_LENGTH) {
+ // _item_length_exit equivalent.
+ *(s->item_length_location) = MAX_ITEM_LENGTH;
+ // _item_length_init equivalent.
+ s->item_length_location = rdata_tail++;
+
+ if (rdata_tail > rdata_stop) {
+ WARN(ZS_TEXT_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+
+ *(rdata_tail++) = (*p);
+ } else {
+ WARN(ZS_TEXT_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 59:
+ {
+ WARN(ZS_BAD_TEXT_CHAR);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 60:
+ {
+ WARN(ZS_BAD_TEXT);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 61:
+ {
+ if (rdata_tail <= rdata_stop) {
+ // Split long string.
+ if (s->long_string &&
+ rdata_tail - s->item_length_location == 1 + MAX_ITEM_LENGTH) {
+ // _item_length_exit equivalent.
+ *(s->item_length_location) = MAX_ITEM_LENGTH;
+ // _item_length_init equivalent.
+ s->item_length_location = rdata_tail++;
+
+ if (rdata_tail > rdata_stop) {
+ WARN(ZS_TEXT_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+
+ *rdata_tail = 0;
+ s->item_length++;
+ } else {
+ WARN(ZS_TEXT_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 62:
+ {
+ if ((*rdata_tail < (UINT8_MAX / 10)) || // Dominant fast check.
+ ((*rdata_tail == (UINT8_MAX / 10)) && // Marginal case.
+ ((*p) <= (UINT8_MAX % 10) + '0')
+ )
+ ) {
+ *rdata_tail *= 10;
+ *rdata_tail += digit_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 63:
+ {
+ rdata_tail++;
+ }
+ break;
+ case 64:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 65:
+ { p--; {stack[top++] = cs; cs = 279;goto _again;} }
+ break;
+ case 66:
+ {
+ s->long_string = true;
+ }
+ break;
+ case 67:
+ {
+ s->long_string = false;
+ }
+ break;
+ case 68:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->default_ttl = (uint32_t)(s->number64);
+ } else {
+ ERR(ZS_NUMBER32_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 69:
+ {
+ ERR(ZS_BAD_TTL);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 70:
+ { p--; {stack[top++] = cs; cs = 291;goto _again;} }
+ break;
+ case 71:
+ {
+ s->dname = s->zone_origin;
+ }
+ break;
+ case 72:
+ {
+ s->zone_origin_length = s->dname_tmp_length;
+ }
+ break;
+ case 73:
+ {
+ ERR(ZS_BAD_ORIGIN);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 74:
+ { p--; {stack[top++] = cs; cs = 300;goto _again;} }
+ break;
+ case 75:
+ {
+ rdata_tail = s->r_data;
+ }
+ break;
+ case 76:
+ {
+ size_t len = rdata_tail - s->r_data;
+ if (len >= sizeof(s->include_filename)) {
+ ERR(ZS_BAD_INCLUDE_FILENAME);
+ p--; {cs = 268;goto _again;}
+ }
+
+ // Store zero terminated include filename.
+ memcpy(s->include_filename, s->r_data, len);
+ s->include_filename[len] = '\0';
+
+ // For detection whether origin is not present.
+ s->dname = NULL;
+ }
+ break;
+ case 77:
+ {
+ ERR(ZS_BAD_INCLUDE_FILENAME);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 78:
+ {
+ s->dname = s->r_data;
+ }
+ break;
+ case 79:
+ {
+ s->r_data_length = s->dname_tmp_length;
+ }
+ break;
+ case 80:
+ {
+ ERR(ZS_BAD_INCLUDE_ORIGIN);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 81:
+ {
+ // Extend relative file path.
+ if (s->include_filename[0] != '/') {
+ int ret = snprintf((char *)(s->buffer), sizeof(s->buffer),
+ "%s/%s", s->path, s->include_filename);
+ if (ret <= 0 || ret > sizeof(s->buffer)) {
+ ERR(ZS_BAD_INCLUDE_FILENAME);
+ p--; {cs = 268;goto _again;}
+ }
+ memcpy(s->include_filename, s->buffer, ret);
+ }
+
+ // Origin conversion from wire to text form in \DDD notation.
+ if (s->dname == NULL) { // Use current origin.
+ wire_dname_to_str(s->zone_origin,
+ s->zone_origin_length,
+ (char *)s->buffer);
+ } else { // Use specified origin.
+ wire_dname_to_str(s->r_data,
+ s->r_data_length,
+ (char *)s->buffer);
+ }
+
+ // Let the caller to solve the include.
+ if (s->process.automatic) {
+ // Create new scanner for included zone file.
+ zs_scanner_t *ss = malloc(sizeof(zs_scanner_t));
+ if (ss == NULL) {
+ ERR(ZS_UNPROCESSED_INCLUDE);
+ p--; {cs = 268;goto _again;}
+ }
+
+ // Parse included zone file.
+ if (zs_init(ss, (char *)s->buffer, s->default_class,
+ s->default_ttl) != 0 ||
+ zs_set_input_file(ss, (char *)(s->include_filename)) != 0 ||
+ zs_set_processing(ss, s->process.record, s->process.error,
+ s->process.data) != 0 ||
+ zs_parse_all(ss) != 0) {
+ // File internal errors are handled by error callback.
+ if (ss->error.counter > 0) {
+ s->error.counter += ss->error.counter;
+ ERR(ZS_UNPROCESSED_INCLUDE);
+ // General include file error.
+ } else {
+ ERR(ss->error.code);
+ }
+ zs_deinit(ss);
+ free(ss);
+ p--; {cs = 268;goto _again;}
+ }
+ zs_deinit(ss);
+ free(ss);
+ } else {
+ s->state = ZS_STATE_INCLUDE;
+ p--; cs = 1127; {p++; goto _out; }
+ }
+ }
+ break;
+ case 82:
+ { p--; {stack[top++] = cs; cs = 312;goto _again;} }
+ break;
+ case 83:
+ {
+ ERR(ZS_OK);
+ }
+ break;
+ case 84:
+ {
+ NOERR;
+ }
+ break;
+ case 85:
+ {
+ ERR(ZS_BAD_DIRECTIVE);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 86:
+ {
+ s->r_class = s->default_class;
+ }
+ break;
+ case 87:
+ {
+ s->r_ttl = s->default_ttl;
+ }
+ break;
+ case 88:
+ {
+ s->r_class = KNOT_CLASS_IN;
+ }
+ break;
+ case 89:
+ {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 90:
+ {
+ s->buffer_length = 0;
+ }
+ break;
+ case 91:
+ {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = (*p);
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 92:
+ {
+ WARN(ZS_BAD_ADDRESS_CHAR);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 93:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV4);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 94:
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET4_ADDR_LENGTH);
+ rdata_tail += ZS_INET4_ADDR_LENGTH;
+ }
+ break;
+ case 95:
+ {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET6, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV6);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 96:
+ {
+ memcpy(rdata_tail, s->addr, ZS_INET6_ADDR_LENGTH);
+ rdata_tail += ZS_INET6_ADDR_LENGTH;
+ }
+ break;
+ case 97:
+ {
+ memset(&(s->apl), 0, sizeof(s->apl));
+ }
+ break;
+ case 98:
+ {
+ s->apl.excl_flag = 128; // dec 128 = bin 10000000.
+ }
+ break;
+ case 99:
+ {
+ s->apl.addr_family = 1;
+ }
+ break;
+ case 100:
+ {
+ s->apl.addr_family = 2;
+ }
+ break;
+ case 101:
+ {
+ if ((s->apl.addr_family == 1 && s->number64 <= 32) ||
+ (s->apl.addr_family == 2 && s->number64 <= 128)) {
+ s->apl.prefix_length = (uint8_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_APL);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 102:
+ {
+ // Copy address to buffer.
+ uint8_t len;
+ switch (s->apl.addr_family) {
+ case 1:
+ len = ZS_INET4_ADDR_LENGTH;
+ memcpy(s->buffer, s->addr, len);
+ break;
+ case 2:
+ len = ZS_INET6_ADDR_LENGTH;
+ memcpy(s->buffer, s->addr, len);
+ break;
+ default:
+ WARN(ZS_BAD_APL);
+ p--; {cs = 268;goto _again;}
+ }
+ // Find prefix without trailing zeroes.
+ while (len > 0) {
+ if ((s->buffer[len - 1] & 255) != 0) {
+ break;
+ }
+ len--;
+ }
+ // Check for rdata overflow.
+ if (rdata_tail + 4 + len > rdata_stop) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ // Write address family.
+ *((uint16_t *)rdata_tail) = htons(s->apl.addr_family);
+ rdata_tail += 2;
+ // Write prefix length in bits.
+ *(rdata_tail) = s->apl.prefix_length;
+ rdata_tail += 1;
+ // Write negation flag + prefix length in bytes.
+ *(rdata_tail) = len + s->apl.excl_flag;
+ rdata_tail += 1;
+ // Write address prefix non-null data.
+ memcpy(rdata_tail, s->buffer, len);
+ rdata_tail += len;
+ }
+ break;
+ case 103:
+ {
+ WARN(ZS_BAD_APL);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 104:
+ {
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = first_hex_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 105:
+ {
+ *rdata_tail += second_hex_to_num[(uint8_t)(*p)];
+ rdata_tail++;
+ }
+ break;
+ case 106:
+ {
+ WARN(ZS_BAD_HEX_CHAR);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 107:
+ {
+ if ((rdata_tail - s->r_data) != s->r_data_length) {
+ WARN(ZS_BAD_RDATA_LENGTH);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 108:
+ {
+ WARN(ZS_BAD_HEX_RDATA);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 109:
+ {
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = first_base64_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 110:
+ {
+ *(rdata_tail++) += second_left_base64_to_num[(uint8_t)(*p)];
+
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = second_right_base64_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 111:
+ {
+ *(rdata_tail++) += third_left_base64_to_num[(uint8_t)(*p)];
+
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = third_right_base64_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 112:
+ {
+ *(rdata_tail++) += fourth_base64_to_num[(uint8_t)(*p)];
+ }
+ break;
+ case 113:
+ {
+ WARN(ZS_BAD_BASE64_CHAR);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 114:
+ { p--; {stack[top++] = cs; cs = 329;goto _again;} }
+ break;
+ case 115:
+ {
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = first_base32hex_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 116:
+ {
+ *(rdata_tail++) += second_left_base32hex_to_num[(uint8_t)(*p)];
+
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = second_right_base32hex_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 117:
+ {
+ *rdata_tail += third_base32hex_to_num[(uint8_t)(*p)];
+ }
+ break;
+ case 118:
+ {
+ *(rdata_tail++) += fourth_left_base32hex_to_num[(uint8_t)(*p)];
+
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = fourth_right_base32hex_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 119:
+ {
+ *(rdata_tail++) += fifth_left_base32hex_to_num[(uint8_t)(*p)];
+
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = fifth_right_base32hex_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 120:
+ {
+ *rdata_tail += sixth_base32hex_to_num[(uint8_t)(*p)];
+ }
+ break;
+ case 121:
+ {
+ *(rdata_tail++) += seventh_left_base32hex_to_num[(uint8_t)(*p)];
+
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = seventh_right_base32hex_to_num[(uint8_t)(*p)];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 122:
+ {
+ *(rdata_tail++) += eighth_base32hex_to_num[(uint8_t)(*p)];
+ }
+ break;
+ case 123:
+ {
+ WARN(ZS_BAD_BASE32HEX_CHAR);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 124:
+ {
+ *(rdata_tail++) = 0;
+ }
+ break;
+ case 125:
+ {
+ *(rdata_tail++) = 1;
+ }
+ break;
+ case 126:
+ {
+ *(rdata_tail++) = 2;
+ }
+ break;
+ case 127:
+ {
+ *(rdata_tail++) = 3;
+ }
+ break;
+ case 128:
+ {
+ *(rdata_tail++) = 5;
+ }
+ break;
+ case 129:
+ {
+ *(rdata_tail++) = 6;
+ }
+ break;
+ case 130:
+ {
+ *(rdata_tail++) = 7;
+ }
+ break;
+ case 131:
+ {
+ *(rdata_tail++) = 8;
+ }
+ break;
+ case 132:
+ {
+ *(rdata_tail++) = 10;
+ }
+ break;
+ case 133:
+ {
+ *(rdata_tail++) = 12;
+ }
+ break;
+ case 134:
+ {
+ *(rdata_tail++) = 13;
+ }
+ break;
+ case 135:
+ {
+ *(rdata_tail++) = 14;
+ }
+ break;
+ case 136:
+ {
+ *(rdata_tail++) = 15;
+ }
+ break;
+ case 137:
+ {
+ *(rdata_tail++) = 16;
+ }
+ break;
+ case 138:
+ {
+ *(rdata_tail++) = 252;
+ }
+ break;
+ case 139:
+ {
+ *(rdata_tail++) = 253;
+ }
+ break;
+ case 140:
+ {
+ *(rdata_tail++) = 254;
+ }
+ break;
+ case 141:
+ {
+ *((uint16_t *)rdata_tail) = htons(1);
+ rdata_tail += 2;
+ }
+ break;
+ case 142:
+ {
+ *((uint16_t *)rdata_tail) = htons(2);
+ rdata_tail += 2;
+ }
+ break;
+ case 143:
+ {
+ *((uint16_t *)rdata_tail) = htons(3);
+ rdata_tail += 2;
+ }
+ break;
+ case 144:
+ {
+ *((uint16_t *)rdata_tail) = htons(4);
+ rdata_tail += 2;
+ }
+ break;
+ case 145:
+ {
+ *((uint16_t *)rdata_tail) = htons(5);
+ rdata_tail += 2;
+ }
+ break;
+ case 146:
+ {
+ *((uint16_t *)rdata_tail) = htons(6);
+ rdata_tail += 2;
+ }
+ break;
+ case 147:
+ {
+ *((uint16_t *)rdata_tail) = htons(7);
+ rdata_tail += 2;
+ }
+ break;
+ case 148:
+ {
+ *((uint16_t *)rdata_tail) = htons(8);
+ rdata_tail += 2;
+ }
+ break;
+ case 149:
+ {
+ *((uint16_t *)rdata_tail) = htons(253);
+ rdata_tail += 2;
+ }
+ break;
+ case 150:
+ {
+ *((uint16_t *)rdata_tail) = htons(254);
+ rdata_tail += 2;
+ }
+ break;
+ case 151:
+ {
+ WARN(ZS_BAD_GATEWAY);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 152:
+ {
+ WARN(ZS_BAD_GATEWAY_KEY);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 153:
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 154:
+ { type_num(KNOT_RRTYPE_A, &rdata_tail); }
+ break;
+ case 155:
+ { type_num(KNOT_RRTYPE_NS, &rdata_tail); }
+ break;
+ case 156:
+ { type_num(KNOT_RRTYPE_CNAME, &rdata_tail); }
+ break;
+ case 157:
+ { type_num(KNOT_RRTYPE_SOA, &rdata_tail); }
+ break;
+ case 158:
+ { type_num(KNOT_RRTYPE_PTR, &rdata_tail); }
+ break;
+ case 159:
+ { type_num(KNOT_RRTYPE_HINFO, &rdata_tail); }
+ break;
+ case 160:
+ { type_num(KNOT_RRTYPE_MINFO, &rdata_tail); }
+ break;
+ case 161:
+ { type_num(KNOT_RRTYPE_MX, &rdata_tail); }
+ break;
+ case 162:
+ { type_num(KNOT_RRTYPE_TXT, &rdata_tail); }
+ break;
+ case 163:
+ { type_num(KNOT_RRTYPE_RP, &rdata_tail); }
+ break;
+ case 164:
+ { type_num(KNOT_RRTYPE_AFSDB, &rdata_tail); }
+ break;
+ case 165:
+ { type_num(KNOT_RRTYPE_RT, &rdata_tail); }
+ break;
+ case 166:
+ { type_num(KNOT_RRTYPE_KEY, &rdata_tail); }
+ break;
+ case 167:
+ { type_num(KNOT_RRTYPE_AAAA, &rdata_tail); }
+ break;
+ case 168:
+ { type_num(KNOT_RRTYPE_LOC, &rdata_tail); }
+ break;
+ case 169:
+ { type_num(KNOT_RRTYPE_SRV, &rdata_tail); }
+ break;
+ case 170:
+ { type_num(KNOT_RRTYPE_NAPTR, &rdata_tail); }
+ break;
+ case 171:
+ { type_num(KNOT_RRTYPE_KX, &rdata_tail); }
+ break;
+ case 172:
+ { type_num(KNOT_RRTYPE_CERT, &rdata_tail); }
+ break;
+ case 173:
+ { type_num(KNOT_RRTYPE_DNAME, &rdata_tail); }
+ break;
+ case 174:
+ { type_num(KNOT_RRTYPE_APL, &rdata_tail); }
+ break;
+ case 175:
+ { type_num(KNOT_RRTYPE_DS, &rdata_tail); }
+ break;
+ case 176:
+ { type_num(KNOT_RRTYPE_SSHFP, &rdata_tail); }
+ break;
+ case 177:
+ { type_num(KNOT_RRTYPE_IPSECKEY, &rdata_tail); }
+ break;
+ case 178:
+ { type_num(KNOT_RRTYPE_RRSIG, &rdata_tail); }
+ break;
+ case 179:
+ { type_num(KNOT_RRTYPE_NSEC, &rdata_tail); }
+ break;
+ case 180:
+ { type_num(KNOT_RRTYPE_DNSKEY, &rdata_tail); }
+ break;
+ case 181:
+ { type_num(KNOT_RRTYPE_DHCID, &rdata_tail); }
+ break;
+ case 182:
+ { type_num(KNOT_RRTYPE_NSEC3, &rdata_tail); }
+ break;
+ case 183:
+ { type_num(KNOT_RRTYPE_NSEC3PARAM, &rdata_tail); }
+ break;
+ case 184:
+ { type_num(KNOT_RRTYPE_TLSA, &rdata_tail); }
+ break;
+ case 185:
+ { type_num(KNOT_RRTYPE_CDS, &rdata_tail); }
+ break;
+ case 186:
+ { type_num(KNOT_RRTYPE_CDNSKEY, &rdata_tail); }
+ break;
+ case 187:
+ { type_num(KNOT_RRTYPE_SPF, &rdata_tail); }
+ break;
+ case 188:
+ { type_num(KNOT_RRTYPE_NID, &rdata_tail); }
+ break;
+ case 189:
+ { type_num(KNOT_RRTYPE_L32, &rdata_tail); }
+ break;
+ case 190:
+ { type_num(KNOT_RRTYPE_L64, &rdata_tail); }
+ break;
+ case 191:
+ { type_num(KNOT_RRTYPE_LP, &rdata_tail); }
+ break;
+ case 192:
+ { type_num(KNOT_RRTYPE_EUI48, &rdata_tail); }
+ break;
+ case 193:
+ { type_num(KNOT_RRTYPE_EUI64, &rdata_tail); }
+ break;
+ case 194:
+ { type_num(KNOT_RRTYPE_URI, &rdata_tail); }
+ break;
+ case 195:
+ { type_num(KNOT_RRTYPE_CAA, &rdata_tail); }
+ break;
+ case 196:
+ {
+ if (s->number64 <= UINT16_MAX) {
+ window_add_bit(s->number64, s);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 197:
+ { window_add_bit(KNOT_RRTYPE_A, s); }
+ break;
+ case 198:
+ { window_add_bit(KNOT_RRTYPE_NS, s); }
+ break;
+ case 199:
+ { window_add_bit(KNOT_RRTYPE_CNAME, s); }
+ break;
+ case 200:
+ { window_add_bit(KNOT_RRTYPE_SOA, s); }
+ break;
+ case 201:
+ { window_add_bit(KNOT_RRTYPE_PTR, s); }
+ break;
+ case 202:
+ { window_add_bit(KNOT_RRTYPE_HINFO, s); }
+ break;
+ case 203:
+ { window_add_bit(KNOT_RRTYPE_MINFO, s); }
+ break;
+ case 204:
+ { window_add_bit(KNOT_RRTYPE_MX, s); }
+ break;
+ case 205:
+ { window_add_bit(KNOT_RRTYPE_TXT, s); }
+ break;
+ case 206:
+ { window_add_bit(KNOT_RRTYPE_RP, s); }
+ break;
+ case 207:
+ { window_add_bit(KNOT_RRTYPE_AFSDB, s); }
+ break;
+ case 208:
+ { window_add_bit(KNOT_RRTYPE_RT, s); }
+ break;
+ case 209:
+ { window_add_bit(KNOT_RRTYPE_KEY, s); }
+ break;
+ case 210:
+ { window_add_bit(KNOT_RRTYPE_AAAA, s); }
+ break;
+ case 211:
+ { window_add_bit(KNOT_RRTYPE_LOC, s); }
+ break;
+ case 212:
+ { window_add_bit(KNOT_RRTYPE_SRV, s); }
+ break;
+ case 213:
+ { window_add_bit(KNOT_RRTYPE_NAPTR, s); }
+ break;
+ case 214:
+ { window_add_bit(KNOT_RRTYPE_KX, s); }
+ break;
+ case 215:
+ { window_add_bit(KNOT_RRTYPE_CERT, s); }
+ break;
+ case 216:
+ { window_add_bit(KNOT_RRTYPE_DNAME, s); }
+ break;
+ case 217:
+ { window_add_bit(KNOT_RRTYPE_APL, s); }
+ break;
+ case 218:
+ { window_add_bit(KNOT_RRTYPE_DS, s); }
+ break;
+ case 219:
+ { window_add_bit(KNOT_RRTYPE_SSHFP, s); }
+ break;
+ case 220:
+ { window_add_bit(KNOT_RRTYPE_IPSECKEY, s); }
+ break;
+ case 221:
+ { window_add_bit(KNOT_RRTYPE_RRSIG, s); }
+ break;
+ case 222:
+ { window_add_bit(KNOT_RRTYPE_NSEC, s); }
+ break;
+ case 223:
+ { window_add_bit(KNOT_RRTYPE_DNSKEY, s); }
+ break;
+ case 224:
+ { window_add_bit(KNOT_RRTYPE_DHCID, s); }
+ break;
+ case 225:
+ { window_add_bit(KNOT_RRTYPE_NSEC3, s); }
+ break;
+ case 226:
+ { window_add_bit(KNOT_RRTYPE_NSEC3PARAM, s); }
+ break;
+ case 227:
+ { window_add_bit(KNOT_RRTYPE_TLSA, s); }
+ break;
+ case 228:
+ { window_add_bit(KNOT_RRTYPE_CDS, s); }
+ break;
+ case 229:
+ { window_add_bit(KNOT_RRTYPE_CDNSKEY, s); }
+ break;
+ case 230:
+ { window_add_bit(KNOT_RRTYPE_SPF, s); }
+ break;
+ case 231:
+ { window_add_bit(KNOT_RRTYPE_NID, s); }
+ break;
+ case 232:
+ { window_add_bit(KNOT_RRTYPE_L32, s); }
+ break;
+ case 233:
+ { window_add_bit(KNOT_RRTYPE_L64, s); }
+ break;
+ case 234:
+ { window_add_bit(KNOT_RRTYPE_LP, s); }
+ break;
+ case 235:
+ { window_add_bit(KNOT_RRTYPE_EUI48, s); }
+ break;
+ case 236:
+ { window_add_bit(KNOT_RRTYPE_EUI64, s); }
+ break;
+ case 237:
+ { window_add_bit(KNOT_RRTYPE_URI, s); }
+ break;
+ case 238:
+ { window_add_bit(KNOT_RRTYPE_CAA, s); }
+ break;
+ case 239:
+ {
+ memset(s->windows, 0, sizeof(s->windows));
+ s->last_window = -1;
+ }
+ break;
+ case 240:
+ {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ }
+ }
+ break;
+ case 241:
+ {
+ WARN(ZS_BAD_BITMAP);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 242:
+ { p--; {stack[top++] = cs; cs = 336;goto _again;} }
+ break;
+ case 243:
+ {
+ if (s->number64 <= 90) {
+ s->loc.d1 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 244:
+ {
+ if (s->number64 <= 180) {
+ s->loc.d2 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 245:
+ {
+ if (s->number64 <= 59) {
+ s->loc.m1 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 246:
+ {
+ if (s->number64 <= 59) {
+ s->loc.m2 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 247:
+ {
+ if (s->number64 <= 59999) {
+ s->loc.s1 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 248:
+ {
+ if (s->number64 <= 59999) {
+ s->loc.s2 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 249:
+ {
+ if ((s->loc.alt_sign == 1 && s->number64 <= 4284967295) ||
+ (s->loc.alt_sign == -1 && s->number64 <= 10000000))
+ {
+ s->loc.alt = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 250:
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.siz = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 251:
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.hp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 252:
+ {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.vp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 253:
+ {
+ s->loc.lat_sign = -1;
+ }
+ break;
+ case 254:
+ {
+ s->loc.long_sign = -1;
+ }
+ break;
+ case 255:
+ {
+ s->loc.alt_sign = -1;
+ }
+ break;
+ case 256:
+ {
+ memset(&(s->loc), 0, sizeof(s->loc));
+ // Defaults.
+ s->loc.siz = 100;
+ s->loc.vp = 1000;
+ s->loc.hp = 1000000;
+ s->loc.lat_sign = 1;
+ s->loc.long_sign = 1;
+ s->loc.alt_sign = 1;
+ }
+ break;
+ case 257:
+ {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ break;
+ case 258:
+ {
+ WARN(ZS_BAD_LOC_DATA);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 259:
+ {
+ WARN(ZS_BAD_HEX_RDATA);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 260:
+ {
+ s->item_length = 0;
+ }
+ break;
+ case 261:
+ {
+ s->item_length++;
+ }
+ break;
+ case 262:
+ {
+ if (s->item_length != 6) {
+ WARN(ZS_BAD_EUI_LENGTH);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 263:
+ {
+ if (s->item_length != 8) {
+ WARN(ZS_BAD_EUI_LENGTH);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 264:
+ {
+ WARN(ZS_BAD_CHAR_DASH);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 265:
+ {
+ s->item_length = 0;
+ }
+ break;
+ case 266:
+ {
+ s->item_length++;
+ }
+ break;
+ case 267:
+ {
+ if (s->item_length != 4) {
+ WARN(ZS_BAD_L64_LENGTH);
+ p--; {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 268:
+ {
+ WARN(ZS_BAD_CHAR_COLON);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 269:
+ {
+ WARN(ZS_BAD_ALGORITHM);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 270:
+ {
+ WARN(ZS_BAD_CERT_TYPE);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 271:
+ { p--; {stack[top++] = cs; cs = 487;goto _again;} }
+ break;
+ case 272:
+ { p--; {stack[top++] = cs; cs = 591;goto _again;} }
+ break;
+ case 273:
+ {
+ rdata_tail = s->r_data;
+ }
+ break;
+ case 274:
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 275:
+ {
+ p--;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ {stack[top++] = cs; cs = 632;goto _again;}
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ {stack[top++] = cs; cs = 634;goto _again;}
+ case KNOT_RRTYPE_SOA:
+ {stack[top++] = cs; cs = 636;goto _again;}
+ case KNOT_RRTYPE_HINFO:
+ {stack[top++] = cs; cs = 668;goto _again;}
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ {stack[top++] = cs; cs = 673;goto _again;}
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ {stack[top++] = cs; cs = 678;goto _again;}
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ {stack[top++] = cs; cs = 683;goto _again;}
+ case KNOT_RRTYPE_AAAA:
+ {stack[top++] = cs; cs = 687;goto _again;}
+ case KNOT_RRTYPE_LOC:
+ {stack[top++] = cs; cs = 689;goto _again;}
+ case KNOT_RRTYPE_SRV:
+ {stack[top++] = cs; cs = 744;goto _again;}
+ case KNOT_RRTYPE_NAPTR:
+ {stack[top++] = cs; cs = 755;goto _again;}
+ case KNOT_RRTYPE_CERT:
+ {stack[top++] = cs; cs = 772;goto _again;}
+ case KNOT_RRTYPE_APL:
+ {stack[top++] = cs; cs = 783;goto _again;}
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ {stack[top++] = cs; cs = 794;goto _again;}
+ case KNOT_RRTYPE_SSHFP:
+ {stack[top++] = cs; cs = 807;goto _again;}
+ case KNOT_RRTYPE_IPSECKEY:
+ {stack[top++] = cs; cs = 817;goto _again;}
+ case KNOT_RRTYPE_RRSIG:
+ {stack[top++] = cs; cs = 856;goto _again;}
+ case KNOT_RRTYPE_NSEC:
+ {stack[top++] = cs; cs = 1010;goto _again;}
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ {stack[top++] = cs; cs = 1013;goto _again;}
+ case KNOT_RRTYPE_DHCID:
+ {stack[top++] = cs; cs = 1024;goto _again;}
+ case KNOT_RRTYPE_NSEC3:
+ {stack[top++] = cs; cs = 1026;goto _again;}
+ case KNOT_RRTYPE_NSEC3PARAM:
+ {stack[top++] = cs; cs = 1055;goto _again;}
+ case KNOT_RRTYPE_TLSA:
+ {stack[top++] = cs; cs = 1068;goto _again;}
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ {stack[top++] = cs; cs = 1086;goto _again;}
+ case KNOT_RRTYPE_L32:
+ {stack[top++] = cs; cs = 1081;goto _again;}
+ case KNOT_RRTYPE_EUI48:
+ {stack[top++] = cs; cs = 1099;goto _again;}
+ case KNOT_RRTYPE_EUI64:
+ {stack[top++] = cs; cs = 1105;goto _again;}
+ case KNOT_RRTYPE_URI:
+ {stack[top++] = cs; cs = 1111;goto _again;}
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = cs; cs = 1119;goto _again;}
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ {cs = 268;goto _again;}
+ }
+ }
+ break;
+ case 276:
+ {
+ switch (s->r_type) {
+ // Next types must not have empty rdata.
+ case KNOT_RRTYPE_A:
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ case KNOT_RRTYPE_SOA:
+ case KNOT_RRTYPE_HINFO:
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ case KNOT_RRTYPE_RP:
+ case KNOT_RRTYPE_AAAA:
+ case KNOT_RRTYPE_LOC:
+ case KNOT_RRTYPE_SRV:
+ case KNOT_RRTYPE_NAPTR:
+ case KNOT_RRTYPE_CERT:
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_SSHFP:
+ case KNOT_RRTYPE_IPSECKEY:
+ case KNOT_RRTYPE_RRSIG:
+ case KNOT_RRTYPE_NSEC:
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_DHCID:
+ case KNOT_RRTYPE_NSEC3:
+ case KNOT_RRTYPE_NSEC3PARAM:
+ case KNOT_RRTYPE_TLSA:
+ case KNOT_RRTYPE_CDS:
+ case KNOT_RRTYPE_CDNSKEY:
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L32:
+ case KNOT_RRTYPE_L64:
+ case KNOT_RRTYPE_LP:
+ case KNOT_RRTYPE_EUI48:
+ case KNOT_RRTYPE_EUI64:
+ case KNOT_RRTYPE_URI:
+ case KNOT_RRTYPE_CAA:
+ {stack[top++] = cs; cs = 468;goto _again;}
+ // Next types can have empty rdata.
+ case KNOT_RRTYPE_APL:
+ default:
+ {stack[top++] = cs; cs = 477;goto _again;}
+ }
+ }
+ break;
+ case 277:
+ {
+ if (pe - p == 1) {
+ *wrap = WRAP_DETECTED;
+ }
+ }
+ break;
+ case 278:
+ {
+ if (*wrap == WRAP_NONE) {
+ p--;
+ }
+ }
+ break;
+ case 279:
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; {cs = 268;goto _again;}
+ }
+ break;
+ case 280:
+ { s->r_type = KNOT_RRTYPE_A; }
+ break;
+ case 281:
+ { s->r_type = KNOT_RRTYPE_NS; }
+ break;
+ case 282:
+ { s->r_type = KNOT_RRTYPE_CNAME; }
+ break;
+ case 283:
+ { s->r_type = KNOT_RRTYPE_SOA; }
+ break;
+ case 284:
+ { s->r_type = KNOT_RRTYPE_PTR; }
+ break;
+ case 285:
+ { s->r_type = KNOT_RRTYPE_HINFO; }
+ break;
+ case 286:
+ { s->r_type = KNOT_RRTYPE_MINFO; }
+ break;
+ case 287:
+ { s->r_type = KNOT_RRTYPE_MX; }
+ break;
+ case 288:
+ { s->r_type = KNOT_RRTYPE_TXT; }
+ break;
+ case 289:
+ { s->r_type = KNOT_RRTYPE_RP; }
+ break;
+ case 290:
+ { s->r_type = KNOT_RRTYPE_AFSDB; }
+ break;
+ case 291:
+ { s->r_type = KNOT_RRTYPE_RT; }
+ break;
+ case 292:
+ { s->r_type = KNOT_RRTYPE_KEY; }
+ break;
+ case 293:
+ { s->r_type = KNOT_RRTYPE_AAAA; }
+ break;
+ case 294:
+ { s->r_type = KNOT_RRTYPE_LOC; }
+ break;
+ case 295:
+ { s->r_type = KNOT_RRTYPE_SRV; }
+ break;
+ case 296:
+ { s->r_type = KNOT_RRTYPE_NAPTR; }
+ break;
+ case 297:
+ { s->r_type = KNOT_RRTYPE_KX; }
+ break;
+ case 298:
+ { s->r_type = KNOT_RRTYPE_CERT; }
+ break;
+ case 299:
+ { s->r_type = KNOT_RRTYPE_DNAME; }
+ break;
+ case 300:
+ { s->r_type = KNOT_RRTYPE_APL; }
+ break;
+ case 301:
+ { s->r_type = KNOT_RRTYPE_DS; }
+ break;
+ case 302:
+ { s->r_type = KNOT_RRTYPE_SSHFP; }
+ break;
+ case 303:
+ { s->r_type = KNOT_RRTYPE_IPSECKEY; }
+ break;
+ case 304:
+ { s->r_type = KNOT_RRTYPE_RRSIG; }
+ break;
+ case 305:
+ { s->r_type = KNOT_RRTYPE_NSEC; }
+ break;
+ case 306:
+ { s->r_type = KNOT_RRTYPE_DNSKEY; }
+ break;
+ case 307:
+ { s->r_type = KNOT_RRTYPE_DHCID; }
+ break;
+ case 308:
+ { s->r_type = KNOT_RRTYPE_NSEC3; }
+ break;
+ case 309:
+ { s->r_type = KNOT_RRTYPE_NSEC3PARAM; }
+ break;
+ case 310:
+ { s->r_type = KNOT_RRTYPE_TLSA; }
+ break;
+ case 311:
+ { s->r_type = KNOT_RRTYPE_CDS; }
+ break;
+ case 312:
+ { s->r_type = KNOT_RRTYPE_CDNSKEY; }
+ break;
+ case 313:
+ { s->r_type = KNOT_RRTYPE_SPF; }
+ break;
+ case 314:
+ { s->r_type = KNOT_RRTYPE_NID; }
+ break;
+ case 315:
+ { s->r_type = KNOT_RRTYPE_L32; }
+ break;
+ case 316:
+ { s->r_type = KNOT_RRTYPE_L64; }
+ break;
+ case 317:
+ { s->r_type = KNOT_RRTYPE_LP; }
+ break;
+ case 318:
+ { s->r_type = KNOT_RRTYPE_EUI48; }
+ break;
+ case 319:
+ { s->r_type = KNOT_RRTYPE_EUI64; }
+ break;
+ case 320:
+ { s->r_type = KNOT_RRTYPE_URI; }
+ break;
+ case 321:
+ { s->r_type = KNOT_RRTYPE_CAA; }
+ break;
+ case 322:
+ {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ p--; {cs = 268;goto _again;}
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ {p++; goto _out; }
+ }
+ }
+ } else {
+ // Return if external processing.
+ p--; {p++; goto _out; }
+ }
+ }
+ break;
+ }
+ }
+
+_again:
+ if ( cs == 0 )
+ goto _out;
+ if ( ++p != pe )
+ goto _resume;
+ _test_eof: {}
+ if ( p == eof )
+ {
+ const short *__acts = _zone_scanner_actions + _zone_scanner_eof_actions[cs];
+ unsigned int __nacts = (unsigned int) *__acts++;
+ while ( __nacts-- > 0 ) {
+ switch ( *__acts++ ) {
+ case 8:
+ {
+ WARN(ZS_BAD_REST);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 18:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 23:
+ {
+ WARN(ZS_BAD_DNAME_CHAR);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 30:
+ {
+ s->r_owner_length = 0;
+ WARN(ZS_BAD_OWNER);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 35:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 47:
+ {
+ WARN(ZS_BAD_TIME_UNIT);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 57:
+ {
+ WARN(ZS_BAD_TIMESTAMP_CHAR);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 59:
+ {
+ WARN(ZS_BAD_TEXT_CHAR);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 60:
+ {
+ WARN(ZS_BAD_TEXT);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 64:
+ {
+ WARN(ZS_BAD_NUMBER);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 67:
+ {
+ s->long_string = false;
+ }
+ break;
+ case 69:
+ {
+ ERR(ZS_BAD_TTL);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 73:
+ {
+ ERR(ZS_BAD_ORIGIN);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 77:
+ {
+ ERR(ZS_BAD_INCLUDE_FILENAME);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 80:
+ {
+ ERR(ZS_BAD_INCLUDE_ORIGIN);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 84:
+ {
+ NOERR;
+ }
+ break;
+ case 85:
+ {
+ ERR(ZS_BAD_DIRECTIVE);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 92:
+ {
+ WARN(ZS_BAD_ADDRESS_CHAR);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 103:
+ {
+ WARN(ZS_BAD_APL);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 106:
+ {
+ WARN(ZS_BAD_HEX_CHAR);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 108:
+ {
+ WARN(ZS_BAD_HEX_RDATA);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 113:
+ {
+ WARN(ZS_BAD_BASE64_CHAR);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 123:
+ {
+ WARN(ZS_BAD_BASE32HEX_CHAR);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 151:
+ {
+ WARN(ZS_BAD_GATEWAY);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 152:
+ {
+ WARN(ZS_BAD_GATEWAY_KEY);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 153:
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 241:
+ {
+ WARN(ZS_BAD_BITMAP);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 258:
+ {
+ WARN(ZS_BAD_LOC_DATA);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 259:
+ {
+ WARN(ZS_BAD_HEX_RDATA);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 264:
+ {
+ WARN(ZS_BAD_CHAR_DASH);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 268:
+ {
+ WARN(ZS_BAD_CHAR_COLON);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 269:
+ {
+ WARN(ZS_BAD_ALGORITHM);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 270:
+ {
+ WARN(ZS_BAD_CERT_TYPE);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 274:
+ {
+ WARN(ZS_BAD_RDATA);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ case 279:
+ {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ p--; {cs = 268; if ( p == pe )
+ goto _test_eof;
+goto _again;}
+ }
+ break;
+ }
+ }
+ }
+
+ _out: {}
+ }
+
+
+ // Check if the scanner state machine is in an uncovered state.
+ bool extra_error = false;
+ if (cs == 0) {
+ ERR(ZS_UNCOVERED_STATE);
+ extra_error = true;
+ // Check for an unclosed multiline record.
+ } else if (s->input.eof && s->multiline) {
+ ERR(ZS_UNCLOSED_MULTILINE);
+ extra_error = true;
+ }
+
+ // Treat the extra error.
+ if (extra_error) {
+ s->error.counter++;
+ s->state = ZS_STATE_ERROR;
+
+ // Copy the error context just for the part of the current line.
+ s->buffer_length = 0;
+ while (p < pe && *p != '\n' && s->buffer_length < 50) {
+ s->buffer[s->buffer_length++] = *p++;
+ }
+ s->buffer[s->buffer_length++] = 0;
+
+ // Execute the error callback.
+ if (s->process.automatic && s->process.error != NULL) {
+ s->process.error(s);
+ }
+
+ return;
+ }
+
+ // Storing scanner states.
+ s->cs = cs;
+ s->top = top;
+ memcpy(s->stack, stack, sizeof(stack));
+
+ // Store the current parser position.
+ s->input.current = p;
+
+ // Storing r_data pointer.
+ s->r_data_tail = rdata_tail - s->r_data;
+
+ if (*wrap == WRAP_DETECTED) {
+ if (set_input_string(s, "\\", 1, true) != 0) {
+ return;
+ }
+
+ *wrap = WRAP_PROCESS;
+ parse(s, wrap);
+ } else {
+ *wrap = WRAP_NONE;
+ }
+}
+
+__attribute__((visibility("default")))
+int zs_parse_record(
+ zs_scanner_t *s)
+{
+ if (s == NULL) {
+ return -1;
+ }
+
+ // Check if parsing is possible.
+ switch (s->state) {
+ case ZS_STATE_NONE:
+ case ZS_STATE_DATA:
+ case ZS_STATE_INCLUDE:
+ break;
+ case ZS_STATE_ERROR:
+ if (s->error.fatal) {
+ return -1;
+ }
+ break;
+ default:
+ // Return if stop or end of file.
+ return 0;
+ }
+
+ // Check for the end of the input.
+ if (s->input.current != s->input.end) {
+ // Try to parse another item.
+ s->state = ZS_STATE_NONE;
+ wrap_t wrap = WRAP_NONE;
+ parse(s, &wrap);
+
+ // Finish if nothing was parsed.
+ if (s->state == ZS_STATE_NONE) {
+ // Parse the final block.
+ if (set_input_string(s, "\n", 1, true) != 0) {
+ return -1;
+ }
+ parse(s, &wrap);
+ if (s->state == ZS_STATE_NONE) {
+ s->state = ZS_STATE_EOF;
+ }
+ }
+ } else {
+ s->state = ZS_STATE_EOF;
+ }
+
+ return 0;
+}
+
+__attribute__((visibility("default")))
+int zs_parse_all(
+ zs_scanner_t *s)
+{
+ if (s == NULL) {
+ return -1;
+ }
+
+ s->process.automatic = true;
+
+ // Parse input block.
+ wrap_t wrap = WRAP_NONE;
+ parse(s, &wrap);
+
+ // Parse trailing newline-char block if it makes sense.
+ if (s->state != ZS_STATE_STOP && !s->error.fatal) {
+ if (set_input_string(s, "\n", 1, true) != 0) {
+ return -1;
+ }
+ parse(s, &wrap);
+ }
+
+ // Check if any errors have occurred.
+ if (s->error.counter > 0) {
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/libzscanner/scanner.h b/src/libzscanner/scanner.h
new file mode 100644
index 0000000..283dce5
--- /dev/null
+++ b/src/libzscanner/scanner.h
@@ -0,0 +1,370 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief Zone scanner core interface.
+ *
+ * \addtogroup zscanner
+ * @{
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "libzscanner/error.h"
+
+/*! \brief Maximal length of rdata. */
+#define ZS_MAX_RDATA_LENGTH 65535
+/*! \brief Maximal length of domain name. */
+#define ZS_MAX_DNAME_LENGTH 255
+/*! \brief Maximal length of domain name label. */
+#define ZS_MAX_LABEL_LENGTH 63
+
+/*! \brief Length of ipv4 address in the wire format. */
+#define ZS_INET4_ADDR_LENGTH 4
+/*! \brief Length of ipv6 address in the wire format. */
+#define ZS_INET6_ADDR_LENGTH 16
+
+/*! \brief Number of bitmap windows. */
+#define ZS_BITMAP_WINDOWS 256
+
+/*! \brief Ragel call stack size (see Ragel internals). */
+#define ZS_RAGEL_STACK_SIZE 16
+
+/*! \brief Auxiliary structure for storing bitmap window items (see RFC4034). */
+typedef struct {
+ uint8_t bitmap[32];
+ uint8_t length;
+} zs_win_t;
+
+/*! \brief Auxiliary structure for storing one APL record (see RFC3123). */
+typedef struct {
+ uint8_t excl_flag;
+ uint16_t addr_family;
+ uint8_t prefix_length;
+} zs_apl_t;
+
+/*! \brief Auxiliary structure for storing LOC information (see RFC1876). */
+typedef struct {
+ uint32_t d1, d2;
+ uint32_t m1, m2;
+ uint32_t s1, s2;
+ uint32_t alt;
+ uint64_t siz, hp, vp;
+ int8_t lat_sign, long_sign, alt_sign;
+} zs_loc_t;
+
+/*! \brief Scanner states describing the result. */
+typedef enum {
+ ZS_STATE_NONE, /*!< Initial state (no data). */
+ ZS_STATE_DATA, /*!< A record parsed. */
+ ZS_STATE_ERROR, /*!< An error occurred. */
+ ZS_STATE_INCLUDE, /*!< An include directive (see include_filename, buffer). */
+ ZS_STATE_EOF, /*!< The end of the current input reached. */
+ ZS_STATE_STOP /*!< Early stop (possibly set from a callback). */
+} zs_state_t;
+
+/*!
+ * \brief Context structure for zone scanner.
+ *
+ * This structure contains following items:
+ * - Copies of Ragel internal variables. The scanner can be called many times
+ * on smaller parts of zone file/memory. So it is necessary to preserve
+ * internal values between subsequent scanner callings.
+ * - Auxiliary variables which are used during processing zone data.
+ * - Pointers to callback functions and pointer to any arbitrary data which
+ * can be used in callback functions.
+ * - Zone file and error information.
+ * - Output variables (r_ prefix) containing all parts of zone record. These
+ * data are useful during processing via callback function.
+ */
+typedef struct zs_scanner zs_scanner_t; // Forward declaration due to arguments.
+struct zs_scanner {
+ /*! Current state (Ragel internals). */
+ int cs;
+ /*! Stack top (Ragel internals). */
+ int top;
+ /*! Call stack (Ragel internals). */
+ int stack[ZS_RAGEL_STACK_SIZE];
+
+ /*! Indicates whether current record is multiline. */
+ bool multiline;
+ /*! Auxiliary number for all numeric operations. */
+ uint64_t number64;
+ /*! Auxiliary variable for time and other numeric operations. */
+ uint64_t number64_tmp;
+ /*! Auxiliary variable for float numeric operations. */
+ uint32_t decimals;
+ /*! Auxiliary variable for float numeric operations. */
+ uint32_t decimal_counter;
+
+ /*! Auxiliary variable for item length (label, base64, ...). */
+ uint32_t item_length;
+ /*! Auxiliary index for item length position in array. */
+ uint32_t item_length_position;
+ /*! Auxiliary pointer to item length. */
+ uint8_t *item_length_location;
+ /*! Auxiliary buffer length. Is zero if no comment after a valid record. */
+ uint32_t buffer_length;
+ /*! Auxiliary buffer. Contains a comment after a valid record. */
+ uint8_t buffer[ZS_MAX_RDATA_LENGTH];
+ /*! Auxiliary buffer for current included file name. */
+ char include_filename[ZS_MAX_RDATA_LENGTH];
+ /*! Absolute path for relative includes. */
+ char *path;
+
+ /*! Auxiliary array of bitmap window blocks. */
+ zs_win_t windows[ZS_BITMAP_WINDOWS];
+ /*! Last window block which is used (-1 means no window). */
+ int16_t last_window;
+ /*! Auxiliary apl structure. */
+ zs_apl_t apl;
+ /*! Auxiliary loc structure. */
+ zs_loc_t loc;
+ /*! Auxiliary IP address storage. */
+ uint8_t addr[ZS_INET6_ADDR_LENGTH];
+ /*! Allow text strings longer than 255 characters. */
+ bool long_string;
+
+ /*! Pointer to the actual dname storage (origin/owner/rdata). */
+ uint8_t *dname;
+ /*! Pointer to the actual dname length storage. */
+ uint32_t *dname_length;
+ /*!
+ * Temporary dname length which is copied to dname_length after
+ * dname processing.
+ */
+ uint32_t dname_tmp_length;
+ /*! Position of the last free r_data byte. */
+ uint32_t r_data_tail;
+
+ /*! Length of the current origin. */
+ uint32_t zone_origin_length;
+ /*!
+ * Wire format of the current origin (ORIGIN directive sets this).
+ *
+ * \note Maximal dname length check is after each valid label.
+ */
+ uint8_t zone_origin[ZS_MAX_DNAME_LENGTH + ZS_MAX_LABEL_LENGTH];
+ /*! Value of the default class. */
+ uint16_t default_class;
+ /*! Value of the current default ttl (TTL directive sets this). */
+ uint32_t default_ttl;
+
+ /*! The current processing state. */
+ zs_state_t state;
+
+ /*! Processing callbacks and auxiliary data. */
+ struct {
+ /*! Automatic zone processing using record/error callbacks. */
+ bool automatic;
+ /*! Callback function for correct zone record. */
+ void (*record)(zs_scanner_t *);
+ /*! Callback function for wrong situations. */
+ void (*error)(zs_scanner_t *);
+ /*! Arbitrary data useful inside callback functions. */
+ void *data;
+ } process;
+
+ /*! Input parameters. */
+ struct {
+ /*! Start of the block. */
+ const char *start;
+ /*! Current parser position. */
+ const char *current;
+ /*! End of the block. */
+ const char *end;
+ /*! Indication for the final block parsing. */
+ bool eof;
+ /*! Indication of being mmap()-ed (malloc()-ed otherwise). */
+ bool mmaped;
+ } input;
+
+ /*! File input parameters. */
+ struct {
+ /*! Zone file name. */
+ char *name;
+ /*!< File descriptor. */
+ int descriptor;
+ } file;
+
+ struct {
+ /*! Last occurred error/warning code. */
+ int code;
+ /*! Error/warning counter. */
+ uint64_t counter;
+ /*! Indicates serious error - parsing cannot continue. */
+ bool fatal;
+ } error;
+
+ /*! Zone data line counter. */
+ uint64_t line_counter;
+
+ /*! Length of the current record owner. */
+ uint32_t r_owner_length;
+ /*!
+ * Owner of the current record.
+ *
+ * \note Maximal dname length check is after each valid label.
+ */
+ uint8_t r_owner[ZS_MAX_DNAME_LENGTH + ZS_MAX_LABEL_LENGTH];
+ /*! Class of the current record. */
+ uint16_t r_class;
+ /*! TTL of the current record. */
+ uint32_t r_ttl;
+ /*! Type of the current record data. */
+ uint16_t r_type;
+ /*! Length of the current rdata. */
+ uint32_t r_data_length;
+ /*! Current rdata. */
+ uint8_t r_data[ZS_MAX_RDATA_LENGTH];
+
+ /*
+ * Example: a. IN 60 MX 1 b. ; A comment
+ *
+ * r_owner_length = 3
+ * r_owner = 016100
+ * r_class = 1
+ * r_ttl = 60
+ * r_type = 15
+ * r_data_length = 5
+ * r_data = 0001016200
+ * buffer_length = 11
+ * buffer = " A comment"
+ */
+};
+
+/*!
+ * \brief Initializes the scanner context.
+ *
+ * \note Error code is stored in the scanner context.
+ *
+ * \param scanner Scanner context.
+ * \param origin Initial zone origin.
+ * \param rclass Zone class value.
+ * \param ttl Initial ttl value.
+ *
+ * \retval 0 if success.
+ * \retval -1 if error.
+ */
+int zs_init(
+ zs_scanner_t *scanner,
+ const char *origin,
+ const uint16_t rclass,
+ const uint32_t ttl
+);
+
+/*!
+ * \brief Deinitializes the scanner context.
+ *
+ * \param scanner Scanner context.
+ */
+void zs_deinit(
+ zs_scanner_t *scanner
+);
+
+/*!
+ * \brief Sets the scanner to parse a zone data string.
+ *
+ * \note Error code is stored in the scanner context.
+ *
+ * \param scanner Scanner context.
+ * \param input Input zone data string to parse.
+ * \param size Size of the input string.
+ *
+ * \retval 0 if success.
+ * \retval -1 if error.
+ */
+int zs_set_input_string(
+ zs_scanner_t *scanner,
+ const char *input,
+ size_t size
+);
+
+/*!
+ * \brief Sets the scanner to parse a zone file..
+ *
+ * \note Error code is stored in the scanner context.
+ *
+ * \param scanner Scanner context.
+ * \param file_name Name of the file to parse.
+ *
+ * \retval 0 if success.
+ * \retval -1 if error.
+ */
+int zs_set_input_file(
+ zs_scanner_t *scanner,
+ const char *file_name
+);
+
+/*!
+ * \brief Sets the scanner processing callbacks for automatic processing.
+ *
+ * \note Error code is stored in the scanner context.
+ *
+ * \param scanner Scanner context.
+ * \param process_record Processing callback function (may be NULL).
+ * \param process_error Error callback function (may be NULL).
+ * \param data Arbitrary data useful in callback functions.
+ *
+ * \retval 0 if success.
+ * \retval -1 if error.
+ */
+int zs_set_processing(
+ zs_scanner_t *scanner,
+ void (*process_record)(zs_scanner_t *),
+ void (*process_error)(zs_scanner_t *),
+ void *data
+);
+
+/*!
+ * \brief Parses one record from the input.
+ *
+ * The following processing should be based on the scanner->state.
+ *
+ * \note Error code and other information are stored in the scanner context.
+ *
+ * \param scanner Scanner context.
+ *
+ * \retval 0 if success.
+ * \retval -1 if error.
+ */
+int zs_parse_record(
+ zs_scanner_t *scanner
+);
+
+/*!
+ * \brief Launches automatic parsing of the whole input.
+ *
+ * For each correctly recognized record, the record callback is executed.
+ * If any syntax error occurs, the error callback is executed.
+ *
+ * \note Error code and other information are stored in the scanner context.
+ *
+ * \param scanner Scanner context.
+ *
+ * \retval 0 if success.
+ * \retval -1 if error.
+ */
+int zs_parse_all(
+ zs_scanner_t *scanner
+);
+
+/*! @} */
diff --git a/src/libzscanner/scanner.rl b/src/libzscanner/scanner.rl
new file mode 100644
index 0000000..4050b56
--- /dev/null
+++ b/src/libzscanner/scanner.rl
@@ -0,0 +1,541 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libgen.h>
+#include <math.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "libzscanner/scanner.h"
+#include "libzscanner/functions.h"
+#include "libknot/descriptor.h"
+
+/*! \brief Maximal length of rdata item. */
+#define MAX_ITEM_LENGTH 255
+
+/*! \brief Latitude value for equator (2^31). */
+#define LOC_LAT_ZERO (uint32_t)2147483648
+/*! \brief Longitude value for meridian (2^31). */
+#define LOC_LONG_ZERO (uint32_t)2147483648
+/*! \brief Zero level altitude value. */
+#define LOC_ALT_ZERO (uint32_t)10000000
+
+/*! \brief Shorthand for setting warning data. */
+#define WARN(err_code) { s->error.code = err_code; }
+/*! \brief Shorthand for setting error data. */
+#define ERR(err_code) { WARN(err_code); s->error.fatal = true; }
+/*! \brief Shorthand for error reset. */
+#define NOERR { WARN(ZS_OK); s->error.fatal = false; }
+
+/*!
+ * \brief Writes record type number to r_data.
+ *
+ * \param type Type number.
+ * \param rdata_tail Position where to write type number to.
+ */
+static inline void type_num(const uint16_t type, uint8_t **rdata_tail)
+{
+ *((uint16_t *)*rdata_tail) = htons(type);
+ *rdata_tail += 2;
+}
+
+/*!
+ * \brief Sets bit to bitmap window.
+ *
+ * \param type Type number.
+ * \param s Scanner context.
+ */
+static inline void window_add_bit(const uint16_t type, zs_scanner_t *s) {
+ uint8_t win = type / 256;
+ uint8_t bit_pos = type % 256;
+ uint8_t byte_pos = bit_pos / 8;
+
+ ((s->windows[win]).bitmap)[byte_pos] |= 128 >> (bit_pos % 8);
+
+ if ((s->windows[win]).length < byte_pos + 1) {
+ (s->windows[win]).length = byte_pos + 1;
+ }
+
+ if (s->last_window < win) {
+ s->last_window = win;
+ }
+}
+
+// Include scanner file (in Ragel).
+%%{
+ machine zone_scanner;
+
+ include "scanner_body.rl";
+
+ write data;
+}%%
+
+__attribute__((visibility("default")))
+int zs_init(
+ zs_scanner_t *s,
+ const char *origin,
+ const uint16_t rclass,
+ const uint32_t ttl)
+{
+ if (s == NULL) {
+ return -1;
+ }
+
+ memset(s, 0, sizeof(*s));
+
+ // Nonzero initial scanner state.
+ s->cs = %%{ write start; }%%;
+
+ // Reset the file descriptor.
+ s->file.descriptor = -1;
+
+ // Use the root zone as origin if not specified.
+ if (origin == NULL || strlen(origin) == 0) {
+ origin = ".";
+ }
+ size_t origin_len = strlen(origin);
+
+ // Prepare a zone settings header.
+ const char *format;
+ if (origin[origin_len - 1] != '.') {
+ format = "$ORIGIN %s.\n";
+ } else {
+ format = "$ORIGIN %s\n";
+ }
+
+ char settings[1024];
+ int ret = snprintf(settings, sizeof(settings), format, origin);
+ if (ret <= 0 || ret >= sizeof(settings)) {
+ ERR(ZS_ENOMEM);
+ return -1;
+ }
+
+ // Parse the settings to set up the scanner origin.
+ if (zs_set_input_string(s, settings, ret) != 0 ||
+ zs_parse_all(s) != 0) {
+ return -1;
+ }
+
+ // Set scanner defaults.
+ s->path = strdup(".");
+ if (s->path == NULL) {
+ ERR(ZS_ENOMEM);
+ return -1;
+ }
+ s->default_class = rclass;
+ s->default_ttl = ttl;
+ s->line_counter = 1;
+
+ s->state = ZS_STATE_NONE;
+ s->process.automatic = false;
+
+ return 0;
+}
+
+static void input_deinit(
+ zs_scanner_t *s,
+ bool keep_filename)
+{
+ // Deinit the file input.
+ if (s->file.descriptor != -1) {
+ // Unmap the file content.
+ if (s->input.start != NULL) {
+ if (s->input.mmaped) {
+ munmap((void *)s->input.start,
+ s->input.end - s->input.start);
+ } else {
+ free((void *)s->input.start);
+ }
+ }
+
+ // Close the opened file.
+ close(s->file.descriptor);
+ s->file.descriptor = -1;
+ }
+
+ // Keep file name for possible trailing error report.
+ if (!keep_filename) {
+ free(s->file.name);
+ s->file.name = NULL;
+ }
+
+ // Unset the input limits.
+ s->input.start = NULL;
+ s->input.current = NULL;
+ s->input.end = NULL;
+ s->input.eof = false;
+}
+
+__attribute__((visibility("default")))
+void zs_deinit(
+ zs_scanner_t *s)
+{
+ if (s == NULL) {
+ return;
+ }
+
+ input_deinit(s, false);
+ free(s->path);
+}
+
+static int set_input_string(
+ zs_scanner_t *s,
+ const char *input,
+ size_t size,
+ bool final_block)
+{
+ if (s == NULL) {
+ return -1;
+ }
+
+ if (input == NULL) {
+ ERR(ZS_EINVAL);
+ return -1;
+ }
+
+ // Deinit possibly opened file.
+ input_deinit(s, final_block);
+
+ // Set the scanner input limits.
+ s->input.start = input;
+ s->input.current = input;
+ s->input.end = input + size;
+ s->input.eof = final_block;
+
+ return 0;
+}
+
+static char *read_file_to_buf(
+ int fd,
+ size_t *bufsize)
+{
+ size_t bufs = 0, newbufs = 8192;
+ char *buf = malloc(bufs + newbufs);
+ int ret = 0;
+
+ while (buf != NULL && (ret = read(fd, buf + bufs, newbufs)) == newbufs) {
+ bufs += newbufs;
+ newbufs = bufs;
+ char *newbuf = realloc(buf, bufs + newbufs);
+ if (newbuf == NULL) {
+ free(buf);
+ }
+ buf = newbuf;
+ }
+ if (ret < 0) {
+ free(buf);
+ return NULL;
+ }
+
+ *bufsize = bufs + ret;
+ return buf;
+}
+
+__attribute__((visibility("default")))
+int zs_set_input_string(
+ zs_scanner_t *s,
+ const char *input,
+ size_t size)
+{
+ s->state = ZS_STATE_NONE;
+
+ return set_input_string(s, input, size, false);
+}
+
+__attribute__((visibility("default")))
+int zs_set_input_file(
+ zs_scanner_t *s,
+ const char *file_name)
+{
+ if (s == NULL) {
+ return -1;
+ }
+
+ if (file_name == NULL) {
+ ERR(ZS_EINVAL);
+ return -1;
+ }
+
+ // Deinit possibly opened file.
+ input_deinit(s, false);
+
+ // Try to open the file.
+ s->file.descriptor = open(file_name, O_RDONLY);
+ if (s->file.descriptor == -1) {
+ ERR(ZS_FILE_OPEN);
+ return -1;
+ }
+
+ char *start = NULL;
+ size_t size = 0;
+
+ // Check the input.
+ struct stat file_stat;
+ if (fstat(s->file.descriptor, &file_stat) == -1) {
+ ERR(ZS_FILE_INVALID);
+ input_deinit(s, false);
+ return -1;
+ } else if (S_ISCHR(file_stat.st_mode) ||
+ S_ISBLK(file_stat.st_mode) ||
+ S_ISFIFO(file_stat.st_mode)) {
+ // Workaround if cannot mmap, read to memory.
+ start = read_file_to_buf(s->file.descriptor, &size);
+ if (start == NULL) {
+ ERR(ZS_FILE_INVALID);
+ input_deinit(s, false);
+ return -1;
+ }
+ } else if (!S_ISREG(file_stat.st_mode)) { // Require regular file.
+ ERR(ZS_FILE_INVALID);
+ input_deinit(s, false);
+ return -1;
+ } else if (file_stat.st_size > 0) { // Mmap non-emtpy file.
+ start = mmap(0, file_stat.st_size, PROT_READ, MAP_SHARED,
+ s->file.descriptor, 0);
+ if (start == MAP_FAILED) {
+ ERR(ZS_FILE_INVALID);
+ input_deinit(s, false);
+ return -1;
+ }
+
+ size = file_stat.st_size;
+ s->input.mmaped = true;
+
+ // Try to set the mapped memory advise to sequential.
+ (void)madvise(start, size, MADV_SEQUENTIAL);
+ }
+
+ // Set the scanner input limits.
+ s->input.start = start;
+ s->input.current = start;
+ s->input.end = start + size;
+
+ // Get absolute path of the zone file if possible.
+ char *full_name = realpath(file_name, NULL);
+ if (full_name != NULL) {
+ free(s->path);
+ s->path = strdup(dirname(full_name));
+ free(full_name);
+ if (s->path == NULL) {
+ ERR(ZS_ENOMEM);
+ input_deinit(s, false);
+ return -1;
+ }
+ }
+
+ s->file.name = strdup(file_name);
+ if (s->file.name == NULL) {
+ ERR(ZS_ENOMEM);
+ input_deinit(s, false);
+ return -1;
+ }
+
+ s->state = ZS_STATE_NONE;
+
+ return 0;
+}
+
+__attribute__((visibility("default")))
+int zs_set_processing(
+ zs_scanner_t *s,
+ void (*process_record)(zs_scanner_t *),
+ void (*process_error)(zs_scanner_t *),
+ void *data)
+{
+ if (s == NULL) {
+ return -1;
+ }
+
+ s->process.record = process_record;
+ s->process.error = process_error;
+ s->process.data = data;
+
+ return 0;
+}
+
+typedef enum {
+ WRAP_NONE, // Initial state.
+ WRAP_DETECTED, // Input block end is a first '\' in rdata.
+ WRAP_PROCESS // Parsing of auxiliary block = "\".
+} wrap_t;
+
+static void parse(
+ zs_scanner_t *s,
+ wrap_t *wrap)
+{
+ // Restore scanner input limits (Ragel internals).
+ const char *p = s->input.current;
+ const char *pe = s->input.end;
+ const char *eof = s->input.eof ? pe : NULL;
+
+ // Restore state variables (Ragel internals).
+ int cs = s->cs;
+ int top = s->top;
+ int stack[ZS_RAGEL_STACK_SIZE];
+ memcpy(stack, s->stack, sizeof(stack));
+
+ // Next 2 variables are for better performance.
+ // Restoring r_data pointer to next free space.
+ uint8_t *rdata_tail = s->r_data + s->r_data_tail;
+ // Initialization of the last r_data byte.
+ uint8_t *rdata_stop = s->r_data + ZS_MAX_RDATA_LENGTH - 1;
+
+ // Write scanner body (in C).
+ %% write exec;
+
+ // Check if the scanner state machine is in an uncovered state.
+ bool extra_error = false;
+ if (cs == %%{ write error; }%%) {
+ ERR(ZS_UNCOVERED_STATE);
+ extra_error = true;
+ // Check for an unclosed multiline record.
+ } else if (s->input.eof && s->multiline) {
+ ERR(ZS_UNCLOSED_MULTILINE);
+ extra_error = true;
+ }
+
+ // Treat the extra error.
+ if (extra_error) {
+ s->error.counter++;
+ s->state = ZS_STATE_ERROR;
+
+ // Copy the error context just for the part of the current line.
+ s->buffer_length = 0;
+ while (p < pe && *p != '\n' && s->buffer_length < 50) {
+ s->buffer[s->buffer_length++] = *p++;
+ }
+ s->buffer[s->buffer_length++] = 0;
+
+ // Execute the error callback.
+ if (s->process.automatic && s->process.error != NULL) {
+ s->process.error(s);
+ }
+
+ return;
+ }
+
+ // Storing scanner states.
+ s->cs = cs;
+ s->top = top;
+ memcpy(s->stack, stack, sizeof(stack));
+
+ // Store the current parser position.
+ s->input.current = p;
+
+ // Storing r_data pointer.
+ s->r_data_tail = rdata_tail - s->r_data;
+
+ if (*wrap == WRAP_DETECTED) {
+ if (set_input_string(s, "\\", 1, true) != 0) {
+ return;
+ }
+
+ *wrap = WRAP_PROCESS;
+ parse(s, wrap);
+ } else {
+ *wrap = WRAP_NONE;
+ }
+}
+
+__attribute__((visibility("default")))
+int zs_parse_record(
+ zs_scanner_t *s)
+{
+ if (s == NULL) {
+ return -1;
+ }
+
+ // Check if parsing is possible.
+ switch (s->state) {
+ case ZS_STATE_NONE:
+ case ZS_STATE_DATA:
+ case ZS_STATE_INCLUDE:
+ break;
+ case ZS_STATE_ERROR:
+ if (s->error.fatal) {
+ return -1;
+ }
+ break;
+ default:
+ // Return if stop or end of file.
+ return 0;
+ }
+
+ // Check for the end of the input.
+ if (s->input.current != s->input.end) {
+ // Try to parse another item.
+ s->state = ZS_STATE_NONE;
+ wrap_t wrap = WRAP_NONE;
+ parse(s, &wrap);
+
+ // Finish if nothing was parsed.
+ if (s->state == ZS_STATE_NONE) {
+ // Parse the final block.
+ if (set_input_string(s, "\n", 1, true) != 0) {
+ return -1;
+ }
+ parse(s, &wrap);
+ if (s->state == ZS_STATE_NONE) {
+ s->state = ZS_STATE_EOF;
+ }
+ }
+ } else {
+ s->state = ZS_STATE_EOF;
+ }
+
+ return 0;
+}
+
+__attribute__((visibility("default")))
+int zs_parse_all(
+ zs_scanner_t *s)
+{
+ if (s == NULL) {
+ return -1;
+ }
+
+ s->process.automatic = true;
+
+ // Parse input block.
+ wrap_t wrap = WRAP_NONE;
+ parse(s, &wrap);
+
+ // Parse trailing newline-char block if it makes sense.
+ if (s->state != ZS_STATE_STOP && !s->error.fatal) {
+ if (set_input_string(s, "\n", 1, true) != 0) {
+ return -1;
+ }
+ parse(s, &wrap);
+ }
+
+ // Check if any errors have occurred.
+ if (s->error.counter > 0) {
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/libzscanner/scanner_body.rl b/src/libzscanner/scanner_body.rl
new file mode 100644
index 0000000..022cc9b
--- /dev/null
+++ b/src/libzscanner/scanner_body.rl
@@ -0,0 +1,2088 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+%%{
+ machine zone_scanner;
+
+ # Comeback function to calling state machine.
+ action _ret {
+ fhold; fret;
+ }
+
+ # BEGIN - Blank space processing
+ action _newline {
+ s->line_counter++;
+ }
+
+ action _check_multiline_begin {
+ if (s->multiline == true) {
+ ERR(ZS_LEFT_PARENTHESIS);
+ fhold; fgoto err_line;
+ }
+ s->multiline = true;
+ }
+ action _check_multiline_end {
+ if (s->multiline == false) {
+ ERR(ZS_RIGHT_PARENTHESIS);
+ fhold; fgoto err_line;
+ }
+ s->multiline = false;
+ }
+
+ action _comment_init {
+ s->buffer_length = 0;
+ }
+ action _comment {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = fc;
+ }
+ }
+ action _comment_exit {
+ s->buffer[s->buffer_length++] = 0;
+ }
+
+ action _rest_init {
+ s->buffer[0] = 0;
+ s->buffer_length = 0;
+ }
+ action _rest_error {
+ WARN(ZS_BAD_REST);
+ fhold; fgoto err_line;
+ }
+
+ newline = '\n' $_newline;
+ comment = (';' . (^newline)* $_comment) >_comment_init %_comment_exit;
+
+ # White space separation. With respect to parentheses and included comments.
+ sep = ( [ \t] # Blank characters.
+ | (comment? . newline) when { s->multiline } # Comment in multiline.
+ | '(' $_check_multiline_begin # Start of multiline.
+ | ')' $_check_multiline_end # End of multiline.
+ )+; # Apply more times.
+
+ rest = (sep? :> comment?) >_rest_init $!_rest_error; # Comments.
+
+ # Artificial machines which are used for next state transition only!
+ all_wchar = [ \t\n;()];
+ end_wchar = [\n;] when { !s->multiline }; # For noncontinuous ending tokens.
+ # END
+
+ # BEGIN - Error line processing
+ action _err_line_init {
+ s->buffer_length = 0;
+ }
+ action _err_line {
+ if (fc == '\r') {
+ ERR(ZS_DOS_NEWLINE);
+ }
+
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = fc;
+ }
+ }
+ action _err_line_exit {
+ // Terminate the error context string.
+ s->buffer[s->buffer_length++] = 0;
+
+ // Error counter incrementation.
+ s->error.counter++;
+
+ // Initialize the fcall stack.
+ top = 0;
+
+ // Reset the multiline context.
+ s->multiline = false;
+
+ s->state = ZS_STATE_ERROR;
+
+ // Execute the error callback.
+ if (s->process.automatic) {
+ if (s->process.error != NULL) {
+ s->process.error(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ fbreak;
+ }
+ }
+
+ // Stop the scanner if fatal error.
+ if (s->error.fatal) {
+ fbreak;
+ }
+ fgoto main;
+ } else {
+ // Return if external processing.
+ fhold; fnext main; fbreak;
+ }
+ }
+
+ # Fill rest of the line to buffer and skip to main loop.
+ err_line := (^newline $_err_line)* >_err_line_init
+ %_err_line_exit . newline;
+ # END
+
+ # BEGIN - Domain name labels processing
+ action _label_init {
+ s->item_length = 0;
+ s->item_length_position = s->dname_tmp_length++;
+ }
+ action _label_char {
+ // Check for maximum dname label length.
+ if (s->item_length < ZS_MAX_LABEL_LENGTH) {
+ (s->dname)[s->dname_tmp_length++] = fc;
+ s->item_length++;
+ } else {
+ WARN(ZS_LABEL_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+ action _label_exit {
+ // Check for maximum dname length overflow after each label.
+ // (at least the next label length must follow).
+ if (s->dname_tmp_length < ZS_MAX_DNAME_LENGTH) {
+ (s->dname)[s->item_length_position] =
+ (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_DNAME_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+
+ action _label_dec_init {
+ if (s->item_length < ZS_MAX_LABEL_LENGTH) {
+ (s->dname)[s->dname_tmp_length] = 0;
+ s->item_length++;
+ } else {
+ WARN(ZS_LABEL_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+ action _label_dec {
+ (s->dname)[s->dname_tmp_length] *= 10;
+ (s->dname)[s->dname_tmp_length] += digit_to_num[(uint8_t)fc];
+ }
+ action _label_dec_exit {
+ s->dname_tmp_length++;
+ }
+ action _label_dec_error {
+ WARN(ZS_BAD_NUMBER);
+ fhold; fgoto err_line;
+ }
+
+ label_char =
+ ( (alnum | [*\-_/]) $_label_char # One common char.
+ | ('\\' . ^digit) @_label_char # One "\x" char.
+ | ('\\' %_label_dec_init # Initial "\" char.
+ . digit {3} $_label_dec %_label_dec_exit # "DDD" rest.
+ $!_label_dec_error
+ )
+ );
+
+ label = label_char+ >_label_init %_label_exit;
+ labels = (label . '.')* . label;
+ # END
+
+ # BEGIN - Domain name processing.
+ action _absolute_dname_exit {
+ // Enough room for the terminal label is guaranteed (_label_exit).
+ (s->dname)[s->dname_tmp_length++] = 0;
+ }
+ action _relative_dname_exit {
+ // Check for (relative + origin) dname length overflow.
+ if (s->dname_tmp_length + s->zone_origin_length <= ZS_MAX_DNAME_LENGTH) {
+ memcpy(s->dname + s->dname_tmp_length,
+ s->zone_origin,
+ s->zone_origin_length);
+
+ s->dname_tmp_length += s->zone_origin_length;
+ } else {
+ WARN(ZS_DNAME_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+ action _origin_dname_exit {
+ // Copy already verified zone origin.
+ memcpy(s->dname,
+ s->zone_origin,
+ s->zone_origin_length);
+
+ s->dname_tmp_length = s->zone_origin_length;
+ }
+
+ action _dname_init {
+ s->item_length_position = 0;
+ s->dname_tmp_length = 0;
+ }
+ action _dname_error {
+ WARN(ZS_BAD_DNAME_CHAR);
+ fhold; fgoto err_line;
+ }
+
+ relative_dname = (labels ) >_dname_init %_relative_dname_exit;
+ absolute_dname = (labels? . '.') >_dname_init %_absolute_dname_exit;
+
+ dname_ := ( relative_dname
+ | absolute_dname
+ | '@' %_origin_dname_exit
+ ) $!_dname_error %_ret . all_wchar;
+ dname = (alnum | [\-_/\\] | [*.@]) ${ fhold; fcall dname_; };
+ # END
+
+ # BEGIN - Common r_data item processing
+ action _item_length_init {
+ if (rdata_tail <= rdata_stop) {
+ s->item_length_location = rdata_tail++;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+ action _item_length_exit {
+ s->item_length = rdata_tail - s->item_length_location - 1;
+
+ if (s->item_length <= MAX_ITEM_LENGTH) {
+ *(s->item_length_location) = (uint8_t)(s->item_length);
+ } else {
+ WARN(ZS_ITEM_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+ # END
+
+ # BEGIN - Owner processing
+ action _r_owner_init {
+ s->dname = s->r_owner;
+ s->r_owner_length = 0;
+ }
+ action _r_owner_exit {
+ s->r_owner_length = s->dname_tmp_length;
+ }
+ action _r_owner_empty_exit {
+ if (s->r_owner_length == 0) {
+ WARN(ZS_BAD_PREVIOUS_OWNER);
+ fhold; fgoto err_line;
+ }
+ }
+ action _r_owner_error {
+ s->r_owner_length = 0;
+ WARN(ZS_BAD_OWNER);
+ fhold; fgoto err_line;
+ }
+
+ r_owner = ( dname >_r_owner_init %_r_owner_exit
+ | zlen %_r_owner_empty_exit # Empty owner - use the previous one.
+ ) $!_r_owner_error;
+ # END
+
+ # BEGIN - domain name in record data processing
+ action _r_dname_init {
+ s->dname = rdata_tail;
+ }
+ action _r_dname_exit {
+ rdata_tail += s->dname_tmp_length;
+ }
+
+ r_dname = dname >_r_dname_init %_r_dname_exit;
+ # END
+
+ # BEGIN - Number processing
+ action _number_digit {
+ // Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
+ if ((s->number64 < (UINT64_MAX / 10)) || // Dominant fast check.
+ ((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
+ ((uint8_t)fc <= (UINT64_MAX % 10) + '0')
+ )
+ ) {
+ s->number64 *= 10;
+ s->number64 += digit_to_num[(uint8_t)fc];
+ } else {
+ WARN(ZS_NUMBER64_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+
+ number_digit = [0-9] $_number_digit;
+
+ action _number_init {
+ s->number64 = 0;
+ }
+ action _number_error {
+ WARN(ZS_BAD_NUMBER);
+ fhold; fgoto err_line;
+ }
+
+ # General integer number that cover all necessary integer ranges.
+ number = number_digit+ >_number_init;
+
+ action _float_init {
+ s->decimal_counter = 0;
+ }
+ action _decimal_init {
+ s->number64_tmp = s->number64;
+ }
+ action _decimal_digit {
+ s->decimal_counter++;
+ }
+
+ action _float_exit {
+ if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals);
+ } else if (s->decimal_counter <= s->decimals &&
+ s->number64_tmp < UINT32_MAX) {
+ s->number64 *= pow(10, s->decimals - s->decimal_counter);
+ s->number64 += s->number64_tmp * pow(10, s->decimals);
+ } else {
+ WARN(ZS_FLOAT_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+
+ # Next float can't be used directly (doesn't contain decimals init)!
+ float = (number . ('.' . number? >_decimal_init $_decimal_digit)?)
+ >_float_init %_float_exit;
+
+ action _float2_init {
+ s->decimals = 2;
+ }
+ action _float3_init {
+ s->decimals = 3;
+ }
+
+ # Float number (in hundredths)with 2 possible decimal digits.
+ float2 = float >_float2_init;
+ # Float number (in thousandths) with 3 possible decimal digits.
+ float3 = float >_float3_init;
+
+ action _num8_write {
+ if (s->number64 <= UINT8_MAX) {
+ *rdata_tail = (uint8_t)(s->number64);
+ rdata_tail += 1;
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+ action _num16_write {
+ if (s->number64 <= UINT16_MAX) {
+ uint16_t num16 = htons((uint16_t)s->number64);
+ memcpy(rdata_tail, &num16, 2);
+ rdata_tail += 2;
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+ action _num32_write {
+ if (s->number64 <= UINT32_MAX) {
+ uint32_t num32 = htonl((uint32_t)s->number64);
+ memcpy(rdata_tail, &num32, 4);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+
+ action _type_number_exit {
+ if (s->number64 <= UINT16_MAX) {
+ s->r_type = (uint16_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+
+ action _length_number_exit {
+ if (s->number64 <= UINT16_MAX) {
+ s->r_data_length = (uint16_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+ num8 = number %_num8_write $!_number_error;
+ num16 = number %_num16_write $!_number_error;
+ num32 = number %_num32_write $!_number_error;
+
+ type_number = number %_type_number_exit $!_number_error;
+ length_number = number %_length_number_exit $!_number_error;
+ # END
+
+ # BEGIN - Time processing
+ action _time_unit_error {
+ WARN(ZS_BAD_TIME_UNIT);
+ fhold; fgoto err_line;
+ }
+
+ time_unit =
+ ( 's'i
+ | 'm'i ${ if (s->number64 <= (UINT32_MAX / 60)) {
+ s->number64 *= 60;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+ | 'h'i ${ if (s->number64 <= (UINT32_MAX / 3600)) {
+ s->number64 *= 3600;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+ | 'd'i ${ if (s->number64 <= (UINT32_MAX / 86400)) {
+ s->number64 *= 86400;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+ | 'w'i ${ if (s->number64 <= (UINT32_MAX / 604800)) {
+ s->number64 *= 604800;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+ ) $!_time_unit_error;
+
+
+ action _time_block_init {
+ s->number64_tmp = s->number64;
+ }
+ action _time_block_exit {
+ if (s->number64 + s->number64_tmp < UINT32_MAX) {
+ s->number64 += s->number64_tmp;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+
+ time_block = (number . time_unit) >_time_block_init %_time_block_exit;
+
+ # Time is either a number or a sequence of time blocks (1w1h1m).
+ time = (number . (time_unit . (time_block)*)?) $!_number_error;
+
+ time32 = time %_num32_write;
+ # END
+
+ # BEGIN - Timestamp processing
+ action _timestamp_init {
+ s->buffer_length = 0;
+ }
+ action _timestamp {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = fc;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+ action _timestamp_exit {
+ s->buffer[s->buffer_length] = 0;
+
+ if (s->buffer_length == 14) { // Date; 14 = len("YYYYMMDDHHmmSS").
+ uint32_t timestamp;
+ int ret = date_to_timestamp(s->buffer, &timestamp);
+
+ if (ret == ZS_OK) {
+ *((uint32_t *)rdata_tail) = htonl(timestamp);
+ rdata_tail += 4;
+ } else {
+ WARN(ret);
+ fhold; fgoto err_line;
+ }
+ } else if (s->buffer_length <= 10) { // Timestamp format.
+ char *end;
+
+ s->number64 = strtoull((char *)(s->buffer), &end, 10);
+
+ if (end == (char *)(s->buffer) || *end != '\0') {
+ WARN(ZS_BAD_TIMESTAMP);
+ fhold; fgoto err_line;
+ }
+
+ if (s->number64 <= UINT32_MAX) {
+ *((uint32_t *)rdata_tail) = htonl((uint32_t)s->number64);
+ rdata_tail += 4;
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ } else {
+ WARN(ZS_BAD_TIMESTAMP_LENGTH);
+ fhold; fgoto err_line;
+ }
+ }
+ action _timestamp_error {
+ WARN(ZS_BAD_TIMESTAMP_CHAR);
+ fhold; fgoto err_line;
+ }
+
+ timestamp = digit+ >_timestamp_init $_timestamp
+ %_timestamp_exit $!_timestamp_error;
+ # END
+
+ # BEGIN - Text processing
+ action _text_char {
+ if (rdata_tail <= rdata_stop) {
+ // Split long string.
+ if (s->long_string &&
+ rdata_tail - s->item_length_location == 1 + MAX_ITEM_LENGTH) {
+ // _item_length_exit equivalent.
+ *(s->item_length_location) = MAX_ITEM_LENGTH;
+ // _item_length_init equivalent.
+ s->item_length_location = rdata_tail++;
+
+ if (rdata_tail > rdata_stop) {
+ WARN(ZS_TEXT_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+
+ *(rdata_tail++) = fc;
+ } else {
+ WARN(ZS_TEXT_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+ action _text_char_error {
+ WARN(ZS_BAD_TEXT_CHAR);
+ fhold; fgoto err_line;
+ }
+ action _text_error {
+ WARN(ZS_BAD_TEXT);
+ fhold; fgoto err_line;
+ }
+
+ action _text_dec_init {
+ if (rdata_tail <= rdata_stop) {
+ // Split long string.
+ if (s->long_string &&
+ rdata_tail - s->item_length_location == 1 + MAX_ITEM_LENGTH) {
+ // _item_length_exit equivalent.
+ *(s->item_length_location) = MAX_ITEM_LENGTH;
+ // _item_length_init equivalent.
+ s->item_length_location = rdata_tail++;
+
+ if (rdata_tail > rdata_stop) {
+ WARN(ZS_TEXT_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+
+ *rdata_tail = 0;
+ s->item_length++;
+ } else {
+ WARN(ZS_TEXT_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+ action _text_dec {
+ if ((*rdata_tail < (UINT8_MAX / 10)) || // Dominant fast check.
+ ((*rdata_tail == (UINT8_MAX / 10)) && // Marginal case.
+ (fc <= (UINT8_MAX % 10) + '0')
+ )
+ ) {
+ *rdata_tail *= 10;
+ *rdata_tail += digit_to_num[(uint8_t)fc];
+ } else {
+ WARN(ZS_NUMBER8_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+ action _text_dec_exit {
+ rdata_tail++;
+ }
+ action _text_dec_error {
+ WARN(ZS_BAD_NUMBER);
+ fhold; fgoto err_line;
+ }
+
+ text_char =
+ ( (33..126 - [\\;\"]) $_text_char # One printable char.
+ | ('\\' . (32..126 - digit)) @_text_char # One "\x" char.
+ | ('\\' %_text_dec_init # Initial "\" char.
+ . digit {3} $_text_dec %_text_dec_exit # "DDD" rest.
+ $!_text_dec_error
+ )
+ ) $!_text_char_error;
+
+ quoted_text_char =
+ ( text_char
+ | ([ \t;] | [\n] when { s->multiline }) $_text_char
+ ) $!_text_char_error;
+
+ # Text string machine instantiation (for smaller code).
+ text_ := (('\"' . quoted_text_char* . '\"') | text_char+)
+ $!_text_error %_ret . all_wchar;
+ text = ^all_wchar ${ fhold; fcall text_; };
+
+ # Text string with forward 1-byte length.
+ text_string = text >_item_length_init %_item_length_exit;
+
+ action _text_array_init {
+ s->long_string = true;
+ }
+ action _text_array_exit {
+ s->long_string = false;
+ }
+
+ # Text string array as one rdata item.
+ text_array =
+ ( (text_string . (sep . text_string)* . sep?)
+ ) >_text_array_init %_text_array_exit $!_text_array_exit;
+ # END
+
+ # BEGIN - TTL directive processing
+ action _default_ttl_exit {
+ if (s->number64 <= UINT32_MAX) {
+ s->default_ttl = (uint32_t)(s->number64);
+ } else {
+ ERR(ZS_NUMBER32_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+ action _default_ttl_error {
+ ERR(ZS_BAD_TTL);
+ fhold; fgoto err_line;
+ }
+
+ default_ttl_ := (sep . time . rest) $!_default_ttl_error
+ %_default_ttl_exit %_ret . newline;
+ default_ttl = all_wchar ${ fhold; fcall default_ttl_; };
+ # END
+
+ # BEGIN - ORIGIN directive processing
+ action _zone_origin_init {
+ s->dname = s->zone_origin;
+ }
+ action _zone_origin_exit {
+ s->zone_origin_length = s->dname_tmp_length;
+ }
+ action _zone_origin_error {
+ ERR(ZS_BAD_ORIGIN);
+ fhold; fgoto err_line;
+ }
+
+ zone_origin_ := (sep . absolute_dname >_zone_origin_init . rest)
+ $!_zone_origin_error %_zone_origin_exit %_ret . newline;
+ zone_origin = all_wchar ${ fhold; fcall zone_origin_; };
+ # END
+
+ # BEGIN - INCLUDE directive processing
+ action _incl_filename_init {
+ rdata_tail = s->r_data;
+ }
+ action _incl_filename_exit {
+ size_t len = rdata_tail - s->r_data;
+ if (len >= sizeof(s->include_filename)) {
+ ERR(ZS_BAD_INCLUDE_FILENAME);
+ fhold; fgoto err_line;
+ }
+
+ // Store zero terminated include filename.
+ memcpy(s->include_filename, s->r_data, len);
+ s->include_filename[len] = '\0';
+
+ // For detection whether origin is not present.
+ s->dname = NULL;
+ }
+ action _incl_filename_error {
+ ERR(ZS_BAD_INCLUDE_FILENAME);
+ fhold; fgoto err_line;
+ }
+
+ action _incl_origin_init {
+ s->dname = s->r_data;
+ }
+ action _incl_origin_exit {
+ s->r_data_length = s->dname_tmp_length;
+ }
+ action _incl_origin_error {
+ ERR(ZS_BAD_INCLUDE_ORIGIN);
+ fhold; fgoto err_line;
+ }
+
+ action _include_exit {
+ // Extend relative file path.
+ if (s->include_filename[0] != '/') {
+ int ret = snprintf((char *)(s->buffer), sizeof(s->buffer),
+ "%s/%s", s->path, s->include_filename);
+ if (ret <= 0 || ret > sizeof(s->buffer)) {
+ ERR(ZS_BAD_INCLUDE_FILENAME);
+ fhold; fgoto err_line;
+ }
+ memcpy(s->include_filename, s->buffer, ret);
+ }
+
+ // Origin conversion from wire to text form in \DDD notation.
+ if (s->dname == NULL) { // Use current origin.
+ wire_dname_to_str(s->zone_origin,
+ s->zone_origin_length,
+ (char *)s->buffer);
+ } else { // Use specified origin.
+ wire_dname_to_str(s->r_data,
+ s->r_data_length,
+ (char *)s->buffer);
+ }
+
+ // Let the caller to solve the include.
+ if (s->process.automatic) {
+ // Create new scanner for included zone file.
+ zs_scanner_t *ss = malloc(sizeof(zs_scanner_t));
+ if (ss == NULL) {
+ ERR(ZS_UNPROCESSED_INCLUDE);
+ fhold; fgoto err_line;
+ }
+
+ // Parse included zone file.
+ if (zs_init(ss, (char *)s->buffer, s->default_class,
+ s->default_ttl) != 0 ||
+ zs_set_input_file(ss, (char *)(s->include_filename)) != 0 ||
+ zs_set_processing(ss, s->process.record, s->process.error,
+ s->process.data) != 0 ||
+ zs_parse_all(ss) != 0) {
+ // File internal errors are handled by error callback.
+ if (ss->error.counter > 0) {
+ s->error.counter += ss->error.counter;
+ ERR(ZS_UNPROCESSED_INCLUDE);
+ // General include file error.
+ } else {
+ ERR(ss->error.code);
+ }
+ zs_deinit(ss);
+ free(ss);
+ fhold; fgoto err_line;
+ }
+ zs_deinit(ss);
+ free(ss);
+ } else {
+ s->state = ZS_STATE_INCLUDE;
+ fhold; fnext main; fbreak;
+ }
+ }
+
+ include_file_ :=
+ (sep . text >_incl_filename_init %_incl_filename_exit
+ $!_incl_filename_error .
+ (sep . absolute_dname >_incl_origin_init %_incl_origin_exit
+ $!_incl_origin_error
+ )? . rest
+ ) %_include_exit %_ret newline;
+ include_file = all_wchar ${ fhold; fcall include_file_; };
+ # END
+
+ # BEGIN - Directive switch
+ # Each error/warning in directive should stop processing.
+ # Some internal errors cause warning only. This causes stop processing.
+ action _directive_init {
+ ERR(ZS_OK);
+ }
+ # Remove stop processing flag.
+ action _directive_exit {
+ NOERR;
+ }
+ action _directive_error {
+ ERR(ZS_BAD_DIRECTIVE);
+ fhold; fgoto err_line;
+ }
+
+ directive = '$' . ( ("TTL"i . default_ttl)
+ | ("ORIGIN"i . zone_origin)
+ | ("INCLUDE"i . include_file)
+ ) >_directive_init %_directive_exit $!_directive_error;
+ # END
+
+ # BEGIN - RRecord class and ttl processing
+ action _default_r_class_exit {
+ s->r_class = s->default_class;
+ }
+
+ action _default_r_ttl_exit {
+ s->r_ttl = s->default_ttl;
+ }
+
+ action _r_class_in_exit {
+ s->r_class = KNOT_CLASS_IN;
+ }
+
+ action _r_ttl_exit {
+ if (s->number64 <= UINT32_MAX) {
+ s->r_ttl = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_NUMBER32_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+
+ r_class = "IN"i %_r_class_in_exit;
+
+ r_ttl = time %_r_ttl_exit;
+ # END
+
+ # BEGIN - IPv4 and IPv6 address processing
+ action _addr_init {
+ s->buffer_length = 0;
+ }
+ action _addr {
+ if (s->buffer_length < sizeof(s->buffer) - 1) {
+ s->buffer[s->buffer_length++] = fc;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+ action _addr_error {
+ WARN(ZS_BAD_ADDRESS_CHAR);
+ fhold; fgoto err_line;
+ }
+
+ action _ipv4_addr_exit {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV4);
+ fhold; fgoto err_line;
+ }
+ }
+ action _ipv4_addr_write {
+ memcpy(rdata_tail, s->addr, ZS_INET4_ADDR_LENGTH);
+ rdata_tail += ZS_INET4_ADDR_LENGTH;
+ }
+
+ action _ipv6_addr_exit {
+ s->buffer[s->buffer_length] = 0;
+
+ if (inet_pton(AF_INET6, (char *)s->buffer, s->addr) <= 0) {
+ WARN(ZS_BAD_IPV6);
+ fhold; fgoto err_line;
+ }
+ }
+ action _ipv6_addr_write {
+ memcpy(rdata_tail, s->addr, ZS_INET6_ADDR_LENGTH);
+ rdata_tail += ZS_INET6_ADDR_LENGTH;
+ }
+
+ # Address parsers only.
+ ipv4_addr = (digit | '.')+ >_addr_init $_addr %_ipv4_addr_exit
+ $!_addr_error;
+ ipv6_addr = (xdigit | [.:])+ >_addr_init $_addr %_ipv6_addr_exit
+ $!_addr_error;
+
+ # Write parsed address to r_data.
+ ipv4_addr_write = ipv4_addr %_ipv4_addr_write;
+ ipv6_addr_write = ipv6_addr %_ipv6_addr_write;
+ # END
+
+ # BEGIN - apl record processing
+ action _apl_init {
+ memset(&(s->apl), 0, sizeof(s->apl));
+ }
+ action _apl_excl_flag {
+ s->apl.excl_flag = 128; // dec 128 = bin 10000000.
+ }
+ action _apl_addr_1 {
+ s->apl.addr_family = 1;
+ }
+ action _apl_addr_2 {
+ s->apl.addr_family = 2;
+ }
+ action _apl_prefix_length {
+ if ((s->apl.addr_family == 1 && s->number64 <= 32) ||
+ (s->apl.addr_family == 2 && s->number64 <= 128)) {
+ s->apl.prefix_length = (uint8_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_APL);
+ fhold; fgoto err_line;
+ }
+ }
+ action _apl_exit {
+ // Copy address to buffer.
+ uint8_t len;
+ switch (s->apl.addr_family) {
+ case 1:
+ len = ZS_INET4_ADDR_LENGTH;
+ memcpy(s->buffer, s->addr, len);
+ break;
+ case 2:
+ len = ZS_INET6_ADDR_LENGTH;
+ memcpy(s->buffer, s->addr, len);
+ break;
+ default:
+ WARN(ZS_BAD_APL);
+ fhold; fgoto err_line;
+ }
+ // Find prefix without trailing zeroes.
+ while (len > 0) {
+ if ((s->buffer[len - 1] & 255) != 0) {
+ break;
+ }
+ len--;
+ }
+ // Check for rdata overflow.
+ if (rdata_tail + 4 + len > rdata_stop) {
+ WARN(ZS_RDATA_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ // Write address family.
+ *((uint16_t *)rdata_tail) = htons(s->apl.addr_family);
+ rdata_tail += 2;
+ // Write prefix length in bits.
+ *(rdata_tail) = s->apl.prefix_length;
+ rdata_tail += 1;
+ // Write negation flag + prefix length in bytes.
+ *(rdata_tail) = len + s->apl.excl_flag;
+ rdata_tail += 1;
+ // Write address prefix non-null data.
+ memcpy(rdata_tail, s->buffer, len);
+ rdata_tail += len;
+ }
+ action _apl_error {
+ WARN(ZS_BAD_APL);
+ fhold; fgoto err_line;
+ }
+
+ apl = ('!'? $_apl_excl_flag .
+ ( ('1' $_apl_addr_1 . ':' . ipv4_addr . '/' . number
+ %_apl_prefix_length)
+ | ('2' $_apl_addr_2 . ':' . ipv6_addr . '/' . number
+ %_apl_prefix_length)
+ )
+ ) >_apl_init %_apl_exit $!_apl_error;
+
+ # Array of APL records (can be empty).
+ apl_array = apl? . (sep . apl)* . sep?;
+ # END
+
+ # BEGIN - Hexadecimal string array processing
+ action _first_hex_char {
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = first_hex_to_num[(uint8_t)fc];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+ action _second_hex_char {
+ *rdata_tail += second_hex_to_num[(uint8_t)fc];
+ rdata_tail++;
+ }
+ action _hex_char_error {
+ WARN(ZS_BAD_HEX_CHAR);
+ fhold; fgoto err_line;
+ }
+
+ hex_char = (xdigit $_first_hex_char . xdigit $_second_hex_char);
+
+ # Hex array with possibility of inside white spaces and multiline.
+ hex_array = (hex_char+ . sep?)+ $!_hex_char_error;
+
+ # Continuous hex array (or "-") with forward length processing.
+ salt = (hex_char+ | '-') >_item_length_init %_item_length_exit
+ $!_hex_char_error;
+
+ action _type_data_exit {
+ if ((rdata_tail - s->r_data) != s->r_data_length) {
+ WARN(ZS_BAD_RDATA_LENGTH);
+ fhold; fgoto err_line;
+ }
+ }
+
+ action _type_data_error {
+ WARN(ZS_BAD_HEX_RDATA);
+ fhold; fgoto err_line;
+ }
+
+ # Hex array with control to forward length statement.
+ type_data = hex_array %_type_data_exit $!_type_data_error;
+ # END
+
+ # BEGIN - Base64 processing (RFC 4648)
+ action _first_base64_char {
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = first_base64_to_num[(uint8_t)fc];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+ action _second_base64_char {
+ *(rdata_tail++) += second_left_base64_to_num[(uint8_t)fc];
+
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = second_right_base64_to_num[(uint8_t)fc];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+ action _third_base64_char {
+ *(rdata_tail++) += third_left_base64_to_num[(uint8_t)fc];
+
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = third_right_base64_to_num[(uint8_t)fc];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+ action _fourth_base64_char {
+ *(rdata_tail++) += fourth_base64_to_num[(uint8_t)fc];
+ }
+
+ action _base64_char_error {
+ WARN(ZS_BAD_BASE64_CHAR);
+ fhold; fgoto err_line;
+ }
+
+ base64_char = alnum | [+/];
+ base64_padd = '=';
+ base64_quartet =
+ ( base64_char $_first_base64_char . # A
+ base64_char $_second_base64_char . # AB
+ ( ( base64_char $_third_base64_char . # ABC
+ ( base64_char $_fourth_base64_char # ABCD
+ | base64_padd{1} # ABC=
+ )
+ )
+ | base64_padd{2} # AB==
+ )
+ );
+
+ # Base64 array with possibility of inside white spaces and multiline.
+ base64_ := (base64_quartet+ . sep?)+ $!_base64_char_error
+ %_ret . end_wchar;
+ base64 = base64_char ${ fhold; fcall base64_; };
+ # END
+
+ # BEGIN - Base32hex processing (RFC 4648)
+ action _first_base32hex_char {
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = first_base32hex_to_num[(uint8_t)fc];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+ action _second_base32hex_char {
+ *(rdata_tail++) += second_left_base32hex_to_num[(uint8_t)fc];
+
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = second_right_base32hex_to_num[(uint8_t)fc];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+ action _third_base32hex_char {
+ *rdata_tail += third_base32hex_to_num[(uint8_t)fc];
+ }
+ action _fourth_base32hex_char {
+ *(rdata_tail++) += fourth_left_base32hex_to_num[(uint8_t)fc];
+
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = fourth_right_base32hex_to_num[(uint8_t)fc];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+ action _fifth_base32hex_char {
+ *(rdata_tail++) += fifth_left_base32hex_to_num[(uint8_t)fc];
+
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = fifth_right_base32hex_to_num[(uint8_t)fc];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+ action _sixth_base32hex_char {
+ *rdata_tail += sixth_base32hex_to_num[(uint8_t)fc];
+ }
+ action _seventh_base32hex_char {
+ *(rdata_tail++) += seventh_left_base32hex_to_num[(uint8_t)fc];
+
+ if (rdata_tail <= rdata_stop) {
+ *rdata_tail = seventh_right_base32hex_to_num[(uint8_t)fc];
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+ action _eighth_base32hex_char {
+ *(rdata_tail++) += eighth_base32hex_to_num[(uint8_t)fc];
+ }
+
+ action _base32hex_char_error {
+ WARN(ZS_BAD_BASE32HEX_CHAR);
+ fhold; fgoto err_line;
+ }
+
+ base32hex_char = [0-9a-vA-V];
+ base32hex_padd = '=';
+ base32hex_octet =
+ ( base32hex_char $_first_base32hex_char . # A
+ base32hex_char $_second_base32hex_char . # AB
+ ( ( base32hex_char $_third_base32hex_char . # ABC
+ base32hex_char $_fourth_base32hex_char . # ABCD
+ ( ( base32hex_char $_fifth_base32hex_char . # ABCDE
+ ( ( base32hex_char $_sixth_base32hex_char . # ABCDEF
+ base32hex_char $_seventh_base32hex_char . # ABCDEFG
+ ( base32hex_char $_eighth_base32hex_char # ABCDEFGH
+ | base32hex_padd{1} # ABCDEFG=
+ )
+ )
+ | base32hex_padd{3} # ABCDE===
+ )
+ )
+ | base32hex_padd{4} # ABCD====
+ )
+ )
+ | base32hex_padd{6} # AB======
+ )
+ );
+
+ # Continuous base32hex (with padding!) array with forward length processing.
+ hash = base32hex_octet+ >_item_length_init %_item_length_exit
+ $!_base32hex_char_error;
+ # END
+
+ # BEGIN - Simple number write functions.
+ action _write8_0 {
+ *(rdata_tail++) = 0;
+ }
+ action _write8_1 {
+ *(rdata_tail++) = 1;
+ }
+ action _write8_2 {
+ *(rdata_tail++) = 2;
+ }
+ action _write8_3 {
+ *(rdata_tail++) = 3;
+ }
+ action _write8_5 {
+ *(rdata_tail++) = 5;
+ }
+ action _write8_6 {
+ *(rdata_tail++) = 6;
+ }
+ action _write8_7 {
+ *(rdata_tail++) = 7;
+ }
+ action _write8_8 {
+ *(rdata_tail++) = 8;
+ }
+ action _write8_10 {
+ *(rdata_tail++) = 10;
+ }
+ action _write8_12 {
+ *(rdata_tail++) = 12;
+ }
+ action _write8_13 {
+ *(rdata_tail++) = 13;
+ }
+ action _write8_14 {
+ *(rdata_tail++) = 14;
+ }
+ action _write8_15 {
+ *(rdata_tail++) = 15;
+ }
+ action _write8_16 {
+ *(rdata_tail++) = 16;
+ }
+ action _write8_252 {
+ *(rdata_tail++) = 252;
+ }
+ action _write8_253 {
+ *(rdata_tail++) = 253;
+ }
+ action _write8_254 {
+ *(rdata_tail++) = 254;
+ }
+
+ action _write16_1 {
+ *((uint16_t *)rdata_tail) = htons(1);
+ rdata_tail += 2;
+ }
+ action _write16_2 {
+ *((uint16_t *)rdata_tail) = htons(2);
+ rdata_tail += 2;
+ }
+ action _write16_3 {
+ *((uint16_t *)rdata_tail) = htons(3);
+ rdata_tail += 2;
+ }
+ action _write16_4 {
+ *((uint16_t *)rdata_tail) = htons(4);
+ rdata_tail += 2;
+ }
+ action _write16_5 {
+ *((uint16_t *)rdata_tail) = htons(5);
+ rdata_tail += 2;
+ }
+ action _write16_6 {
+ *((uint16_t *)rdata_tail) = htons(6);
+ rdata_tail += 2;
+ }
+ action _write16_7 {
+ *((uint16_t *)rdata_tail) = htons(7);
+ rdata_tail += 2;
+ }
+ action _write16_8 {
+ *((uint16_t *)rdata_tail) = htons(8);
+ rdata_tail += 2;
+ }
+ action _write16_253 {
+ *((uint16_t *)rdata_tail) = htons(253);
+ rdata_tail += 2;
+ }
+ action _write16_254 {
+ *((uint16_t *)rdata_tail) = htons(254);
+ rdata_tail += 2;
+ }
+ # END
+
+ # BEGIN - Gateway
+ action _gateway_error {
+ WARN(ZS_BAD_GATEWAY);
+ fhold; fgoto err_line;
+ }
+ action _gateway_key_error {
+ WARN(ZS_BAD_GATEWAY_KEY);
+ fhold; fgoto err_line;
+ }
+
+ gateway = (( ('0' $_write8_0 . sep . num8 . sep . '.')
+ | ('1' $_write8_1 . sep . num8 . sep . ipv4_addr_write)
+ | ('2' $_write8_2 . sep . num8 . sep . ipv6_addr_write)
+ | ('3' $_write8_3 . sep . num8 . sep . r_dname)
+ ) $!_gateway_error .
+ # If algorithm is 0 then key isn't present and vice versa.
+ ( ((sep . base64) when { s->number64 != 0 })
+ | ((sep?) when { s->number64 == 0 }) # remove blank space
+ ) $!_gateway_key_error
+ );
+ # END
+
+ # BEGIN - Type processing
+ action _type_error {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ fhold; fgoto err_line;
+ }
+
+ type_num =
+ ( "A"i %{ type_num(KNOT_RRTYPE_A, &rdata_tail); }
+ | "NS"i %{ type_num(KNOT_RRTYPE_NS, &rdata_tail); }
+ | "CNAME"i %{ type_num(KNOT_RRTYPE_CNAME, &rdata_tail); }
+ | "SOA"i %{ type_num(KNOT_RRTYPE_SOA, &rdata_tail); }
+ | "PTR"i %{ type_num(KNOT_RRTYPE_PTR, &rdata_tail); }
+ | "HINFO"i %{ type_num(KNOT_RRTYPE_HINFO, &rdata_tail); }
+ | "MINFO"i %{ type_num(KNOT_RRTYPE_MINFO, &rdata_tail); }
+ | "MX"i %{ type_num(KNOT_RRTYPE_MX, &rdata_tail); }
+ | "TXT"i %{ type_num(KNOT_RRTYPE_TXT, &rdata_tail); }
+ | "RP"i %{ type_num(KNOT_RRTYPE_RP, &rdata_tail); }
+ | "AFSDB"i %{ type_num(KNOT_RRTYPE_AFSDB, &rdata_tail); }
+ | "RT"i %{ type_num(KNOT_RRTYPE_RT, &rdata_tail); }
+ | "KEY"i %{ type_num(KNOT_RRTYPE_KEY, &rdata_tail); }
+ | "AAAA"i %{ type_num(KNOT_RRTYPE_AAAA, &rdata_tail); }
+ | "LOC"i %{ type_num(KNOT_RRTYPE_LOC, &rdata_tail); }
+ | "SRV"i %{ type_num(KNOT_RRTYPE_SRV, &rdata_tail); }
+ | "NAPTR"i %{ type_num(KNOT_RRTYPE_NAPTR, &rdata_tail); }
+ | "KX"i %{ type_num(KNOT_RRTYPE_KX, &rdata_tail); }
+ | "CERT"i %{ type_num(KNOT_RRTYPE_CERT, &rdata_tail); }
+ | "DNAME"i %{ type_num(KNOT_RRTYPE_DNAME, &rdata_tail); }
+ | "APL"i %{ type_num(KNOT_RRTYPE_APL, &rdata_tail); }
+ | "DS"i %{ type_num(KNOT_RRTYPE_DS, &rdata_tail); }
+ | "SSHFP"i %{ type_num(KNOT_RRTYPE_SSHFP, &rdata_tail); }
+ | "IPSECKEY"i %{ type_num(KNOT_RRTYPE_IPSECKEY, &rdata_tail); }
+ | "RRSIG"i %{ type_num(KNOT_RRTYPE_RRSIG, &rdata_tail); }
+ | "NSEC"i %{ type_num(KNOT_RRTYPE_NSEC, &rdata_tail); }
+ | "DNSKEY"i %{ type_num(KNOT_RRTYPE_DNSKEY, &rdata_tail); }
+ | "DHCID"i %{ type_num(KNOT_RRTYPE_DHCID, &rdata_tail); }
+ | "NSEC3"i %{ type_num(KNOT_RRTYPE_NSEC3, &rdata_tail); }
+ | "NSEC3PARAM"i %{ type_num(KNOT_RRTYPE_NSEC3PARAM, &rdata_tail); }
+ | "TLSA"i %{ type_num(KNOT_RRTYPE_TLSA, &rdata_tail); }
+ | "CDS"i %{ type_num(KNOT_RRTYPE_CDS, &rdata_tail); }
+ | "CDNSKEY"i %{ type_num(KNOT_RRTYPE_CDNSKEY, &rdata_tail); }
+ | "SPF"i %{ type_num(KNOT_RRTYPE_SPF, &rdata_tail); }
+ | "NID"i %{ type_num(KNOT_RRTYPE_NID, &rdata_tail); }
+ | "L32"i %{ type_num(KNOT_RRTYPE_L32, &rdata_tail); }
+ | "L64"i %{ type_num(KNOT_RRTYPE_L64, &rdata_tail); }
+ | "LP"i %{ type_num(KNOT_RRTYPE_LP, &rdata_tail); }
+ | "EUI48"i %{ type_num(KNOT_RRTYPE_EUI48, &rdata_tail); }
+ | "EUI64"i %{ type_num(KNOT_RRTYPE_EUI64, &rdata_tail); }
+ | "URI"i %{ type_num(KNOT_RRTYPE_URI, &rdata_tail); }
+ | "CAA"i %{ type_num(KNOT_RRTYPE_CAA, &rdata_tail); }
+ | "TYPE"i . num16 # TYPE0-TYPE65535.
+ ) $!_type_error;
+ # END
+
+ # BEGIN - Bitmap processing
+ action _type_bitmap_exit {
+ if (s->number64 <= UINT16_MAX) {
+ window_add_bit(s->number64, s);
+ } else {
+ WARN(ZS_NUMBER16_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+
+ # TYPE0-TYPE65535.
+ type_bitmap = number %_type_bitmap_exit;
+
+ type_bit =
+ ( "A"i %{ window_add_bit(KNOT_RRTYPE_A, s); }
+ | "NS"i %{ window_add_bit(KNOT_RRTYPE_NS, s); }
+ | "CNAME"i %{ window_add_bit(KNOT_RRTYPE_CNAME, s); }
+ | "SOA"i %{ window_add_bit(KNOT_RRTYPE_SOA, s); }
+ | "PTR"i %{ window_add_bit(KNOT_RRTYPE_PTR, s); }
+ | "HINFO"i %{ window_add_bit(KNOT_RRTYPE_HINFO, s); }
+ | "MINFO"i %{ window_add_bit(KNOT_RRTYPE_MINFO, s); }
+ | "MX"i %{ window_add_bit(KNOT_RRTYPE_MX, s); }
+ | "TXT"i %{ window_add_bit(KNOT_RRTYPE_TXT, s); }
+ | "RP"i %{ window_add_bit(KNOT_RRTYPE_RP, s); }
+ | "AFSDB"i %{ window_add_bit(KNOT_RRTYPE_AFSDB, s); }
+ | "RT"i %{ window_add_bit(KNOT_RRTYPE_RT, s); }
+ | "KEY"i %{ window_add_bit(KNOT_RRTYPE_KEY, s); }
+ | "AAAA"i %{ window_add_bit(KNOT_RRTYPE_AAAA, s); }
+ | "LOC"i %{ window_add_bit(KNOT_RRTYPE_LOC, s); }
+ | "SRV"i %{ window_add_bit(KNOT_RRTYPE_SRV, s); }
+ | "NAPTR"i %{ window_add_bit(KNOT_RRTYPE_NAPTR, s); }
+ | "KX"i %{ window_add_bit(KNOT_RRTYPE_KX, s); }
+ | "CERT"i %{ window_add_bit(KNOT_RRTYPE_CERT, s); }
+ | "DNAME"i %{ window_add_bit(KNOT_RRTYPE_DNAME, s); }
+ | "APL"i %{ window_add_bit(KNOT_RRTYPE_APL, s); }
+ | "DS"i %{ window_add_bit(KNOT_RRTYPE_DS, s); }
+ | "SSHFP"i %{ window_add_bit(KNOT_RRTYPE_SSHFP, s); }
+ | "IPSECKEY"i %{ window_add_bit(KNOT_RRTYPE_IPSECKEY, s); }
+ | "RRSIG"i %{ window_add_bit(KNOT_RRTYPE_RRSIG, s); }
+ | "NSEC"i %{ window_add_bit(KNOT_RRTYPE_NSEC, s); }
+ | "DNSKEY"i %{ window_add_bit(KNOT_RRTYPE_DNSKEY, s); }
+ | "DHCID"i %{ window_add_bit(KNOT_RRTYPE_DHCID, s); }
+ | "NSEC3"i %{ window_add_bit(KNOT_RRTYPE_NSEC3, s); }
+ | "NSEC3PARAM"i %{ window_add_bit(KNOT_RRTYPE_NSEC3PARAM, s); }
+ | "TLSA"i %{ window_add_bit(KNOT_RRTYPE_TLSA, s); }
+ | "CDS"i %{ window_add_bit(KNOT_RRTYPE_CDS, s); }
+ | "CDNSKEY"i %{ window_add_bit(KNOT_RRTYPE_CDNSKEY, s); }
+ | "SPF"i %{ window_add_bit(KNOT_RRTYPE_SPF, s); }
+ | "NID"i %{ window_add_bit(KNOT_RRTYPE_NID, s); }
+ | "L32"i %{ window_add_bit(KNOT_RRTYPE_L32, s); }
+ | "L64"i %{ window_add_bit(KNOT_RRTYPE_L64, s); }
+ | "LP"i %{ window_add_bit(KNOT_RRTYPE_LP, s); }
+ | "EUI48"i %{ window_add_bit(KNOT_RRTYPE_EUI48, s); }
+ | "EUI64"i %{ window_add_bit(KNOT_RRTYPE_EUI64, s); }
+ | "URI"i %{ window_add_bit(KNOT_RRTYPE_URI, s); }
+ | "CAA"i %{ window_add_bit(KNOT_RRTYPE_CAA, s); }
+ | "TYPE"i . type_bitmap # TYPE0-TYPE65535.
+ );
+
+ action _bitmap_init {
+ memset(s->windows, 0, sizeof(s->windows));
+ s->last_window = -1;
+ }
+ action _bitmap_exit {
+ for (uint16_t window = 0; window <= s->last_window; window++) {
+ if ((s->windows[window]).length > 0) {
+ if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
+ {
+ // Window number.
+ *rdata_tail = (uint8_t)window;
+ rdata_tail += 1;
+ // Bitmap length.
+ *rdata_tail = (s->windows[window]).length;
+ rdata_tail += 1;
+ // Copying bitmap.
+ memcpy(rdata_tail,
+ (s->windows[window]).bitmap,
+ (s->windows[window]).length);
+ rdata_tail += (s->windows[window]).length;
+ } else {
+ WARN(ZS_RDATA_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ }
+ }
+ }
+ action _bitmap_error {
+ WARN(ZS_BAD_BITMAP);
+ fhold; fgoto err_line;
+ }
+
+ # Blank bitmap is allowed too.
+ bitmap_ := ((sep . type_bit)* . sep?) >_bitmap_init
+ %_bitmap_exit %_ret $!_bitmap_error . end_wchar;
+ bitmap = all_wchar ${ fhold; fcall bitmap_; };
+ # END
+
+ # BEGIN - Location processing
+ action _d1_exit {
+ if (s->number64 <= 90) {
+ s->loc.d1 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ fhold; fgoto err_line;
+ }
+ }
+ action _d2_exit {
+ if (s->number64 <= 180) {
+ s->loc.d2 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ fhold; fgoto err_line;
+ }
+ }
+ action _m1_exit {
+ if (s->number64 <= 59) {
+ s->loc.m1 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ fhold; fgoto err_line;
+ }
+ }
+ action _m2_exit {
+ if (s->number64 <= 59) {
+ s->loc.m2 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ fhold; fgoto err_line;
+ }
+ }
+ action _s1_exit {
+ if (s->number64 <= 59999) {
+ s->loc.s1 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ fhold; fgoto err_line;
+ }
+ }
+ action _s2_exit {
+ if (s->number64 <= 59999) {
+ s->loc.s2 = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ fhold; fgoto err_line;
+ }
+ }
+ action _alt_exit {
+ if ((s->loc.alt_sign == 1 && s->number64 <= 4284967295) ||
+ (s->loc.alt_sign == -1 && s->number64 <= 10000000))
+ {
+ s->loc.alt = (uint32_t)(s->number64);
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ fhold; fgoto err_line;
+ }
+ }
+ action _siz_exit {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.siz = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ fhold; fgoto err_line;
+ }
+ }
+ action _hp_exit {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.hp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ fhold; fgoto err_line;
+ }
+ }
+ action _vp_exit {
+ if (s->number64 <= 9000000000ULL) {
+ s->loc.vp = s->number64;
+ } else {
+ WARN(ZS_BAD_NUMBER);
+ fhold; fgoto err_line;
+ }
+ }
+ action _lat_sign {
+ s->loc.lat_sign = -1;
+ }
+ action _long_sign {
+ s->loc.long_sign = -1;
+ }
+ action _alt_sign {
+ s->loc.alt_sign = -1;
+ }
+
+ d1 = number %_d1_exit;
+ d2 = number %_d2_exit;
+ m1 = number %_m1_exit;
+ m2 = number %_m2_exit;
+ s1 = float3 %_s1_exit;
+ s2 = float3 %_s2_exit;
+ siz = float2 %_siz_exit;
+ hp = float2 %_hp_exit;
+ vp = float2 %_vp_exit;
+ alt = ('-' %_alt_sign)? . float2 %_alt_exit;
+ lat_sign = 'N' | 'S' %_lat_sign;
+ long_sign = 'E' | 'W' %_long_sign;
+
+ action _loc_init {
+ memset(&(s->loc), 0, sizeof(s->loc));
+ // Defaults.
+ s->loc.siz = 100;
+ s->loc.vp = 1000;
+ s->loc.hp = 1000000;
+ s->loc.lat_sign = 1;
+ s->loc.long_sign = 1;
+ s->loc.alt_sign = 1;
+ }
+ action _loc_exit {
+ // Write version.
+ *(rdata_tail) = 0;
+ rdata_tail += 1;
+ // Write size.
+ *(rdata_tail) = loc64to8(s->loc.siz);
+ rdata_tail += 1;
+ // Write horizontal precision.
+ *(rdata_tail) = loc64to8(s->loc.hp);
+ rdata_tail += 1;
+ // Write vertical precision.
+ *(rdata_tail) = loc64to8(s->loc.vp);
+ rdata_tail += 1;
+ // Write latitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
+ (3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
+ rdata_tail += 4;
+ // Write longitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
+ (3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
+ rdata_tail += 4;
+ // Write altitude.
+ *((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
+ (s->loc.alt));
+ rdata_tail += 4;
+ }
+ action _loc_error {
+ WARN(ZS_BAD_LOC_DATA);
+ fhold; fgoto err_line;
+ }
+
+ loc = (d1 . sep . (m1 . sep . (s1 . sep)?)? . lat_sign . sep .
+ d2 . sep . (m2 . sep . (s2 . sep)?)? . long_sign . sep .
+ alt 'm'? . (sep . siz 'm'? . (sep . hp 'm'? . (sep . vp 'm'?)?)?)? .
+ sep?
+ ) >_loc_init %_loc_exit $!_loc_error;
+ # END
+
+ # BEGIN - Hexadecimal rdata processing
+ action _hex_r_data_error {
+ WARN(ZS_BAD_HEX_RDATA);
+ fhold; fgoto err_line;
+ }
+
+ nonempty_hex_r_data :=
+ (sep . length_number . sep . type_data)
+ $!_hex_r_data_error %_ret . end_wchar;
+
+ hex_r_data :=
+ (sep .
+ ( ('0' %_ret . all_wchar)
+ | (length_number . sep . type_data %_ret . end_wchar)
+ )
+ ) $!_hex_r_data_error;
+ # END
+
+ # BEGIN - EUI processing
+ action _eui_init {
+ s->item_length = 0;
+ }
+ action _eui_count {
+ s->item_length++;
+ }
+ action _eui48_exit {
+ if (s->item_length != 6) {
+ WARN(ZS_BAD_EUI_LENGTH);
+ fhold; fgoto err_line;
+ }
+ }
+ action _eui64_exit {
+ if (s->item_length != 8) {
+ WARN(ZS_BAD_EUI_LENGTH);
+ fhold; fgoto err_line;
+ }
+ }
+ action _eui_sep_error {
+ WARN(ZS_BAD_CHAR_DASH);
+ fhold; fgoto err_line;
+ }
+
+ eui48 = (hex_char %_eui_count .
+ ('-' >!_eui_sep_error . hex_char %_eui_count)+
+ ) $!_hex_char_error >_eui_init %_eui48_exit;
+
+ eui64 = (hex_char %_eui_count .
+ ('-' >!_eui_sep_error . hex_char %_eui_count)+
+ ) $!_hex_char_error >_eui_init %_eui64_exit;
+ # END
+
+ # BEGIN - ILNP processing
+ action _l64_init {
+ s->item_length = 0;
+ }
+ action _l64_count {
+ s->item_length++;
+ }
+ action _l64_exit {
+ if (s->item_length != 4) {
+ WARN(ZS_BAD_L64_LENGTH);
+ fhold; fgoto err_line;
+ }
+ }
+ action _l64_sep_error {
+ WARN(ZS_BAD_CHAR_COLON);
+ fhold; fgoto err_line;
+ }
+
+ l64_label = (hex_char . hex_char) $!_hex_char_error %_l64_count;
+ l64 = (l64_label . (':' >!_l64_sep_error . l64_label)+
+ ) $!_hex_char_error >_l64_init %_l64_exit;
+
+ l32 = ipv4_addr %_ipv4_addr_write;
+ # END
+
+ # BEGIN - Mnemomic names processing
+ action _dns_alg_error {
+ WARN(ZS_BAD_ALGORITHM);
+ fhold; fgoto err_line;
+ }
+ action _cert_type_error {
+ WARN(ZS_BAD_CERT_TYPE);
+ fhold; fgoto err_line;
+ }
+
+ dns_alg_ :=
+ ( number %_num8_write
+ | "RSAMD5"i %_write8_1
+ | "DH"i %_write8_2
+ | "DSA"i %_write8_3
+ | "RSASHA1"i %_write8_5
+ | "DSA-NSEC3-SHA1"i %_write8_6
+ | "RSASHA1-NSEC3-SHA1"i %_write8_7
+ | "RSASHA256"i %_write8_8
+ | "RSASHA512"i %_write8_10
+ | "ECC-GOST"i %_write8_12
+ | "ECDSAP256SHA256"i %_write8_13
+ | "ECDSAP384SHA384"i %_write8_14
+ | "ED25519"i %_write8_15
+ | "ED448"i %_write8_16
+ | "INDIRECT"i %_write8_252
+ | "PRIVATEDNS"i %_write8_253
+ | "PRIVATEOID"i %_write8_254
+ ) $!_dns_alg_error %_ret . all_wchar;
+ dns_alg = alnum ${ fhold; fcall dns_alg_; };
+
+ cert_type_ :=
+ ( number %_num16_write
+ | "PKIX"i %_write16_1
+ | "SPKI"i %_write16_2
+ | "PGP"i %_write16_3
+ | "IPKIX"i %_write16_4
+ | "ISPKI"i %_write16_5
+ | "IPGP"i %_write16_6
+ | "ACPKIX"i %_write16_7
+ | "IACPKIX"i %_write16_8
+ | "URI"i %_write16_253
+ | "OID"i %_write16_254
+ ) $!_cert_type_error %_ret . all_wchar;
+ cert_type = alnum ${ fhold; fcall cert_type_; };
+ # END
+
+ # BEGIN - Rdata processing
+ action _r_data_init {
+ rdata_tail = s->r_data;
+ }
+ action _r_data_error {
+ WARN(ZS_BAD_RDATA);
+ fhold; fgoto err_line;
+ }
+
+ r_data_a :=
+ (ipv4_addr_write)
+ $!_r_data_error %_ret . all_wchar;
+
+ r_data_ns :=
+ (r_dname)
+ $!_r_data_error %_ret . all_wchar;
+
+ r_data_soa :=
+ (r_dname . sep . r_dname . sep . num32 . sep . time32 .
+ sep . time32 . sep . time32 . sep . time32)
+ $!_r_data_error %_ret . all_wchar;
+
+ r_data_hinfo :=
+ (text_string . sep . text_string)
+ $!_r_data_error %_ret . all_wchar;
+
+ r_data_minfo :=
+ (r_dname . sep . r_dname)
+ $!_r_data_error %_ret . all_wchar;
+
+ r_data_mx :=
+ (num16 . sep . r_dname)
+ $!_r_data_error %_ret . all_wchar;
+
+ r_data_txt :=
+ (text_array)
+ $!_r_data_error %_ret . end_wchar;
+
+ r_data_aaaa :=
+ (ipv6_addr_write)
+ $!_r_data_error %_ret . all_wchar;
+
+ r_data_loc :=
+ (loc)
+ $!_r_data_error %_ret . end_wchar;
+
+ r_data_srv :=
+ (num16 . sep . num16 . sep . num16 . sep . r_dname)
+ $!_r_data_error %_ret . all_wchar;
+
+ r_data_naptr :=
+ (num16 . sep . num16 . sep . text_string . sep . text_string .
+ sep . text_string . sep . r_dname)
+ $!_r_data_error %_ret . all_wchar;
+
+ r_data_cert :=
+ (cert_type . sep . num16 . sep . dns_alg . sep . base64)
+ $!_r_data_error %_ret . end_wchar;
+
+ r_data_apl :=
+ (apl_array)
+ $!_r_data_error %_ret . end_wchar;
+
+ r_data_ds :=
+ (num16 . sep . dns_alg . sep . num8 . sep . hex_array)
+ $!_r_data_error %_ret . end_wchar;
+
+ r_data_sshfp :=
+ (num8 . sep . num8 . sep . hex_array)
+ $!_r_data_error %_ret . end_wchar;
+
+ r_data_ipseckey :=
+ (num8 . sep . gateway)
+ $!_r_data_error %_ret . end_wchar;
+
+ r_data_rrsig :=
+ (type_num . sep . dns_alg . sep . num8 . sep . num32 . sep .
+ timestamp . sep . timestamp . sep . num16 . sep . r_dname .
+ sep . base64)
+ $!_r_data_error %_ret . end_wchar;
+
+ r_data_nsec :=
+ (r_dname . bitmap)
+ $!_r_data_error %_ret . all_wchar;
+
+ r_data_dnskey :=
+ (num16 . sep . num8 . sep . dns_alg . sep . base64)
+ $!_r_data_error %_ret . end_wchar;
+
+ r_data_dhcid :=
+ (base64)
+ $!_r_data_error %_ret . end_wchar;
+
+ r_data_nsec3 :=
+ (num8 . sep . num8 . sep . num16 . sep . salt . sep .
+ hash . bitmap)
+ $!_r_data_error %_ret . all_wchar;
+
+ r_data_nsec3param :=
+ (num8 . sep . num8 . sep . num16 . sep . salt)
+ $!_r_data_error %_ret . all_wchar;
+
+ r_data_tlsa :=
+ (num8 . sep . num8 . sep . num8 . sep . hex_array)
+ $!_r_data_error %_ret . end_wchar;
+
+ r_data_l32 :=
+ (num16 . sep . l32)
+ $!_r_data_error %_ret . all_wchar;
+
+ r_data_l64 :=
+ (num16 . sep . l64)
+ $!_r_data_error %_ret . all_wchar;
+
+ r_data_eui48 :=
+ (eui48)
+ $!_r_data_error %_ret . all_wchar;
+
+ r_data_eui64 :=
+ (eui64)
+ $!_r_data_error %_ret . all_wchar;
+
+ r_data_uri :=
+ (num16 . sep . num16 . sep . text)
+ $!_r_data_error %_ret . all_wchar;
+
+ r_data_caa :=
+ (num8 . sep . text_string . sep . text)
+ $!_r_data_error %_ret . all_wchar;
+
+ action _text_r_data {
+ fhold;
+ switch (s->r_type) {
+ case KNOT_RRTYPE_A:
+ fcall r_data_a;
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ fcall r_data_ns;
+ case KNOT_RRTYPE_SOA:
+ fcall r_data_soa;
+ case KNOT_RRTYPE_HINFO:
+ fcall r_data_hinfo;
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_RP:
+ fcall r_data_minfo;
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_LP:
+ fcall r_data_mx;
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ fcall r_data_txt;
+ case KNOT_RRTYPE_AAAA:
+ fcall r_data_aaaa;
+ case KNOT_RRTYPE_LOC:
+ fcall r_data_loc;
+ case KNOT_RRTYPE_SRV:
+ fcall r_data_srv;
+ case KNOT_RRTYPE_NAPTR:
+ fcall r_data_naptr;
+ case KNOT_RRTYPE_CERT:
+ fcall r_data_cert;
+ case KNOT_RRTYPE_APL:
+ fcall r_data_apl;
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_CDS:
+ fcall r_data_ds;
+ case KNOT_RRTYPE_SSHFP:
+ fcall r_data_sshfp;
+ case KNOT_RRTYPE_IPSECKEY:
+ fcall r_data_ipseckey;
+ case KNOT_RRTYPE_RRSIG:
+ fcall r_data_rrsig;
+ case KNOT_RRTYPE_NSEC:
+ fcall r_data_nsec;
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_CDNSKEY:
+ fcall r_data_dnskey;
+ case KNOT_RRTYPE_DHCID:
+ fcall r_data_dhcid;
+ case KNOT_RRTYPE_NSEC3:
+ fcall r_data_nsec3;
+ case KNOT_RRTYPE_NSEC3PARAM:
+ fcall r_data_nsec3param;
+ case KNOT_RRTYPE_TLSA:
+ fcall r_data_tlsa;
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L64:
+ fcall r_data_l64;
+ case KNOT_RRTYPE_L32:
+ fcall r_data_l32;
+ case KNOT_RRTYPE_EUI48:
+ fcall r_data_eui48;
+ case KNOT_RRTYPE_EUI64:
+ fcall r_data_eui64;
+ case KNOT_RRTYPE_URI:
+ fcall r_data_uri;
+ case KNOT_RRTYPE_CAA:
+ fcall r_data_caa;
+ default:
+ WARN(ZS_CANNOT_TEXT_DATA);
+ fgoto err_line;
+ }
+ }
+ action _hex_r_data {
+ switch (s->r_type) {
+ // Next types must not have empty rdata.
+ case KNOT_RRTYPE_A:
+ case KNOT_RRTYPE_NS:
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_PTR:
+ case KNOT_RRTYPE_DNAME:
+ case KNOT_RRTYPE_SOA:
+ case KNOT_RRTYPE_HINFO:
+ case KNOT_RRTYPE_MINFO:
+ case KNOT_RRTYPE_MX:
+ case KNOT_RRTYPE_AFSDB:
+ case KNOT_RRTYPE_RT:
+ case KNOT_RRTYPE_KX:
+ case KNOT_RRTYPE_TXT:
+ case KNOT_RRTYPE_SPF:
+ case KNOT_RRTYPE_RP:
+ case KNOT_RRTYPE_AAAA:
+ case KNOT_RRTYPE_LOC:
+ case KNOT_RRTYPE_SRV:
+ case KNOT_RRTYPE_NAPTR:
+ case KNOT_RRTYPE_CERT:
+ case KNOT_RRTYPE_DS:
+ case KNOT_RRTYPE_SSHFP:
+ case KNOT_RRTYPE_IPSECKEY:
+ case KNOT_RRTYPE_RRSIG:
+ case KNOT_RRTYPE_NSEC:
+ case KNOT_RRTYPE_KEY:
+ case KNOT_RRTYPE_DNSKEY:
+ case KNOT_RRTYPE_DHCID:
+ case KNOT_RRTYPE_NSEC3:
+ case KNOT_RRTYPE_NSEC3PARAM:
+ case KNOT_RRTYPE_TLSA:
+ case KNOT_RRTYPE_CDS:
+ case KNOT_RRTYPE_CDNSKEY:
+ case KNOT_RRTYPE_NID:
+ case KNOT_RRTYPE_L32:
+ case KNOT_RRTYPE_L64:
+ case KNOT_RRTYPE_LP:
+ case KNOT_RRTYPE_EUI48:
+ case KNOT_RRTYPE_EUI64:
+ case KNOT_RRTYPE_URI:
+ case KNOT_RRTYPE_CAA:
+ fcall nonempty_hex_r_data;
+ // Next types can have empty rdata.
+ case KNOT_RRTYPE_APL:
+ default:
+ fcall hex_r_data;
+ }
+ }
+
+ # Avoidance of multiple fhold at the input block end.
+ action _wrap_in {
+ if (pe - p == 1) {
+ *wrap = WRAP_DETECTED;
+ }
+ }
+ action _wrap_out {
+ if (*wrap == WRAP_NONE) {
+ fhold;
+ }
+ }
+
+ # rdata can be in text or hex format with leading "\#" string.
+ r_data =
+ ( sep . ^('\\' | all_wchar) $_text_r_data
+ | sep . '\\' $_wrap_in . ^'#' $_wrap_out $_text_r_data
+ | sep . '\\' . '#' $_hex_r_data # Hex format.
+ | sep? . end_wchar $_text_r_data # Empty rdata.
+ ) >_r_data_init $!_r_data_error;
+ # END
+
+ # BEGIN - Record type processing
+ action _r_type_error {
+ WARN(ZS_UNSUPPORTED_TYPE);
+ fhold; fgoto err_line;
+ }
+
+ r_type =
+ ( "A"i %{ s->r_type = KNOT_RRTYPE_A; }
+ | "NS"i %{ s->r_type = KNOT_RRTYPE_NS; }
+ | "CNAME"i %{ s->r_type = KNOT_RRTYPE_CNAME; }
+ | "SOA"i %{ s->r_type = KNOT_RRTYPE_SOA; }
+ | "PTR"i %{ s->r_type = KNOT_RRTYPE_PTR; }
+ | "HINFO"i %{ s->r_type = KNOT_RRTYPE_HINFO; }
+ | "MINFO"i %{ s->r_type = KNOT_RRTYPE_MINFO; }
+ | "MX"i %{ s->r_type = KNOT_RRTYPE_MX; }
+ | "TXT"i %{ s->r_type = KNOT_RRTYPE_TXT; }
+ | "RP"i %{ s->r_type = KNOT_RRTYPE_RP; }
+ | "AFSDB"i %{ s->r_type = KNOT_RRTYPE_AFSDB; }
+ | "RT"i %{ s->r_type = KNOT_RRTYPE_RT; }
+ | "KEY"i %{ s->r_type = KNOT_RRTYPE_KEY; }
+ | "AAAA"i %{ s->r_type = KNOT_RRTYPE_AAAA; }
+ | "LOC"i %{ s->r_type = KNOT_RRTYPE_LOC; }
+ | "SRV"i %{ s->r_type = KNOT_RRTYPE_SRV; }
+ | "NAPTR"i %{ s->r_type = KNOT_RRTYPE_NAPTR; }
+ | "KX"i %{ s->r_type = KNOT_RRTYPE_KX; }
+ | "CERT"i %{ s->r_type = KNOT_RRTYPE_CERT; }
+ | "DNAME"i %{ s->r_type = KNOT_RRTYPE_DNAME; }
+ | "APL"i %{ s->r_type = KNOT_RRTYPE_APL; }
+ | "DS"i %{ s->r_type = KNOT_RRTYPE_DS; }
+ | "SSHFP"i %{ s->r_type = KNOT_RRTYPE_SSHFP; }
+ | "IPSECKEY"i %{ s->r_type = KNOT_RRTYPE_IPSECKEY; }
+ | "RRSIG"i %{ s->r_type = KNOT_RRTYPE_RRSIG; }
+ | "NSEC"i %{ s->r_type = KNOT_RRTYPE_NSEC; }
+ | "DNSKEY"i %{ s->r_type = KNOT_RRTYPE_DNSKEY; }
+ | "DHCID"i %{ s->r_type = KNOT_RRTYPE_DHCID; }
+ | "NSEC3"i %{ s->r_type = KNOT_RRTYPE_NSEC3; }
+ | "NSEC3PARAM"i %{ s->r_type = KNOT_RRTYPE_NSEC3PARAM; }
+ | "TLSA"i %{ s->r_type = KNOT_RRTYPE_TLSA; }
+ | "CDS"i %{ s->r_type = KNOT_RRTYPE_CDS; }
+ | "CDNSKEY"i %{ s->r_type = KNOT_RRTYPE_CDNSKEY; }
+ | "SPF"i %{ s->r_type = KNOT_RRTYPE_SPF; }
+ | "NID"i %{ s->r_type = KNOT_RRTYPE_NID; }
+ | "L32"i %{ s->r_type = KNOT_RRTYPE_L32; }
+ | "L64"i %{ s->r_type = KNOT_RRTYPE_L64; }
+ | "LP"i %{ s->r_type = KNOT_RRTYPE_LP; }
+ | "EUI48"i %{ s->r_type = KNOT_RRTYPE_EUI48; }
+ | "EUI64"i %{ s->r_type = KNOT_RRTYPE_EUI64; }
+ | "URI"i %{ s->r_type = KNOT_RRTYPE_URI; }
+ | "CAA"i %{ s->r_type = KNOT_RRTYPE_CAA; }
+ | "TYPE"i . type_number
+ ) $!_r_type_error;
+ # END
+
+ # BEGIN - The highest level processing
+ action _record_exit {
+ if (rdata_tail - s->r_data > UINT16_MAX) {
+ WARN(ZS_RDATA_OVERFLOW);
+ fhold; fgoto err_line;
+ }
+ s->r_data_length = rdata_tail - s->r_data;
+
+ s->state = ZS_STATE_DATA;
+
+ // Execute the record callback.
+ if (s->process.automatic) {
+ if (s->process.record != NULL) {
+ s->process.record(s);
+
+ // Stop if required from the callback.
+ if (s->state == ZS_STATE_STOP) {
+ fbreak;
+ }
+ }
+ } else {
+ // Return if external processing.
+ fhold; fbreak;
+ }
+ }
+
+ # Resource record.
+ record =
+ r_owner . sep .
+ ( (r_class . sep . ((r_ttl . sep) | (zlen %_default_r_ttl_exit )))
+ | (r_ttl . sep . ((r_class . sep) | (zlen %_default_r_class_exit)))
+ | zlen %_default_r_class_exit %_default_r_ttl_exit
+ ) $!_r_type_error .
+ r_type . r_data .
+ rest %_record_exit .
+ newline;
+
+ # Blank spaces with comments.
+ blank = rest . newline;
+
+ # Main processing loop.
+ main := (record | directive | blank)*;
+ # END
+}%%
diff --git a/src/libzscanner/version.h b/src/libzscanner/version.h
new file mode 100644
index 0000000..59b19e4
--- /dev/null
+++ b/src/libzscanner/version.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#define ZSCANNER_VERSION_MAJOR 2
+#define ZSCANNER_VERSION_MINOR 7
+#define ZSCANNER_VERSION_PATCH 0x06
+
+#define ZSCANNER_VERSION_HEX ((ZSCANNER_VERSION_MAJOR << 16) | \
+ (ZSCANNER_VERSION_MINOR << 8) | \
+ (ZSCANNER_VERSION_PATCH))
diff --git a/src/libzscanner/version.h.in b/src/libzscanner/version.h.in
new file mode 100644
index 0000000..bdbee9a
--- /dev/null
+++ b/src/libzscanner/version.h.in
@@ -0,0 +1,25 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#define ZSCANNER_VERSION_MAJOR @KNOT_VERSION_MAJOR@
+#define ZSCANNER_VERSION_MINOR @KNOT_VERSION_MINOR@
+#define ZSCANNER_VERSION_PATCH 0x0@KNOT_VERSION_PATCH@
+
+#define ZSCANNER_VERSION_HEX ((ZSCANNER_VERSION_MAJOR << 16) | \
+ (ZSCANNER_VERSION_MINOR << 8) | \
+ (ZSCANNER_VERSION_PATCH))
diff --git a/src/utils/Makefile.inc b/src/utils/Makefile.inc
new file mode 100644
index 0000000..bc28961
--- /dev/null
+++ b/src/utils/Makefile.inc
@@ -0,0 +1,139 @@
+if HAVE_LIBUTILS
+noinst_LTLIBRARIES += libknotus.la
+
+libknotus_la_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAG_VISIBILITY) $(libidn2_CFLAGS) \
+ $(libidn_CFLAGS) $(libedit_CFLAGS) $(gnutls_CFLAGS)
+libknotus_la_LDFLAGS = $(AM_LDFLAGS) $(LDFLAG_EXCLUDE_LIBS)
+libknotus_la_LIBADD = libcontrib.la libknot.la $(libidn2_LIBS) $(libidn_LIBS) \
+ $(libedit_LIBS) $(gnutls_LIBS)
+
+libknotus_la_SOURCES = \
+ utils/common/cert.c \
+ utils/common/cert.h \
+ utils/common/exec.c \
+ utils/common/exec.h \
+ utils/common/hex.c \
+ utils/common/hex.h \
+ utils/common/lookup.c \
+ utils/common/lookup.h \
+ utils/common/msg.c \
+ utils/common/msg.h \
+ utils/common/netio.c \
+ utils/common/netio.h \
+ utils/common/params.c \
+ utils/common/params.h \
+ utils/common/resolv.c \
+ utils/common/resolv.h \
+ utils/common/sign.c \
+ utils/common/sign.h \
+ utils/common/tls.c \
+ utils/common/tls.h \
+ utils/common/token.c \
+ utils/common/token.h
+endif HAVE_LIBUTILS
+
+if HAVE_UTILS
+bin_PROGRAMS = kdig khost knsec3hash knsupdate
+
+kdig_SOURCES = \
+ utils/kdig/kdig_exec.c \
+ utils/kdig/kdig_exec.h \
+ utils/kdig/kdig_main.c \
+ utils/kdig/kdig_params.c \
+ utils/kdig/kdig_params.h
+
+khost_SOURCES = \
+ utils/kdig/kdig_exec.c \
+ utils/kdig/kdig_exec.h \
+ utils/kdig/kdig_params.c \
+ utils/kdig/kdig_params.h \
+ utils/khost/khost_main.c \
+ utils/khost/khost_params.c \
+ utils/khost/khost_params.h
+
+knsec3hash_SOURCES = \
+ utils/knsec3hash/knsec3hash.c
+
+knsupdate_SOURCES = \
+ utils/knsupdate/knsupdate_exec.c \
+ utils/knsupdate/knsupdate_exec.h \
+ utils/knsupdate/knsupdate_main.c \
+ utils/knsupdate/knsupdate_params.c \
+ utils/knsupdate/knsupdate_params.h
+
+kdig_CPPFLAGS = $(AM_CPPFLAGS) $(gnutls_CFLAGS)
+kdig_LDADD = libknotus.la
+khost_CPPFLAGS = $(AM_CPPFLAGS) $(gnutls_CFLAGS)
+khost_LDADD = libknotus.la
+knsec3hash_CPPFLAGS = $(AM_CPPFLAGS)
+knsec3hash_LDADD = libcontrib.la libdnssec.la libknot.la libshared.la
+knsupdate_CPPFLAGS = $(AM_CPPFLAGS) $(gnutls_CFLAGS)
+knsupdate_LDADD = libknotus.la libzscanner.la
+
+if HAVE_DNSTAP
+kdig_LDADD += $(DNSTAP_LIBS) libdnstap.la
+khost_LDADD += $(DNSTAP_LIBS) libdnstap.la
+kdig_CPPFLAGS += $(DNSTAP_CFLAGS)
+khost_CPPFLAGS += $(DNSTAP_CFLAGS)
+endif HAVE_DNSTAP
+endif HAVE_UTILS
+
+if HAVE_DAEMON
+# Create storage and run-time directories
+install-data-hook:
+ $(INSTALL) -d $(DESTDIR)/@config_dir@
+ $(INSTALL) -d $(DESTDIR)/@run_dir@
+ $(INSTALL) -d $(DESTDIR)/@storage_dir@
+
+sbin_PROGRAMS = knotc knotd
+
+knotc_SOURCES = \
+ utils/knotc/commands.c \
+ utils/knotc/commands.h \
+ utils/knotc/estimator.c \
+ utils/knotc/estimator.h \
+ utils/knotc/interactive.c \
+ utils/knotc/interactive.h \
+ utils/knotc/process.c \
+ utils/knotc/process.h \
+ utils/knotc/main.c
+
+knotd_SOURCES = \
+ utils/knotd/main.c
+
+knotc_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAG_VISIBILITY) $(libedit_CFLAGS)
+knotc_LDADD = libcontrib.la libknotd.la libknotus.la $(libedit_LIBS)
+knotc_LDFLAGS = $(AM_LDFLAGS) -rdynamic
+knotd_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAG_VISIBILITY) $(liburcu_CFLAGS)
+knotd_LDADD = $(malloc_LIBS) libcontrib.la libknotd.la $(liburcu_LIBS) \
+ $(cap_ng_LIBS)
+knotd_LDFLAGS = $(AM_LDFLAGS) -rdynamic
+
+if HAVE_UTILS
+bin_PROGRAMS += kzonecheck
+sbin_PROGRAMS += keymgr kjournalprint
+
+kzonecheck_SOURCES = \
+ utils/kzonecheck/main.c \
+ utils/kzonecheck/zone_check.c \
+ utils/kzonecheck/zone_check.h
+
+keymgr_SOURCES = \
+ utils/keymgr/bind_privkey.c \
+ utils/keymgr/bind_privkey.h \
+ utils/keymgr/functions.c \
+ utils/keymgr/functions.h \
+ utils/keymgr/main.c
+
+kjournalprint_SOURCES = \
+ utils/kjournalprint/main.c
+
+kzonecheck_CPPFLAGS = $(AM_CPPFLAGS)
+kzonecheck_LDADD = libcontrib.la libknotd.la
+keymgr_CPPFLAGS = $(AM_CPPFLAGS) $(gnutls_CFLAGS)
+keymgr_LDADD = libcontrib.la libknotd.la libknotus.la libdnssec.la \
+ libshared.la libzscanner.la
+kjournalprint_CPPFLAGS = $(AM_CPPFLAGS) $(gnutls_CFLAGS)
+kjournalprint_LDADD = libcontrib.la libknotd.la
+endif HAVE_UTILS
+endif HAVE_DAEMON
diff --git a/src/utils/common/cert.c b/src/utils/common/cert.c
new file mode 100644
index 0000000..b9cf2c4
--- /dev/null
+++ b/src/utils/common/cert.c
@@ -0,0 +1,61 @@
+/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gnutls/abstract.h>
+#include <gnutls/crypto.h>
+
+#include "utils/common/cert.h"
+#include "libknot/error.h"
+
+static int spki_hash(gnutls_x509_crt_t cert, gnutls_digest_algorithm_t alg,
+ uint8_t *hash, size_t size)
+{
+ if (!cert || !hash || gnutls_hash_get_len(alg) != size) {
+ return KNOT_EINVAL;
+ }
+
+ gnutls_pubkey_t key = { 0 };
+ if (gnutls_pubkey_init(&key) != GNUTLS_E_SUCCESS) {
+ return KNOT_ENOMEM;
+ }
+
+ if (gnutls_pubkey_import_x509(key, cert, 0) != GNUTLS_E_SUCCESS) {
+ gnutls_pubkey_deinit(key);
+ return KNOT_ERROR;
+ }
+
+ gnutls_datum_t der = { 0 };
+ if (gnutls_pubkey_export2(key, GNUTLS_X509_FMT_DER, &der) != GNUTLS_E_SUCCESS) {
+ gnutls_pubkey_deinit(key);
+ return KNOT_ERROR;
+ }
+
+ int ret = gnutls_hash_fast(alg, der.data, der.size, hash);
+
+ gnutls_free(der.data);
+ gnutls_pubkey_deinit(key);
+
+ if (ret != GNUTLS_E_SUCCESS) {
+ return KNOT_ERROR;
+ }
+
+ return KNOT_EOK;
+}
+
+int cert_get_pin(gnutls_x509_crt_t cert, uint8_t *pin, size_t size)
+{
+ return spki_hash(cert, GNUTLS_DIG_SHA256, pin, size);
+}
diff --git a/src/utils/common/cert.h b/src/utils/common/cert.h
new file mode 100644
index 0000000..ad4901b
--- /dev/null
+++ b/src/utils/common/cert.h
@@ -0,0 +1,36 @@
+/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <gnutls/x509.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#define CERT_PIN_LEN 32
+
+/*!
+ * \brief Get certificate pin value.
+ *
+ * The pin is a SHA-256 hash of the X.509 SubjectPublicKeyInfo.
+ *
+ * \param[in] crt Certificate.
+ * \param[out] pin Pin.
+ * \param[in] size Length of the pin, must be CERT_PIN_LEN.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int cert_get_pin(gnutls_x509_crt_t crt, uint8_t *pin, size_t size);
diff --git a/src/utils/common/exec.c b/src/utils/common/exec.c
new file mode 100644
index 0000000..1d97600
--- /dev/null
+++ b/src/utils/common/exec.c
@@ -0,0 +1,692 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "libdnssec/random.h"
+#include "utils/common/exec.h"
+#include "utils/common/msg.h"
+#include "utils/common/netio.h"
+#include "utils/common/params.h"
+#include "libknot/libknot.h"
+#include "contrib/ctype.h"
+#include "contrib/sockaddr.h"
+#include "contrib/openbsd/strlcat.h"
+#include "contrib/ucw/lists.h"
+#include "contrib/wire_ctx.h"
+
+static knot_lookup_t rtypes[] = {
+ { KNOT_RRTYPE_A, "has IPv4 address" },
+ { KNOT_RRTYPE_NS, "nameserver is" },
+ { KNOT_RRTYPE_CNAME, "is an alias for" },
+ { KNOT_RRTYPE_SOA, "start of authority is" },
+ { KNOT_RRTYPE_PTR, "points to" },
+ { KNOT_RRTYPE_MX, "mail is handled by" },
+ { KNOT_RRTYPE_TXT, "description is" },
+ { KNOT_RRTYPE_AAAA, "has IPv6 address" },
+ { KNOT_RRTYPE_LOC, "location is" },
+ { KNOT_RRTYPE_DS, "delegation signature is" },
+ { KNOT_RRTYPE_SSHFP, "SSH fingerprint is" },
+ { KNOT_RRTYPE_RRSIG, "RR set signature is" },
+ { KNOT_RRTYPE_DNSKEY, "DNSSEC key is" },
+ { KNOT_RRTYPE_TLSA, "has TLS certificate" },
+ { 0, NULL }
+};
+
+static void print_header(const knot_pkt_t *packet, const style_t *style)
+{
+ char flags[64] = "";
+ char unknown_rcode[64] = "";
+ char unknown_opcode[64] = "";
+
+ const char *rcode_str = NULL;
+ const char *opcode_str = NULL;
+
+ // Get extended RCODE.
+ const char *code_name = knot_pkt_ext_rcode_name(packet);
+ if (code_name[0] != '\0') {
+ rcode_str = code_name;
+ } else {
+ uint16_t code = knot_pkt_ext_rcode(packet);
+ (void)snprintf(unknown_rcode, sizeof(unknown_rcode), "RCODE %d", code);
+ rcode_str = unknown_rcode;
+ }
+
+ // Get OPCODE.
+ uint8_t code = knot_wire_get_opcode(packet->wire);
+ const knot_lookup_t *opcode = knot_lookup_by_id(knot_opcode_names, code);
+ if (opcode != NULL) {
+ opcode_str = opcode->name;
+ } else {
+ (void)snprintf(unknown_opcode, sizeof(unknown_opcode), "OPCODE %d", code);
+ opcode_str = unknown_opcode;
+ }
+
+ // Get flags.
+ size_t flags_rest = sizeof(flags);
+ const size_t flag_len = 4;
+ if (knot_wire_get_qr(packet->wire) != 0 && flags_rest > flag_len) {
+ flags_rest -= strlcat(flags, " qr", flags_rest);
+ }
+ if (knot_wire_get_aa(packet->wire) != 0 && flags_rest > flag_len) {
+ flags_rest -= strlcat(flags, " aa", flags_rest);
+ }
+ if (knot_wire_get_tc(packet->wire) != 0 && flags_rest > flag_len) {
+ flags_rest -= strlcat(flags, " tc", flags_rest);
+ }
+ if (knot_wire_get_rd(packet->wire) != 0 && flags_rest > flag_len) {
+ flags_rest -= strlcat(flags, " rd", flags_rest);
+ }
+ if (knot_wire_get_ra(packet->wire) != 0 && flags_rest > flag_len) {
+ flags_rest -= strlcat(flags, " ra", flags_rest);
+ }
+ if (knot_wire_get_z(packet->wire) != 0 && flags_rest > flag_len) {
+ flags_rest -= strlcat(flags, " z", flags_rest);
+ }
+ if (knot_wire_get_ad(packet->wire) != 0 && flags_rest > flag_len) {
+ flags_rest -= strlcat(flags, " ad", flags_rest);
+ }
+ if (knot_wire_get_cd(packet->wire) != 0 && flags_rest > flag_len) {
+ strlcat(flags, " cd", flags_rest);
+ }
+
+ uint16_t id = knot_wire_get_id(packet->wire);
+ uint16_t qdcount = knot_wire_get_qdcount(packet->wire);
+ uint16_t ancount = knot_wire_get_ancount(packet->wire);
+ uint16_t nscount = knot_wire_get_nscount(packet->wire);
+ uint16_t arcount = knot_wire_get_arcount(packet->wire);
+
+ if (knot_pkt_has_tsig(packet)) {
+ arcount++;
+ }
+
+ // Print formatted info.
+ switch (style->format) {
+ case FORMAT_NSUPDATE:
+ printf(";; ->>HEADER<<- opcode: %s; status: %s; id: %u\n"
+ ";; Flags:%1s; "
+ "ZONE: %u; PREREQ: %u; UPDATE: %u; ADDITIONAL: %u\n",
+ opcode_str, rcode_str, id, flags, qdcount, ancount,
+ nscount, arcount);
+ break;
+ default:
+ printf(";; ->>HEADER<<- opcode: %s; status: %s; id: %u\n"
+ ";; Flags:%1s; "
+ "QUERY: %u; ANSWER: %u; AUTHORITY: %u; ADDITIONAL: %u\n",
+ opcode_str, rcode_str, id, flags, qdcount, ancount,
+ nscount, arcount);
+ break;
+ }
+}
+
+static void print_footer(const size_t total_len,
+ const size_t msg_count,
+ const size_t rr_count,
+ const net_t *net,
+ const float elapsed,
+ time_t exec_time,
+ const bool incoming)
+{
+ struct tm tm;
+ char date[64];
+
+ // Get current timestamp.
+ if (exec_time == 0) {
+ exec_time = time(NULL);
+ }
+
+ // Create formatted date-time string.
+ localtime_r(&exec_time, &tm);
+ strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S %Z", &tm);
+
+ // Print messages statistics.
+ if (incoming) {
+ printf(";; Received %zu B", total_len);
+ } else {
+ printf(";; Sent %zu B", total_len);
+ }
+
+ // If multimessage (XFR) print additional statistics.
+ if (msg_count > 0) {
+ printf(" (%zu messages, %zu records)\n", msg_count, rr_count);
+ } else {
+ printf("\n");
+ }
+ // Print date.
+ printf(";; Time %s\n", date);
+
+ // Print connection statistics.
+ if (net != NULL) {
+ if (incoming) {
+ printf(";; From %s", net->remote_str);
+ } else {
+ printf(";; To %s", net->remote_str);
+ }
+
+ if (elapsed >= 0) {
+ printf(" in %.1f ms\n", elapsed);
+ } else {
+ printf("\n");
+ }
+ }
+}
+
+static void print_hex(const uint8_t *data, uint16_t len)
+{
+ for (int i = 0; i < len; i++) {
+ printf("%02X", data[i]);
+ }
+}
+
+static void print_nsid(const uint8_t *data, uint16_t len)
+{
+ if (len == 0) {
+ return;
+ }
+
+ print_hex(data, len);
+
+ // Check if printable string.
+ for (int i = 0; i < len; i++) {
+ if (!is_print(data[i])) {
+ return;
+ }
+ }
+ printf(" \"%.*s\"", len, data);
+}
+
+static void print_edns_client_subnet(const uint8_t *data, uint16_t len)
+{
+ knot_edns_client_subnet_t ecs = { 0 };
+ int ret = knot_edns_client_subnet_parse(&ecs, data, len);
+ if (ret != KNOT_EOK) {
+ return;
+ }
+
+ struct sockaddr_storage addr = { 0 };
+ ret = knot_edns_client_subnet_get_addr(&addr, &ecs);
+ assert(ret == KNOT_EOK);
+
+ char addr_str[SOCKADDR_STRLEN] = { 0 };
+ sockaddr_tostr(addr_str, sizeof(addr_str), (struct sockaddr *)&addr);
+
+ printf("%s/%u/%u", addr_str, ecs.source_len, ecs.scope_len);
+}
+
+static void print_section_opt(const knot_pkt_t *packet)
+{
+ char unknown_ercode[64] = "";
+ const char *ercode_str = NULL;
+
+ uint16_t ercode = knot_edns_get_ext_rcode(packet->opt_rr);
+ if (ercode > 0) {
+ ercode = knot_edns_whole_rcode(ercode,
+ knot_wire_get_rcode(packet->wire));
+ }
+
+ const knot_lookup_t *item = knot_lookup_by_id(knot_rcode_names, ercode);
+ if (item != NULL) {
+ ercode_str = item->name;
+ } else {
+ (void)snprintf(unknown_ercode, sizeof(unknown_ercode), "RCODE %d", ercode);
+ ercode_str = unknown_ercode;
+ }
+
+ printf("Version: %u; flags: %s; UDP size: %u B; ext-rcode: %s\n",
+ knot_edns_get_version(packet->opt_rr),
+ (knot_edns_do(packet->opt_rr) != 0) ? "do" : "",
+ knot_edns_get_payload(packet->opt_rr),
+ ercode_str);
+
+ assert(packet->opt_rr->rrs.count > 0);
+ knot_rdata_t *rdata = packet->opt_rr->rrs.rdata;
+ wire_ctx_t wire = wire_ctx_init_const(rdata->data, rdata->len);
+
+ while (wire_ctx_available(&wire) >= KNOT_EDNS_OPTION_HDRLEN) {
+ uint16_t opt_code = wire_ctx_read_u16(&wire);
+ uint16_t opt_len = wire_ctx_read_u16(&wire);
+ uint8_t *opt_data = wire.position;
+
+ if (wire.error != KNOT_EOK) {
+ WARN("invalid OPT record data\n");
+ return;
+ }
+
+ switch (opt_code) {
+ case KNOT_EDNS_OPTION_NSID:
+ printf(";; NSID: ");
+ print_nsid(opt_data, opt_len);
+ break;
+ case KNOT_EDNS_OPTION_CLIENT_SUBNET:
+ printf(";; CLIENT-SUBNET: ");
+ print_edns_client_subnet(opt_data, opt_len);
+ break;
+ case KNOT_EDNS_OPTION_PADDING:
+ printf(";; PADDING: %u B", opt_len);
+ break;
+ case KNOT_EDNS_OPTION_COOKIE:
+ printf(";; COOKIE: ");
+ print_hex(opt_data, opt_len);
+ break;
+ default:
+ printf(";; Option (%u): ", opt_code);
+ print_hex(opt_data, opt_len);
+ }
+ printf("\n");
+
+ wire_ctx_skip(&wire, opt_len);
+ }
+
+ if (wire_ctx_available(&wire) > 0) {
+ WARN("invalid OPT record data\n");
+ }
+}
+
+static void print_section_question(const knot_dname_t *owner,
+ const uint16_t qclass,
+ const uint16_t qtype,
+ const style_t *style)
+{
+ size_t buflen = 8192;
+ char *buf = calloc(buflen, 1);
+
+ // Don't print zero TTL.
+ knot_dump_style_t qstyle = style->style;
+ qstyle.empty_ttl = true;
+
+ knot_rrset_t *question = knot_rrset_new(owner, qtype, qclass, 0, NULL);
+
+ if (knot_rrset_txt_dump_header(question, 0, buf, buflen, &qstyle) < 0) {
+ WARN("can't print whole question section\n");
+ }
+
+ printf("%s\n", buf);
+
+ knot_rrset_free(question, NULL);
+ free(buf);
+}
+
+static void print_section_full(const knot_rrset_t *rrsets,
+ const uint16_t count,
+ const style_t *style,
+ const bool no_tsig)
+{
+ size_t buflen = 8192;
+ char *buf = calloc(buflen, 1);
+
+ for (size_t i = 0; i < count; i++) {
+ // Ignore OPT records.
+ if (rrsets[i].type == KNOT_RRTYPE_OPT) {
+ continue;
+ }
+
+ // Exclude TSIG record.
+ if (no_tsig && rrsets[i].type == KNOT_RRTYPE_TSIG) {
+ continue;
+ }
+
+ if (knot_rrset_txt_dump(&rrsets[i], &buf, &buflen,
+ &(style->style)) < 0) {
+ WARN("can't print whole section\n");
+ break;
+ }
+ printf("%s", buf);
+ }
+
+ free(buf);
+}
+
+static void print_section_dig(const knot_rrset_t *rrsets,
+ const uint16_t count,
+ const style_t *style)
+{
+ size_t buflen = 8192;
+ char *buf = calloc(buflen, 1);
+
+ for (size_t i = 0; i < count; i++) {
+ const knot_rrset_t *rrset = &rrsets[i];
+ uint16_t rrset_rdata_count = rrset->rrs.count;
+ for (uint16_t j = 0; j < rrset_rdata_count; j++) {
+ while (knot_rrset_txt_dump_data(rrset, j, buf, buflen,
+ &(style->style)) < 0) {
+ buflen += 4096;
+ // Oversize protection.
+ if (buflen > 100000) {
+ WARN("can't print whole section\n");
+ break;
+ }
+
+ char *newbuf = realloc(buf, buflen);
+ if (newbuf == NULL) {
+ WARN("can't print whole section\n");
+ break;
+ }
+ buf = newbuf;
+ }
+ printf("%s\n", buf);
+ }
+ }
+
+ free(buf);
+}
+
+static void print_section_host(const knot_rrset_t *rrsets,
+ const uint16_t count,
+ const style_t *style)
+{
+ size_t buflen = 8192;
+ char *buf = calloc(buflen, 1);
+
+ for (size_t i = 0; i < count; i++) {
+ const knot_rrset_t *rrset = &rrsets[i];
+ const knot_lookup_t *descr;
+ char type[32] = "NULL";
+ char *owner;
+
+ owner = knot_dname_to_str_alloc(rrset->owner);
+ if (style->style.ascii_to_idn != NULL) {
+ style->style.ascii_to_idn(&owner);
+ }
+ descr = knot_lookup_by_id(rtypes, rrset->type);
+
+ uint16_t rrset_rdata_count = rrset->rrs.count;
+ for (uint16_t j = 0; j < rrset_rdata_count; j++) {
+ if (rrset->type == KNOT_RRTYPE_CNAME &&
+ style->hide_cname) {
+ continue;
+ }
+
+ while (knot_rrset_txt_dump_data(rrset, j, buf, buflen,
+ &(style->style)) < 0) {
+ buflen += 4096;
+ // Oversize protection.
+ if (buflen > 100000) {
+ WARN("can't print whole section\n");
+ break;
+ }
+
+ char *newbuf = realloc(buf, buflen);
+ if (newbuf == NULL) {
+ WARN("can't print whole section\n");
+ break;
+ }
+ buf = newbuf;
+ }
+
+ if (descr != NULL) {
+ printf("%s %s %s\n", owner, descr->name, buf);
+ } else {
+ knot_rrtype_to_string(rrset->type, type,
+ sizeof(type));
+ printf("%s has %s record %s\n",
+ owner, type, buf);
+ }
+ }
+
+ free(owner);
+ }
+
+ free(buf);
+}
+
+static void print_error_host(const knot_pkt_t *packet, const style_t *style)
+{
+ char type[32] = "Unknown";
+ const char *rcode_str = "Unknown";
+
+ knot_rrtype_to_string(knot_pkt_qtype(packet), type, sizeof(type));
+
+ // Get extended RCODE.
+ const char *code_name = knot_pkt_ext_rcode_name(packet);
+ if (code_name[0] != '\0') {
+ rcode_str = code_name;
+ }
+
+ // Get record owner.
+ char *owner = knot_dname_to_str_alloc(knot_pkt_qname(packet));
+ if (style->style.ascii_to_idn != NULL) {
+ style->style.ascii_to_idn(&owner);
+ }
+
+ if (knot_pkt_ext_rcode(packet) == KNOT_RCODE_NOERROR) {
+ printf("Host %s has no %s record\n", owner, type);
+ } else {
+ printf("Host %s type %s error: %s\n", owner, type, rcode_str);
+ }
+
+ free(owner);
+}
+
+knot_pkt_t *create_empty_packet(const uint16_t max_size)
+{
+ // Create packet skeleton.
+ knot_pkt_t *packet = knot_pkt_new(NULL, max_size, NULL);
+ if (packet == NULL) {
+ DBG_NULL;
+ return NULL;
+ }
+
+ // Set random sequence id.
+ knot_wire_set_id(packet->wire, dnssec_random_uint16_t());
+
+ return packet;
+}
+
+void print_header_xfr(const knot_pkt_t *packet, const style_t *style)
+{
+ if (style == NULL) {
+ DBG_NULL;
+ return;
+ }
+
+ char xfr[16] = "AXFR";
+
+ switch (knot_pkt_qtype(packet)) {
+ case KNOT_RRTYPE_AXFR:
+ break;
+ case KNOT_RRTYPE_IXFR:
+ xfr[0] = 'I';
+ break;
+ default:
+ return;
+ }
+
+ if (style->show_header) {
+ char *owner = knot_dname_to_str_alloc(knot_pkt_qname(packet));
+ if (style->style.ascii_to_idn != NULL) {
+ style->style.ascii_to_idn(&owner);
+ }
+ if (owner != NULL) {
+ printf(";; %s for %s\n", xfr, owner);
+ free(owner);
+ }
+ }
+}
+
+void print_data_xfr(const knot_pkt_t *packet,
+ const style_t *style)
+{
+ if (packet == NULL || style == NULL) {
+ DBG_NULL;
+ return;
+ }
+
+ const knot_pktsection_t *answers = knot_pkt_section(packet, KNOT_ANSWER);
+
+ switch (style->format) {
+ case FORMAT_DIG:
+ print_section_dig(knot_pkt_rr(answers, 0), answers->count, style);
+ break;
+ case FORMAT_HOST:
+ print_section_host(knot_pkt_rr(answers, 0), answers->count, style);
+ break;
+ case FORMAT_FULL:
+ print_section_full(knot_pkt_rr(answers, 0), answers->count, style, true);
+
+ // Print TSIG record.
+ if (style->show_tsig && knot_pkt_has_tsig(packet)) {
+ print_section_full(packet->tsig_rr, 1, style, false);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void print_footer_xfr(const size_t total_len,
+ const size_t msg_count,
+ const size_t rr_count,
+ const net_t *net,
+ const float elapsed,
+ const time_t exec_time,
+ const style_t *style)
+{
+ if (style == NULL) {
+ DBG_NULL;
+ return;
+ }
+
+ if (style->show_footer) {
+ print_footer(total_len, msg_count, rr_count, net, elapsed,
+ exec_time, true);
+ }
+}
+
+void print_packet(const knot_pkt_t *packet,
+ const net_t *net,
+ const size_t size,
+ const float elapsed,
+ const time_t exec_time,
+ const bool incoming,
+ const style_t *style)
+{
+ if (packet == NULL || style == NULL) {
+ DBG_NULL;
+ return;
+ }
+
+ const knot_pktsection_t *answers = knot_pkt_section(packet,
+ KNOT_ANSWER);
+ const knot_pktsection_t *authority = knot_pkt_section(packet,
+ KNOT_AUTHORITY);
+ const knot_pktsection_t *additional = knot_pkt_section(packet,
+ KNOT_ADDITIONAL);
+
+ uint16_t qdcount = knot_wire_get_qdcount(packet->wire);
+ uint16_t ancount = knot_wire_get_ancount(packet->wire);
+ uint16_t nscount = knot_wire_get_nscount(packet->wire);
+ uint16_t arcount = knot_wire_get_arcount(packet->wire);
+
+ // Disable additionals printing if there are no other records.
+ // OPT record may be placed anywhere within additionals!
+ if (knot_pkt_has_edns(packet) && arcount == 1) {
+ arcount = 0;
+ }
+
+ // Print packet information header.
+ if (style->show_header) {
+ if (net != NULL) {
+ print_tls(&net->tls);
+ }
+ print_header(packet, style);
+ }
+
+ // Print EDNS section.
+ if (style->show_edns && knot_pkt_has_edns(packet)) {
+ printf("%s", style->show_section ? "\n;; EDNS PSEUDOSECTION:\n;; " : ";;");
+ print_section_opt(packet);
+ }
+
+ // Print DNS sections.
+ switch (style->format) {
+ case FORMAT_DIG:
+ if (ancount > 0) {
+ print_section_dig(knot_pkt_rr(answers, 0), ancount, style);
+ }
+ break;
+ case FORMAT_HOST:
+ if (ancount > 0) {
+ print_section_host(knot_pkt_rr(answers, 0), ancount, style);
+ } else {
+ print_error_host(packet, style);
+ }
+ break;
+ case FORMAT_NSUPDATE:
+ if (style->show_question && qdcount > 0) {
+ printf("%s", style->show_section ? "\n;; ZONE SECTION:\n;; " : ";;");
+ print_section_question(knot_pkt_qname(packet),
+ knot_pkt_qclass(packet),
+ knot_pkt_qtype(packet),
+ style);
+ }
+
+ if (style->show_answer && ancount > 0) {
+ printf("%s", style->show_section ? "\n;; PREREQUISITE SECTION:\n" : "");
+ print_section_full(knot_pkt_rr(answers, 0), ancount, style, true);
+ }
+
+ if (style->show_authority && nscount > 0) {
+ printf("%s", style->show_section ? "\n;; UPDATE SECTION:\n" : "");
+ print_section_full(knot_pkt_rr(authority, 0), nscount, style, true);
+ }
+
+ if (style->show_additional && arcount > 0) {
+ printf("%s", style->show_section ? "\n;; ADDITIONAL DATA:\n" : "");
+ print_section_full(knot_pkt_rr(additional, 0), arcount, style, true);
+ }
+ break;
+ case FORMAT_FULL:
+ if (style->show_question && qdcount > 0) {
+ printf("%s", style->show_section ? "\n;; QUESTION SECTION:\n;; " : ";;");
+ print_section_question(knot_pkt_qname(packet),
+ knot_pkt_qclass(packet),
+ knot_pkt_qtype(packet),
+ style);
+ }
+
+ if (style->show_answer && ancount > 0) {
+ printf("%s", style->show_section ? "\n;; ANSWER SECTION:\n" : "");
+ print_section_full(knot_pkt_rr(answers, 0), ancount, style, true);
+ }
+
+ if (style->show_authority && nscount > 0) {
+ printf("%s", style->show_section ? "\n;; AUTHORITY SECTION:\n" : "");
+ print_section_full(knot_pkt_rr(authority, 0), nscount, style, true);
+ }
+
+ if (style->show_additional && arcount > 0) {
+ printf("%s", style->show_section ? "\n;; ADDITIONAL SECTION:\n" : "");
+ print_section_full(knot_pkt_rr(additional, 0), arcount, style, true);
+ }
+ break;
+ default:
+ break;
+ }
+
+ // Print TSIG section.
+ if (style->show_tsig && knot_pkt_has_tsig(packet)) {
+ printf("%s", style->show_section ? "\n;; TSIG PSEUDOSECTION:\n" : "");
+ print_section_full(packet->tsig_rr, 1, style, false);
+ }
+
+ // Print packet statistics.
+ if (style->show_footer) {
+ printf("\n");
+ print_footer(size, 0, 0, net, elapsed, exec_time, incoming);
+ }
+}
diff --git a/src/utils/common/exec.h b/src/utils/common/exec.h
new file mode 100644
index 0000000..0c5ad5d
--- /dev/null
+++ b/src/utils/common/exec.h
@@ -0,0 +1,97 @@
+/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief Common executives for utils.
+ *
+ * \addtogroup knot_utils
+ * @{
+ */
+
+#pragma once
+
+#include <time.h>
+
+#include "utils/common/netio.h"
+#include "utils/common/params.h"
+#include "libknot/libknot.h"
+
+/*!
+ * \brief Allocates empty packet and sets packet size and random id.
+ *
+ * \param max_size Maximal packet size.
+ *
+ * \retval packet if success.
+ * \retval NULL if error.
+ */
+knot_pkt_t *create_empty_packet(const uint16_t max_size);
+
+/*!
+ * \brief Prints information header for transfer.
+ *
+ * \param packet Parsed packet.
+ * \param style Style of the output.
+ */
+void print_header_xfr(const knot_pkt_t *packet, const style_t *style);
+
+/*!
+ * \brief Prints answer section for 1 transfer message.
+ *
+ * \param packet Response packet.
+ * \param style Style of the output.
+ */
+void print_data_xfr(const knot_pkt_t *packet, const style_t *style);
+
+/*!
+ * \brief Prints trailing statistics for transfer.
+ *
+ * \param total_len Total reply size (all messages).
+ * \param msg_count Number of messages.
+ * \param rr_count Total number of answer records.
+ * \param net Connection information.
+ * \param elapsed Total elapsed time.
+ * \param exec_time Time of the packet creation.
+ * \param style Style of the otput.
+ */
+void print_footer_xfr(const size_t total_len,
+ const size_t msg_count,
+ const size_t rr_count,
+ const net_t *net,
+ const float elapsed,
+ const time_t exec_time,
+ const style_t *style);
+
+/*!
+ * \brief Prints one response packet.
+ *
+ * \param packet Response packet.
+ * \param net Connection information.
+ * \param size Original packet wire size.
+ * \param elapsed Total elapsed time.
+ * \param exec_time Time of the packet creation.
+ * \param incoming Indicates if the packet is input.
+ * \param style Style of the otput.
+ */
+void print_packet(const knot_pkt_t *packet,
+ const net_t *net,
+ const size_t size,
+ const float elapsed,
+ const time_t exec_time,
+ const bool incoming,
+ const style_t *style);
+
+/*! @} */
diff --git a/src/utils/common/hex.c b/src/utils/common/hex.c
new file mode 100644
index 0000000..2ffa9f2
--- /dev/null
+++ b/src/utils/common/hex.c
@@ -0,0 +1,82 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include "libknot/libknot.h"
+#include "contrib/ctype.h"
+#include "contrib/tolower.h"
+
+/*!
+ * \brief Convert HEX char to byte.
+ * \note Expects valid lowercase letters.
+ */
+static uint8_t hex_to_num(int c)
+{
+ if (c >= '0' && c <= '9') {
+ return c - '0';
+ } else {
+ return c - 'a' + 10;
+ }
+}
+
+/*!
+ * \brief Convert string encoded in hex to bytes.
+ */
+int hex_decode(const char *input, uint8_t **output, size_t *output_size)
+{
+ if (!input || input[0] == '\0' || !output || !output_size) {
+ return KNOT_EINVAL;
+ }
+
+ // input validation (length and content)
+
+ size_t input_size = strlen(input);
+ if (input_size % 2 != 0) {
+ return KNOT_EMALF;
+ }
+
+ for (size_t i = 0; i < input_size; i++) {
+ if (!is_xdigit(input[i])) {
+ return KNOT_EMALF;
+ }
+ }
+
+ // output allocation
+
+ size_t result_size = input_size / 2;
+ assert(result_size > 0);
+ uint8_t *result = malloc(result_size);
+ if (!result) {
+ return KNOT_ENOMEM;
+ }
+
+ // conversion
+
+ for (size_t i = 0; i < result_size; i++) {
+ int high_nib = knot_tolower(input[2 * i]);
+ int low_nib = knot_tolower(input[2 * i + 1]);
+
+ result[i] = hex_to_num(high_nib) << 4 | hex_to_num(low_nib);
+ }
+
+ *output = result;
+ *output_size = result_size;
+
+ return KNOT_EOK;
+}
diff --git a/src/utils/common/hex.h b/src/utils/common/hex.h
new file mode 100644
index 0000000..8f9f445
--- /dev/null
+++ b/src/utils/common/hex.h
@@ -0,0 +1,42 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*!
+ * \file
+ *
+ * \brief Coversion between HEX strings and bytes.
+ *
+ * \addtogroup knot_utils
+ * @{
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdlib.h>
+
+/*!
+ * \brief Convert string encoded in hex to bytes.
+ *
+ * \param input Hex encoded input string.
+ * \param output Decoded bytes.
+ * \param output_size Size of the output.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int hex_decode(const char *input, uint8_t **output, size_t *output_size);
+
+/*! @} */
diff --git a/src/utils/common/lookup.c b/src/utils/common/lookup.c
new file mode 100644
index 0000000..168d649
--- /dev/null
+++ b/src/utils/common/lookup.c
@@ -0,0 +1,279 @@
+/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <string.h>
+
+#include "utils/common/lookup.h"
+#include "contrib/mempattern.h"
+#include "contrib/ucw/mempool.h"
+#include "libknot/error.h"
+
+int lookup_init(lookup_t *lookup)
+{
+ if (lookup == NULL) {
+ return KNOT_EINVAL;
+ }
+ memset(lookup, 0, sizeof(*lookup));
+
+ mm_ctx_mempool(&lookup->mm, MM_DEFAULT_BLKSIZE);
+ lookup->trie = trie_create(&lookup->mm);
+ if (lookup->trie == NULL) {
+ mp_delete(lookup->mm.ctx);
+ return KNOT_ENOMEM;
+ }
+
+ return KNOT_EOK;
+}
+
+static void reset_output(lookup_t *lookup)
+{
+ if (lookup == NULL) {
+ return;
+ }
+
+ mm_free(&lookup->mm, lookup->found.key);
+ lookup->found.key = NULL;
+ lookup->found.data = NULL;
+
+ lookup->iter.count = 0;
+
+ mm_free(&lookup->mm, lookup->iter.first_key);
+ lookup->iter.first_key = NULL;
+
+ trie_it_free(lookup->iter.it);
+ lookup->iter.it = NULL;
+}
+
+void lookup_deinit(lookup_t *lookup)
+{
+ if (lookup == NULL) {
+ return;
+ }
+
+ reset_output(lookup);
+
+ trie_free(lookup->trie);
+ mp_delete(lookup->mm.ctx);
+}
+
+int lookup_insert(lookup_t *lookup, const char *str, void *data)
+{
+ if (lookup == NULL || str == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ size_t str_len = strlen(str);
+ if (str_len == 0) {
+ return KNOT_EINVAL;
+ }
+
+ trie_val_t *val = trie_get_ins(lookup->trie, str, str_len);
+ if (val == NULL) {
+ return KNOT_ENOMEM;
+ }
+ *val = data;
+
+ return KNOT_EOK;
+}
+
+static int set_key(lookup_t *lookup, char **dst, const char *key, size_t key_len)
+{
+ if (*dst != NULL) {
+ mm_free(&lookup->mm, *dst);
+ }
+ *dst = mm_alloc(&lookup->mm, key_len + 1);
+ if (*dst == NULL) {
+ return KNOT_ENOMEM;
+ }
+ memcpy(*dst, key, key_len);
+ (*dst)[key_len] = '\0';
+
+ return KNOT_EOK;
+}
+
+int lookup_search(lookup_t *lookup, const char *str, size_t str_len)
+{
+ if (lookup == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ // Change NULL string to the empty one.
+ if (str == NULL) {
+ str = "";
+ }
+
+ reset_output(lookup);
+
+ size_t new_len = 0;
+ trie_it_t *it = trie_it_begin(lookup->trie);
+ for (; !trie_it_finished(it); trie_it_next(it)) {
+ size_t len;
+ const char *key = trie_it_key(it, &len);
+
+ // Compare with a shorter key.
+ if (len < str_len) {
+ int ret = memcmp(str, key, len);
+ if (ret >= 0) {
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ // Compare with an equal length or longer key.
+ int ret = memcmp(str, key, str_len);
+ if (ret == 0) {
+ lookup->iter.count++;
+
+ // First candidate.
+ if (lookup->iter.count == 1) {
+ ret = set_key(lookup, &lookup->found.key, key, len);
+ if (ret != KNOT_EOK) {
+ break;
+ }
+ lookup->found.data = *trie_it_val(it);
+ new_len = len;
+ // Another candidate.
+ } else if (new_len > str_len) {
+ if (new_len > len) {
+ new_len = len;
+ }
+ while (memcmp(lookup->found.key, key, new_len) != 0) {
+ new_len--;
+ }
+ }
+ // Stop if greater than the key, and also than all the following keys.
+ } else if (ret < 0) {
+ break;
+ }
+ }
+ trie_it_free(it);
+
+ switch (lookup->iter.count) {
+ case 0:
+ return KNOT_ENOENT;
+ case 1:
+ return KNOT_EOK;
+ default:
+ // Store full name of the first candidate.
+ if (set_key(lookup, &lookup->iter.first_key, lookup->found.key,
+ strlen(lookup->found.key)) != KNOT_EOK) {
+ return KNOT_ENOMEM;
+ }
+ lookup->found.key[new_len] = '\0';
+ lookup->found.data = NULL;
+
+ return KNOT_EFEWDATA;
+ }
+}
+
+void lookup_list(lookup_t *lookup)
+{
+ if (lookup == NULL || lookup->iter.first_key == NULL) {
+ return;
+ }
+
+ if (lookup->iter.it != NULL) {
+ if (trie_it_finished(lookup->iter.it)) {
+ trie_it_free(lookup->iter.it);
+ lookup->iter.it = NULL;
+ return;
+ }
+
+ trie_it_next(lookup->iter.it);
+
+ size_t len;
+ const char *key = trie_it_key(lookup->iter.it, &len);
+
+ int ret = set_key(lookup, &lookup->found.key, key, len);
+ if (ret == KNOT_EOK) {
+ lookup->found.data = *trie_it_val(lookup->iter.it);
+ }
+ return;
+ }
+
+ lookup->iter.it = trie_it_begin(lookup->trie);
+ while (!trie_it_finished(lookup->iter.it)) {
+ size_t len;
+ const char *key = trie_it_key(lookup->iter.it, &len);
+
+ if (strncmp(key, lookup->iter.first_key, len) == 0) {
+ int ret = set_key(lookup, &lookup->found.key, key, len);
+ if (ret == KNOT_EOK) {
+ lookup->found.data = *trie_it_val(lookup->iter.it);
+ }
+ break;
+ }
+ trie_it_next(lookup->iter.it);
+ }
+}
+
+static void print_options(lookup_t *lookup, EditLine *el)
+{
+ // Get terminal lines.
+ unsigned lines = 0;
+ if (el_get(el, EL_GETTC, "li", &lines) != 0 || lines < 3) {
+ return;
+ }
+
+ for (size_t i = 1; i <= lookup->iter.count; i++) {
+ lookup_list(lookup);
+ printf("\n%s", lookup->found.key);
+
+ if (i > 1 && i % (lines - 1) == 0 && i < lookup->iter.count) {
+ printf("\n Display next from %zu possibilities? (y or n)",
+ lookup->iter.count);
+ char next;
+ el_getc(el, &next);
+ if (next != 'y') {
+ break;
+ }
+ }
+ }
+
+ printf("\n");
+ fflush(stdout);
+}
+
+void lookup_complete(lookup_t *lookup, const char *str, size_t str_len,
+ EditLine *el, bool add_space)
+{
+ if (lookup == NULL || el == NULL) {
+ return;
+ }
+
+ // Try to complete the command name.
+ int ret = lookup_search(lookup, str, str_len);
+ switch (ret) {
+ case KNOT_EOK:
+ el_deletestr(el, str_len);
+ el_insertstr(el, lookup->found.key);
+ if (add_space) {
+ el_insertstr(el, " ");
+ }
+ break;
+ case KNOT_EFEWDATA:
+ if (strlen(lookup->found.key) > str_len) {
+ el_deletestr(el, str_len);
+ el_insertstr(el, lookup->found.key);
+ } else {
+ print_options(lookup, el);
+ }
+ break;
+ default:
+ break;
+ }
+}
diff --git a/src/utils/common/lookup.h b/src/utils/common/lookup.h
new file mode 100644
index 0000000..a8eb065
--- /dev/null
+++ b/src/utils/common/lookup.h
@@ -0,0 +1,122 @@
+/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief Lookup container for textual strings.
+ *
+ * \addtogroup knot_utils
+ * @{
+ */
+
+#pragma once
+
+#include <histedit.h>
+
+#include "libknot/mm_ctx.h"
+#include "contrib/qp-trie/trie.h"
+
+/*! Lookup context. */
+typedef struct {
+ /*! Memory pool context. */
+ knot_mm_t mm;
+ /*! Main trie storage. */
+ trie_t *trie;
+
+ /*! Current (iteration) data context. */
+ struct {
+ /*! Stored key. */
+ char *key;
+ /*! Corresponding key data. */
+ void *data;
+ } found;
+
+ /*! Iteration context. */
+ struct {
+ /*! Total number of possibilies. */
+ size_t count;
+ /*! The first possibility. */
+ char *first_key;
+ /*! Hat-trie iterator. */
+ trie_it_t *it;
+ } iter;
+} lookup_t;
+
+/*!
+ * Initializes the lookup context.
+ *
+ * \param[in] lookup Lookup context.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int lookup_init(lookup_t *lookup);
+
+/*!
+ * Deinitializes the lookup context.
+ *
+ * \param[in] lookup Lookup context.
+ */
+void lookup_deinit(lookup_t *lookup);
+
+/*!
+ * Inserts given key and data into the lookup.
+ *
+ * \param[in] lookup Lookup context.
+ * \param[in] str Textual key.
+ * \param[in] data Key textual data.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int lookup_insert(lookup_t *lookup, const char *str, void *data);
+
+/*!
+ * Searches the lookup container for the given key.
+ *
+ * \note If one candidate, lookup.found contains the key/data,
+ * if more candidates, lookup.found contains the common key prefix and
+ * lookup.iter.first_key is the first candidate key.
+ *
+ * \param[in] lookup Lookup context.
+ * \param[in] str Textual key.
+ * \param[in] str_len Textual key length.
+ *
+ * \return Error code, KNOT_EOK if 1 candidate, KNOT_ENOENT if no candidate,
+ * and KNOT_EFEWDATA if more candidates are possible.
+ */
+int lookup_search(lookup_t *lookup, const char *str, size_t str_len);
+
+/*!
+ * Moves the lookup iterator to the next key candidate.
+ *
+ * \note lookup.found is updated.
+ *
+ * \param[in] lookup Lookup context.
+ */
+void lookup_list(lookup_t *lookup);
+
+/*!
+ * Completes the string based on the lookup content or prints all candidates.
+ *
+ * \param[in] lookup Lookup context.
+ * \param[in] str Textual key.
+ * \param[in] str_len Textual key length.
+ * \param[in] el Editline context.
+ * \param[in] add_space Add one space after completed string flag.
+ */
+void lookup_complete(lookup_t *lookup, const char *str, size_t str_len,
+ EditLine *el, bool add_space);
+
+/*! @} */
diff --git a/src/utils/common/msg.c b/src/utils/common/msg.c
new file mode 100644
index 0000000..c3375d3
--- /dev/null
+++ b/src/utils/common/msg.c
@@ -0,0 +1,40 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "utils/common/msg.h"
+
+static volatile int MSG_DBG_STATE = 0; /* True if debugging is enabled. */
+
+int msg_enable_debug(int val)
+{
+ return MSG_DBG_STATE = val;
+}
+
+int msg_debug(const char *fmt, ...)
+{
+ int n = 0;
+ if (MSG_DBG_STATE) {
+ va_list ap;
+ va_start(ap, fmt);
+ n = vprintf(fmt, ap);
+ va_end(ap);
+ }
+ return n;
+}
diff --git a/src/utils/common/msg.h b/src/utils/common/msg.h
new file mode 100644
index 0000000..a300afe
--- /dev/null
+++ b/src/utils/common/msg.h
@@ -0,0 +1,50 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file msg.h
+ *
+ * \author Daniel Salzman <daniel.salzman@nic.cz>
+ *
+ * \brief Simple output formatting framework.
+ *
+ * \addtogroup knot_utils
+ * @{
+ */
+
+#pragma once
+
+#include <stdio.h>
+
+#define ERROR_ ";; ERROR: "
+#define INFO_ ";; INFO: "
+#define WARNING_ ";; WARNING: "
+#define DEBUG_ ";; DEBUG: "
+
+#define ERR(msg, ...) { fprintf(stderr, ERROR_ msg, ##__VA_ARGS__); fflush(stderr); }
+#define INFO(msg, ...) { fprintf(stdout, INFO_ msg, ##__VA_ARGS__); fflush(stdout); }
+#define WARN(msg, ...) { fprintf(stderr, WARNING_ msg, ##__VA_ARGS__); fflush(stderr); }
+#define DBG(msg, ...) msg_debug(DEBUG_ msg, ##__VA_ARGS__)
+
+/*! \brief Enable/disable debugging. */
+int msg_enable_debug(int val);
+
+/*! \brief Print debug message. */
+int msg_debug(const char *fmt, ...);
+
+/*! \brief Debug message for null input. */
+#define DBG_NULL DBG("%s: null parameter\n", __func__)
+
+/*! @} */
diff --git a/src/utils/common/netio.c b/src/utils/common/netio.c
new file mode 100644
index 0000000..9a27d33
--- /dev/null
+++ b/src/utils/common/netio.c
@@ -0,0 +1,593 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <poll.h>
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#include "utils/common/netio.h"
+#include "utils/common/msg.h"
+#include "utils/common/tls.h"
+#include "libknot/libknot.h"
+#include "contrib/sockaddr.h"
+
+srv_info_t *srv_info_create(const char *name, const char *service)
+{
+ if (name == NULL || service == NULL) {
+ DBG_NULL;
+ return NULL;
+ }
+
+ // Create output structure.
+ srv_info_t *server = calloc(1, sizeof(srv_info_t));
+
+ // Check output.
+ if (server == NULL) {
+ return NULL;
+ }
+
+ // Fill output.
+ server->name = strdup(name);
+ server->service = strdup(service);
+
+ if (server->name == NULL || server->service == NULL) {
+ srv_info_free(server);
+ return NULL;
+ }
+
+ // Return result.
+ return server;
+}
+
+void srv_info_free(srv_info_t *server)
+{
+ if (server == NULL) {
+ DBG_NULL;
+ return;
+ }
+
+ free(server->name);
+ free(server->service);
+ free(server);
+}
+
+int get_iptype(const ip_t ip)
+{
+ switch (ip) {
+ case IP_4:
+ return AF_INET;
+ case IP_6:
+ return AF_INET6;
+ default:
+ return AF_UNSPEC;
+ }
+}
+
+int get_socktype(const protocol_t proto, const uint16_t type)
+{
+ switch (proto) {
+ case PROTO_TCP:
+ return SOCK_STREAM;
+ case PROTO_UDP:
+ return SOCK_DGRAM;
+ default:
+ if (type == KNOT_RRTYPE_AXFR || type == KNOT_RRTYPE_IXFR) {
+ return SOCK_STREAM;
+ } else {
+ return SOCK_DGRAM;
+ }
+ }
+}
+
+const char *get_sockname(const int socktype)
+{
+ switch (socktype) {
+ case SOCK_STREAM:
+ return "TCP";
+ case SOCK_DGRAM:
+ return "UDP";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+static int get_addr(const srv_info_t *server,
+ const int iptype,
+ const int socktype,
+ struct addrinfo **info)
+{
+ struct addrinfo hints;
+
+ // Set connection hints.
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = iptype;
+ hints.ai_socktype = socktype;
+
+ // Get connection parameters.
+ if (getaddrinfo(server->name, server->service, &hints, info) != 0) {
+ ERR("can't resolve address %s@%s\n",
+ server->name, server->service);
+ return -1;
+ }
+
+ return 0;
+}
+
+void get_addr_str(const struct sockaddr_storage *ss,
+ const int socktype,
+ char **dst)
+{
+ char addr_str[SOCKADDR_STRLEN] = {0};
+
+ // Get network address string and port number.
+ sockaddr_tostr(addr_str, sizeof(addr_str), (struct sockaddr *)ss);
+
+ // Calculate needed buffer size
+ const char *sock_name = get_sockname(socktype);
+ size_t buflen = strlen(addr_str) + strlen(sock_name) + 3 /* () */;
+
+ // Free previous string if any and write result
+ free(*dst);
+ *dst = malloc(buflen);
+ if (*dst != NULL) {
+ int ret = snprintf(*dst, buflen, "%s(%s)", addr_str, sock_name);
+ if (ret <= 0 || ret >= buflen) {
+ **dst = '\0';
+ }
+ }
+}
+
+int net_init(const srv_info_t *local,
+ const srv_info_t *remote,
+ const int iptype,
+ const int socktype,
+ const int wait,
+ const net_flags_t flags,
+ const tls_params_t *tls_params,
+ net_t *net)
+{
+ if (remote == NULL || net == NULL) {
+ DBG_NULL;
+ return KNOT_EINVAL;
+ }
+
+ // Clean network structure.
+ memset(net, 0, sizeof(*net));
+
+ // Get remote address list.
+ if (get_addr(remote, iptype, socktype, &net->remote_info) != 0) {
+ net_clean(net);
+ return KNOT_NET_EADDR;
+ }
+
+ // Set current remote address.
+ net->srv = net->remote_info;
+
+ // Get local address if specified.
+ if (local != NULL) {
+ if (get_addr(local, iptype, socktype, &net->local_info) != 0) {
+ net_clean(net);
+ return KNOT_NET_EADDR;
+ }
+ }
+
+ // Store network parameters.
+ net->iptype = iptype;
+ net->socktype = socktype;
+ net->wait = wait;
+ net->local = local;
+ net->remote = remote;
+ net->flags = flags;
+
+ // Prepare for TLS.
+ if (tls_params != NULL && tls_params->enable) {
+ int ret = tls_ctx_init(&net->tls, tls_params, net->wait);
+ if (ret != KNOT_EOK) {
+ net_clean(net);
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+/**
+ * Connect with TCP Fast Open.
+ */
+static int fastopen_connect(int sockfd, const struct addrinfo *srv)
+{
+#if __APPLE__
+ // connection is performed lazily when first data are sent
+ struct sa_endpoints ep = {0};
+ ep.sae_dstaddr = srv->ai_addr;
+ ep.sae_dstaddrlen = srv->ai_addrlen;
+ int flags = CONNECT_DATA_IDEMPOTENT|CONNECT_RESUME_ON_READ_WRITE;
+
+ return connectx(sockfd, &ep, SAE_ASSOCID_ANY, flags, NULL, 0, NULL, NULL);
+#elif defined(MSG_FASTOPEN) // Linux with RFC 7413
+ // connect() will be called implicitly with sendto(), sendmsg()
+ return 0;
+#else
+ errno = ENOTSUP;
+ return -1;
+#endif
+}
+
+/**
+ * Sends data with TCP Fast Open.
+ */
+static int fastopen_send(int sockfd, const struct msghdr *msg, int timeout)
+{
+#if __APPLE__
+ return sendmsg(sockfd, msg, 0);
+#elif defined(MSG_FASTOPEN)
+ int ret = sendmsg(sockfd, msg, MSG_FASTOPEN);
+ if (ret == -1 && errno == EINPROGRESS) {
+ struct pollfd pfd = {
+ .fd = sockfd,
+ .events = POLLOUT,
+ .revents = 0,
+ };
+ if (poll(&pfd, 1, 1000 * timeout) != 1) {
+ errno = ETIMEDOUT;
+ return -1;
+ }
+ ret = sendmsg(sockfd, msg, 0);
+ }
+ return ret;
+#else
+ errno = ENOTSUP;
+ return -1;
+#endif
+}
+
+int net_connect(net_t *net)
+{
+ if (net == NULL || net->srv == NULL) {
+ DBG_NULL;
+ return KNOT_EINVAL;
+ }
+
+ // Set remote information string.
+ get_addr_str((struct sockaddr_storage *)net->srv->ai_addr,
+ net->socktype, &net->remote_str);
+
+ // Create socket.
+ int sockfd = socket(net->srv->ai_family, net->socktype, 0);
+ if (sockfd == -1) {
+ WARN("can't create socket for %s\n", net->remote_str);
+ return KNOT_NET_ESOCKET;
+ }
+
+ // Initialize poll descriptor structure.
+ struct pollfd pfd = {
+ .fd = sockfd,
+ .events = POLLOUT,
+ .revents = 0,
+ };
+
+ // Set non-blocking socket.
+ if (fcntl(sockfd, F_SETFL, O_NONBLOCK) == -1) {
+ WARN("can't set non-blocking socket for %s\n", net->remote_str);
+ return KNOT_NET_ESOCKET;
+ }
+
+ // Bind address to socket if specified.
+ if (net->local_info != NULL) {
+ if (bind(sockfd, net->local_info->ai_addr,
+ net->local_info->ai_addrlen) == -1) {
+ WARN("can't assign address %s\n", net->local->name);
+ return KNOT_NET_ESOCKET;
+ }
+ }
+
+ if (net->socktype == SOCK_STREAM) {
+ int cs, err, ret = 0;
+ socklen_t err_len = sizeof(err);
+ bool fastopen = net->flags & NET_FLAGS_FASTOPEN;
+
+ // Connect using socket.
+ if (fastopen) {
+ ret = fastopen_connect(sockfd, net->srv);
+ } else {
+ ret = connect(sockfd, net->srv->ai_addr, net->srv->ai_addrlen);
+ }
+ if (ret != 0 && errno != EINPROGRESS) {
+ WARN("can't connect to %s\n", net->remote_str);
+ close(sockfd);
+ return KNOT_NET_ECONNECT;
+ }
+
+ // Check for connection timeout.
+ if (!fastopen && poll(&pfd, 1, 1000 * net->wait) != 1) {
+ WARN("connection timeout for %s\n", net->remote_str);
+ close(sockfd);
+ return KNOT_NET_ECONNECT;
+ }
+
+ // Check if NB socket is writeable.
+ cs = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &err, &err_len);
+ if (cs < 0 || err != 0) {
+ WARN("can't connect to %s\n", net->remote_str);
+ close(sockfd);
+ return KNOT_NET_ECONNECT;
+ }
+
+ // Establish TLS connection.
+ if (net->tls.params != NULL) {
+ int ret = tls_ctx_connect(&net->tls, sockfd, net->tls.params->sni);
+ if (ret != KNOT_EOK) {
+ close(sockfd);
+ return ret;
+ }
+ }
+ }
+
+ // Store socket descriptor.
+ net->sockfd = sockfd;
+
+ return KNOT_EOK;
+}
+
+int net_set_local_info(net_t *net)
+{
+ if (net == NULL) {
+ DBG_NULL;
+ return KNOT_EINVAL;
+ }
+
+ if (net->local_info != NULL) {
+ free(net->local_info->ai_addr);
+ freeaddrinfo(net->local_info);
+ }
+
+ socklen_t local_addr_len = sizeof(struct sockaddr_storage);
+ struct sockaddr_storage *local_addr = calloc(1, local_addr_len);
+
+ if (getsockname(net->sockfd, (struct sockaddr *)local_addr,
+ &local_addr_len) == -1) {
+ WARN("can't get local address\n");
+ free(local_addr);
+ return KNOT_NET_ESOCKET;
+ }
+
+ net->local_info = calloc(1, sizeof(struct addrinfo));
+ net->local_info->ai_family = net->srv->ai_family;
+ net->local_info->ai_socktype = net->srv->ai_socktype;
+ net->local_info->ai_protocol = net->srv->ai_protocol;
+ net->local_info->ai_addrlen = local_addr_len;
+ net->local_info->ai_addr = (struct sockaddr *)local_addr;
+
+ get_addr_str((struct sockaddr_storage *)net->local_info->ai_addr,
+ net->socktype, &net->local_str);
+
+ return KNOT_EOK;
+}
+
+int net_send(const net_t *net, const uint8_t *buf, const size_t buf_len)
+{
+ if (net == NULL || buf == NULL) {
+ DBG_NULL;
+ return KNOT_EINVAL;
+ }
+
+ // Send data over UDP.
+ if (net->socktype == SOCK_DGRAM) {
+ if (sendto(net->sockfd, buf, buf_len, 0, net->srv->ai_addr,
+ net->srv->ai_addrlen) != (ssize_t)buf_len) {
+ WARN("can't send query to %s\n", net->remote_str);
+ return KNOT_NET_ESEND;
+ }
+ // Send data over TLS.
+ } else if (net->tls.params != NULL) {
+ int ret = tls_ctx_send((tls_ctx_t *)&net->tls, buf, buf_len);
+ if (ret != KNOT_EOK) {
+ WARN("can't send query to %s\n", net->remote_str);
+ return KNOT_NET_ESEND;
+ }
+ // Send data over TCP.
+ } else {
+ bool fastopen = net->flags & NET_FLAGS_FASTOPEN;
+
+ // Leading packet length bytes.
+ uint16_t pktsize = htons(buf_len);
+
+ struct iovec iov[2];
+ iov[0].iov_base = &pktsize;
+ iov[0].iov_len = sizeof(pktsize);
+ iov[1].iov_base = (uint8_t *)buf;
+ iov[1].iov_len = buf_len;
+
+ // Compute packet total length.
+ ssize_t total = iov[0].iov_len + iov[1].iov_len;
+
+ struct msghdr msg = {0};
+ msg.msg_iov = iov;
+ msg.msg_iovlen = sizeof(iov) / sizeof(*iov);
+ msg.msg_name = net->srv->ai_addr;
+ msg.msg_namelen = net->srv->ai_addrlen;
+
+ int ret = 0;
+ if (fastopen) {
+ ret = fastopen_send(net->sockfd, &msg, net->wait);
+ } else {
+ ret = sendmsg(net->sockfd, &msg, 0);
+ }
+ if (ret != total) {
+ WARN("can't send query to %s\n", net->remote_str);
+ return KNOT_NET_ESEND;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+int net_receive(const net_t *net, uint8_t *buf, const size_t buf_len)
+{
+ if (net == NULL || buf == NULL) {
+ DBG_NULL;
+ return KNOT_EINVAL;
+ }
+
+ // Initialize poll descriptor structure.
+ struct pollfd pfd = {
+ .fd = net->sockfd,
+ .events = POLLIN,
+ .revents = 0,
+ };
+
+ // Receive data over UDP.
+ if (net->socktype == SOCK_DGRAM) {
+ struct sockaddr_storage from;
+ memset(&from, '\0', sizeof(from));
+
+ // Receive replies unless correct reply or timeout.
+ while (true) {
+ socklen_t from_len = sizeof(from);
+
+ // Wait for datagram data.
+ if (poll(&pfd, 1, 1000 * net->wait) != 1) {
+ WARN("response timeout for %s\n",
+ net->remote_str);
+ return KNOT_NET_ETIMEOUT;
+ }
+
+ // Receive whole UDP datagram.
+ ssize_t ret = recvfrom(net->sockfd, buf, buf_len, 0,
+ (struct sockaddr *)&from, &from_len);
+ if (ret <= 0) {
+ WARN("can't receive reply from %s\n",
+ net->remote_str);
+ return KNOT_NET_ERECV;
+ }
+
+ // Compare reply address with the remote one.
+ if (from_len > sizeof(from) ||
+ memcmp(&from, net->srv->ai_addr, from_len) != 0) {
+ char *src = NULL;
+ get_addr_str(&from, net->socktype, &src);
+ WARN("unexpected reply source %s\n", src);
+ free(src);
+ continue;
+ }
+
+ return ret;
+ }
+ // Receive data over TLS.
+ } else if (net->tls.params != NULL) {
+ int ret = tls_ctx_receive((tls_ctx_t *)&net->tls, buf, buf_len);
+ if (ret < 0) {
+ WARN("can't receive reply from %s\n", net->remote_str);
+ return KNOT_NET_ERECV;
+ }
+
+ return ret;
+ // Receive data over TCP.
+ } else {
+ uint32_t total = 0;
+
+ uint16_t msg_len = 0;
+ // Receive TCP message header.
+ while (total < sizeof(msg_len)) {
+ if (poll(&pfd, 1, 1000 * net->wait) != 1) {
+ WARN("response timeout for %s\n",
+ net->remote_str);
+ return KNOT_NET_ETIMEOUT;
+ }
+
+ // Receive piece of message.
+ ssize_t ret = recv(net->sockfd, (uint8_t *)&msg_len + total,
+ sizeof(msg_len) - total, 0);
+ if (ret <= 0) {
+ WARN("can't receive reply from %s\n",
+ net->remote_str);
+ return KNOT_NET_ERECV;
+ }
+ total += ret;
+ }
+
+ // Convert number to host format.
+ msg_len = ntohs(msg_len);
+ if (msg_len > buf_len) {
+ return KNOT_ESPACE;
+ }
+
+ total = 0;
+
+ // Receive whole answer message by parts.
+ while (total < msg_len) {
+ if (poll(&pfd, 1, 1000 * net->wait) != 1) {
+ WARN("response timeout for %s\n",
+ net->remote_str);
+ return KNOT_NET_ETIMEOUT;
+ }
+
+ // Receive piece of message.
+ ssize_t ret = recv(net->sockfd, buf + total, msg_len - total, 0);
+ if (ret <= 0) {
+ WARN("can't receive reply from %s\n",
+ net->remote_str);
+ return KNOT_NET_ERECV;
+ }
+ total += ret;
+ }
+
+ return total;
+ }
+
+ return KNOT_NET_ERECV;
+}
+
+void net_close(net_t *net)
+{
+ if (net == NULL) {
+ DBG_NULL;
+ return;
+ }
+
+ tls_ctx_close(&net->tls);
+ close(net->sockfd);
+ net->sockfd = -1;
+}
+
+void net_clean(net_t *net)
+{
+ if (net == NULL) {
+ DBG_NULL;
+ return;
+ }
+
+ free(net->local_str);
+ free(net->remote_str);
+
+ if (net->local_info != NULL) {
+ freeaddrinfo(net->local_info);
+ }
+
+ if (net->remote_info != NULL) {
+ freeaddrinfo(net->remote_info);
+ }
+
+ tls_ctx_deinit(&net->tls);
+}
diff --git a/src/utils/common/netio.h b/src/utils/common/netio.h
new file mode 100644
index 0000000..d861149
--- /dev/null
+++ b/src/utils/common/netio.h
@@ -0,0 +1,229 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief Networking abstraction for utilities.
+ *
+ * \addtogroup knot_utils
+ * @{
+ */
+
+#pragma once
+
+#include <netdb.h>
+#include <stdint.h>
+#include <sys/socket.h>
+
+#include "utils/common/params.h"
+#include "utils/common/tls.h"
+
+/*! \brief Structure containing server information. */
+typedef struct {
+ /*! List node (for list container). */
+ node_t n;
+ /*! Name or address of the server. */
+ char *name;
+ /*! Name or number of the service. */
+ char *service;
+} srv_info_t;
+
+typedef enum {
+ NET_FLAGS_NONE = 0,
+ NET_FLAGS_FASTOPEN = 1 << 0,
+} net_flags_t;
+
+typedef struct {
+ /*! Socket descriptor. */
+ int sockfd;
+
+ /*! IP protocol type. */
+ int iptype;
+ /*! Socket type. */
+ int socktype;
+ /*! Timeout for all network operations. */
+ int wait;
+ /*! Connection flags. */
+ net_flags_t flags;
+
+ /*! Local interface parameters. */
+ const srv_info_t *local;
+ /*! Remote server parameters. */
+ const srv_info_t *remote;
+
+ /*! Local description string (used for logging). */
+ char *local_str;
+ /*! Remote description string (used for logging). */
+ char *remote_str;
+
+ /*! Output from getaddrinfo for remote server. If the server is
+ * specified using domain name, this structure may contain more
+ * results.
+ */
+ struct addrinfo *remote_info;
+ /*! Currently used result from remote_info. */
+ struct addrinfo *srv;
+ /*! Output from getaddrinfo for local address. Only first result is
+ * used.
+ */
+ struct addrinfo *local_info;
+
+ /*! TLS context. */
+ tls_ctx_t tls;
+} net_t;
+
+/*!
+ * \brief Creates and fills server structure.
+ *
+ * \param name Address or host name.
+ * \param service Port number or service name.
+ *
+ * \retval server if success.
+ * \retval NULL if error.
+ */
+srv_info_t *srv_info_create(const char *name, const char *service);
+
+/*!
+ * \brief Destroys server structure.
+ *
+ * \param server Server structure to destroy.
+ */
+void srv_info_free(srv_info_t *server);
+
+/*!
+ * \brief Translates enum IP version type to int version.
+ *
+ * \param ip IP version to convert.
+ *
+ * \retval AF_INET, AF_INET6 or AF_UNSPEC.
+ */
+int get_iptype(const ip_t ip);
+
+/*!
+ * \brief Translates enum IP protocol type to int version in context to the
+ * current DNS query type.
+ *
+ * \param proto IP protocol type to convert.
+ * \param type DNS query type number.
+ *
+ * \retval SOCK_STREAM or SOCK_DGRAM.
+ */
+int get_socktype(const protocol_t proto, const uint16_t type);
+
+/*!
+ * \brief Translates int socket type to the common string one.
+ *
+ * \param socktype Socket type (SOCK_STREAM or SOCK_DGRAM).
+ *
+ * \retval "TCP" or "UDP".
+ */
+const char *get_sockname(const int socktype);
+
+/*!
+ * \brief Translates int socket type to the common string one.
+ *
+ * \param ss Socket address storage.
+ * \param socktype Socket type (SOCK_STREAM or SOCK_DGRAM).
+ * \param dst Output string.
+ */
+void get_addr_str(const struct sockaddr_storage *ss,
+ const int socktype,
+ char **dst);
+
+/*!
+ * \brief Initializes network structure and resolves local and remote addresses.
+ *
+ * \param local Local address and service description.
+ * \param remote Remote address and service description.
+ * \param iptype IP version.
+ * \param socktype Socket type.
+ * \param wait Network timeout interval.
+ * \param tls_params TLS parameters.
+ * \param flags Connection flags.
+ * \param net Network structure to initialize.
+ *
+ * \retval KNOT_EOK if success.
+ * \retval errcode if error.
+ */
+int net_init(const srv_info_t *local,
+ const srv_info_t *remote,
+ const int iptype,
+ const int socktype,
+ const int wait,
+ const net_flags_t flags,
+ const tls_params_t *tls_params,
+ net_t *net);
+
+/*!
+ * \brief Creates socket and connects (if TCP) to remote address specified
+ * by net->srv.
+ *
+ * \param net Connection parameters.
+ *
+ * \retval KNOT_EOK if success.
+ * \retval errcode if error.
+ */
+int net_connect(net_t *net);
+
+/*!
+ * \brief Fills in local address information.
+ *
+ * \param net Connection parameters.
+ *
+ * \retval KNOT_EOK if success.
+ * \retval errcode if error.
+ */
+int net_set_local_info(net_t *net);
+
+/*!
+ * \brief Sends data to connected remote server.
+ *
+ * \param net Connection parameters.
+ * \param buf Data to send.
+ * \param buf_len Length of the data to send.
+ *
+ * \retval KNOT_EOK if success.
+ * \retval errcode if error.
+ */
+int net_send(const net_t *net, const uint8_t *buf, const size_t buf_len);
+
+/*!
+ * \brief Receives data from connected remote server.
+ *
+ * \param net Connection parameters.
+ * \param buf Buffer for incoming data.
+ * \param buf_len Length of the buffer.
+ *
+ * \retval >=0 length of successfully received data.
+ * \retval errcode if error.
+ */
+int net_receive(const net_t *net, uint8_t *buf, const size_t buf_len);
+
+/*!
+ * \brief Closes current network connection.
+ *
+ * \param net Connection parameters.
+ */
+void net_close(net_t *net);
+
+/*!
+ * \brief Cleans up network structure.
+ *
+ * \param net Connection parameters.
+ */
+void net_clean(net_t *net);
+
+/*! @} */
diff --git a/src/utils/common/params.c b/src/utils/common/params.c
new file mode 100644
index 0000000..e374314
--- /dev/null
+++ b/src/utils/common/params.c
@@ -0,0 +1,347 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#ifdef LIBIDN
+#include LIBIDN_HEADER
+#endif
+
+#include "utils/common/params.h"
+#include "utils/common/msg.h"
+#include "utils/common/resolv.h"
+#include "utils/common/token.h"
+#include "libknot/libknot.h"
+#include "contrib/macros.h"
+#include "contrib/mempattern.h"
+#include "contrib/openbsd/strlcpy.h"
+#include "contrib/strtonum.h"
+
+#define IPV4_REVERSE_DOMAIN "in-addr.arpa."
+#define IPV6_REVERSE_DOMAIN "ip6.arpa."
+
+char *name_from_idn(const char *idn_name) {
+#ifdef LIBIDN
+ char *name = NULL;
+
+ int rc = idna_to_ascii_lz(idn_name, &name, 0);
+ if (rc != IDNA_SUCCESS) {
+ ERR("IDNA (%s)\n", idna_strerror(rc));
+ return NULL;
+ }
+
+ return name;
+#endif
+ return strdup(idn_name);
+}
+
+void name_to_idn(char **name) {
+#ifdef LIBIDN
+ char *idn_name = NULL;
+
+ int rc = idna_to_unicode_8zlz(*name, &idn_name, 0);
+ if (rc != IDNA_SUCCESS) {
+ return;
+ }
+
+ free(*name);
+ *name = idn_name;
+#endif
+ return;
+}
+
+/*!
+ * \brief Checks if string is a prefix of reference string.
+ *
+ * \param pref Prefix string.
+ * \param pref_len Prefix length.
+ * \param str Reference string (must have trailing zero).
+ *
+ * \retval -1 \a pref is not a prefix of \a str.
+ * \retval 0<= number of chars after prefix \a pref in \a str.
+ */
+static int cmp_prefix(const char *pref, const size_t pref_len,
+ const char *str)
+{
+ size_t i = 0;
+ while (1) {
+ // Different characters => NOT prefix.
+ if (pref[i] != str[i]) {
+ return -1;
+ }
+
+ i++;
+
+ // Pref IS a prefix of pref.
+ if (i == pref_len) {
+ size_t rest = 0;
+ while (str[i + rest] != '\0') {
+ rest++;
+ }
+ return rest;
+ // Pref is longer then ref => NOT prefix.
+ } else if (str[i] == '\0') {
+ return -1;
+ }
+ }
+}
+
+int best_param(const char *str, const size_t str_len, const param_t *tbl,
+ bool *unique)
+{
+ if (str == NULL || str_len == 0 || tbl == NULL) {
+ DBG_NULL;
+ return KNOT_EINVAL;
+ }
+
+ int best_pos = -1;
+ int best_match = INT_MAX;
+ size_t matches = 0;
+ for (int i = 0; tbl[i].name != NULL; i++) {
+ int ret = cmp_prefix(str, str_len, tbl[i].name);
+ switch (ret) {
+ case -1:
+ continue;
+ case 0:
+ *unique = true;
+ return i;
+ default:
+ if (ret < best_match) {
+ best_pos = i;
+ best_match = ret;
+ }
+ matches++;
+ }
+ }
+
+ switch (matches) {
+ case 0:
+ return KNOT_ENOTSUP;
+ case 1:
+ *unique = true;
+ return best_pos;
+ default:
+ *unique = false;
+ return best_pos;
+ }
+}
+
+char *get_reverse_name(const char *name)
+{
+ struct in_addr addr4;
+ struct in6_addr addr6;
+ int ret;
+ char buf[128] = "\0";
+
+ if (name == NULL) {
+ DBG_NULL;
+ return NULL;
+ }
+
+ // Check name for IPv4 address, IPv6 address or other.
+ if (inet_pton(AF_INET, name, &addr4) == 1) {
+ uint32_t num = ntohl(addr4.s_addr);
+
+ // Create IPv4 reverse FQD name.
+ ret = snprintf(buf, sizeof(buf), "%u.%u.%u.%u.%s",
+ (num >> 0) & 0xFF, (num >> 8) & 0xFF,
+ (num >> 16) & 0xFF, (num >> 24) & 0xFF,
+ IPV4_REVERSE_DOMAIN);
+ if (ret < 0 || (size_t)ret >= sizeof(buf)) {
+ return NULL;
+ }
+
+ return strdup(buf);
+ } else if (inet_pton(AF_INET6, name, &addr6) == 1) {
+ char *pos = buf;
+ size_t len = sizeof(buf);
+ uint8_t left, right;
+
+ // Create IPv6 reverse name.
+ for (int i = 15; i >= 0; i--) {
+ left = ((addr6.s6_addr)[i] & 0xF0) >> 4;
+ right = (addr6.s6_addr)[i] & 0x0F;
+
+ ret = snprintf(pos, len, "%x.%x.", right, left);
+ if (ret < 0 || (size_t)ret >= len) {
+ return NULL;
+ }
+
+ pos += ret;
+ len -= ret;
+ }
+
+ // Add IPv6 reverse domain.
+ ret = snprintf(pos, len, "%s", IPV6_REVERSE_DOMAIN);
+ if (ret < 0 || (size_t)ret >= len) {
+ return NULL;
+ }
+
+ return strdup(buf);
+ } else {
+ return NULL;
+ }
+}
+
+char *get_fqd_name(const char *name)
+{
+ char *fqd_name = NULL;
+
+ if (name == NULL) {
+ DBG_NULL;
+ return NULL;
+ }
+
+ size_t name_len = strlen(name);
+
+ // If the name is FQDN, make a copy.
+ if (name[name_len - 1] == '.') {
+ fqd_name = strdup(name);
+ // Else make a copy and append a trailing dot.
+ } else {
+ size_t fqd_name_size = name_len + 2;
+ fqd_name = malloc(fqd_name_size);
+ if (fqd_name != NULL) {
+ strlcpy(fqd_name, name, fqd_name_size);
+ fqd_name[name_len] = '.';
+ fqd_name[name_len + 1] = 0;
+ }
+ }
+
+ return fqd_name;
+}
+
+int params_parse_class(const char *value, uint16_t *rclass)
+{
+ if (value == NULL || rclass == NULL) {
+ DBG_NULL;
+ return KNOT_EINVAL;
+ }
+
+ if (knot_rrclass_from_string(value, rclass) == 0) {
+ return KNOT_EOK;
+ } else {
+ return KNOT_EINVAL;
+ }
+}
+
+int params_parse_type(const char *value, uint16_t *rtype, int64_t *serial,
+ bool *notify)
+{
+ if (value == NULL || rtype == NULL || serial == NULL) {
+ DBG_NULL;
+ return KNOT_EINVAL;
+ }
+
+ // Find and parse type name.
+ size_t param_pos = strcspn(value, "=");
+ char *type_char = strndup(value, param_pos);
+
+ if (knot_rrtype_from_string(type_char, rtype) != 0) {
+ size_t cmp_len = MAX(strlen("NOTIFY"), param_pos);
+ if (strncasecmp(type_char, "NOTIFY", cmp_len) == 0) {
+ *rtype = KNOT_RRTYPE_SOA;
+ *notify = true;
+ } else {
+ free(type_char);
+ return KNOT_EINVAL;
+ }
+ } else {
+ *notify = false;
+ }
+
+ free(type_char);
+
+ // Parse additional parameter.
+ if (param_pos == strlen(value)) {
+ // IXFR requires serial parameter.
+ if (*rtype == KNOT_RRTYPE_IXFR) {
+ DBG("SOA serial is required for IXFR query\n");
+ return KNOT_EINVAL;
+ } else {
+ *serial = -1;
+ }
+ } else {
+ // Additional parameter is accepted for IXFR or NOTIFY.
+ if (*rtype == KNOT_RRTYPE_IXFR || *notify) {
+ const char *param_str = value + 1 + param_pos;
+ char *end;
+
+ // Convert string to serial.
+ unsigned long long num = strtoull(param_str, &end, 10);
+
+ // Check for bad serial string.
+ if (end == param_str || *end != '\0' || num > UINT32_MAX) {
+ DBG("bad SOA serial '%s'\n", param_str);
+ return KNOT_EINVAL;
+ }
+
+ *serial = num;
+ } else {
+ DBG("unsupported parameter '%s'\n", value);
+ return KNOT_EINVAL;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+int params_parse_server(const char *value, list_t *servers, const char *def_port)
+{
+ if (value == NULL || servers == NULL) {
+ DBG_NULL;
+ return KNOT_EINVAL;
+ }
+
+ // Add specified nameserver.
+ srv_info_t *server = parse_nameserver(value, def_port);
+ if (server == NULL) {
+ return KNOT_EINVAL;
+ }
+ add_tail(servers, (node_t *)server);
+
+ return KNOT_EOK;
+}
+
+int params_parse_wait(const char *value, int32_t *dst)
+{
+ if (value == NULL || dst == NULL) {
+ DBG_NULL;
+ return KNOT_EINVAL;
+ }
+
+ uint32_t num;
+ int ret = str_to_u32(value, &num);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Check for minimal value.
+ if (num < 1) {
+ num = 1;
+ // Reduce maximal value. Poll takes signed int in milliseconds.
+ } else if (num > INT32_MAX / 1000) {
+ num = INT32_MAX / 1000;
+ }
+
+ *dst = num;
+
+ return KNOT_EOK;
+}
diff --git a/src/utils/common/params.h b/src/utils/common/params.h
new file mode 100644
index 0000000..4059446
--- /dev/null
+++ b/src/utils/common/params.h
@@ -0,0 +1,172 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file
+ *
+ * \brief Common utils parameters processing.
+ *
+ * \addtogroup knot_utils
+ * @{
+ */
+
+#pragma once
+
+#include <limits.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+#include "libknot/libknot.h"
+#include "contrib/ucw/lists.h"
+
+#define DEFAULT_IPV4_NAME "127.0.0.1"
+#define DEFAULT_IPV6_NAME "::1"
+#define DEFAULT_DNS_PORT "53"
+#define DEFAULT_DNS_TLS_PORT "853"
+#define DEFAULT_UDP_SIZE 512
+#define DEFAULT_EDNS_SIZE 4096
+#define MAX_PACKET_SIZE 65535
+
+#define SEP_CHARS "\n\t "
+
+/*! \brief Variants of IP protocol. */
+typedef enum {
+ IP_ALL,
+ IP_4,
+ IP_6
+} ip_t;
+
+/*! \brief Variants of transport protocol. */
+typedef enum {
+ PROTO_ALL,
+ PROTO_TCP,
+ PROTO_UDP
+} protocol_t;
+
+/*! \brief Variants of output type. */
+typedef enum {
+ /*!< Verbose output (same for host and dig). */
+ FORMAT_FULL,
+ /*!< Short dig output. */
+ FORMAT_DIG,
+ /*!< Brief host output. */
+ FORMAT_HOST,
+ /*!< Brief nsupdate output. */
+ FORMAT_NSUPDATE
+} format_t;
+
+/*! \brief Text output settings. */
+typedef struct {
+ /*!< Output format. */
+ format_t format;
+
+ /*!< Style of rrset dump. */
+ knot_dump_style_t style;
+
+ /*!< Show query packet. */
+ bool show_query;
+ /*!< Show header info. */
+ bool show_header;
+ /*!< Show section name. */
+ bool show_section;
+ /*!< Show EDNS pseudosection. */
+ bool show_edns;
+ /*!< Show QUERY/ZONE section. */
+ bool show_question;
+ /*!< Show ANSWER/PREREQ section. */
+ bool show_answer;
+ /*!< Show UPDATE/AUTHORITY section. */
+ bool show_authority;
+ /*!< Show ADDITIONAL section. */
+ bool show_additional;
+ /*!< Show TSIG pseudosection. */
+ bool show_tsig;
+ /*!< Show footer info. */
+ bool show_footer;
+
+ /*!< KHOST - Hide CNAME record in answer (duplicity reduction). */
+ bool hide_cname;
+} style_t;
+
+/*! \brief Parameter handler. */
+typedef int (*param_handle_f)(const char *arg, void *params);
+
+/*! \brief Parameter argument type. */
+typedef enum {
+ ARG_NONE,
+ ARG_REQUIRED,
+ ARG_OPTIONAL
+} arg_t;
+
+/*! \brief Parameter specification. */
+typedef struct {
+ const char *name;
+ arg_t arg;
+ param_handle_f handler;
+} param_t;
+
+inline static void print_version(const char *program_name)
+{
+ printf("%s (Knot DNS), version %s\n", program_name, PACKAGE_VERSION);
+}
+
+/*!
+ * \brief Transforms localized IDN string to ASCII punycode.
+ *
+ * \param idn_name IDN name to transform.
+ *
+ * \retval NULL if transformation fails.
+ * \retval string if ok.
+ */
+char *name_from_idn(const char *idn_name);
+
+/*!
+ * \brief Transforms ASCII punycode to localized IDN string.
+ *
+ * If an error occurs or IDN support is missing, this function does nothing.
+ *
+ * \param name ASCII name to transform and replace with IDN name.
+ */
+void name_to_idn(char **name);
+
+/*!
+ * \brief Find the best parameter match in table based on prefix equality.
+ *
+ * \param str Parameter name to look up.
+ * \param str_len Parameter name length.
+ * \param tbl Parameter table.
+ * \param unique Indication if output is unique result.
+ *
+ * \retval >=0 looked up parameter position in \a tbl.
+ * \retval err if error.
+ */
+int best_param(const char *str, const size_t str_len, const param_t *tbl,
+ bool *unique);
+
+char *get_reverse_name(const char *name);
+
+char *get_fqd_name(const char *name);
+
+int params_parse_class(const char *value, uint16_t *rclass);
+
+int params_parse_type(const char *value, uint16_t *rtype, int64_t *serial,
+ bool *notify);
+
+int params_parse_server(const char *value, list_t *servers, const char *def_port);
+
+int params_parse_wait(const char *value, int32_t *dst);
+
+/*! @} */
diff --git a/src/utils/common/resolv.c b/src/utils/common/resolv.c
new file mode 100644
index 0000000..b5f84c5
--- /dev/null
+++ b/src/utils/common/resolv.c
@@ -0,0 +1,208 @@
+/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "utils/common/resolv.h"
+#include "utils/common/msg.h"
+#include "utils/common/params.h"
+#include "libknot/libknot.h"
+#include "contrib/ucw/lists.h"
+
+#define RESOLV_FILE "/etc/resolv.conf"
+
+srv_info_t* parse_nameserver(const char *str, const char *def_port)
+{
+ char *host = NULL, *port = NULL;
+ const char *addr = NULL, *sep = NULL;
+ size_t addr_len = 0;
+ char separator = ':';
+
+ if (str == NULL || def_port == NULL) {
+ DBG_NULL;
+ return NULL;
+ }
+
+ const size_t str_len = strlen(str);
+ const char *str_end = str + str_len;
+
+ // [address]:port notation.
+ if (*str == '[') {
+ addr = str + 1;
+ const char *addr_end = strchr(addr, ']');
+ // Missing closing bracket -> stop processing.
+ if (addr_end == NULL) {
+ return NULL;
+ }
+ addr_len = addr_end - addr;
+ str += 1 + addr_len + 1;
+ // Address@port notation.
+ } else if ((sep = strchr(str, '@')) != NULL) {
+ addr = str;
+ addr_len = sep - addr;
+ str += addr_len;
+ separator = '@';
+ // Address#port notation.
+ } else if ((sep = strchr(str, '#')) != NULL) {
+ addr = str;
+ addr_len = sep - addr;
+ str += addr_len;
+ separator = '#';
+ // IPv4:port notation.
+ } else if ((sep = strchr(str, ':')) != NULL) {
+ addr = str;
+ // Not IPv4 address -> no port.
+ if (strchr(sep + 1, ':') != NULL) {
+ addr_len = str_len;
+ str = str_end;
+ } else {
+ addr_len = sep - addr;
+ str += addr_len;
+ }
+ // No port specified.
+ } else {
+ addr = str;
+ addr_len = str_len;
+ str = str_end;
+ }
+
+ // Process port.
+ if (str < str_end) {
+ // Check port separator.
+ if (*str != separator) {
+ return NULL;
+ }
+ str++;
+
+ // Check for missing port.
+ if (str >= str_end) {
+ return NULL;
+ }
+
+ port = strdup(str);
+ } else {
+ port = strdup(def_port);
+ }
+
+ host = strndup(addr, addr_len);
+
+ // Create server structure.
+ srv_info_t *server = srv_info_create(host, port);
+
+ free(host);
+ free(port);
+
+ return server;
+}
+
+static size_t get_resolv_nameservers(list_t *servers, const char *def_port)
+{
+ char line[512];
+
+ // Open config file.
+ FILE *f = fopen(RESOLV_FILE, "r");
+ if (f == NULL) {
+ return 0;
+ }
+
+ // Read lines from config file.
+ while (fgets(line, sizeof(line), f) != NULL) {
+ size_t len;
+ char *pos = line;
+ char *option, *value;
+
+ // Find leading white characters.
+ len = strspn(pos, SEP_CHARS);
+ pos += len;
+
+ // Start of the first token.
+ option = pos;
+
+ // Find length of the token.
+ len = strcspn(pos, SEP_CHARS);
+ pos += len;
+
+ // Check if the token is not empty.
+ if (len == 0) {
+ continue;
+ }
+
+ // Find separating white characters.
+ len = strspn(pos, SEP_CHARS);
+ pos += len;
+
+ // Check if there is a separation between tokens.
+ if (len == 0) {
+ continue;
+ }
+
+ // Copy of the second token.
+ value = strndup(pos, strcspn(pos, SEP_CHARS));
+
+ // Process value with respect to option name.
+ if (strncmp(option, "nameserver", strlen("nameserver")) == 0) {
+ srv_info_t *server;
+
+ server = parse_nameserver(value, def_port);
+
+ // If value is correct, add nameserver to the list.
+ if (server != NULL) {
+ add_tail(servers, (node_t *)server);
+ }
+ }
+
+ // Drop value string.
+ free(value);
+ }
+
+ // Close config file.
+ fclose(f);
+
+ // Return number of servers.
+ return list_size(servers);
+}
+
+void get_nameservers(list_t *servers, const char *def_port)
+{
+ if (servers == NULL || def_port == NULL) {
+ DBG_NULL;
+ return;
+ }
+
+ // Initialize list of servers.
+ init_list(servers);
+
+ // Read nameservers from resolv file or use the default ones.
+ if (get_resolv_nameservers(servers, def_port) == 0) {
+ srv_info_t *server;
+
+ // Add default ipv6 nameservers.
+ server = srv_info_create(DEFAULT_IPV6_NAME, def_port);
+
+ if (server != NULL) {
+ add_tail(servers, (node_t *)server);
+ }
+
+ // Add default ipv4 nameservers.
+ server = srv_info_create(DEFAULT_IPV4_NAME, def_port);
+
+ if (server != NULL) {
+ add_tail(servers, (node_t *)server);
+ }
+ }
+}
diff --git a/src/utils/common/resolv.h b/src/utils/common/resolv.h
new file mode 100644
index 0000000..bcf1a0f
--- /dev/null
+++ b/src/utils/common/resolv.h
@@ -0,0 +1,36 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file resolv.h
+ *
+ * \author Daniel Salzman <daniel.salzman@nic.cz>
+ *
+ * \brief resolv.conf processing.
+ *
+ * \addtogroup knot_utils
+ * @{
+ */
+
+#pragma once
+
+#include "utils/common/netio.h"
+#include "contrib/ucw/lists.h"
+
+srv_info_t* parse_nameserver(const char *str, const char *def_port);
+
+void get_nameservers(list_t *servers, const char *def_port);
+
+/*! @} */
diff --git a/src/utils/common/sign.c b/src/utils/common/sign.c
new file mode 100644
index 0000000..f8e9f29
--- /dev/null
+++ b/src/utils/common/sign.c
@@ -0,0 +1,109 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <string.h>
+
+#include "utils/common/sign.h"
+#include "libknot/errcode.h"
+#include "libknot/tsig-op.h"
+
+int sign_context_init_tsig(sign_context_t *ctx, const knot_tsig_key_t *key)
+{
+ if (!ctx || !key) {
+ return KNOT_EINVAL;
+ }
+
+ size_t digest_size = dnssec_tsig_algorithm_size(key->algorithm);
+ if (digest_size == 0) {
+ return KNOT_EINVAL;
+ }
+
+ uint8_t *digest = calloc(1, digest_size);
+ if (!digest) {
+ return KNOT_ENOMEM;
+ }
+
+ ctx->digest_size = digest_size;
+ ctx->digest = digest;
+ ctx->tsig_key = key;
+
+ return KNOT_EOK;
+}
+
+void sign_context_deinit(sign_context_t *ctx)
+{
+ if (!ctx) {
+ return;
+ }
+
+ free(ctx->digest);
+
+ memset(ctx, 0, sizeof(*ctx));
+}
+
+int sign_packet(knot_pkt_t *pkt, sign_context_t *sign_ctx)
+{
+ if (pkt == NULL || sign_ctx == NULL || sign_ctx->digest == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ uint8_t *wire = pkt->wire;
+ size_t *wire_size = &pkt->size;
+ size_t max_size = pkt->max_size;
+
+ int ret = knot_pkt_reserve(pkt, knot_tsig_wire_size(sign_ctx->tsig_key));
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ return knot_tsig_sign(wire, wire_size, max_size, NULL, 0,
+ sign_ctx->digest, &sign_ctx->digest_size,
+ sign_ctx->tsig_key, 0, 0);
+}
+
+int verify_packet(const knot_pkt_t *pkt, const sign_context_t *sign_ctx)
+{
+ if (pkt == NULL || sign_ctx == NULL || sign_ctx->digest == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ const uint8_t *wire = pkt->wire;
+ const size_t *wire_size = &pkt->size;
+
+ if (pkt->tsig_rr == NULL) {
+ return KNOT_ENOTSIG;
+ }
+
+ int ret = knot_tsig_client_check(pkt->tsig_rr, wire, *wire_size,
+ sign_ctx->digest, sign_ctx->digest_size,
+ sign_ctx->tsig_key, 0);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ switch (knot_tsig_rdata_error(pkt->tsig_rr)) {
+ case KNOT_RCODE_BADSIG:
+ return KNOT_TSIG_EBADSIG;
+ case KNOT_RCODE_BADKEY:
+ return KNOT_TSIG_EBADKEY;
+ case KNOT_RCODE_BADTIME:
+ return KNOT_TSIG_EBADTIME;
+ case KNOT_RCODE_BADTRUNC:
+ return KNOT_TSIG_EBADTRUNC;
+ default:
+ return KNOT_EOK;
+ }
+}
diff --git a/src/utils/common/sign.h b/src/utils/common/sign.h
new file mode 100644
index 0000000..d1912a0
--- /dev/null
+++ b/src/utils/common/sign.h
@@ -0,0 +1,63 @@
+/* Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include "libknot/packet/pkt.h"
+#include "libknot/tsig.h"
+
+/*!
+ * \brief Holds data required between signing and signature verification.
+ */
+struct sign_context {
+ size_t digest_size;
+ uint8_t *digest;
+ const knot_tsig_key_t *tsig_key;
+};
+
+typedef struct sign_context sign_context_t;
+
+/*!
+ * \brief Initialize signing context for TSIG.
+ */
+int sign_context_init_tsig(sign_context_t *ctx, const knot_tsig_key_t *key);
+
+/*!
+ * \brief Clean up signing context.
+ *
+ * \param ctx Sign context.
+ */
+void sign_context_deinit(sign_context_t *ctx);
+
+/*!
+ * \brief Signs outgoing DNS packet.
+ *
+ * \param pkt Packet to sign.
+ * \param sign_ctx Signing context.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int sign_packet(knot_pkt_t *pkt, sign_context_t *sign_ctx);
+
+/*!
+ * \brief Verifies signature for incoming DNS packet.
+ *
+ * \param pkt Packet verify sign.
+ * \param sign_ctx Signing context.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int verify_packet(const knot_pkt_t *pkt, const sign_context_t *sign_ctx);
diff --git a/src/utils/common/tls.c b/src/utils/common/tls.c
new file mode 100644
index 0000000..91b747f
--- /dev/null
+++ b/src/utils/common/tls.c
@@ -0,0 +1,495 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <arpa/inet.h>
+#include <stdbool.h>
+#include <string.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+#include <poll.h>
+
+#include "utils/common/tls.h"
+#include "utils/common/cert.h"
+#include "utils/common/msg.h"
+#include "contrib/base64.h"
+#include "libknot/errcode.h"
+
+void tls_params_init(tls_params_t *params)
+{
+ if (params == NULL) {
+ return;
+ }
+
+ memset(params, 0, sizeof(*params));
+
+ init_list(&params->ca_files);
+ init_list(&params->pins);
+}
+
+int tls_params_copy(tls_params_t *dst, const tls_params_t *src)
+{
+ if (dst == NULL || src == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ tls_params_init(dst);
+
+ dst->enable = src->enable;
+ dst->system_ca = src->system_ca;
+ if (src->hostname != NULL) {
+ dst->hostname = strdup(src->hostname);
+ if (dst->hostname == NULL) {
+ tls_params_clean(dst);
+ return KNOT_ENOMEM;
+ }
+ }
+
+ if (src->sni != NULL) {
+ dst->sni = strdup(src->sni);
+ if (dst->sni == NULL) {
+ tls_params_clean(dst);
+ return KNOT_ENOMEM;
+ }
+ }
+
+ ptrnode_t *n = NULL;
+ WALK_LIST(n, src->ca_files) {
+ char *src_file = (char *)n->d;
+ char *file = strdup(src_file);
+ if (file == NULL || ptrlist_add(&dst->ca_files, file, NULL) == NULL) {
+ tls_params_clean(dst);
+ return KNOT_ENOMEM;
+ }
+ }
+ WALK_LIST(n, src->pins) {
+ uint8_t *src_pin = (uint8_t *)n->d;
+ uint8_t *pin = malloc(1 + src_pin[0]);
+ if (pin == NULL || ptrlist_add(&dst->pins, pin, NULL) == NULL) {
+ tls_params_clean(dst);
+ return KNOT_ENOMEM;
+ }
+ memcpy(pin, src_pin, 1 + src_pin[0]);
+ }
+
+ return KNOT_EOK;
+}
+
+void tls_params_clean(tls_params_t *params)
+{
+ if (params == NULL) {
+ return;
+ }
+
+ ptrnode_t *node = NULL, *nxt = NULL;
+ WALK_LIST_DELSAFE(node, nxt, params->ca_files) {
+ free(node->d);
+ }
+ ptrlist_free(&params->ca_files, NULL);
+
+ WALK_LIST_DELSAFE(node, nxt, params->pins) {
+ free(node->d);
+ }
+ ptrlist_free(&params->pins, NULL);
+
+ free(params->hostname);
+ free(params->sni);
+
+ memset(params, 0, sizeof(*params));
+}
+
+static bool check_pin(const uint8_t *cert_pin, size_t cert_pin_len, const list_t *pins)
+{
+ if (EMPTY_LIST(*pins)) {
+ return false;
+ }
+
+ ptrnode_t *n = NULL;
+ WALK_LIST(n, *pins) {
+ uint8_t *pin = (uint8_t *)n->d;
+ if (pin[0] == cert_pin_len &&
+ memcmp(cert_pin, &pin[1], cert_pin_len) == 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static int check_certificates(gnutls_session_t session, const list_t *pins)
+{
+ if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509) {
+ DBG("TLS, invalid certificate type\n");
+ return GNUTLS_E_CERTIFICATE_ERROR;
+ }
+
+ unsigned cert_list_size;
+ const gnutls_datum_t *cert_list =
+ gnutls_certificate_get_peers(session, &cert_list_size);
+ if (cert_list == NULL || cert_list_size == 0) {
+ DBG("TLS, empty certificate list\n");
+ return GNUTLS_E_CERTIFICATE_ERROR;
+ }
+
+ size_t matches = 0;
+
+ DBG("TLS, received certificate hierarchy:\n");
+ for (int i = 0; i < cert_list_size; i++) {
+ gnutls_x509_crt_t cert;
+ int ret = gnutls_x509_crt_init(&cert);
+ if (ret != GNUTLS_E_SUCCESS) {
+ return ret;
+ }
+
+ ret = gnutls_x509_crt_import(cert, &cert_list[i], GNUTLS_X509_FMT_DER);
+ if (ret != GNUTLS_E_SUCCESS) {
+ gnutls_x509_crt_deinit(cert);
+ return ret;
+ }
+
+ gnutls_datum_t cert_name = { 0 };
+ ret = gnutls_x509_crt_get_dn2(cert, &cert_name);
+ if (ret != GNUTLS_E_SUCCESS) {
+ gnutls_x509_crt_deinit(cert);
+ return ret;
+ }
+ DBG(" #%i, %s\n", i + 1, cert_name.data);
+ gnutls_free(cert_name.data);
+
+ uint8_t cert_pin[CERT_PIN_LEN] = { 0 };
+ ret = cert_get_pin(cert, cert_pin, sizeof(cert_pin));
+ if (ret != KNOT_EOK) {
+ gnutls_x509_crt_deinit(cert);
+ return GNUTLS_E_CERTIFICATE_ERROR;
+ }
+
+ // Check if correspond to a specified PIN.
+ bool match = check_pin(cert_pin, sizeof(cert_pin), pins);
+ if (match) {
+ matches++;
+ }
+
+ uint8_t *txt_pin;
+ ret = base64_encode_alloc(cert_pin, sizeof(cert_pin), &txt_pin);
+ if (ret < 0) {
+ gnutls_x509_crt_deinit(cert);
+ return ret;
+ }
+ DBG(" SHA-256 PIN: %.*s%s\n", ret, txt_pin, match ? ", MATCH" : "");
+ free(txt_pin);
+
+ gnutls_x509_crt_deinit(cert);
+ }
+
+ if (matches > 0) {
+ return GNUTLS_E_SUCCESS;
+ } else if (EMPTY_LIST(*pins)) {
+ DBG("TLS, skipping certificate PIN check\n");
+ return GNUTLS_E_SUCCESS;
+ } else {
+ DBG("TLS, no certificate PIN match\n");
+ return GNUTLS_E_CERTIFICATE_ERROR;
+ }
+}
+
+static bool do_verification(const tls_params_t *params)
+{
+ return params->hostname != NULL || params->system_ca ||
+ !EMPTY_LIST(params->ca_files);
+}
+
+static int verify_certificate(gnutls_session_t session)
+{
+ tls_ctx_t *ctx = gnutls_session_get_ptr(session);
+
+ // Check for pinned certificates and print certificate hierarchy.
+ int ret = check_certificates(session, &ctx->params->pins);
+ if (ret != GNUTLS_E_SUCCESS) {
+ return ret;
+ }
+
+ if (!do_verification(ctx->params)) {
+ DBG("TLS, skipping certificate verification\n");
+ return GNUTLS_E_SUCCESS;
+ }
+
+ // Set server certificate check.
+ gnutls_typed_vdata_st data[2] = {
+ { .type = GNUTLS_DT_KEY_PURPOSE_OID,
+ .data = (void *)GNUTLS_KP_TLS_WWW_SERVER },
+ { .type = GNUTLS_DT_DNS_HOSTNAME,
+ .data = (void *)ctx->params->hostname }
+ };
+ size_t data_count = (ctx->params->hostname != NULL) ? 2 : 1;
+ if (data_count == 1) {
+ WARN("TLS, no hostname provided, will not verify certificate owner\n")
+ }
+
+ unsigned int status;
+ ret = gnutls_certificate_verify_peers(session, data, data_count, &status);
+ if (ret != GNUTLS_E_SUCCESS) {
+ WARN("TLS, failed to verify peer certificate\n");
+ return GNUTLS_E_CERTIFICATE_ERROR;
+ }
+
+ gnutls_datum_t msg;
+ ret = gnutls_certificate_verification_status_print(
+ status, gnutls_certificate_type_get(session), &msg, 0);
+ if (ret == GNUTLS_E_SUCCESS) {
+ DBG("TLS, %s\n", msg.data);
+ }
+ gnutls_free(msg.data);
+
+ return (status == 0) ? GNUTLS_E_SUCCESS : GNUTLS_E_CERTIFICATE_ERROR;
+}
+
+int tls_ctx_init(tls_ctx_t *ctx, const tls_params_t *params, int wait)
+{
+ if (ctx == NULL || params == NULL || !params->enable) {
+ return KNOT_EINVAL;
+ }
+
+ memset(ctx, 0, sizeof(*ctx));
+ ctx->params = params;
+ ctx->wait = wait;
+ ctx->sockfd = -1;
+
+ int ret = gnutls_certificate_allocate_credentials(&ctx->credentials);
+ if (ret != GNUTLS_E_SUCCESS) {
+ return KNOT_ENOMEM;
+ }
+
+ // Import system certificates.
+ if (ctx->params->system_ca ||
+ (ctx->params->hostname != NULL && EMPTY_LIST(ctx->params->ca_files))) {
+ ret = gnutls_certificate_set_x509_system_trust(ctx->credentials);
+ if (ret < 0) {
+ WARN("TLS, failed to import system certificates (%s)\n",
+ gnutls_strerror_name(ret));
+ return KNOT_ERROR;
+ } else {
+ DBG("TLS, imported %i system certificates\n", ret);
+ }
+ }
+
+ // Import provided certificate files.
+ ptrnode_t *n = NULL;
+ WALK_LIST(n, ctx->params->ca_files) {
+ const char *file = (char *)n->d;
+ ret = gnutls_certificate_set_x509_trust_file(ctx->credentials, file,
+ GNUTLS_X509_FMT_PEM);
+ if (ret < 0) {
+ WARN("TLS, failed to import certificate file '%s' (%s)\n",
+ file, gnutls_strerror_name(ret));
+ return KNOT_ERROR;
+ } else {
+ DBG("TLS, imported %i certificates from '%s'\n", ret, file);
+ }
+ }
+
+ gnutls_certificate_set_verify_function(ctx->credentials, verify_certificate);
+
+ return KNOT_EOK;
+}
+
+int tls_ctx_connect(tls_ctx_t *ctx, int sockfd, const char *remote)
+{
+ if (ctx == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = gnutls_init(&ctx->session, GNUTLS_CLIENT | GNUTLS_NONBLOCK);
+ if (ret != GNUTLS_E_SUCCESS) {
+ return KNOT_NET_ECONNECT;
+ }
+
+ ret = gnutls_set_default_priority(ctx->session);
+ if (ret != GNUTLS_E_SUCCESS) {
+ return KNOT_NET_ECONNECT;
+ }
+
+ ret = gnutls_credentials_set(ctx->session, GNUTLS_CRD_CERTIFICATE,
+ ctx->credentials);
+ if (ret != GNUTLS_E_SUCCESS) {
+ return KNOT_NET_ECONNECT;
+ }
+
+ if (remote != NULL) {
+ ret = gnutls_server_name_set(ctx->session, GNUTLS_NAME_DNS, remote,
+ strlen(remote));
+ if (ret != GNUTLS_E_SUCCESS) {
+ return KNOT_NET_ECONNECT;
+ }
+ }
+
+ gnutls_session_set_ptr(ctx->session, ctx);
+ gnutls_transport_set_int(ctx->session, sockfd);
+ gnutls_handshake_set_timeout(ctx->session, 1000 * ctx->wait);
+
+ // Initialize poll descriptor structure.
+ struct pollfd pfd = {
+ .fd = sockfd,
+ .events = POLLIN,
+ .revents = 0,
+ };
+
+ // Perform the TLS handshake
+ do {
+ ret = gnutls_handshake(ctx->session);
+ if (ret != GNUTLS_E_SUCCESS && gnutls_error_is_fatal(ret) == 0) {
+ if (poll(&pfd, 1, 1000 * ctx->wait) != 1) {
+ WARN("TLS, peer took too long to respond\n");
+ return KNOT_NET_ETIMEOUT;
+ }
+ }
+ } while (ret != GNUTLS_E_SUCCESS && gnutls_error_is_fatal(ret) == 0);
+ if (ret != GNUTLS_E_SUCCESS) {
+ WARN("TLS, handshake failed (%s)\n", gnutls_strerror(ret));
+ tls_ctx_close(ctx);
+ return KNOT_NET_ESOCKET;
+ }
+
+ // Save the socket descriptor.
+ ctx->sockfd = sockfd;
+
+ return KNOT_EOK;
+}
+
+int tls_ctx_send(tls_ctx_t *ctx, const uint8_t *buf, const size_t buf_len)
+{
+ if (ctx == NULL || buf == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ uint16_t msg_len = htons(buf_len);
+
+ gnutls_record_cork(ctx->session);
+
+ if (gnutls_record_send(ctx->session, &msg_len, sizeof(msg_len)) <= 0) {
+ WARN("TLS, failed to send\n");
+ return KNOT_NET_ESEND;
+ }
+ if (gnutls_record_send(ctx->session, buf, buf_len) <= 0) {
+ WARN("TLS, failed to send\n");
+ return KNOT_NET_ESEND;
+ }
+
+ while (gnutls_record_check_corked(ctx->session) > 0) {
+ int ret = gnutls_record_uncork(ctx->session, 0);
+ if (ret < 0 && gnutls_error_is_fatal(ret) != 0) {
+ WARN("TLS, failed to send (%s)\n", gnutls_strerror(ret));
+ return KNOT_NET_ESEND;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+int tls_ctx_receive(tls_ctx_t *ctx, uint8_t *buf, const size_t buf_len)
+{
+ if (ctx == NULL || buf == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ // Initialize poll descriptor structure.
+ struct pollfd pfd = {
+ .fd = ctx->sockfd,
+ .events = POLLIN,
+ .revents = 0,
+ };
+
+ uint32_t total = 0;
+ uint16_t msg_len = 0;
+
+ // Receive message header.
+ while (total < sizeof(msg_len)) {
+ ssize_t ret = gnutls_record_recv(ctx->session, &msg_len + total,
+ sizeof(msg_len) - total);
+ if (ret > 0) {
+ total += ret;
+ } else if (ret == 0) {
+ WARN("TLS, peer has closed the connection\n");
+ return KNOT_NET_ERECV;
+ } else if (gnutls_error_is_fatal(ret) != 0) {
+ WARN("TLS, failed to receive reply (%s)\n",
+ gnutls_strerror(ret));
+ return KNOT_NET_ERECV;
+ } else if (poll(&pfd, 1, 1000 * ctx->wait) != 1) {
+ WARN("TLS, peer took too long to respond\n");
+ return KNOT_NET_ETIMEOUT;
+ }
+ }
+
+ // Convert number to host format.
+ msg_len = ntohs(msg_len);
+ if (msg_len > buf_len) {
+ return KNOT_ESPACE;
+ }
+
+ total = 0;
+
+ // Receive data over TLS
+ while (total < msg_len) {
+ ssize_t ret = gnutls_record_recv(ctx->session, buf + total,
+ msg_len - total);
+ if (ret > 0) {
+ total += ret;
+ } else if (ret == 0) {
+ WARN("TLS, peer has closed the connection\n");
+ return KNOT_NET_ERECV;
+ } else if (gnutls_error_is_fatal(ret) != 0) {
+ WARN("TLS, failed to receive reply (%s)\n",
+ gnutls_strerror(ret));
+ return KNOT_NET_ERECV;
+ } else if (poll(&pfd, 1, 1000 * ctx->wait) != 1) {
+ WARN("TLS, peer took too long to respond\n");
+ return KNOT_NET_ETIMEOUT;
+ }
+ }
+
+ return total;
+}
+
+void tls_ctx_close(tls_ctx_t *ctx)
+{
+ if (ctx == NULL || ctx->session == NULL) {
+ return;
+ }
+
+ gnutls_bye(ctx->session, GNUTLS_SHUT_RDWR);
+ gnutls_deinit(ctx->session);
+}
+
+void tls_ctx_deinit(tls_ctx_t *ctx)
+{
+ if (ctx == NULL) {
+ return;
+ }
+
+ if (ctx->credentials != NULL) {
+ gnutls_certificate_free_credentials(ctx->credentials);
+ }
+}
+
+void print_tls(const tls_ctx_t *ctx)
+{
+ if (ctx == NULL || ctx->session == NULL) {
+ return;
+ }
+
+ char *msg = gnutls_session_get_desc(ctx->session);
+ printf(";; TLS session %s\n", msg);
+ gnutls_free(msg);
+}
diff --git a/src/utils/common/tls.h b/src/utils/common/tls.h
new file mode 100644
index 0000000..487a0de
--- /dev/null
+++ b/src/utils/common/tls.h
@@ -0,0 +1,64 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <gnutls/gnutls.h>
+
+#include "contrib/ucw/lists.h"
+
+/*! \brief TLS parameters. */
+typedef struct {
+ /*! Use TLS indicator. */
+ bool enable;
+ /*! Import system certificates indicator. */
+ bool system_ca;
+ /*! Certificate files to import. */
+ list_t ca_files;
+ /*! Pinned certificates. */
+ list_t pins;
+ /*! Required server hostname. */
+ char *hostname;
+ /*! Optional server name indicator. */
+ char *sni;
+} tls_params_t;
+
+/*! \brief TLS context. */
+typedef struct {
+ /*! TLS handshake timeout. */
+ int wait;
+ /*! Socket descriptor. */
+ int sockfd;
+ /*! TLS parameters. */
+ const tls_params_t *params;
+ /*! GnuTLS session handle. */
+ gnutls_session_t session;
+ /*! GnuTLS credentials handle. */
+ gnutls_certificate_credentials_t credentials;
+} tls_ctx_t;
+
+void tls_params_init(tls_params_t *params);
+int tls_params_copy(tls_params_t *dst, const tls_params_t *src);
+void tls_params_clean(tls_params_t *params);
+
+int tls_ctx_init(tls_ctx_t *ctx, const tls_params_t *params, int wait);
+int tls_ctx_connect(tls_ctx_t *ctx, int sockfd, const char *remote);
+int tls_ctx_send(tls_ctx_t *ctx, const uint8_t *buf, const size_t buf_len);
+int tls_ctx_receive(tls_ctx_t *ctx, uint8_t *buf, const size_t buf_len);
+void tls_ctx_close(tls_ctx_t *ctx);
+void tls_ctx_deinit(tls_ctx_t *ctx);
+void print_tls(const tls_ctx_t *ctx);
diff --git a/src/utils/common/token.c b/src/utils/common/token.c
new file mode 100644
index 0000000..0bba3c7
--- /dev/null
+++ b/src/utils/common/token.c
@@ -0,0 +1,115 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "utils/common/token.h"
+#include "utils/common/msg.h"
+#include "libknot/libknot.h"
+#include "contrib/ctype.h"
+
+int tok_scan(const char* lp, const char **tbl, int *lpm)
+{
+ if (lp == NULL || tbl == NULL || *tbl == NULL || lpm == NULL) {
+ DBG_NULL;
+ return -1;
+ }
+
+ const char *prefix = lp; /* Ptr to line start. */
+ int i = 0, pl = 1; /* Match index, prefix length. */
+ unsigned char len = 0; /* Read length. */
+ for(;;) {
+ const char *tok = tbl[i];
+ if (*lp == '\0' || is_space(*lp)) {
+ if (tok && TOK_L(tok) == len) { /* Consumed whole w? */
+ return i; /* Identifier */
+ } else { /* Word is shorter than cmd? */
+ break;
+ }
+ }
+
+ /* Find next prefix match. */
+ ++len;
+ while (tok) {
+ if (TOK_L(tok) >= len) { /* Is prefix of current token */
+ if (*lp < tok[pl]) { /* Terminate early. */
+ tok = NULL;
+ break; /* No match could be found. */
+ }
+ if (*lp == tok[pl]) { /* Match */
+ if(lpm) *lpm = i;
+ ++pl;
+ break;
+ }
+ }
+
+ /* No early cut, no match - seek next. */
+ while ((tok = tbl[++i]) != NULL) {
+ if (TOK_L(tok) >= len &&
+ memcmp(TOK_S(tok), prefix, len) == 0) {
+ break;
+ }
+ }
+ }
+
+ if (tok == NULL) {
+ break; /* All tokens exhausted. */
+ } else {
+ ++lp; /* Next char */
+ }
+ }
+
+ return -1;
+}
+
+int tok_find(const char *lp, const char **tbl)
+{
+ if (lp == NULL || tbl == NULL || *tbl == NULL) {
+ DBG_NULL;
+ return KNOT_EINVAL;
+ }
+
+ int lpm = -1;
+ int bp = 0;
+ if ((bp = tok_scan(lp, tbl, &lpm)) < 0) {
+ if (lpm > -1) {
+ ERR("unexpected literal: '%s', did you mean '%s' ?\n",
+ lp, TOK_S(tbl[lpm]));
+ } else {
+ ERR("unexpected literal: '%s'\n", lp);
+ }
+
+ return KNOT_EPARSEFAIL;
+ }
+
+ return bp;
+}
+
+const char *tok_skipspace(const char *lp)
+{
+ if (lp == NULL) {
+ DBG_NULL;
+ return NULL;
+ }
+
+ while (is_space(*lp)) {
+ lp += 1;
+ }
+
+ return lp;
+}
diff --git a/src/utils/common/token.h b/src/utils/common/token.h
new file mode 100644
index 0000000..b4d33d2
--- /dev/null
+++ b/src/utils/common/token.h
@@ -0,0 +1,77 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file token.h
+ *
+ * \author Marek Vavrusa <marek.vavrusa@nic.cz>
+ *
+ * \brief String tokenizer and simple scanner.
+ *
+ * \addtogroup knot_utils
+ * @{
+ */
+
+#pragma once
+
+#include <stdio.h>
+
+/*!
+ * \brief Example of token table:
+ *
+ * \warning Table _must_ be lexicographically ordered.
+ *
+ * const char *tok_tbl[] = {
+ * // LEN STRING
+ * "\x4" "abcd",
+ * "\x5" "class",
+ * NULL // END
+ * }
+ */
+/*! \brief String part of the token. */
+#define TOK_S(x) ((x)+1)
+/*! \brief Len of the token. */
+#define TOK_L(x) ((unsigned char)(x)[0])
+
+/*!
+ * \brief Scan for matching token described by a match table.
+ *
+ * Table consists of strings, prefixed with 1B length.
+ *
+ * \param lp Pointer to current line.
+ * \param tbl Match description table.
+ * \param lpm Pointer to longest prefix match.
+ * \retval index to matching record.
+ * \retval -1 if no match is found, lpm may be set to longest prefix match.
+ */
+int tok_scan(const char* lp, const char **tbl, int *lpm);
+
+/*!
+ * \brief Find token from table in a line buffer.
+ * \param lp Pointer to current line.
+ * \param tbl Match description table.
+ * \retval index to matching record.
+ * \retval error code if no match is found
+ */
+int tok_find(const char *lp, const char **tbl);
+
+/*!
+ * \brief Return pointer to next non-blank character.
+ * \param lp Pointer to current line.
+ * \return ptr to next non-blank character.
+ */
+const char *tok_skipspace(const char *lp);
+
+/*! @} */
diff --git a/src/utils/kdig/kdig_exec.c b/src/utils/kdig/kdig_exec.c
new file mode 100644
index 0000000..782a2d5
--- /dev/null
+++ b/src/utils/kdig/kdig_exec.c
@@ -0,0 +1,1181 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include "utils/kdig/kdig_exec.h"
+#include "utils/common/exec.h"
+#include "utils/common/msg.h"
+#include "utils/common/netio.h"
+#include "utils/common/sign.h"
+#include "libknot/libknot.h"
+#include "contrib/sockaddr.h"
+#include "contrib/time.h"
+#include "contrib/ucw/lists.h"
+
+#if USE_DNSTAP
+# include "contrib/dnstap/convert.h"
+# include "contrib/dnstap/message.h"
+# include "contrib/dnstap/writer.h"
+
+static int write_dnstap(dt_writer_t *writer,
+ const bool is_query,
+ const uint8_t *wire,
+ const size_t wire_len,
+ net_t *net,
+ const struct timespec *mtime)
+{
+ Dnstap__Message msg;
+ Dnstap__Message__Type msg_type;
+ int ret;
+ int protocol = 0;
+
+ if (writer == NULL) {
+ return KNOT_EOK;
+ }
+
+ net_set_local_info(net);
+
+ msg_type = is_query ? DNSTAP__MESSAGE__TYPE__TOOL_QUERY :
+ DNSTAP__MESSAGE__TYPE__TOOL_RESPONSE;
+
+ if (net->socktype == SOCK_DGRAM) {
+ protocol = IPPROTO_UDP;
+ } else if (net->socktype == SOCK_STREAM) {
+ protocol = IPPROTO_TCP;
+ }
+
+ ret = dt_message_fill(&msg, msg_type, net->local_info->ai_addr,
+ net->srv->ai_addr, protocol,
+ wire, wire_len, mtime);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ return dt_writer_write(writer, (const ProtobufCMessage *)&msg);
+}
+
+static float get_query_time(const Dnstap__Dnstap *frame)
+{
+ if (!frame->message->has_query_time_sec ||
+ !frame->message->has_query_time_nsec ||
+ !frame->message->has_response_time_sec ||
+ !frame->message->has_response_time_sec) {
+ return 0;
+ }
+
+ struct timespec from = {
+ .tv_sec = frame->message->query_time_sec,
+ .tv_nsec = frame->message->query_time_nsec
+ };
+
+ struct timespec to = {
+ .tv_sec = frame->message->response_time_sec,
+ .tv_nsec = frame->message->response_time_nsec
+ };
+
+ return time_diff_ms(&from, &to);
+}
+
+static void fill_remote_addr(net_t *net, Dnstap__Message *message, bool is_initiator)
+{
+ if (!message->has_socket_family || !message->has_socket_protocol) {
+ return;
+ }
+
+ if ((message->response_address.data == NULL && is_initiator) ||
+ message->query_address.data == NULL) {
+ return;
+ }
+
+ struct sockaddr_storage ss = { 0 };
+ int family = dt_family_decode(message->socket_family);
+ int proto = dt_protocol_decode(message->socket_protocol);
+ int sock_type = 0;
+
+ switch (proto) {
+ case IPPROTO_TCP:
+ sock_type = SOCK_STREAM;
+ break;
+ case IPPROTO_UDP:
+ sock_type = SOCK_DGRAM;
+ break;
+ default:
+ break;
+ }
+
+ ProtobufCBinaryData *addr = NULL;
+ uint32_t port = 0;
+ if (is_initiator) {
+ addr = &message->response_address;
+ port = message->response_port;
+ } else {
+ addr = &message->query_address;
+ port = message->query_port;
+ }
+
+ sockaddr_set_raw(&ss, family, addr->data, addr->len);
+ sockaddr_port_set((struct sockaddr *)&ss, port);
+
+ get_addr_str(&ss, sock_type, &net->remote_str);
+}
+
+static int process_dnstap(const query_t *query)
+{
+ dt_reader_t *reader = query->dt_reader;
+
+ if (query->dt_reader == NULL) {
+ return -1;
+ }
+
+ bool first_message = true;
+
+ for (;;) {
+ Dnstap__Dnstap *frame = NULL;
+ Dnstap__Message *message = NULL;
+ ProtobufCBinaryData *wire = NULL;
+ bool is_query;
+ bool is_initiator;
+
+ // Read next message.
+ int ret = dt_reader_read(reader, &frame);
+ if (ret == KNOT_EOF) {
+ break;
+ } else if (ret != KNOT_EOK) {
+ ERR("can't read dnstap message\n");
+ break;
+ }
+
+ // Check for dnstap message.
+ if (frame->type == DNSTAP__DNSTAP__TYPE__MESSAGE) {
+ message = frame->message;
+ } else {
+ WARN("ignoring non-dnstap message\n");
+ dt_reader_free_frame(reader, &frame);
+ continue;
+ }
+
+ // Check for the type of dnstap message.
+ if (message->has_response_message) {
+ wire = &message->response_message;
+ is_query = false;
+ } else if (message->has_query_message) {
+ wire = &message->query_message;
+ is_query = true;
+ } else {
+ WARN("dnstap frame contains no message\n");
+ dt_reader_free_frame(reader, &frame);
+ continue;
+ }
+
+ // Ignore query message if requested.
+ if (is_query && !query->style.show_query) {
+ dt_reader_free_frame(reader, &frame);
+ continue;
+ }
+
+ // Get the message role.
+ is_initiator = dt_message_role_is_initiator(message->type);
+
+ // Create dns packet based on dnstap wire data.
+ knot_pkt_t *pkt = knot_pkt_new(wire->data, wire->len, NULL);
+ if (pkt == NULL) {
+ ERR("can't allocate packet\n");
+ dt_reader_free_frame(reader, &frame);
+ break;
+ }
+
+ // Parse packet and reconstruct required data.
+ if (knot_pkt_parse(pkt, 0) == KNOT_EOK) {
+ time_t timestamp = 0;
+ float query_time = 0.0;
+ net_t net_ctx = { 0 };
+
+ if (is_query) {
+ if (message->has_query_time_sec) {
+ timestamp = message->query_time_sec;
+ }
+ } else {
+ if (message->has_response_time_sec) {
+ timestamp = message->response_time_sec;
+ }
+ query_time = get_query_time(frame);
+ }
+
+ // Prepare connection information string.
+ fill_remote_addr(&net_ctx, message, is_initiator);
+
+ if (first_message) {
+ first_message = false;
+ } else {
+ printf("\n");
+ }
+
+ print_packet(pkt, &net_ctx, pkt->size, query_time, timestamp,
+ is_query ^ is_initiator, &query->style);
+
+ net_clean(&net_ctx);
+ } else {
+ ERR("can't print dnstap message\n");
+ }
+
+ knot_pkt_free(pkt);
+ dt_reader_free_frame(reader, &frame);
+ }
+
+ return 0;
+}
+#endif // USE_DNSTAP
+
+static int add_query_edns(knot_pkt_t *packet, const query_t *query, uint16_t max_size)
+{
+ /* Initialize OPT RR. */
+ knot_rrset_t opt_rr;
+ int ret = knot_edns_init(&opt_rr, max_size, 0,
+ query->edns > -1 ? query->edns : 0, &packet->mm);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ if (query->flags.do_flag) {
+ knot_edns_set_do(&opt_rr);
+ }
+
+ /* Append NSID. */
+ if (query->nsid) {
+ ret = knot_edns_add_option(&opt_rr, KNOT_EDNS_OPTION_NSID,
+ 0, NULL, &packet->mm);
+ if (ret != KNOT_EOK) {
+ knot_rrset_clear(&opt_rr, &packet->mm);
+ return ret;
+ }
+ }
+
+ /* Append EDNS-client-subnet. */
+ if (query->subnet.family != AF_UNSPEC) {
+ uint16_t size = knot_edns_client_subnet_size(&query->subnet);
+ uint8_t data[size];
+
+ ret = knot_edns_client_subnet_write(data, size, &query->subnet);
+ if (ret != KNOT_EOK) {
+ knot_rrset_clear(&opt_rr, &packet->mm);
+ return ret;
+ }
+
+ ret = knot_edns_add_option(&opt_rr, KNOT_EDNS_OPTION_CLIENT_SUBNET,
+ size, data, &packet->mm);
+ if (ret != KNOT_EOK) {
+ knot_rrset_clear(&opt_rr, &packet->mm);
+ return ret;
+ }
+ }
+
+ /* Append a cookie option if present. */
+ if (query->cc.len > 0) {
+ uint16_t size = knot_edns_cookie_size(&query->cc, &query->sc);
+ uint8_t data[size];
+
+ ret = knot_edns_cookie_write(data, size, &query->cc, &query->sc);
+ if (ret != KNOT_EOK) {
+ knot_rrset_clear(&opt_rr, &packet->mm);
+ return ret;
+ }
+
+ ret = knot_edns_add_option(&opt_rr, KNOT_EDNS_OPTION_COOKIE,
+ size, data, &packet->mm);
+ if (ret != KNOT_EOK) {
+ knot_rrset_clear(&opt_rr, &packet->mm);
+ return ret;
+ }
+ }
+
+ /* Append EDNS Padding. */
+ int padding = query->padding;
+ if (padding != -3 && query->alignment > 0) {
+ padding = knot_edns_alignment_size(packet->size,
+ knot_rrset_size(&opt_rr),
+ query->alignment);
+ } else if (query->padding == -2 || (query->padding == -1 && query->tls.enable)) {
+ padding = knot_pkt_default_padding_size(packet, &opt_rr);
+ }
+ if (padding > -1) {
+ uint8_t zeros[padding];
+ memset(zeros, 0, sizeof(zeros));
+
+ ret = knot_edns_add_option(&opt_rr, KNOT_EDNS_OPTION_PADDING,
+ padding, zeros, &packet->mm);
+ if (ret != KNOT_EOK) {
+ knot_rrset_clear(&opt_rr, &packet->mm);
+ return ret;
+ }
+ }
+
+ /* Append custom EDNS options. */
+ node_t *node = NULL;
+ WALK_LIST(node, query->edns_opts) {
+ ednsopt_t *opt = (ednsopt_t *)node;
+ ret = knot_edns_add_option(&opt_rr, opt->code, opt->length,
+ opt->data, &packet->mm);
+ if (ret != KNOT_EOK) {
+ knot_rrset_clear(&opt_rr, &packet->mm);
+ return ret;
+ }
+ }
+
+ /* Add prepared OPT to packet. */
+ ret = knot_pkt_put(packet, KNOT_COMPR_HINT_NONE, &opt_rr, KNOT_PF_FREE);
+ if (ret != KNOT_EOK) {
+ knot_rrset_clear(&opt_rr, &packet->mm);
+ }
+
+ return ret;
+}
+
+static bool do_padding(const query_t *query)
+{
+ return (query->padding != -3) && // Disabled padding.
+ (query->padding > -1 || query->alignment > 0 || // Explicit padding.
+ query->padding == -2 || // Default padding.
+ (query->padding == -1 && query->tls.enable)); // TLS automatic.
+}
+
+static bool use_edns(const query_t *query)
+{
+ return query->edns > -1 || query->udp_size > -1 || query->nsid ||
+ query->flags.do_flag || query->subnet.family != AF_UNSPEC ||
+ query->cc.len > 0 || do_padding(query) ||
+ !ednsopt_list_empty(&query->edns_opts);
+}
+
+static knot_pkt_t *create_query_packet(const query_t *query)
+{
+ // Set packet buffer size.
+ uint16_t max_size;
+ if (query->udp_size < 0) {
+ if (use_edns(query)) {
+ max_size = DEFAULT_EDNS_SIZE;
+ } else {
+ max_size = DEFAULT_UDP_SIZE;
+ }
+ } else {
+ max_size = query->udp_size;
+ }
+
+ // Create packet skeleton.
+ knot_pkt_t *packet = create_empty_packet(max_size);
+ if (packet == NULL) {
+ return NULL;
+ }
+
+ // Set flags to wireformat.
+ if (query->flags.aa_flag) {
+ knot_wire_set_aa(packet->wire);
+ }
+ if (query->flags.tc_flag) {
+ knot_wire_set_tc(packet->wire);
+ }
+ if (query->flags.rd_flag) {
+ knot_wire_set_rd(packet->wire);
+ }
+ if (query->flags.ra_flag) {
+ knot_wire_set_ra(packet->wire);
+ }
+ if (query->flags.z_flag) {
+ knot_wire_set_z(packet->wire);
+ }
+ if (query->flags.ad_flag) {
+ knot_wire_set_ad(packet->wire);
+ }
+ if (query->flags.cd_flag) {
+ knot_wire_set_cd(packet->wire);
+ }
+
+ // Set NOTIFY opcode.
+ if (query->notify) {
+ knot_wire_set_opcode(packet->wire, KNOT_OPCODE_NOTIFY);
+ }
+
+ // Set packet question if available.
+ knot_dname_t *qname = knot_dname_from_str_alloc(query->owner);
+ if (qname != NULL) {
+ int ret = knot_pkt_put_question(packet, qname, query->class_num,
+ query->type_num);
+ if (ret != KNOT_EOK) {
+ knot_dname_free(qname, NULL);
+ knot_pkt_free(packet);
+ return NULL;
+ }
+ }
+
+ // For IXFR query or NOTIFY query with SOA serial, add a proper section.
+ if (query->serial >= 0) {
+ if (query->notify) {
+ knot_pkt_begin(packet, KNOT_ANSWER);
+ } else {
+ knot_pkt_begin(packet, KNOT_AUTHORITY);
+ }
+
+ // SOA rdata in wireformat.
+ uint8_t wire[22] = { 0x0 };
+
+ // Create rrset with SOA record.
+ knot_rrset_t *soa = knot_rrset_new(qname,
+ KNOT_RRTYPE_SOA,
+ query->class_num,
+ 0,
+ &packet->mm);
+ knot_dname_free(qname, NULL);
+ if (soa == NULL) {
+ knot_pkt_free(packet);
+ return NULL;
+ }
+
+ // Fill in blank SOA rdata to rrset.
+ int ret = knot_rrset_add_rdata(soa, wire, sizeof(wire), &packet->mm);
+ if (ret != KNOT_EOK) {
+ knot_rrset_free(soa, &packet->mm);
+ knot_pkt_free(packet);
+ return NULL;
+ }
+
+ // Set SOA serial.
+ knot_soa_serial_set(soa->rrs.rdata, query->serial);
+
+ ret = knot_pkt_put(packet, KNOT_COMPR_HINT_NONE, soa, KNOT_PF_FREE);
+ if (ret != KNOT_EOK) {
+ knot_rrset_free(soa, &packet->mm);
+ knot_pkt_free(packet);
+ return NULL;
+ }
+
+ free(soa);
+ } else {
+ knot_dname_free(qname, NULL);
+ }
+
+ // Begin additional section
+ knot_pkt_begin(packet, KNOT_ADDITIONAL);
+
+ // Create EDNS section if required.
+ if (use_edns(query)) {
+ int ret = add_query_edns(packet, query, max_size);
+ if (ret != KNOT_EOK) {
+ ERR("can't set up EDNS section\n");
+ knot_pkt_free(packet);
+ return NULL;
+ }
+ }
+
+ return packet;
+}
+
+static bool check_reply_id(const knot_pkt_t *reply,
+ const knot_pkt_t *query)
+{
+ uint16_t query_id = knot_wire_get_id(query->wire);
+ uint16_t reply_id = knot_wire_get_id(reply->wire);
+
+ if (reply_id != query_id) {
+ WARN("reply ID (%u) is different from query ID (%u)\n",
+ reply_id, query_id);
+ return false;
+ }
+
+ return true;
+}
+
+static void check_reply_qr(const knot_pkt_t *reply)
+{
+ if (!knot_wire_get_qr(reply->wire)) {
+ WARN("response QR bit not set\n");
+ }
+}
+
+static void check_reply_question(const knot_pkt_t *reply,
+ const knot_pkt_t *query)
+{
+ if (knot_wire_get_qdcount(reply->wire) < 1) {
+ WARN("response doesn't have question section\n");
+ return;
+ }
+
+ if (!knot_dname_is_equal(knot_pkt_qname(reply), knot_pkt_qname(query)) ||
+ knot_pkt_qclass(reply) != knot_pkt_qclass(query) ||
+ knot_pkt_qtype(reply) != knot_pkt_qtype(query)) {
+ WARN("query/response question sections are different\n");
+ return;
+ }
+}
+
+static int64_t first_serial_check(const knot_pkt_t *reply)
+{
+ const knot_pktsection_t *answer = knot_pkt_section(reply, KNOT_ANSWER);
+
+ if (answer->count <= 0) {
+ return -1;
+ }
+
+ const knot_rrset_t *first = knot_pkt_rr(answer, 0);
+
+ if (first->type != KNOT_RRTYPE_SOA) {
+ return -1;
+ } else {
+ return knot_soa_serial(first->rrs.rdata);
+ }
+}
+
+static bool finished_xfr(const uint32_t serial, const knot_pkt_t *reply,
+ const size_t msg_count, bool is_ixfr)
+{
+ const knot_pktsection_t *answer = knot_pkt_section(reply, KNOT_ANSWER);
+
+ if (answer->count <= 0) {
+ return false;
+ }
+
+ const knot_rrset_t *last = knot_pkt_rr(answer, answer->count - 1);
+
+ if (last->type != KNOT_RRTYPE_SOA) {
+ return false;
+ } else if (answer->count == 1 && msg_count == 1) {
+ return is_ixfr;
+ } else {
+ return knot_soa_serial(last->rrs.rdata) == serial;
+ }
+}
+
+static int sign_query(knot_pkt_t *pkt, const query_t *query, sign_context_t *ctx)
+{
+ if (query->tsig_key.name == NULL) {
+ return KNOT_EOK;
+ }
+
+ int ret = sign_context_init_tsig(ctx, &query->tsig_key);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = sign_packet(pkt, ctx);
+ if (ret != KNOT_EOK) {
+ sign_context_deinit(ctx);
+ return ret;
+ }
+
+ return KNOT_EOK;
+}
+
+static int process_query_packet(const knot_pkt_t *query,
+ net_t *net,
+ const query_t *query_ctx,
+ const bool ignore_tc,
+ const sign_context_t *sign_ctx,
+ const style_t *style)
+{
+ struct timespec t_start, t_query, t_query_full, t_end, t_end_full;
+ time_t timestamp;
+ knot_pkt_t *reply;
+ uint8_t in[MAX_PACKET_SIZE];
+ int in_len;
+ int ret;
+
+ // Get start query time.
+ timestamp = time(NULL);
+ t_start = time_now();
+
+ // Connect to the server.
+ ret = net_connect(net);
+ if (ret != KNOT_EOK) {
+ return -1;
+ }
+
+ // Send query packet.
+ ret = net_send(net, query->wire, query->size);
+ if (ret != KNOT_EOK) {
+ net_close(net);
+ return -1;
+ }
+
+ // Get stop query time and start reply time.
+ t_query = time_now();
+ t_query_full = time_diff(&t_start, &t_query);
+ t_query_full.tv_sec += timestamp;
+
+#if USE_DNSTAP
+ // Make the dnstap copy of the query.
+ write_dnstap(query_ctx->dt_writer, true, query->wire, query->size,
+ net, &t_query_full);
+#endif // USE_DNSTAP
+
+ // Print query packet if required.
+ if (style->show_query) {
+ // Create copy of query packet for parsing.
+ knot_pkt_t *q = knot_pkt_new(query->wire, query->size, NULL);
+ if (q != NULL) {
+ if (knot_pkt_parse(q, 0) == KNOT_EOK) {
+ print_packet(q, net, query->size,
+ time_diff_ms(&t_start, &t_query),
+ timestamp, false, style);
+ } else {
+ ERR("can't print query packet\n");
+ }
+ knot_pkt_free(q);
+ } else {
+ ERR("can't print query packet\n");
+ }
+
+ printf("\n");
+ }
+
+ // Loop over incoming messages, unless reply id is correct or timeout.
+ while (true) {
+ // Receive a reply message.
+ in_len = net_receive(net, in, sizeof(in));
+ if (in_len <= 0) {
+ net_close(net);
+ return -1;
+ }
+
+ // Get stop reply time.
+ t_end = time_now();
+ t_end_full = time_diff(&t_start, &t_end);
+ t_end_full.tv_sec += timestamp;
+
+#if USE_DNSTAP
+ // Make the dnstap copy of the response.
+ write_dnstap(query_ctx->dt_writer, false, in, in_len, net,
+ &t_end_full);
+#endif // USE_DNSTAP
+
+ // Create reply packet structure to fill up.
+ reply = knot_pkt_new(in, in_len, NULL);
+ if (reply == NULL) {
+ ERR("internal error (%s)\n", knot_strerror(KNOT_ENOMEM));
+ net_close(net);
+ return -1;
+ }
+
+ // Parse reply to the packet structure.
+ if (knot_pkt_parse(reply, KNOT_PF_NOCANON) != KNOT_EOK) {
+ ERR("malformed reply packet from %s\n", net->remote_str);
+ knot_pkt_free(reply);
+ net_close(net);
+ return -1;
+ }
+
+ // Compare reply header id.
+ if (check_reply_id(reply, query)) {
+ break;
+ // Check for timeout.
+ } else if (time_diff_ms(&t_query, &t_end) > 1000 * net->wait) {
+ knot_pkt_free(reply);
+ net_close(net);
+ return -1;
+ }
+
+ knot_pkt_free(reply);
+ }
+
+ // Check for TC bit and repeat query with TCP if required.
+ if (knot_wire_get_tc(reply->wire) != 0 &&
+ ignore_tc == false && net->socktype == SOCK_DGRAM) {
+ printf("\n");
+ WARN("truncated reply from %s, retrying over TCP\n\n",
+ net->remote_str);
+ knot_pkt_free(reply);
+ net_close(net);
+
+ net->socktype = SOCK_STREAM;
+
+ return process_query_packet(query, net, query_ctx, true,
+ sign_ctx, style);
+ }
+
+ // Check for question sections equality.
+ check_reply_question(reply, query);
+
+ // Check QR bit
+ check_reply_qr(reply);
+
+ // Print reply packet.
+ print_packet(reply, net, in_len, time_diff_ms(&t_query, &t_end), timestamp,
+ true, style);
+
+ // Verify signature if a key was specified.
+ if (sign_ctx->digest != NULL) {
+ ret = verify_packet(reply, sign_ctx);
+ if (ret != KNOT_EOK) {
+ WARN("reply verification for %s (%s)\n",
+ net->remote_str, knot_strerror(ret));
+ }
+ }
+
+ // Check for BADCOOKIE RCODE and repeat query with the new cookie if required.
+ if (knot_pkt_ext_rcode(reply) == KNOT_RCODE_BADCOOKIE && query_ctx->badcookie) {
+ printf("\n");
+ WARN("bad cookie from %s, retrying with the received one\n",
+ net->remote_str);
+ net_close(net);
+
+ // Prepare new query context.
+ query_t new_ctx = *query_ctx;
+
+ uint8_t *opt = knot_pkt_edns_option(reply, KNOT_EDNS_OPTION_COOKIE);
+ if (opt == NULL) {
+ ERR("bad cookie, missing EDNS section\n");
+ knot_pkt_free(reply);
+ return -1;
+ }
+
+ const uint8_t *data = knot_edns_opt_get_data(opt);
+ uint16_t data_len = knot_edns_opt_get_length(opt);
+ int ret = knot_edns_cookie_parse(&new_ctx.cc, &new_ctx.sc,
+ data, data_len);
+ if (ret != KNOT_EOK) {
+ knot_pkt_free(reply);
+ ERR("bad cookie, missing EDNS cookie option\n");
+ return -1;
+ }
+ knot_pkt_free(reply);
+
+ // Restore the original client cookie.
+ new_ctx.cc = query_ctx->cc;
+
+ knot_pkt_t *new_query = create_query_packet(&new_ctx);
+ ret = process_query_packet(new_query, net, &new_ctx, ignore_tc,
+ sign_ctx, style);
+ knot_pkt_free(new_query);
+
+ return ret;
+ }
+
+ knot_pkt_free(reply);
+ net_close(net);
+
+ return 0;
+}
+
+static int process_query(const query_t *query)
+{
+ node_t *server = NULL;
+ knot_pkt_t *out_packet;
+ net_t net;
+ int ret;
+
+ // Create query packet.
+ out_packet = create_query_packet(query);
+ if (out_packet == NULL) {
+ ERR("can't create query packet\n");
+ return -1;
+ }
+
+ // Sign the query.
+ sign_context_t sign_ctx = { 0 };
+ ret = sign_query(out_packet, query, &sign_ctx);
+ if (ret != KNOT_EOK) {
+ ERR("can't sign the packet (%s)\n", knot_strerror(ret));
+ return -1;
+ }
+
+ // Get connection parameters.
+ int iptype = get_iptype(query->ip);
+ int socktype = get_socktype(query->protocol, query->type_num);
+ int flags = query->fastopen ? NET_FLAGS_FASTOPEN : NET_FLAGS_NONE;
+
+ // Loop over server list to process query.
+ WALK_LIST(server, query->servers) {
+ srv_info_t *remote = (srv_info_t *)server;
+
+ DBG("Querying for owner(%s), class(%u), type(%u), server(%s), "
+ "port(%s), protocol(%s)\n", query->owner, query->class_num,
+ query->type_num, remote->name, remote->service,
+ get_sockname(socktype));
+
+ // Loop over the number of retries.
+ for (size_t i = 0; i <= query->retries; i++) {
+ // Initialize network structure for current server.
+ ret = net_init(query->local, remote, iptype, socktype,
+ query->wait, flags, &query->tls, &net);
+ if (ret != KNOT_EOK) {
+ continue;
+ }
+
+ // Loop over all resolved addresses for remote.
+ while (net.srv != NULL) {
+ ret = process_query_packet(out_packet, &net,
+ query,
+ query->ignore_tc,
+ &sign_ctx,
+ &query->style);
+ // If error try next resolved address.
+ if (ret != 0) {
+ net.srv = (net.srv)->ai_next;
+ if (net.srv != NULL && query->style.show_query) {
+ printf("\n");
+ }
+
+ continue;
+ }
+
+ break;
+ }
+
+ // Success.
+ if (ret == 0) {
+ net_clean(&net);
+ sign_context_deinit(&sign_ctx);
+ knot_pkt_free(out_packet);
+ return 0;
+ }
+
+ if (i < query->retries) {
+ DBG("retrying server %s@%s(%s)\n",
+ remote->name, remote->service,
+ get_sockname(socktype));
+
+ if (query->style.show_query) {
+ printf("\n");
+ }
+ }
+
+ net_clean(&net);
+ }
+
+ ERR("failed to query server %s@%s(%s)\n",
+ remote->name, remote->service, get_sockname(socktype));
+
+ // If not last server, print separation.
+ if (server->next->next && query->style.show_query) {
+ printf("\n");
+ }
+ }
+
+ sign_context_deinit(&sign_ctx);
+ knot_pkt_free(out_packet);
+
+ return -1;
+}
+
+static int process_xfr_packet(const knot_pkt_t *query,
+ net_t *net,
+ const query_t *query_ctx,
+ const sign_context_t *sign_ctx,
+ const style_t *style)
+{
+ struct timespec t_start, t_query, t_query_full, t_end, t_end_full;
+ time_t timestamp;
+ knot_pkt_t *reply;
+ uint8_t in[MAX_PACKET_SIZE];
+ int in_len;
+ int ret;
+ int64_t serial = 0;
+ size_t total_len = 0;
+ size_t msg_count = 0;
+ size_t rr_count = 0;
+
+ // Get start query time.
+ timestamp = time(NULL);
+ t_start = time_now();
+
+ // Connect to the server.
+ ret = net_connect(net);
+ if (ret != KNOT_EOK) {
+ return -1;
+ }
+
+ // Send query packet.
+ ret = net_send(net, query->wire, query->size);
+ if (ret != KNOT_EOK) {
+ net_close(net);
+ return -1;
+ }
+
+ // Get stop query time and start reply time.
+ t_query = time_now();
+ t_query_full = time_diff(&t_start, &t_query);
+ t_query_full.tv_sec += timestamp;
+
+#if USE_DNSTAP
+ // Make the dnstap copy of the query.
+ write_dnstap(query_ctx->dt_writer, true, query->wire, query->size,
+ net, &t_query_full);
+#endif // USE_DNSTAP
+
+ // Print query packet if required.
+ if (style->show_query) {
+ // Create copy of query packet for parsing.
+ knot_pkt_t *q = knot_pkt_new(query->wire, query->size, NULL);
+ if (q != NULL) {
+ if (knot_pkt_parse(q, 0) == KNOT_EOK) {
+ print_packet(q, net, query->size,
+ time_diff_ms(&t_start, &t_query),
+ timestamp, false, style);
+ } else {
+ ERR("can't print query packet\n");
+ }
+ knot_pkt_free(q);
+ } else {
+ ERR("can't print query packet\n");
+ }
+
+ printf("\n");
+ }
+
+ // Loop over reply messages unless first and last SOA serials differ.
+ while (true) {
+ // Receive a reply message.
+ in_len = net_receive(net, in, sizeof(in));
+ if (in_len <= 0) {
+ net_close(net);
+ return -1;
+ }
+
+ // Get stop message time.
+ t_end = time_now();
+ t_end_full = time_diff(&t_start, &t_end);
+ t_end_full.tv_sec += timestamp;
+
+#if USE_DNSTAP
+ // Make the dnstap copy of the response.
+ write_dnstap(query_ctx->dt_writer, false, in, in_len, net,
+ &t_end_full);
+#endif // USE_DNSTAP
+
+ // Create reply packet structure to fill up.
+ reply = knot_pkt_new(in, in_len, NULL);
+ if (reply == NULL) {
+ ERR("internal error (%s)\n", knot_strerror(KNOT_ENOMEM));
+ net_close(net);
+ return -1;
+ }
+
+ // Parse reply to the packet structure.
+ if (knot_pkt_parse(reply, 0) != KNOT_EOK) {
+ ERR("malformed reply packet from %s\n", net->remote_str);
+ knot_pkt_free(reply);
+ net_close(net);
+ return -1;
+ }
+
+ // Compare reply header id.
+ if (check_reply_id(reply, query) == false) {
+ ERR("reply ID mismatch from %s\n", net->remote_str);
+ knot_pkt_free(reply);
+ net_close(net);
+ return -1;
+ }
+
+ // Print leading transfer information.
+ if (msg_count == 0) {
+ print_header_xfr(query, style);
+ }
+
+ // Check for error reply.
+ if (knot_pkt_ext_rcode(reply) != KNOT_RCODE_NOERROR) {
+ ERR("server replied with error '%s'\n",
+ knot_pkt_ext_rcode_name(reply));
+ knot_pkt_free(reply);
+ net_close(net);
+ return -1;
+ }
+
+ // The first message has a special treatment.
+ if (msg_count == 0) {
+ // Verify 1. signature if a key was specified.
+ if (sign_ctx->digest != NULL) {
+ ret = verify_packet(reply, sign_ctx);
+ if (ret != KNOT_EOK) {
+ style_t tsig_style = {
+ .format = style->format,
+ .style = style->style,
+ .show_tsig = true
+ };
+ print_data_xfr(reply, &tsig_style);
+
+ ERR("reply verification for %s (%s)\n",
+ net->remote_str, knot_strerror(ret));
+ knot_pkt_free(reply);
+ net_close(net);
+ return -1;
+ }
+ }
+
+ // Read first SOA serial.
+ serial = first_serial_check(reply);
+
+ if (serial < 0) {
+ ERR("first answer record from %s isn't SOA\n",
+ net->remote_str);
+ knot_pkt_free(reply);
+ net_close(net);
+ return -1;
+ }
+
+ // Check for question sections equality.
+ check_reply_question(reply, query);
+
+ // Check QR bit
+ check_reply_qr(reply);
+ }
+
+ msg_count++;
+ rr_count += knot_wire_get_ancount(reply->wire);
+ total_len += in_len;
+
+ // Print reply packet.
+ print_data_xfr(reply, style);
+
+ // Check for finished transfer.
+ if (finished_xfr(serial, reply, msg_count, query_ctx->serial != -1)) {
+ knot_pkt_free(reply);
+ break;
+ }
+
+ knot_pkt_free(reply);
+ }
+
+ // Get stop reply time.
+ t_end = time_now();
+
+ // Print trailing transfer information.
+ print_footer_xfr(total_len, msg_count, rr_count, net,
+ time_diff_ms(&t_query, &t_end), timestamp, style);
+
+ net_close(net);
+
+ return 0;
+}
+
+static int process_xfr(const query_t *query)
+{
+ knot_pkt_t *out_packet;
+ net_t net;
+ int ret;
+
+ // Create query packet.
+ out_packet = create_query_packet(query);
+ if (out_packet == NULL) {
+ ERR("can't create query packet\n");
+ return -1;
+ }
+
+ // Sign the query.
+ sign_context_t sign_ctx = { 0 };
+ ret = sign_query(out_packet, query, &sign_ctx);
+ if (ret != KNOT_EOK) {
+ ERR("can't sign the packet (%s)\n", knot_strerror(ret));
+ return -1;
+ }
+
+ // Get connection parameters.
+ int iptype = get_iptype(query->ip);
+ int socktype = get_socktype(query->protocol, query->type_num);
+ int flags = query->fastopen ? NET_FLAGS_FASTOPEN : NET_FLAGS_NONE;
+
+ // Use the first nameserver from the list.
+ srv_info_t *remote = HEAD(query->servers);
+
+ DBG("Querying for owner(%s), class(%u), type(%u), server(%s), "
+ "port(%s), protocol(%s)\n", query->owner, query->class_num,
+ query->type_num, remote->name, remote->service,
+ get_sockname(socktype));
+
+ // Initialize network structure.
+ ret = net_init(query->local, remote, iptype, socktype, query->wait,
+ flags, &query->tls, &net);
+ if (ret != KNOT_EOK) {
+ sign_context_deinit(&sign_ctx);
+ knot_pkt_free(out_packet);
+ return -1;
+ }
+
+ // Loop over all resolved addresses for remote.
+ while (net.srv != NULL) {
+ ret = process_xfr_packet(out_packet, &net,
+ query,
+ &sign_ctx,
+ &query->style);
+ // If error try next resolved address.
+ if (ret != 0) {
+ net.srv = (net.srv)->ai_next;
+ continue;
+ }
+
+ break;
+ }
+
+ if (ret != 0) {
+ ERR("failed to query server %s@%s(%s)\n",
+ remote->name, remote->service, get_sockname(socktype));
+ }
+
+ net_clean(&net);
+ sign_context_deinit(&sign_ctx);
+ knot_pkt_free(out_packet);
+
+ return ret;
+}
+
+int kdig_exec(const kdig_params_t *params)
+{
+ node_t *n = NULL;
+
+ if (params == NULL) {
+ DBG_NULL;
+ return KNOT_EINVAL;
+ }
+
+ bool success = true;
+
+ // Loop over query list.
+ WALK_LIST(n, params->queries) {
+ query_t *query = (query_t *)n;
+
+ int ret = -1;
+ switch (query->operation) {
+ case OPERATION_QUERY:
+ ret = process_query(query);
+ break;
+ case OPERATION_XFR:
+ ret = process_xfr(query);
+ break;
+#if USE_DNSTAP
+ case OPERATION_LIST_DNSTAP:
+ ret = process_dnstap(query);
+ break;
+#endif // USE_DNSTAP
+ case OPERATION_LIST_SOA:
+ break;
+ default:
+ ERR("unsupported operation\n");
+ break;
+ }
+
+ // All operations must succeed.
+ if (ret != 0) {
+ success = false;
+ }
+
+ // If not last query, print separation.
+ if (n->next->next && params->config->style.format == FORMAT_FULL) {
+ printf("\n");
+ }
+ }
+
+ return success ? KNOT_EOK : KNOT_ERROR;
+}
diff --git a/src/utils/kdig/kdig_exec.h b/src/utils/kdig/kdig_exec.h
new file mode 100644
index 0000000..ee6c548
--- /dev/null
+++ b/src/utils/kdig/kdig_exec.h
@@ -0,0 +1,21 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "utils/kdig/kdig_params.h"
+
+int kdig_exec(const kdig_params_t *params);
diff --git a/src/utils/kdig/kdig_main.c b/src/utils/kdig/kdig_main.c
new file mode 100644
index 0000000..0cfcd47
--- /dev/null
+++ b/src/utils/kdig/kdig_main.c
@@ -0,0 +1,43 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdlib.h>
+
+#include "libdnssec/crypto.h"
+#include "utils/kdig/kdig_params.h"
+#include "utils/kdig/kdig_exec.h"
+#include "libknot/libknot.h"
+
+int main(int argc, char *argv[])
+{
+ int ret = EXIT_SUCCESS;
+
+ kdig_params_t params;
+ if (kdig_parse(&params, argc, argv) == KNOT_EOK) {
+ if (!params.stop) {
+ dnssec_crypto_init();
+ if (kdig_exec(&params) != KNOT_EOK) {
+ ret = EXIT_FAILURE;
+ }
+ dnssec_crypto_cleanup();
+ }
+ } else {
+ ret = EXIT_FAILURE;
+ }
+
+ kdig_clean(&params);
+ return ret;
+}
diff --git a/src/utils/kdig/kdig_params.c b/src/utils/kdig/kdig_params.c
new file mode 100644
index 0000000..abc231c
--- /dev/null
+++ b/src/utils/kdig/kdig_params.c
@@ -0,0 +1,2317 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <arpa/inet.h>
+#include <locale.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "utils/kdig/kdig_params.h"
+#include "utils/common/cert.h"
+#include "utils/common/hex.h"
+#include "utils/common/msg.h"
+#include "utils/common/params.h"
+#include "utils/common/resolv.h"
+#include "libknot/descriptor.h"
+#include "libknot/libknot.h"
+#include "contrib/base64.h"
+#include "contrib/sockaddr.h"
+#include "contrib/string.h"
+#include "contrib/strtonum.h"
+#include "contrib/ucw/lists.h"
+#include "libdnssec/error.h"
+#include "libdnssec/random.h"
+
+#define PROGRAM_NAME "kdig"
+
+#define DEFAULT_RETRIES_DIG 2
+#define DEFAULT_TIMEOUT_DIG 5
+#define DEFAULT_ALIGNMENT_SIZE 128
+
+static const flags_t DEFAULT_FLAGS_DIG = {
+ .aa_flag = false,
+ .tc_flag = false,
+ .rd_flag = true,
+ .ra_flag = false,
+ .z_flag = false,
+ .ad_flag = false,
+ .cd_flag = false,
+ .do_flag = false
+};
+
+static const style_t DEFAULT_STYLE_DIG = {
+ .format = FORMAT_FULL,
+ .style = {
+ .wrap = false,
+ .show_class = true,
+ .show_ttl = true,
+ .verbose = false,
+ .original_ttl = false,
+ .empty_ttl = false,
+ .human_ttl = false,
+ .human_tmstamp = true,
+ .generic = false,
+ .ascii_to_idn = name_to_idn
+ },
+ .show_query = false,
+ .show_header = true,
+ .show_section = true,
+ .show_edns = true,
+ .show_question = true,
+ .show_answer = true,
+ .show_authority = true,
+ .show_additional = true,
+ .show_tsig = true,
+ .show_footer = true
+};
+
+static int opt_multiline(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.style.wrap = true;
+ q->style.format = FORMAT_FULL;
+ q->style.show_header = true;
+ q->style.show_edns = true;
+ q->style.show_footer = true;
+ q->style.style.verbose = true;
+
+ return KNOT_EOK;
+}
+
+static int opt_nomultiline(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.style.wrap = false;
+
+ return KNOT_EOK;
+}
+
+static int opt_short(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.format = FORMAT_DIG;
+ q->style.show_header = false;
+ q->style.show_edns = false;
+ q->style.show_footer = false;
+
+ return KNOT_EOK;
+}
+
+static int opt_noshort(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.format = FORMAT_FULL;
+
+ return KNOT_EOK;
+}
+
+static int opt_generic(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.style.generic = true;
+
+ return KNOT_EOK;
+}
+
+static int opt_nogeneric(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.style.generic = false;
+
+ return KNOT_EOK;
+}
+
+static int opt_aaflag(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->flags.aa_flag = true;
+
+ return KNOT_EOK;
+}
+
+static int opt_noaaflag(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->flags.aa_flag = false;
+
+ return KNOT_EOK;
+}
+
+static int opt_tcflag(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->flags.tc_flag = true;
+
+ return KNOT_EOK;
+}
+
+static int opt_notcflag(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->flags.tc_flag = false;
+
+ return KNOT_EOK;
+}
+
+static int opt_rdflag(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->flags.rd_flag = true;
+
+ return KNOT_EOK;
+}
+
+static int opt_nordflag(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->flags.rd_flag = false;
+
+ return KNOT_EOK;
+}
+
+static int opt_raflag(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->flags.ra_flag = true;
+
+ return KNOT_EOK;
+}
+
+static int opt_noraflag(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->flags.ra_flag = false;
+
+ return KNOT_EOK;
+}
+
+static int opt_zflag(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->flags.z_flag = true;
+
+ return KNOT_EOK;
+}
+
+static int opt_nozflag(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->flags.z_flag = false;
+
+ return KNOT_EOK;
+}
+
+static int opt_adflag(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->flags.ad_flag = true;
+
+ return KNOT_EOK;
+}
+
+static int opt_noadflag(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->flags.ad_flag = false;
+
+ return KNOT_EOK;
+}
+
+static int opt_cdflag(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->flags.cd_flag = true;
+
+ return KNOT_EOK;
+}
+
+static int opt_nocdflag(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->flags.cd_flag = false;
+
+ return KNOT_EOK;
+}
+
+static int opt_doflag(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->flags.do_flag = true;
+
+ return KNOT_EOK;
+}
+
+static int opt_nodoflag(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->flags.do_flag = false;
+
+ return KNOT_EOK;
+}
+
+static int opt_all(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.show_header = true;
+ q->style.show_edns = true;
+ q->style.show_question = true;
+ q->style.show_answer = true;
+ q->style.show_authority = true;
+ q->style.show_additional = true;
+ q->style.show_tsig = true;
+ q->style.show_footer = true;
+
+ return KNOT_EOK;
+}
+
+static int opt_noall(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.show_header = false;
+ q->style.show_edns = false;
+ q->style.show_query = false;
+ q->style.show_question = false;
+ q->style.show_answer = false;
+ q->style.show_authority = false;
+ q->style.show_additional = false;
+ q->style.show_tsig = false;
+ q->style.show_footer = false;
+
+ return KNOT_EOK;
+}
+
+static int opt_qr(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.show_query = true;
+
+ return KNOT_EOK;
+}
+
+static int opt_noqr(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.show_query = false;
+
+ return KNOT_EOK;
+}
+
+static int opt_header(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.show_header = true;
+
+ return KNOT_EOK;
+}
+
+static int opt_noheader(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.show_header = false;
+
+ return KNOT_EOK;
+}
+
+static int opt_comments(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.show_section = true;
+
+ return KNOT_EOK;
+}
+
+static int opt_nocomments(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.show_section = false;
+
+ return KNOT_EOK;
+}
+
+static int opt_opt(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.show_edns = true;
+
+ return KNOT_EOK;
+}
+
+static int opt_noopt(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.show_edns = false;
+
+ return KNOT_EOK;
+}
+
+static int opt_question(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.show_question = true;
+
+ return KNOT_EOK;
+}
+
+static int opt_noquestion(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.show_question = false;
+
+ return KNOT_EOK;
+}
+
+static int opt_answer(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.show_answer = true;
+
+ return KNOT_EOK;
+}
+
+static int opt_noanswer(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.show_answer = false;
+
+ return KNOT_EOK;
+}
+
+static int opt_authority(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.show_authority = true;
+
+ return KNOT_EOK;
+}
+
+static int opt_noauthority(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.show_authority = false;
+
+ return KNOT_EOK;
+}
+
+static int opt_additional(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.show_additional = true;
+
+ return KNOT_EOK;
+}
+
+static int opt_noadditional(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.show_additional = false;
+ q->style.show_edns = false;
+ q->style.show_tsig = false;
+
+ return KNOT_EOK;
+}
+
+static int opt_tsig(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.show_tsig = true;
+
+ return KNOT_EOK;
+}
+
+static int opt_notsig(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.show_tsig = false;
+
+ return KNOT_EOK;
+}
+
+static int opt_stats(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.show_footer = true;
+
+ return KNOT_EOK;
+}
+
+static int opt_nostats(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.show_footer = false;
+
+ return KNOT_EOK;
+}
+
+static int opt_class(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.style.show_class = true;
+
+ return KNOT_EOK;
+}
+
+static int opt_noclass(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.style.show_class = false;
+
+ return KNOT_EOK;
+}
+
+static int opt_ttl(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.style.show_ttl = true;
+
+ return KNOT_EOK;
+}
+
+static int opt_nottl(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.style.show_ttl = false;
+
+ return KNOT_EOK;
+}
+
+static int opt_ignore(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->ignore_tc = true;
+
+ return KNOT_EOK;
+}
+
+static int opt_noignore(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->ignore_tc = false;
+
+ return KNOT_EOK;
+}
+
+static int opt_crypto(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.style.hide_crypto = false;
+
+ return KNOT_EOK;
+}
+
+static int opt_nocrypto(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->style.style.hide_crypto = true;
+
+ return KNOT_EOK;
+}
+
+static int opt_tcp(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->protocol = PROTO_TCP;
+
+ return KNOT_EOK;
+}
+
+static int opt_notcp(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->protocol = PROTO_UDP;
+ return opt_ignore(arg, query);
+}
+
+static int opt_fastopen(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->fastopen = true;
+
+ return KNOT_EOK;
+}
+
+static int opt_nofastopen(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->fastopen = false;
+
+ return opt_ignore(arg, query);
+}
+
+static int opt_tls(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->tls.enable = true;
+ return opt_tcp(arg, query);
+}
+
+static int opt_notls(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ tls_params_clean(&q->tls);
+ tls_params_init(&q->tls);
+
+ return KNOT_EOK;
+}
+
+static int opt_tls_ca(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ if (arg == NULL) {
+ q->tls.system_ca = true;
+ return opt_tls(arg, query);
+ } else {
+ if (ptrlist_add(&q->tls.ca_files, strdup(arg), NULL) == NULL) {
+ return KNOT_ENOMEM;
+ }
+ return opt_tls(arg, query);
+ }
+}
+
+static int opt_notls_ca(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->tls.system_ca = false;
+
+ ptrnode_t *node = NULL, *nxt = NULL;
+ WALK_LIST_DELSAFE(node, nxt, q->tls.ca_files) {
+ free(node->d);
+ }
+ ptrlist_free(&q->tls.ca_files, NULL);
+
+ return KNOT_EOK;
+}
+
+static int opt_tls_pin(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ uint8_t pin[64] = { 0 };
+
+ int ret = base64_decode((const uint8_t *)arg, strlen(arg), pin, sizeof(pin));
+ if (ret < 0) {
+ ERR("invalid +tls-pin=%s\n", arg);
+ return ret;
+ } else if (ret != CERT_PIN_LEN) { // Check for 256-bit value.
+ ERR("invalid sha256 hash length +tls-pin=%s\n", arg);
+ return KNOT_EINVAL;
+ }
+
+ uint8_t *item = malloc(1 + ret); // 1 ~ leading data length.
+ if (item == NULL) {
+ return KNOT_ENOMEM;
+ }
+ item[0] = ret;
+ memcpy(&item[1], pin, ret);
+
+ if (ptrlist_add(&q->tls.pins, item, NULL) == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ return opt_tls(arg, query);
+}
+
+static int opt_notls_pin(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ ptrnode_t *node = NULL, *nxt = NULL;
+ WALK_LIST_DELSAFE(node, nxt, q->tls.pins) {
+ free(node->d);
+ }
+ ptrlist_free(&q->tls.pins, NULL);
+
+ return KNOT_EOK;
+}
+
+static int opt_tls_hostname(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ free(q->tls.hostname);
+ q->tls.hostname = strdup(arg);
+
+ return opt_tls(arg, query);
+}
+
+static int opt_notls_hostname(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ free(q->tls.hostname);
+ q->tls.hostname = NULL;
+
+ return KNOT_EOK;
+}
+
+static int opt_tls_sni(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ free(q->tls.sni);
+ q->tls.sni = strdup(arg);
+
+ return opt_tls(arg, query);
+}
+
+static int opt_notls_sni(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ free(q->tls.sni);
+ q->tls.sni = NULL;
+
+ return KNOT_EOK;
+}
+
+static int opt_nsid(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->nsid = true;
+
+ return KNOT_EOK;
+}
+
+static int opt_nonsid(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->nsid = false;
+
+ return KNOT_EOK;
+}
+
+static int opt_bufsize(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ uint16_t num = 0;
+ if (str_to_u16(arg, &num) != KNOT_EOK) {
+ ERR("invalid +bufsize=%s\n", arg);
+ return KNOT_EINVAL;
+ }
+
+ // Disable EDNS if zero bufsize.
+ if (num == 0) {
+ q->udp_size = -1;
+ } else if (num < KNOT_WIRE_HEADER_SIZE) {
+ q->udp_size = KNOT_WIRE_HEADER_SIZE;
+ } else {
+ q->udp_size = num;
+ }
+
+ return KNOT_EOK;
+}
+
+static int opt_nobufsize(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->udp_size = -1;
+
+ return KNOT_EOK;
+}
+
+static int opt_cookie(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ if (arg != NULL) {
+ uint8_t *input = NULL;
+ size_t input_len;
+
+ int ret = hex_decode(arg, &input, &input_len);
+ if (ret != KNOT_EOK) {
+ ERR("invalid +cookie=%s\n", arg);
+ return KNOT_EINVAL;
+ }
+
+ if (input_len < KNOT_EDNS_COOKIE_CLNT_SIZE) {
+ ERR("too short client +cookie=%s\n", arg);
+ free(input);
+ return KNOT_EINVAL;
+ }
+ q->cc.len = KNOT_EDNS_COOKIE_CLNT_SIZE;
+ memcpy(q->cc.data, input, q->cc.len);
+
+ input_len -= q->cc.len;
+ if (input_len > 0) {
+ if (input_len < KNOT_EDNS_COOKIE_SRVR_MIN_SIZE) {
+ ERR("too short server +cookie=%s\n", arg);
+ free(input);
+ return KNOT_EINVAL;
+ }
+ if (input_len > KNOT_EDNS_COOKIE_SRVR_MAX_SIZE) {
+ ERR("too long server +cookie=%s\n", arg);
+ free(input);
+ return KNOT_EINVAL;
+ }
+ q->sc.len = input_len;
+ memcpy(q->sc.data, input + q->cc.len, q->sc.len);
+ }
+
+ free(input);
+ } else {
+ q->cc.len = KNOT_EDNS_COOKIE_CLNT_SIZE;
+
+ int ret = dnssec_random_buffer(q->cc.data, q->cc.len);
+ if (ret != DNSSEC_EOK) {
+ return knot_error_from_libdnssec(ret);
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+static int opt_nocookie(const char *arg, void *query)
+{
+ query_t *q = query;
+ q->cc.len = 0;
+ q->sc.len = 0;
+ return KNOT_EOK;
+}
+
+static int opt_badcookie(const char *arg, void *query)
+{
+ query_t *q = query;
+ q->badcookie = true;
+ return KNOT_EOK;
+}
+
+static int opt_nobadcookie(const char *arg, void *query)
+{
+ query_t *q = query;
+ q->badcookie = false;
+ return KNOT_EOK;
+}
+
+static int opt_padding(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ if (arg == NULL) {
+ q->padding = -2;
+ return KNOT_EOK;
+ } else {
+ uint16_t num = 0;
+ if (str_to_u16(arg, &num) != KNOT_EOK) {
+ ERR("invalid +padding=%s\n", arg);
+ return KNOT_EINVAL;
+ }
+
+ q->padding = num;
+ return KNOT_EOK;
+ }
+}
+
+static int opt_nopadding(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->padding = -3;
+
+ return KNOT_EOK;
+}
+
+static int opt_alignment(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ if (arg == NULL) {
+ q->alignment = DEFAULT_ALIGNMENT_SIZE;
+ return KNOT_EOK;
+ } else {
+ uint16_t num = 0;
+ if (str_to_u16(arg, &num) != KNOT_EOK || num < 2) {
+ ERR("invalid +alignment=%s\n", arg);
+ return KNOT_EINVAL;
+ }
+
+ q->alignment = num;
+ return KNOT_EOK;
+ }
+}
+
+static int opt_noalignment(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->alignment = 0;
+
+ return KNOT_EOK;
+}
+
+static int opt_subnet(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ char *sep = NULL;
+ const size_t arg_len = strlen(arg);
+ const char *arg_end = arg + arg_len;
+ size_t addr_len = 0;
+
+ // Separate address and network mask.
+ if ((sep = strchr(arg, '/')) != NULL) {
+ addr_len = sep - arg;
+ } else {
+ addr_len = arg_len;
+ }
+
+ // Check IP address.
+
+ struct sockaddr_storage ss = { 0 };
+ struct addrinfo hints = { .ai_flags = AI_NUMERICHOST };
+ struct addrinfo *ai = NULL;
+
+ char *addr_str = strndup(arg, addr_len);
+ if (getaddrinfo(addr_str, NULL, &hints, &ai) != 0) {
+ free(addr_str);
+ ERR("invalid address +subnet=%s\n", arg);
+ return KNOT_EINVAL;
+ }
+
+ memcpy(&ss, ai->ai_addr, ai->ai_addrlen);
+ freeaddrinfo(ai);
+ free(addr_str);
+
+ if (knot_edns_client_subnet_set_addr(&q->subnet, &ss) != KNOT_EOK) {
+ ERR("invalid address +subnet=%s\n", arg);
+ return KNOT_EINVAL;
+ }
+
+ // Parse network mask.
+ const char *mask = arg;
+ if (mask + addr_len < arg_end) {
+ mask += addr_len + 1;
+ uint8_t num = 0;
+ if (str_to_u8(mask, &num) != KNOT_EOK || num > q->subnet.source_len) {
+ ERR("invalid network mask +subnet=%s\n", arg);
+ return KNOT_EINVAL;
+ }
+ q->subnet.source_len = num;
+ }
+
+ return KNOT_EOK;
+}
+
+static int opt_nosubnet(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->subnet.family = AF_UNSPEC;
+
+ return KNOT_EOK;
+}
+
+static int opt_edns(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ if (arg == NULL) {
+ q->edns = 0;
+ return KNOT_EOK;
+ } else {
+ uint8_t num = 0;
+ if (str_to_u8(arg, &num) != KNOT_EOK) {
+ ERR("invalid +edns=%s\n", arg);
+ return KNOT_EINVAL;
+ }
+
+ q->edns = num;
+ return KNOT_EOK;
+ }
+}
+
+static int opt_noedns(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->edns = -1;
+ opt_nodoflag(arg, query);
+ opt_nonsid(arg, query);
+ opt_nobufsize(arg, query);
+ opt_nocookie(arg, query);
+ opt_nopadding(arg, query);
+ opt_noalignment(arg, query);
+ opt_nosubnet(arg, query);
+
+ return KNOT_EOK;
+}
+
+static int opt_timeout(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ if (params_parse_wait(arg, &q->wait) != KNOT_EOK) {
+ ERR("invalid +timeout=%s\n", arg);
+ return KNOT_EINVAL;
+ }
+
+ return KNOT_EOK;
+}
+
+static int opt_notimeout(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->wait = DEFAULT_TIMEOUT_DIG;
+
+ return KNOT_EOK;
+}
+
+static int opt_retry(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ if (str_to_u32(arg, &q->retries) != KNOT_EOK) {
+ ERR("invalid +retry=%s\n", arg);
+ return KNOT_EINVAL;
+ }
+
+ return KNOT_EOK;
+}
+
+static int opt_noretry(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->retries = DEFAULT_RETRIES_DIG;
+
+ return KNOT_EOK;
+}
+
+static int parse_ednsopt(const char *arg, ednsopt_t **opt_ptr)
+{
+ errno = 0;
+ char *end = NULL;
+ unsigned long code = strtoul(arg, &end, 10);
+ if (errno != 0 || arg == end || code > UINT16_MAX) {
+ return KNOT_EINVAL;
+ }
+
+ size_t length = 0;
+ uint8_t *data = NULL;
+ if (end[0] == ':') {
+ if (end[1] != '\0') {
+ int ret = hex_decode(end + 1, &data, &length);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ if (length > UINT16_MAX) {
+ free(data);
+ return KNOT_ERANGE;
+ }
+ }
+ } else if (end[0] != '\0') {
+ return KNOT_EINVAL;
+ }
+
+ ednsopt_t *opt = ednsopt_create(code, length, data);
+ if (opt == NULL) {
+ free(data);
+ return KNOT_ENOMEM;
+ }
+
+ *opt_ptr = opt;
+ return KNOT_EOK;
+}
+
+static int opt_ednsopt(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ ednsopt_t *opt = NULL;
+ int ret = parse_ednsopt(arg, &opt);
+ if (ret != KNOT_EOK) {
+ ERR("invalid +ednsopt=%s\n", arg);
+ return KNOT_EINVAL;
+ }
+
+ add_tail(&q->edns_opts, &opt->n);
+
+ return KNOT_EOK;
+}
+
+static int opt_noednsopt(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ ednsopt_list_deinit(&q->edns_opts);
+
+ return KNOT_EOK;
+}
+
+static int opt_noidn(const char *arg, void *query)
+{
+ query_t *q = query;
+
+ q->idn = false;
+ q->style.style.ascii_to_idn = NULL;
+
+ return KNOT_EOK;
+}
+
+static const param_t kdig_opts2[] = {
+ { "multiline", ARG_NONE, opt_multiline },
+ { "nomultiline", ARG_NONE, opt_nomultiline },
+
+ { "short", ARG_NONE, opt_short },
+ { "noshort", ARG_NONE, opt_noshort },
+
+ { "generic", ARG_NONE, opt_generic },
+ { "nogeneric", ARG_NONE, opt_nogeneric },
+
+ { "aaflag", ARG_NONE, opt_aaflag },
+ { "noaaflag", ARG_NONE, opt_noaaflag },
+
+ { "tcflag", ARG_NONE, opt_tcflag },
+ { "notcflag", ARG_NONE, opt_notcflag },
+
+ { "rdflag", ARG_NONE, opt_rdflag },
+ { "nordflag", ARG_NONE, opt_nordflag },
+
+ { "recurse", ARG_NONE, opt_rdflag },
+ { "norecurse", ARG_NONE, opt_nordflag },
+
+ { "raflag", ARG_NONE, opt_raflag },
+ { "noraflag", ARG_NONE, opt_noraflag },
+
+ { "zflag", ARG_NONE, opt_zflag },
+ { "nozflag", ARG_NONE, opt_nozflag },
+
+ { "adflag", ARG_NONE, opt_adflag },
+ { "noadflag", ARG_NONE, opt_noadflag },
+
+ { "cdflag", ARG_NONE, opt_cdflag },
+ { "nocdflag", ARG_NONE, opt_nocdflag },
+
+ { "dnssec", ARG_NONE, opt_doflag },
+ { "nodnssec", ARG_NONE, opt_nodoflag },
+
+ { "all", ARG_NONE, opt_all },
+ { "noall", ARG_NONE, opt_noall },
+
+ { "qr", ARG_NONE, opt_qr },
+ { "noqr", ARG_NONE, opt_noqr },
+
+ { "header", ARG_NONE, opt_header },
+ { "noheader", ARG_NONE, opt_noheader },
+
+ { "comments", ARG_NONE, opt_comments },
+ { "nocomments", ARG_NONE, opt_nocomments },
+
+ { "opt", ARG_NONE, opt_opt },
+ { "opt", ARG_NONE, opt_opt },
+ { "noopt", ARG_NONE, opt_noopt },
+
+ { "question", ARG_NONE, opt_question },
+ { "noquestion", ARG_NONE, opt_noquestion },
+
+ { "answer", ARG_NONE, opt_answer },
+ { "noanswer", ARG_NONE, opt_noanswer },
+
+ { "authority", ARG_NONE, opt_authority },
+ { "noauthority", ARG_NONE, opt_noauthority },
+
+ { "additional", ARG_NONE, opt_additional },
+ { "noadditional", ARG_NONE, opt_noadditional },
+
+ { "tsig", ARG_NONE, opt_tsig },
+ { "notsig", ARG_NONE, opt_notsig },
+
+ { "stats", ARG_NONE, opt_stats },
+ { "nostats", ARG_NONE, opt_nostats },
+
+ { "class", ARG_NONE, opt_class },
+ { "noclass", ARG_NONE, opt_noclass },
+
+ { "ttl", ARG_NONE, opt_ttl },
+ { "nottl", ARG_NONE, opt_nottl },
+
+ { "crypto", ARG_NONE, opt_crypto },
+ { "nocrypto", ARG_NONE, opt_nocrypto },
+
+ { "tcp", ARG_NONE, opt_tcp },
+ { "notcp", ARG_NONE, opt_notcp },
+
+ { "fastopen", ARG_NONE, opt_fastopen },
+ { "nofastopen", ARG_NONE, opt_nofastopen },
+
+ { "ignore", ARG_NONE, opt_ignore },
+ { "noignore", ARG_NONE, opt_noignore },
+
+ { "tls", ARG_NONE, opt_tls },
+ { "notls", ARG_NONE, opt_notls },
+
+ { "tls-ca", ARG_OPTIONAL, opt_tls_ca },
+ { "notls-ca", ARG_NONE, opt_notls_ca },
+
+ { "tls-pin", ARG_REQUIRED, opt_tls_pin },
+ { "notls-pin", ARG_NONE, opt_notls_pin },
+
+ { "tls-hostname", ARG_REQUIRED, opt_tls_hostname },
+ { "notls-hostname", ARG_NONE, opt_notls_hostname },
+
+ { "tls-sni", ARG_REQUIRED, opt_tls_sni },
+ { "notls-sni", ARG_NONE, opt_notls_sni },
+
+ { "nsid", ARG_NONE, opt_nsid },
+ { "nonsid", ARG_NONE, opt_nonsid },
+
+ { "bufsize", ARG_REQUIRED, opt_bufsize },
+ { "nobufsize", ARG_NONE, opt_nobufsize },
+
+ { "padding", ARG_OPTIONAL, opt_padding },
+ { "nopadding", ARG_NONE, opt_nopadding },
+
+ { "alignment", ARG_OPTIONAL, opt_alignment },
+ { "noalignment", ARG_NONE, opt_noalignment },
+
+ { "subnet", ARG_REQUIRED, opt_subnet },
+ { "nosubnet", ARG_NONE, opt_nosubnet },
+
+ // Obsolete aliases.
+ { "client", ARG_REQUIRED, opt_subnet },
+ { "noclient", ARG_NONE, opt_nosubnet },
+
+ { "edns", ARG_OPTIONAL, opt_edns },
+ { "noedns", ARG_NONE, opt_noedns },
+
+ { "timeout", ARG_REQUIRED, opt_timeout },
+ { "notimeout", ARG_NONE, opt_notimeout },
+
+ { "retry", ARG_REQUIRED, opt_retry },
+ { "noretry", ARG_NONE, opt_noretry },
+
+ { "cookie", ARG_OPTIONAL, opt_cookie },
+ { "nocookie", ARG_NONE, opt_nocookie },
+
+ { "badcookie", ARG_NONE, opt_badcookie },
+ { "nobadcookie", ARG_NONE, opt_nobadcookie },
+
+ { "ednsopt", ARG_REQUIRED, opt_ednsopt },
+ { "noednsopt", ARG_NONE, opt_noednsopt },
+
+ /* "idn" doesn't work since it must be called before query creation. */
+ { "noidn", ARG_NONE, opt_noidn },
+
+ { NULL }
+};
+
+query_t *query_create(const char *owner, const query_t *conf)
+{
+ // Create output structure.
+ query_t *query = calloc(1, sizeof(query_t));
+
+ if (query == NULL) {
+ DBG_NULL;
+ return NULL;
+ }
+
+ // Initialization with defaults or with reference query.
+ if (conf == NULL) {
+ query->conf = NULL;
+ query->local = NULL;
+ query->operation = OPERATION_QUERY;
+ query->ip = IP_ALL;
+ query->protocol = PROTO_ALL;
+ query->fastopen = false;
+ query->port = strdup("");
+ query->udp_size = -1;
+ query->retries = DEFAULT_RETRIES_DIG;
+ query->wait = DEFAULT_TIMEOUT_DIG;
+ query->ignore_tc = false;
+ query->class_num = -1;
+ query->type_num = -1;
+ query->serial = -1;
+ query->notify = false;
+ query->flags = DEFAULT_FLAGS_DIG;
+ query->style = DEFAULT_STYLE_DIG;
+ query->idn = true;
+ query->nsid = false;
+ query->edns = -1;
+ query->cc.len = 0;
+ query->sc.len = 0;
+ query->badcookie = true;
+ query->padding = -1;
+ query->alignment = 0;
+ tls_params_init(&query->tls);
+ //query->tsig_key
+ query->subnet.family = AF_UNSPEC;
+ ednsopt_list_init(&query->edns_opts);
+#if USE_DNSTAP
+ query->dt_reader = NULL;
+ query->dt_writer = NULL;
+#endif // USE_DNSTAP
+ } else {
+ *query = *conf;
+ query->conf = conf;
+ if (conf->local != NULL) {
+ query->local = srv_info_create(conf->local->name,
+ conf->local->service);
+ if (query->local == NULL) {
+ query_free(query);
+ return NULL;
+ }
+ } else {
+ query->local = NULL;
+ }
+ query->port = strdup(conf->port);
+ tls_params_copy(&query->tls, &conf->tls);
+ if (conf->tsig_key.name != NULL) {
+ int ret = knot_tsig_key_copy(&query->tsig_key,
+ &conf->tsig_key);
+ if (ret != KNOT_EOK) {
+ query_free(query);
+ return NULL;
+ }
+ }
+
+ int ret = ednsopt_list_dup(&query->edns_opts, &conf->edns_opts);
+ if (ret != KNOT_EOK) {
+ query_free(query);
+ return NULL;
+ }
+
+#if USE_DNSTAP
+ query->dt_reader = conf->dt_reader;
+ query->dt_writer = conf->dt_writer;
+#endif // USE_DNSTAP
+ }
+
+ // Initialize list of servers.
+ init_list(&query->servers);
+
+ // Set the query owner if any.
+ if (owner != NULL) {
+ if ((query->owner = strdup(owner)) == NULL) {
+ query_free(query);
+ return NULL;
+ }
+ }
+
+ // Check dynamic allocation.
+ if (query->port == NULL) {
+ query_free(query);
+ return NULL;
+ }
+
+ return query;
+}
+
+void query_free(query_t *query)
+{
+ node_t *n = NULL, *nxt = NULL;
+
+ if (query == NULL) {
+ DBG_NULL;
+ return;
+ }
+
+ // Cleanup servers.
+ WALK_LIST_DELSAFE(n, nxt, query->servers) {
+ srv_info_free((srv_info_t *)n);
+ }
+
+ // Cleanup local address.
+ if (query->local != NULL) {
+ srv_info_free(query->local);
+ }
+
+ tls_params_clean(&query->tls);
+
+ // Cleanup signing key.
+ knot_tsig_key_deinit(&query->tsig_key);
+
+ // Cleanup EDNS options.
+ ednsopt_list_deinit(&query->edns_opts);
+
+#if USE_DNSTAP
+ if (query->dt_reader != NULL) {
+ dt_reader_free(query->dt_reader);
+ }
+ if (query->dt_writer != NULL) {
+ // Global writer can be shared!
+ if (query->conf == NULL ||
+ query->conf->dt_writer != query->dt_writer) {
+ dt_writer_free(query->dt_writer);
+ }
+ }
+#endif // USE_DNSTAP
+
+ free(query->owner);
+ free(query->port);
+ free(query);
+}
+
+ednsopt_t *ednsopt_create(uint16_t code, uint16_t length, uint8_t *data)
+{
+ ednsopt_t *opt = calloc(1, sizeof(*opt));
+ if (opt == NULL) {
+ return NULL;
+ }
+
+ opt->code = code;
+ opt->length = length;
+ opt->data = data;
+
+ return opt;
+}
+
+ednsopt_t *ednsopt_dup(const ednsopt_t *opt)
+{
+ ednsopt_t *dup = calloc(1, sizeof(*opt));
+ if (dup == NULL) {
+ return NULL;
+ }
+
+ dup->code = opt->code;
+ dup->length = opt->length;
+ dup->data = memdup(opt->data, opt->length);
+ if (dup->data == NULL) {
+ free(dup);
+ return NULL;
+ }
+
+ return dup;
+}
+
+void ednsopt_free(ednsopt_t *opt)
+{
+ if (opt == NULL) {
+ return;
+ }
+
+ free(opt->data);
+ free(opt);
+}
+
+void ednsopt_list_init(list_t *list)
+{
+ init_list(list);
+}
+
+void ednsopt_list_deinit(list_t *list)
+{
+ node_t *n, *next;
+ WALK_LIST_DELSAFE(n, next, *list) {
+ ednsopt_t *opt = (ednsopt_t *)n;
+ ednsopt_free(opt);
+ }
+
+ init_list(list);
+}
+
+int ednsopt_list_dup(list_t *dest, const list_t *src)
+{
+ list_t backup = *dest;
+ init_list(dest);
+
+ node_t *n = NULL;
+ WALK_LIST(n, *src) {
+ ednsopt_t *opt = (ednsopt_t *)n;
+ ednsopt_t *dup = ednsopt_dup(opt);
+ if (dup == NULL) {
+ ednsopt_list_deinit(dest);
+ *dest = backup;
+ return KNOT_ENOMEM;
+ }
+
+ add_tail(dest, &dup->n);
+ }
+
+ return KNOT_EOK;
+}
+
+bool ednsopt_list_empty(const list_t *list)
+{
+ return EMPTY_LIST(*list);
+}
+
+int kdig_init(kdig_params_t *params)
+{
+ if (params == NULL) {
+ DBG_NULL;
+ return KNOT_EINVAL;
+ }
+
+ memset(params, 0, sizeof(*params));
+
+ params->stop = false;
+
+ // Initialize list of queries.
+ init_list(&params->queries);
+
+ // Create config query.
+ if ((params->config = query_create(NULL, NULL)) == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ return KNOT_EOK;
+}
+
+void kdig_clean(kdig_params_t *params)
+{
+ node_t *n = NULL, *nxt = NULL;
+
+ if (params == NULL) {
+ DBG_NULL;
+ return;
+ }
+
+ // Clean up queries.
+ WALK_LIST_DELSAFE(n, nxt, params->queries) {
+ query_free((query_t *)n);
+ }
+
+ // Clean up config.
+ query_free(params->config);
+
+ // Clean up the structure.
+ memset(params, 0, sizeof(*params));
+}
+
+static int parse_class(const char *value, query_t *query)
+{
+ uint16_t rclass;
+
+ if (params_parse_class(value, &rclass) != KNOT_EOK) {
+ return KNOT_EINVAL;
+ }
+
+ query->class_num = rclass;
+
+ return KNOT_EOK;
+}
+
+static int parse_keyfile(const char *value, query_t *query)
+{
+ knot_tsig_key_deinit(&query->tsig_key);
+
+ if (knot_tsig_key_init_file(&query->tsig_key, value) != KNOT_EOK) {
+ return KNOT_EINVAL;
+ }
+
+ return KNOT_EOK;
+}
+
+static int parse_local(const char *value, query_t *query)
+{
+ srv_info_t *local = parse_nameserver(value, "0");
+ if (local == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ if (query->local != NULL) {
+ srv_info_free(query->local);
+ }
+
+ query->local = local;
+
+ return KNOT_EOK;
+}
+
+static int parse_name(const char *value, list_t *queries, const query_t *conf)
+{
+ query_t *query = NULL;
+ char *ascii_name = (char *)value;
+ char *fqd_name = NULL;
+
+ if (value != NULL) {
+ if (conf->idn) {
+ ascii_name = name_from_idn(value);
+ if (ascii_name == NULL) {
+ return KNOT_EINVAL;
+ }
+ }
+
+ // If name is not FQDN, append trailing dot.
+ fqd_name = get_fqd_name(ascii_name);
+
+ if (conf->idn) {
+ free(ascii_name);
+ }
+ }
+
+ // Create new query.
+ query = query_create(fqd_name, conf);
+
+ free(fqd_name);
+
+ if (query == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ // Add new query to the queries.
+ add_tail(queries, (node_t *)query);
+
+ return KNOT_EOK;
+}
+
+static int parse_port(const char *value, query_t *query)
+{
+ char **port;
+
+ // Set current server port (last or query default).
+ if (list_size(&query->servers) > 0) {
+ srv_info_t *server = TAIL(query->servers);
+ port = &(server->service);
+ } else {
+ port = &(query->port);
+ }
+
+ char *new_port = strdup(value);
+
+ if (new_port == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ // Deallocate old string.
+ free(*port);
+
+ *port = new_port;
+
+ return KNOT_EOK;
+}
+
+static int parse_reverse(const char *value, list_t *queries, const query_t *conf)
+{
+ query_t *query = NULL;
+
+ // Create reverse name.
+ char *reverse = get_reverse_name(value);
+
+ if (reverse == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ // Create reverse query for given address.
+ query = query_create(reverse, conf);
+
+ free(reverse);
+
+ if (query == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ // Set type for reverse query.
+ query->type_num = KNOT_RRTYPE_PTR;
+
+ // Add new query to the queries.
+ add_tail(queries, (node_t *)query);
+
+ return KNOT_EOK;
+}
+
+static int parse_server(const char *value, kdig_params_t *params)
+{
+ query_t *query;
+
+ // Set current query (last or config).
+ if (list_size(&params->queries) > 0) {
+ query = TAIL(params->queries);
+ } else {
+ query = params->config;
+ }
+
+ if (params_parse_server(value, &query->servers, query->port) != KNOT_EOK) {
+ ERR("invalid server @%s\n", value);
+ return KNOT_EINVAL;
+ }
+
+ return KNOT_EOK;
+}
+
+static int parse_tsig(const char *value, query_t *query)
+{
+ knot_tsig_key_deinit(&query->tsig_key);
+
+ if (knot_tsig_key_init_str(&query->tsig_key, value) != KNOT_EOK) {
+ return KNOT_EINVAL;
+ }
+
+ return KNOT_EOK;
+}
+
+static int parse_type(const char *value, query_t *query)
+{
+ uint16_t rtype;
+ int64_t serial;
+ bool notify;
+
+ if (params_parse_type(value, &rtype, &serial, &notify) != KNOT_EOK) {
+ return KNOT_EINVAL;
+ }
+
+ query->type_num = rtype;
+ query->serial = serial;
+ query->notify = notify;
+
+ // If NOTIFY, reset default RD flag.
+ if (query->notify) {
+ query->flags.rd_flag = false;
+ }
+
+ return KNOT_EOK;
+}
+
+#if USE_DNSTAP
+static int parse_dnstap_output(const char *value, query_t *query)
+{
+ if (query->dt_writer != NULL) {
+ if (query->conf == NULL ||
+ query->conf->dt_writer != query->dt_writer) {
+ dt_writer_free(query->dt_writer);
+ }
+ }
+
+ query->dt_writer = dt_writer_create(value, "kdig " PACKAGE_VERSION);
+ if (query->dt_writer == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ return KNOT_EOK;
+}
+
+static int parse_dnstap_input(const char *value, query_t *query)
+{
+ // Just in case, shouldn't happen.
+ if (query->dt_reader != NULL) {
+ dt_reader_free(query->dt_reader);
+ }
+
+ query->dt_reader = dt_reader_create(value);
+ if (query->dt_reader == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ return KNOT_EOK;
+}
+#endif // USE_DNSTAP
+
+static void complete_servers(query_t *query, const query_t *conf)
+{
+ node_t *n = NULL;
+ char *def_port;
+
+ // Decide which default port use.
+ if (strlen(query->port) > 0) {
+ def_port = query->port;
+ } else if (strlen(conf->port) > 0) {
+ def_port = conf->port;
+ } else if (query->tls.enable) {
+ def_port = DEFAULT_DNS_TLS_PORT;
+ } else {
+ def_port = DEFAULT_DNS_PORT;
+ }
+
+ // Complete specified nameservers if any.
+ if (list_size(&query->servers) > 0) {
+ WALK_LIST(n, query->servers) {
+ srv_info_t *s = (srv_info_t *)n;
+
+ // If the port isn't specified yet use the default one.
+ if (strlen(s->service) == 0) {
+ free(s->service);
+ s->service = strdup(def_port);
+ if (s->service == NULL) {
+ WARN("can't set port %s\n", def_port);
+ return;
+ }
+ }
+
+ // Use server name as hostname for TLS if necessary.
+ if (query->tls.enable && query->tls.hostname == NULL &&
+ (query->tls.system_ca || !EMPTY_LIST(query->tls.ca_files))) {
+ query->tls.hostname = strdup(s->name);
+ }
+ }
+ // Use servers from config if any.
+ } else if (list_size(&conf->servers) > 0) {
+ WALK_LIST(n, conf->servers) {
+ srv_info_t *s = (srv_info_t *)n;
+ char *port = def_port;
+
+ // If the port is already specified, use it.
+ if (strlen(s->service) > 0) {
+ port = s->service;
+ }
+
+ srv_info_t *server = srv_info_create(s->name, port);
+ if (server == NULL) {
+ WARN("can't set nameserver %s port %s\n",
+ s->name, s->service);
+ return;
+ }
+ add_tail(&query->servers, (node_t *)server);
+
+ // Use server name as hostname for TLS if necessary.
+ if (query->tls.enable && query->tls.hostname == NULL &&
+ (query->tls.system_ca || !EMPTY_LIST(query->tls.ca_files))) {
+ query->tls.hostname = strdup(s->name);
+ }
+ }
+ // Use system specific.
+ } else {
+ get_nameservers(&query->servers, def_port);
+ }
+}
+
+void complete_queries(list_t *queries, const query_t *conf)
+{
+ node_t *n = NULL;
+
+ if (queries == NULL || conf == NULL) {
+ DBG_NULL;
+ return;
+ }
+
+ // If there is no query, add default query: NS to ".".
+ if (list_size(queries) == 0) {
+ query_t *q = query_create(".", conf);
+ if (q == NULL) {
+ WARN("can't create query . NS IN\n");
+ return;
+ }
+ q->class_num = KNOT_CLASS_IN;
+ q->type_num = KNOT_RRTYPE_NS;
+ add_tail(queries, (node_t *)q);
+ }
+
+ WALK_LIST(n, *queries) {
+ query_t *q = (query_t *)n;
+
+ // Fill class number if missing.
+ if (q->class_num < 0) {
+ if (conf->class_num >= 0) {
+ q->class_num = conf->class_num;
+ } else {
+ q->class_num = KNOT_CLASS_IN;
+ }
+ }
+
+ // Fill type number if missing.
+ if (q->type_num < 0) {
+ if (conf->type_num >= 0) {
+ q->type_num = conf->type_num;
+ q->serial = conf->serial;
+ } else {
+ q->type_num = KNOT_RRTYPE_A;
+ }
+ }
+
+ // Set zone transfer if any.
+ if (q->type_num == KNOT_RRTYPE_AXFR ||
+ q->type_num == KNOT_RRTYPE_IXFR) {
+ q->operation = OPERATION_XFR;
+ }
+
+ // No retries for TCP.
+ if (q->protocol == PROTO_TCP) {
+ q->retries = 0;
+ }
+
+ // Complete nameservers list.
+ complete_servers(q, conf);
+ }
+}
+
+static void print_help(void)
+{
+ printf("Usage: %s [-4] [-6] [-d] [-b address] [-c class] [-p port]\n"
+ " [-q name] [-t type] [-x address] [-k keyfile]\n"
+ " [-y [algo:]keyname:key] [-E tapfile] [-G tapfile]\n"
+ " name [type] [class] [@server]\n"
+ "\n"
+ " +[no]multiline Wrap long records to more lines.\n"
+ " +[no]short Show record data only.\n"
+ " +[no]generic Use generic representation format.\n"
+ " +[no]aaflag Set AA flag.\n"
+ " +[no]tcflag Set TC flag.\n"
+ " +[no]rdflag Set RD flag.\n"
+ " +[no]recurse Same as +[no]rdflag\n"
+ " +[no]raflag Set RA flag.\n"
+ " +[no]zflag Set zero flag bit.\n"
+ " +[no]adflag Set AD flag.\n"
+ " +[no]cdflag Set CD flag.\n"
+ " +[no]dnssec Set DO flag.\n"
+ " +[no]all Show all packet sections.\n"
+ " +[no]qr Show query packet.\n"
+ " +[no]header Show packet header.\n"
+ " +[no]comments Show commented section names.\n"
+ " +[no]opt Show EDNS pseudosection.\n"
+ " +[no]question Show question section.\n"
+ " +[no]answer Show answer section.\n"
+ " +[no]authority Show authority section.\n"
+ " +[no]additional Show additional section.\n"
+ " +[no]tsig Show TSIG pseudosection.\n"
+ " +[no]stats Show trailing packet statistics.\n"
+ " +[no]class Show DNS class.\n"
+ " +[no]ttl Show TTL value.\n"
+ " +[no]crypto Show binary parts of RRSIGs and DNSKEYs.\n"
+ " +[no]tcp Use TCP protocol.\n"
+ " +[no]fastopen Use TCP Fast Open.\n"
+ " +[no]ignore Don't use TCP automatically if truncated.\n"
+ " +[no]tls Use TLS with Opportunistic privacy profile.\n"
+ " +[no]tls-ca[=FILE] Use TLS with Out-Of-Band privacy profile.\n"
+ " +[no]tls-pin=BASE64 Use TLS with pinned certificate.\n"
+ " +[no]tls-hostname=STR Use TLS with remote server hostname.\n"
+ " +[no]tls-sni=STR Use TLS with Server Name Indication.\n"
+ " +[no]nsid Request NSID.\n"
+ " +[no]bufsize=B Set EDNS buffer size.\n"
+ " +[no]padding[=N] Pad with EDNS(0) (default or specify size).\n"
+ " +[no]alignment[=N] Pad with EDNS(0) to blocksize (%u or specify size).\n"
+ " +[no]subnet=SUBN Set EDNS(0) client subnet addr/prefix.\n"
+ " +[no]edns[=N] Use EDNS(=version).\n"
+ " +[no]timeout=T Set wait for reply interval in seconds.\n"
+ " +[no]retry=N Set number of retries.\n"
+ " +[no]cookie=HEX Attach EDNS(0) cookie to the query.\n"
+ " +[no]badcookie Repeat a query with the correct cookie.\n"
+ " +[no]ednsopt=CODE[:HEX] Set custom EDNS option.\n"
+ " +noidn Disable IDN transformation.\n"
+ "\n"
+ " -h, --help Print the program help.\n"
+ " -V, --version Print the program version.\n",
+ PROGRAM_NAME, DEFAULT_ALIGNMENT_SIZE);
+}
+
+static int parse_opt1(const char *opt, const char *value, kdig_params_t *params,
+ int *index)
+{
+ const char *val = value;
+ size_t len = strlen(opt);
+ int add = 1;
+ query_t *query;
+
+ // Set current query (last or config).
+ if (list_size(&params->queries) > 0) {
+ query = TAIL(params->queries);
+ } else {
+ query = params->config;
+ }
+
+ // If there is no space between option and argument.
+ if (len > 1) {
+ val = opt + 1;
+ add = 0;
+ }
+
+ switch (opt[0]) {
+ case '4':
+ if (len > 1) {
+ ERR("invalid option -%s\n", opt);
+ return KNOT_ENOTSUP;
+ }
+
+ query->ip = IP_4;
+ break;
+ case '6':
+ if (len > 1) {
+ ERR("invalid option -%s\n", opt);
+ return KNOT_ENOTSUP;
+ }
+
+ query->ip = IP_6;
+ break;
+ case 'b':
+ if (val == NULL) {
+ ERR("missing address\n");
+ return KNOT_EINVAL;
+ }
+
+ if (parse_local(val, query) != KNOT_EOK) {
+ ERR("bad address %s\n", val);
+ return KNOT_EINVAL;
+ }
+ *index += add;
+ break;
+ case 'd':
+ msg_enable_debug(1);
+ break;
+ case 'h':
+ if (len > 1) {
+ ERR("invalid option -%s\n", opt);
+ return KNOT_ENOTSUP;
+ }
+
+ print_help();
+ params->stop = true;
+ break;
+ case 'c':
+ if (val == NULL) {
+ ERR("missing class\n");
+ return KNOT_EINVAL;
+ }
+
+ if (parse_class(val, query) != KNOT_EOK) {
+ ERR("bad class %s\n", val);
+ return KNOT_EINVAL;
+ }
+ *index += add;
+ break;
+ case 'k':
+ if (val == NULL) {
+ ERR("missing filename\n");
+ return KNOT_EINVAL;
+ }
+
+ if (parse_keyfile(val, query) != KNOT_EOK) {
+ ERR("bad keyfile %s\n", value);
+ return KNOT_EINVAL;
+ }
+ *index += add;
+ break;
+ case 'p':
+ if (val == NULL) {
+ ERR("missing port\n");
+ return KNOT_EINVAL;
+ }
+
+ if (parse_port(val, query) != KNOT_EOK) {
+ ERR("bad port %s\n", value);
+ return KNOT_EINVAL;
+ }
+ *index += add;
+ break;
+ case 'q':
+ // Allow empty QNAME.
+ if (parse_name(val, &params->queries, params->config)
+ != KNOT_EOK) {
+ ERR("bad query name %s\n", val);
+ return KNOT_EINVAL;
+ }
+ *index += add;
+ break;
+ case 't':
+ if (val == NULL) {
+ ERR("missing type\n");
+ return KNOT_EINVAL;
+ }
+
+ if (parse_type(val, query) != KNOT_EOK) {
+ ERR("bad type %s\n", val);
+ return KNOT_EINVAL;
+ }
+ *index += add;
+ break;
+ case 'V':
+ if (len > 1) {
+ ERR("invalid option -%s\n", opt);
+ return KNOT_ENOTSUP;
+ }
+
+ print_version(PROGRAM_NAME);
+ params->stop = true;
+ break;
+ case 'x':
+ if (val == NULL) {
+ ERR("missing address\n");
+ return KNOT_EINVAL;
+ }
+
+ if (parse_reverse(val, &params->queries, params->config)
+ != KNOT_EOK) {
+ ERR("bad reverse name %s\n", val);
+ return KNOT_EINVAL;
+ }
+ *index += add;
+ break;
+ case 'y':
+ if (val == NULL) {
+ ERR("missing key\n");
+ return KNOT_EINVAL;
+ }
+
+ if (parse_tsig(val, query) != KNOT_EOK) {
+ ERR("bad key %s\n", value);
+ return KNOT_EINVAL;
+ }
+ *index += add;
+ break;
+ case 'E':
+#if USE_DNSTAP
+ if (val == NULL) {
+ ERR("missing filename\n");
+ return KNOT_EINVAL;
+ }
+
+ if (parse_dnstap_output(val, query) != KNOT_EOK) {
+ ERR("unable to open dnstap output file %s\n", val);
+ return KNOT_EINVAL;
+ }
+ *index += add;
+#else
+ ERR("no dnstap support but -E specified\n");
+ return KNOT_EINVAL;
+#endif // USE_DNSTAP
+ break;
+ case 'G':
+#if USE_DNSTAP
+ if (val == NULL) {
+ ERR("missing filename\n");
+ return KNOT_EINVAL;
+ }
+
+ query = query_create(NULL, params->config);
+ if (query == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ if (parse_dnstap_input(val, query) != KNOT_EOK) {
+ ERR("unable to open dnstap input file %s\n", val);
+ query_free(query);
+ return KNOT_EINVAL;
+ }
+
+ query->operation = OPERATION_LIST_DNSTAP;
+ add_tail(&params->queries, (node_t *)query);
+
+ *index += add;
+#else
+ ERR("no dnstap support but -G specified\n");
+ return KNOT_EINVAL;
+#endif // USE_DNSTAP
+ break;
+ case '-':
+ if (strcmp(opt, "-help") == 0) {
+ print_help();
+ params->stop = true;
+ } else if (strcmp(opt, "-version") == 0) {
+ print_version(PROGRAM_NAME);
+ params->stop = true;
+ } else {
+ ERR("invalid option: -%s\n", opt);
+ return KNOT_ENOTSUP;
+ }
+ break;
+ default:
+ ERR("invalid option: -%s\n", opt);
+ return KNOT_ENOTSUP;
+ }
+
+ return KNOT_EOK;
+}
+
+static int parse_opt2(const char *value, kdig_params_t *params)
+{
+ query_t *query;
+
+ // Set current query (last or config).
+ if (list_size(&params->queries) > 0) {
+ query = TAIL(params->queries);
+ } else {
+ query = params->config;
+ }
+
+ // Get option name.
+ const char *arg_sep = "=";
+ size_t opt_len = strcspn(value, arg_sep);
+ if (opt_len < 1) {
+ ERR("invalid option: +%s\n", value);
+ return KNOT_ENOTSUP;
+ }
+
+ // Get option argument if any.
+ const char *arg = NULL;
+ const char *rest = value + opt_len;
+ if (strlen(rest) > 0) {
+ arg = rest + strspn(rest, arg_sep);
+ }
+
+ // Check if the given option is supported.
+ bool unique;
+ int ret = best_param(value, opt_len, kdig_opts2, &unique);
+ if (ret < 0) {
+ ERR("invalid option: +%s\n", value);
+ return KNOT_ENOTSUP;
+ } else if (!unique) {
+ ERR("ambiguous option: +%s\n", value);
+ return KNOT_ENOTSUP;
+ }
+
+ // Check argument presence.
+ switch (kdig_opts2[ret].arg) {
+ case ARG_NONE:
+ if (arg != NULL && *arg != '\0') {
+ WARN("superfluous option argument: +%s\n", value);
+ }
+ break;
+ case ARG_REQUIRED:
+ if (arg == NULL) {
+ ERR("missing argument: +%s\n", value);
+ return KNOT_EFEWDATA;
+ }
+ // FALLTHROUGH
+ case ARG_OPTIONAL:
+ if (arg != NULL && *arg == '\0') {
+ ERR("empty argument: +%s\n", value);
+ return KNOT_EFEWDATA;
+ }
+ break;
+ }
+
+ // Call option handler.
+ return kdig_opts2[ret].handler(arg, query);
+}
+
+static int parse_token(const char *value, kdig_params_t *params)
+{
+ query_t *query;
+
+ // Set current query (last or config).
+ if (list_size(&params->queries) > 0) {
+ query = TAIL(params->queries);
+ } else {
+ query = params->config;
+ }
+
+ // Try to guess the meaning of the token.
+ if (strlen(value) == 0) {
+ ERR("invalid empty parameter\n");
+ } else if (parse_type(value, query) == KNOT_EOK) {
+ return KNOT_EOK;
+ } else if (parse_class(value, query) == KNOT_EOK) {
+ return KNOT_EOK;
+ } else if (parse_name(value, &params->queries, params->config) == KNOT_EOK) {
+ return KNOT_EOK;
+ } else {
+ ERR("invalid parameter: %s\n", value);
+ }
+
+ return KNOT_EINVAL;
+}
+
+int kdig_parse(kdig_params_t *params, int argc, char *argv[])
+{
+ if (params == NULL || argv == NULL) {
+ DBG_NULL;
+ return KNOT_EINVAL;
+ }
+
+ // Initialize parameters.
+ if (kdig_init(params) != KNOT_EOK) {
+ return KNOT_ERROR;
+ }
+
+#ifdef LIBIDN
+ // Set up localization.
+ if (setlocale(LC_CTYPE, "") == NULL) {
+ WARN("can't setlocale, disabling IDN\n");
+ params->config->idn = false;
+ params->config->style.style.ascii_to_idn = NULL;
+ }
+#endif
+
+ // Command line parameters processing.
+ for (int i = 1; i < argc; i++) {
+ int ret = KNOT_ERROR;
+
+ // Process parameter.
+ switch (argv[i][0]) {
+ case '@':
+ ret = parse_server(argv[i] + 1, params);
+ break;
+ case '-':
+ ret = parse_opt1(argv[i] + 1, argv[i + 1], params, &i);
+ break;
+ case '+':
+ ret = parse_opt2(argv[i] + 1, params);
+ break;
+ default:
+ ret = parse_token(argv[i], params);
+ break;
+ }
+
+ // Check return.
+ switch (ret) {
+ case KNOT_EOK:
+ if (params->stop) {
+ return KNOT_EOK;
+ }
+ break;
+ case KNOT_ENOTSUP:
+ print_help();
+ default: // Fall through.
+ return ret;
+ }
+ }
+
+ // Complete missing data in queries based on defaults.
+ complete_queries(&params->queries, params->config);
+
+ return KNOT_EOK;
+}
diff --git a/src/utils/kdig/kdig_params.h b/src/utils/kdig/kdig_params.h
new file mode 100644
index 0000000..17907ab
--- /dev/null
+++ b/src/utils/kdig/kdig_params.h
@@ -0,0 +1,176 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+
+#include "utils/common/params.h"
+#include "utils/common/exec.h"
+#include "utils/common/sign.h"
+#include "libknot/libknot.h"
+#include "contrib/sockaddr.h"
+
+#if USE_DNSTAP
+# include "contrib/dnstap/reader.h"
+# include "contrib/dnstap/writer.h"
+#endif // USE_DNSTAP
+
+/*! \brief Operation mode of kdig. */
+typedef enum {
+ /*!< Standard 1-message query/reply. */
+ OPERATION_QUERY,
+ /*!< Zone transfer (AXFR or IXFR). */
+ OPERATION_XFR,
+ /*!< Dump dnstap file. */
+ OPERATION_LIST_DNSTAP,
+ /*!< Query for NS and all authoritative SOA records. */
+ OPERATION_LIST_SOA
+} operation_t;
+
+/*! \brief DNS header and EDNS flags. */
+typedef struct {
+ /*!< Authoritative answer flag. */
+ bool aa_flag;
+ /*!< Truncated flag. */
+ bool tc_flag;
+ /*!< Recursion desired flag. */
+ bool rd_flag;
+ /*!< Recursion available flag. */
+ bool ra_flag;
+ /*!< Z flag. */
+ bool z_flag;
+ /*!< Authenticated data flag. */
+ bool ad_flag;
+ /*!< Checking disabled flag. */
+ bool cd_flag;
+ /*!< DNSSEC OK flag. */
+ bool do_flag;
+} flags_t;
+
+/*! \brief Basic parameters for DNS query. */
+typedef struct query query_t; // Forward declaration due to configuration.
+struct query {
+ /*!< List node (for list container). */
+ node_t n;
+ /*!< Reference to global config. */
+ const query_t *conf;
+ /*!< Name to query on. */
+ char *owner;
+ /*!< List of nameservers to query to. */
+ list_t servers;
+ /*!< Local interface (optional). */
+ srv_info_t *local;
+ /*!< Operation mode. */
+ operation_t operation;
+ /*!< Version of ip protocol to use. */
+ ip_t ip;
+ /*!< Protocol type (TCP, UDP) to use. */
+ protocol_t protocol;
+ /*!< Use TCP Fast Open. */
+ bool fastopen;
+ /*!< Port/service to connect to. */
+ char *port;
+ /*!< UDP buffer size (16unsigned + -1 uninitialized). */
+ int32_t udp_size;
+ /*!< Number of UDP retries. */
+ uint32_t retries;
+ /*!< Wait for network response in seconds (-1 means forever). */
+ int32_t wait;
+ /*!< Ignore truncated response. */
+ bool ignore_tc;
+ /*!< Class number (16unsigned + -1 uninitialized). */
+ int32_t class_num;
+ /*!< Type number (16unsigned + -1 uninitialized). */
+ int32_t type_num;
+ /*!< SOA serial for IXFR and NOTIFY (32unsigned + -1 uninitialized). */
+ int64_t serial;
+ /*!< NOTIFY query. */
+ bool notify;
+ /*!< Header flags. */
+ flags_t flags;
+ /*!< Output settings. */
+ style_t style;
+ /*!< IDN conversion. */
+ bool idn;
+ /*!< Query for NSID. */
+ bool nsid;
+ /*!< EDNS version (8unsigned + -1 uninitialized). */
+ int16_t edns;
+ /*!< EDNS client cookie. */
+ knot_edns_cookie_t cc;
+ /*!< EDNS server cookie. */
+ knot_edns_cookie_t sc;
+ /*!< Repeat query after BADCOOKIE. */
+ bool badcookie;
+ /*!< EDNS0 padding (16unsigned + -1 ~ uninitialized, -2 ~ default, -3 ~ none). */
+ int32_t padding;
+ /*!< Query alignment with EDNS0 padding (0 ~ uninitialized). */
+ uint16_t alignment;
+ /*!< TLS parameters. */
+ tls_params_t tls;
+ /*!< Transaction signature. */
+ knot_tsig_key_t tsig_key;
+ /*!< EDNS client subnet. */
+ knot_edns_client_subnet_t subnet;
+ /*!< Lits of custom EDNS options. */
+ list_t edns_opts;
+#if USE_DNSTAP
+ /*!< Context for dnstap reader input. */
+ dt_reader_t *dt_reader;
+ /*!< Context for dnstap writer output. */
+ dt_writer_t *dt_writer;
+#endif // USE_DNSTAP
+};
+
+/*! \brief EDNS option data. */
+typedef struct {
+ /*! List node (for list container). */
+ node_t n;
+ /*!< OPTION-CODE field. */
+ uint16_t code;
+ /*!< OPTION-LENGTH field. */
+ uint16_t length;
+ /*!< OPTION-DATA field. */
+ uint8_t *data;
+} ednsopt_t;
+
+/*! \brief Settings for kdig. */
+typedef struct {
+ /*!< Stop processing - just print help, version,... */
+ bool stop;
+ /*!< List of DNS queries to process. */
+ list_t queries;
+ /*!< Default settings for queries. */
+ query_t *config;
+} kdig_params_t;
+
+query_t *query_create(const char *owner, const query_t *config);
+void query_free(query_t *query);
+void complete_queries(list_t *queries, const query_t *conf);
+
+ednsopt_t *ednsopt_create(uint16_t code, uint16_t length, uint8_t *data);
+ednsopt_t *ednsopt_dup(const ednsopt_t *opt);
+void ednsopt_free(ednsopt_t *opt);
+
+void ednsopt_list_init(list_t *list);
+void ednsopt_list_deinit(list_t *list);
+int ednsopt_list_dup(list_t *dst, const list_t *src);
+bool ednsopt_list_empty(const list_t *list);
+
+int kdig_init(kdig_params_t *params);
+int kdig_parse(kdig_params_t *params, int argc, char *argv[]);
+void kdig_clean(kdig_params_t *params);
diff --git a/src/utils/keymgr/bind_privkey.c b/src/utils/keymgr/bind_privkey.c
new file mode 100644
index 0000000..7e140e4
--- /dev/null
+++ b/src/utils/keymgr/bind_privkey.c
@@ -0,0 +1,352 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <string.h>
+
+#include "contrib/ctype.h"
+#include "contrib/strtonum.h"
+#include "libdnssec/binary.h"
+#include "libdnssec/error.h"
+#include "libdnssec/shared/pem.h"
+#include "libdnssec/shared/shared.h"
+#include "utils/keymgr/bind_privkey.h"
+
+/* -- private key params conversion ---------------------------------------- */
+
+/*!
+ * Private key attribute conversion.
+ */
+typedef struct param_t {
+ char *name;
+ size_t offset;
+ int (*parse_cb)(char *string, void *data);
+ void (*free_cb)(void *data);
+} param_t;
+
+static int parse_algorithm(char *string, void *_algorithm);
+static int parse_binary(char *string, void *_binary);
+static int parse_time(char *string, void *_time);
+
+static void binary_free(void *_binary)
+{
+ dnssec_binary_t *binary = _binary;
+ dnssec_binary_free(binary);
+}
+
+/*!
+ * Know attributes in private key file.
+ */
+const param_t PRIVKEY_CONVERSION_TABLE[] = {
+ #define o(field) offsetof(bind_privkey_t, field)
+ { "Algorithm", o(algorithm), parse_algorithm, NULL },
+ { "Modulus", o(modulus), parse_binary, binary_free },
+ { "PublicExponent", o(public_exponent), parse_binary, binary_free },
+ { "PrivateExponent", o(private_exponent), parse_binary, binary_free },
+ { "Prime1", o(prime_one), parse_binary, binary_free },
+ { "Prime2", o(prime_two), parse_binary, binary_free },
+ { "Exponent1", o(exponent_one), parse_binary, binary_free },
+ { "Exponent2", o(exponent_two), parse_binary, binary_free },
+ { "Coefficient", o(coefficient), parse_binary, binary_free },
+ { "PrivateKey", o(private_key), parse_binary, binary_free },
+ { "Created", o(time_created), parse_time, NULL },
+ { "Publish", o(time_publish), parse_time, NULL },
+ { "Activate", o(time_activate), parse_time, NULL },
+ { "Revoke", o(time_revoke), parse_time, NULL },
+ { "Inactive", o(time_inactive), parse_time, NULL },
+ { "Delete", o(time_delete), parse_time, NULL },
+ { NULL }
+ #undef o
+};
+
+/* -- attribute parsing ---------------------------------------------------- */
+
+/*!
+ * Parse key algorithm field.
+ *
+ * Example: 7 (NSEC3RSASHA1)
+ *
+ * Only the numeric value is decoded, the rest of the value is ignored.
+ */
+static int parse_algorithm(char *string, void *_algorithm)
+{
+ char *end = string;
+ while (*end != '\0' && !is_space(*end)) {
+ end += 1;
+ }
+ *end = '\0';
+
+ uint8_t *algorithm = _algorithm;
+ int r = str_to_u8(string, algorithm);
+
+ return (r == KNOT_EOK ? DNSSEC_EOK : DNSSEC_INVALID_KEY_ALGORITHM);
+}
+
+/*!
+ * Parse binary data encoded in Base64.
+ *
+ * Example: AQAB
+ */
+static int parse_binary(char *string, void *_binary)
+{
+ dnssec_binary_t base64 = {
+ .data = (uint8_t *)string,
+ .size = strlen(string)
+ };
+
+ dnssec_binary_t *binary = _binary;
+ return dnssec_binary_from_base64(&base64, binary);
+}
+
+#define LEGACY_DATE_FORMAT "%Y%m%d%H%M%S"
+
+/*!
+ * Parse timestamp in a format in \ref LEGACY_DATE_FORMAT.
+ *
+ * Example: 20140415151855
+ */
+static int parse_time(char *string, void *_time)
+{
+ struct tm tm = { 0 };
+
+ char *end = strptime(string, LEGACY_DATE_FORMAT, &tm);
+ if (end == NULL || *end != '\0') {
+ return DNSSEC_MALFORMED_DATA;
+ }
+
+ time_t *time = _time;
+ *time = timegm(&tm);
+
+ return DNSSEC_EOK;
+}
+
+/* -- key parsing ---------------------------------------------------------- */
+
+/*!
+ * Strip string value of left and right whitespaces.
+ *
+ * \param[in,out] value Start of the string.
+ * \param[in,out] length Length of the string.
+ *
+ */
+static void strip(char **value, size_t *length)
+{
+ // strip from left
+ while (*length > 0 && is_space(**value)) {
+ *value += 1;
+ *length -= 1;
+ }
+ // strip from right
+ while (*length > 0 && is_space((*value)[*length - 1])) {
+ *length -= 1;
+ }
+}
+
+/*!
+ * Parse one line of the private key file.
+ */
+static int parse_line(bind_privkey_t *params, char *line, size_t length)
+{
+ assert(params);
+ assert(line);
+
+ char *separator = memchr(line, ':', length);
+ if (!separator) {
+ return DNSSEC_MALFORMED_DATA;
+ }
+
+ char *key = line;
+ size_t key_length = separator - key;
+ strip(&key, &key_length);
+
+ char *value = separator + 1;
+ size_t value_length = (line + length) - value;
+ strip(&value, &value_length);
+
+ if (key_length == 0 || value_length == 0) {
+ return DNSSEC_MALFORMED_DATA;
+ }
+
+ key[key_length] = '\0';
+ value[value_length] = '\0';
+
+ for (const param_t *p = PRIVKEY_CONVERSION_TABLE; p->name != NULL; p++) {
+ size_t name_length = strlen(p->name);
+ if (name_length != key_length) {
+ continue;
+ }
+
+ if (strcasecmp(p->name, key) != 0) {
+ continue;
+ }
+
+ return p->parse_cb(value, (void *)params + p->offset);
+ }
+
+ // ignore unknown attributes
+
+ return DNSSEC_EOK;
+}
+
+int bind_privkey_parse(const char *filename, bind_privkey_t *params_ptr)
+{
+ _cleanup_fclose_ FILE *file = fopen(filename, "r");
+ if (!file) {
+ return DNSSEC_NOT_FOUND;
+ }
+
+ bind_privkey_t params = { 0 };
+
+ _cleanup_free_ char *line = NULL;
+ size_t size = 0;
+ ssize_t read = 0;
+ while ((read = getline(&line, &size, file)) != -1) {
+ int r = parse_line(&params, line, read);
+ if (r != DNSSEC_EOK) {
+ bind_privkey_free(&params);
+ return r;
+ }
+ }
+
+ *params_ptr = params;
+
+ return DNSSEC_EOK;
+}
+
+/* -- freeing -------------------------------------------------------------- */
+
+/*!
+ * Free private key parameters.
+ */
+void bind_privkey_free(bind_privkey_t *params)
+{
+ if (!params) {
+ return;
+ }
+
+ for (const param_t *p = PRIVKEY_CONVERSION_TABLE; p->name != NULL; p++) {
+ if (p->free_cb) {
+ p->free_cb((void *)params + p->offset);
+ }
+ }
+
+ clear_struct(params);
+}
+
+/* -- export to PEM -------------------------------------------------------- */
+
+static int rsa_params_to_pem(const bind_privkey_t *params, dnssec_binary_t *pem)
+{
+ _cleanup_x509_privkey_ gnutls_x509_privkey_t key = NULL;
+ int result = gnutls_x509_privkey_init(&key);
+ if (result != GNUTLS_E_SUCCESS) {
+ return DNSSEC_ENOMEM;
+ }
+
+ gnutls_datum_t m = binary_to_datum(&params->modulus);
+ gnutls_datum_t e = binary_to_datum(&params->public_exponent);
+ gnutls_datum_t d = binary_to_datum(&params->private_exponent);
+ gnutls_datum_t p = binary_to_datum(&params->prime_one);
+ gnutls_datum_t q = binary_to_datum(&params->prime_two);
+ gnutls_datum_t u = binary_to_datum(&params->coefficient);
+
+ result = gnutls_x509_privkey_import_rsa_raw(key, &m, &e, &d, &p, &q, &u);
+ if (result != GNUTLS_E_SUCCESS) {
+ return DNSSEC_KEY_IMPORT_ERROR;
+ }
+
+ return pem_from_x509(key, pem);
+}
+
+/*!
+ * \see lib/key/convert.h
+ */
+static gnutls_ecc_curve_t choose_ecdsa_curve(size_t pubkey_size)
+{
+ switch (pubkey_size) {
+ case 64: return GNUTLS_ECC_CURVE_SECP256R1;
+ case 96: return GNUTLS_ECC_CURVE_SECP384R1;
+ default: return GNUTLS_ECC_CURVE_INVALID;
+ }
+}
+
+static void ecdsa_extract_public_params(dnssec_key_t *key, gnutls_ecc_curve_t *curve,
+ gnutls_datum_t *x, gnutls_datum_t *y)
+{
+ dnssec_binary_t pubkey = { 0 };
+ dnssec_key_get_pubkey(key, &pubkey);
+
+ *curve = choose_ecdsa_curve(pubkey.size);
+
+ size_t param_size = pubkey.size / 2;
+ x->data = pubkey.data;
+ x->size = param_size;
+ y->data = pubkey.data + param_size;
+ y->size = param_size;
+}
+
+static int ecdsa_params_to_pem(dnssec_key_t *dnskey, const bind_privkey_t *params,
+ dnssec_binary_t *pem)
+{
+ _cleanup_x509_privkey_ gnutls_x509_privkey_t key = NULL;
+ int result = gnutls_x509_privkey_init(&key);
+ if (result != GNUTLS_E_SUCCESS) {
+ return DNSSEC_ENOMEM;
+ }
+
+ gnutls_ecc_curve_t curve = 0;
+ gnutls_datum_t x = { 0 };
+ gnutls_datum_t y = { 0 };
+ ecdsa_extract_public_params(dnskey, &curve, &x, &y);
+
+ gnutls_datum_t k = binary_to_datum(&params->private_key);
+
+ result = gnutls_x509_privkey_import_ecc_raw(key, curve, &x, &y, &k);
+ if (result != DNSSEC_EOK) {
+ return DNSSEC_KEY_IMPORT_ERROR;
+ }
+
+ gnutls_x509_privkey_fix(key);
+
+ return pem_from_x509(key, pem);
+}
+
+int bind_privkey_to_pem(dnssec_key_t *key, bind_privkey_t *params, dnssec_binary_t *pem)
+{
+ dnssec_key_algorithm_t algorithm = dnssec_key_get_algorithm(key);
+ switch (algorithm) {
+ case DNSSEC_KEY_ALGORITHM_RSA_SHA1:
+ case DNSSEC_KEY_ALGORITHM_RSA_SHA1_NSEC3:
+ case DNSSEC_KEY_ALGORITHM_RSA_SHA256:
+ case DNSSEC_KEY_ALGORITHM_RSA_SHA512:
+ return rsa_params_to_pem(params, pem);
+ case DNSSEC_KEY_ALGORITHM_ECDSA_P256_SHA256:
+ case DNSSEC_KEY_ALGORITHM_ECDSA_P384_SHA384:
+ return ecdsa_params_to_pem(key, params, pem);
+ default:
+ return DNSSEC_INVALID_KEY_ALGORITHM;
+ }
+}
+
+void bind_privkey_to_timing(bind_privkey_t *params, knot_kasp_key_timing_t *timing)
+{
+ // unsupported: time_created, time_revoke
+
+ timing->publish = (knot_time_t)params->time_publish;
+ timing->ready = 0;
+ timing->active = (knot_time_t)params->time_activate;
+ timing->retire = (knot_time_t)params->time_inactive;
+ timing->remove = (knot_time_t)params->time_delete;
+}
diff --git a/src/utils/keymgr/bind_privkey.h b/src/utils/keymgr/bind_privkey.h
new file mode 100644
index 0000000..6c58e1d
--- /dev/null
+++ b/src/utils/keymgr/bind_privkey.h
@@ -0,0 +1,72 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <stdint.h>
+#include <time.h>
+
+#include "libdnssec/binary.h"
+#include "knot/dnssec/kasp/policy.h"
+
+/*!
+ * Legacy private key parameters.
+ */
+typedef struct {
+ // key information
+ uint8_t algorithm;
+
+ // RSA
+ dnssec_binary_t modulus;
+ dnssec_binary_t public_exponent;
+ dnssec_binary_t private_exponent;
+ dnssec_binary_t prime_one;
+ dnssec_binary_t prime_two;
+ dnssec_binary_t exponent_one;
+ dnssec_binary_t exponent_two;
+ dnssec_binary_t coefficient;
+
+ // ECDSA
+ dnssec_binary_t private_key;
+
+ // key lifetime
+ time_t time_created;
+ time_t time_publish;
+ time_t time_activate;
+ time_t time_revoke;
+ time_t time_inactive;
+ time_t time_delete;
+} bind_privkey_t;
+
+/*!
+ * Extract parameters from legacy private key file.
+ */
+int bind_privkey_parse(const char *filename, bind_privkey_t *params);
+
+/*!
+ * Free private key parameters.
+ */
+void bind_privkey_free(bind_privkey_t *params);
+
+/*!
+ * Generate PEM from pub&priv key.
+ */
+int bind_privkey_to_pem(dnssec_key_t *key, bind_privkey_t *params, dnssec_binary_t *pem);
+
+/*!
+ * Extract timing info.
+ */
+void bind_privkey_to_timing(bind_privkey_t *params, knot_kasp_key_timing_t *timing);
diff --git a/src/utils/keymgr/functions.c b/src/utils/keymgr/functions.c
new file mode 100644
index 0000000..3672928
--- /dev/null
+++ b/src/utils/keymgr/functions.c
@@ -0,0 +1,879 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <limits.h>
+#include <string.h>
+#include <strings.h>
+#include <time.h>
+#include <fcntl.h>
+
+#include "utils/keymgr/functions.h"
+#include "utils/keymgr/bind_privkey.h"
+#include "contrib/base64.h"
+#include "contrib/ctype.h"
+#include "contrib/tolower.h"
+#include "contrib/wire_ctx.h"
+#include "libdnssec/error.h"
+#include "libdnssec/shared/hex.h"
+#include "libdnssec/shared/shared.h"
+#include "knot/dnssec/kasp/policy.h"
+#include "knot/dnssec/zone-keys.h"
+#include "libzscanner/scanner.h"
+
+static bool is_timestamp(char *arg, knot_kasp_key_timing_t *timing)
+{
+ knot_time_t *dst = NULL;
+
+ if (strncasecmp(arg, "created=", 8) == 0) {
+ dst = &timing->created;
+ } else if (strncasecmp(arg, "publish=", 8) == 0) {
+ dst = &timing->publish;
+ } else if (strncasecmp(arg, "ready=", 6) == 0) {
+ dst = &timing->ready;
+ } else if (strncasecmp(arg, "active=", 7) == 0) {
+ dst = &timing->active;
+ } else if (strncasecmp(arg, "retire=", 7) == 0) {
+ dst = &timing->retire;
+ } else if (strncasecmp(arg, "remove=", 7) == 0) {
+ dst = &timing->remove;
+ } else if (strncasecmp(arg, "pre_active=", 11) == 0) {
+ dst = &timing->pre_active;
+ } else if (strncasecmp(arg, "post_active=", 12) == 0) {
+ dst = &timing->post_active;
+ } else if (strncasecmp(arg, "retire_active=", 14) == 0) {
+ dst = &timing->retire_active;
+ } else {
+ return false;
+ }
+
+ knot_time_t stamp;
+ int ret = knot_time_parse("YMDhms|'now'+-#u|'t'+-#u|+-#u|'t'+-#|+-#|#",
+ strchr(arg, '=') + 1, &stamp);
+ if (ret < 0) {
+ printf("Invalid timestamp: %s\n", arg);
+ return true;
+ }
+
+ *dst = stamp;
+
+ return true;
+}
+
+static bool str2bool(const char *s)
+{
+ switch (knot_tolower(s[0])) {
+ case '1':
+ case 'y':
+ case 't':
+ return true;
+ default:
+ return false;
+ }
+}
+
+static void bitmap_set(kdnssec_generate_flags_t *bitmap, int flag, bool onoff)
+{
+ if (onoff) {
+ *bitmap |= flag;
+ } else {
+ *bitmap &= ~flag;
+ }
+}
+
+static bool genkeyargs(int argc, char *argv[], bool just_timing,
+ kdnssec_generate_flags_t *flags, dnssec_key_algorithm_t *algorithm,
+ uint16_t *keysize, knot_kasp_key_timing_t *timing,
+ const char **addtopolicy)
+{
+ // generate algorithms field
+ char *algnames[256] = { 0 };
+ algnames[DNSSEC_KEY_ALGORITHM_RSA_SHA1] = "rsasha1";
+ algnames[DNSSEC_KEY_ALGORITHM_RSA_SHA1_NSEC3] = "rsasha1nsec3sha1";
+ algnames[DNSSEC_KEY_ALGORITHM_RSA_SHA256] = "rsasha256";
+ algnames[DNSSEC_KEY_ALGORITHM_RSA_SHA512] = "rsasha512";
+ algnames[DNSSEC_KEY_ALGORITHM_ECDSA_P256_SHA256] = "ecdsap256sha256";
+ algnames[DNSSEC_KEY_ALGORITHM_ECDSA_P384_SHA384] = "ecdsap384sha384";
+ algnames[DNSSEC_KEY_ALGORITHM_ED25519] = "ed25519";
+
+ // parse args
+ for (int i = 0; i < argc; i++) {
+ if (!just_timing && strncasecmp(argv[i], "algorithm=", 10) == 0) {
+ if (is_digit(argv[i][10]) && atol(argv[i] + 10) < 256) {
+ *algorithm = atol(argv[i] + 10);
+ continue;
+ }
+ int al;
+ for (al = 0; al < 256; al++) {
+ if (algnames[al] != NULL &&
+ strcasecmp(argv[i] + 10, algnames[al]) == 0) {
+ *algorithm = al;
+ break;
+ }
+ }
+ if (al == 256) {
+ printf("Unknown algorithm: %s\n", argv[i] + 10);
+ return false;
+ }
+ } else if (strncasecmp(argv[i], "ksk=", 4) == 0) {
+ bitmap_set(flags, DNSKEY_GENERATE_KSK, str2bool(argv[i] + 4));
+ } else if (strncasecmp(argv[i], "zsk=", 4) == 0) {
+ bitmap_set(flags, DNSKEY_GENERATE_ZSK, str2bool(argv[i] + 4));
+ } else if (!just_timing && strncasecmp(argv[i], "sep=", 4) == 0) {
+ bitmap_set(flags, DNSKEY_GENERATE_SEP_SPEC, true);
+ bitmap_set(flags, DNSKEY_GENERATE_SEP_ON, str2bool(argv[i] + 4));
+ } else if (!just_timing && strncasecmp(argv[i], "size=", 5) == 0) {
+ *keysize = atol(argv[i] + 5);
+ } else if (!just_timing && strncasecmp(argv[i], "addtopolicy=", 12) == 0) {
+ *addtopolicy = argv[i] + 12;
+ } else if (!is_timestamp(argv[i], timing)) {
+ printf("Invalid parameter: %s\n", argv[i]);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool _check_lower(knot_time_t a, knot_time_t b,
+ const char *a_name, const char *b_name)
+{
+ if (knot_time_cmp(a, b) > 0) {
+ fprintf(stderr, "Semantic error: expected '%s' before '%s'.\n", a_name, b_name);
+ return false;
+ }
+ return true;
+}
+
+#define check_lower(t, a, b) if (!_check_lower(t->a, t->b, #a, #b)) return KNOT_ESEMCHECK
+
+static int check_timers(const knot_kasp_key_timing_t *t)
+{
+ check_lower(t, publish, active);
+ check_lower(t, active, retire_active);
+ check_lower(t, active, retire);
+ check_lower(t, active, post_active);
+ if (t->post_active == 0) {
+ check_lower(t, retire, remove);
+ }
+ return KNOT_EOK;
+}
+
+#undef check_lower
+
+// modifies ctx->policy options, so don't do anything afterwards !
+int keymgr_generate_key(kdnssec_ctx_t *ctx, int argc, char *argv[])
+{
+ knot_time_t now = knot_time(), infty = 0;
+ knot_kasp_key_timing_t gen_timing = { now, infty, now, infty, now, infty, infty, infty, infty };
+ kdnssec_generate_flags_t flags = 0;
+ uint16_t keysize = 0;
+ const char *addtopolicy = NULL;
+ if (!genkeyargs(argc, argv, false, &flags, &ctx->policy->algorithm,
+ &keysize, &gen_timing, &addtopolicy)) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = check_timers(&gen_timing);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ if ((flags & DNSKEY_GENERATE_KSK) && gen_timing.ready == infty) {
+ gen_timing.ready = gen_timing.active;
+ }
+
+ if (keysize > 0) {
+ if ((flags & DNSKEY_GENERATE_KSK)) {
+ ctx->policy->ksk_size = keysize;
+ } else {
+ ctx->policy->zsk_size = keysize;
+ }
+ }
+
+ for (size_t i = 0; i < ctx->zone->num_keys; i++) {
+ knot_kasp_key_t *kasp_key = &ctx->zone->keys[i];
+ if ((kasp_key->is_ksk && (flags & DNSKEY_GENERATE_KSK)) &&
+ dnssec_key_get_algorithm(kasp_key->key) != ctx->policy->algorithm) {
+ printf("warning: creating key with different algorithm than "
+ "configured in the policy\n");
+ break;
+ }
+ }
+
+ knot_kasp_key_t *key = NULL;
+ ret = kdnssec_generate_key(ctx, flags, &key);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ key->timing = gen_timing;
+
+ if (addtopolicy != NULL) {
+ char *last_policy_last = NULL;
+
+ knot_dname_t *unused = NULL;
+ ret = kasp_db_get_policy_last(*ctx->kasp_db, addtopolicy, &unused,
+ &last_policy_last);
+ knot_dname_free(unused, NULL);
+ if (ret != KNOT_EOK && ret != KNOT_ENOENT) {
+ return ret;
+ }
+
+ ret = kasp_db_set_policy_last(*ctx->kasp_db, addtopolicy, last_policy_last,
+ ctx->zone->dname, key->id);
+ free(last_policy_last);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ ret = kdnssec_ctx_commit(ctx);
+
+ if (ret == KNOT_EOK) {
+ printf("%s\n", key->id);
+ }
+
+ return ret;
+}
+
+static void parse_record(zs_scanner_t *scanner)
+{
+ dnssec_key_t *key = scanner->process.data;
+
+ if (dnssec_key_get_dname(key) != NULL ||
+ scanner->r_type != KNOT_RRTYPE_DNSKEY) {
+ scanner->state = ZS_STATE_STOP;
+ return;
+ }
+
+ dnssec_binary_t rdata = {
+ .data = scanner->r_data,
+ .size = scanner->r_data_length
+ };
+ dnssec_key_set_dname(key, scanner->dname);
+ dnssec_key_set_rdata(key, &rdata);
+}
+
+int bind_pubkey_parse(const char *filename, dnssec_key_t **key_ptr)
+{
+ dnssec_key_t *key = NULL;
+ int result = dnssec_key_new(&key);
+ if (result != DNSSEC_EOK) {
+ return KNOT_ENOMEM;
+ }
+
+ uint16_t cls = KNOT_CLASS_IN;
+ uint32_t ttl = 0;
+ zs_scanner_t *scanner = malloc(sizeof(zs_scanner_t));
+ if (scanner == NULL) {
+ dnssec_key_free(key);
+ return KNOT_ENOMEM;
+ }
+
+ if (zs_init(scanner, ".", cls, ttl) != 0 ||
+ zs_set_input_file(scanner, filename) != 0 ||
+ zs_set_processing(scanner, parse_record, NULL, key) != 0 ||
+ zs_parse_all(scanner) != 0) {
+ zs_deinit(scanner);
+ free(scanner);
+ dnssec_key_free(key);
+ return KNOT_ENOENT;
+ }
+ zs_deinit(scanner);
+ free(scanner);
+
+ if (dnssec_key_get_dname(key) == NULL) {
+ dnssec_key_free(key);
+ return KNOT_INVALID_PUBLIC_KEY;
+ }
+
+ *key_ptr = key;
+ return KNOT_EOK;
+}
+
+static char *genname(const char *orig, const char *wantsuff, const char *altsuff)
+{
+ char *res;
+ if (orig == NULL || wantsuff == NULL || altsuff == NULL ||
+ (res = malloc(strlen(orig) + strlen(wantsuff) + 1)) == NULL) {
+ return NULL;
+ }
+ strcpy(res, orig);
+ char *dot = strrchr(res, '.');
+ if (dot != NULL && strcmp(dot, wantsuff) == 0) {
+ ;
+ } else if (dot != NULL && strcmp(dot, altsuff) == 0) {
+ strcpy(dot, wantsuff);
+ } else {
+ strcat(res, wantsuff);
+ }
+ return res;
+}
+
+int keymgr_import_bind(kdnssec_ctx_t *ctx, const char *import_file, bool pub_only)
+{
+ if (ctx == NULL || import_file == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ knot_kasp_key_timing_t timing = { 0 };
+ dnssec_key_t *key = NULL;
+ char *keyid = NULL;
+
+ char *pubname = genname(import_file, ".key", ".private");
+ if (pubname == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = bind_pubkey_parse(pubname, &key);
+ free(pubname);
+ if (ret != KNOT_EOK) {
+ goto fail;
+ }
+
+ if (!pub_only) {
+ bind_privkey_t bpriv = { 0 };
+
+ char *privname = genname(import_file, ".private", ".key");
+ if (privname == NULL) {
+ goto fail;
+ }
+
+ ret = bind_privkey_parse(privname, &bpriv);
+ free(privname);
+ if (ret != DNSSEC_EOK) {
+ goto fail;
+ }
+
+ dnssec_binary_t pem = { 0 };
+ ret = bind_privkey_to_pem(key, &bpriv, &pem);
+ if (ret != DNSSEC_EOK) {
+ bind_privkey_free(&bpriv);
+ goto fail;
+ }
+
+ bind_privkey_to_timing(&bpriv, &timing); // time created remains always zero
+
+ bind_privkey_free(&bpriv);
+
+ ret = dnssec_keystore_import(ctx->keystore, &pem, &keyid);
+ dnssec_binary_free(&pem);
+ if (ret != DNSSEC_EOK) {
+ goto fail;
+ }
+ } else {
+ timing.publish = ctx->now;
+
+ ret = dnssec_key_get_keyid(key, &keyid);
+ if (ret != DNSSEC_EOK) {
+ goto fail;
+ }
+ }
+
+ // allocate kasp key
+ knot_kasp_key_t *kkey = calloc(1, sizeof(*kkey));
+ if (!kkey) {
+ ret = KNOT_ENOMEM;
+ goto fail;
+ }
+
+ kkey->id = keyid;
+ kkey->key = key;
+ kkey->timing = timing;
+ kkey->is_pub_only = pub_only;
+ kkey->is_ksk = (dnssec_key_get_flags(kkey->key) == DNSKEY_FLAGS_KSK);
+ kkey->is_zsk = !kkey->is_ksk;
+
+ // append to zone
+ ret = kasp_zone_append(ctx->zone, kkey);
+ free(kkey);
+ if (ret != KNOT_EOK) {
+ goto fail;
+ }
+ ret = kdnssec_ctx_commit(ctx);
+ if (ret == KNOT_EOK) {
+ printf("%s\n", keyid);
+ return KNOT_EOK;
+ }
+fail:
+ dnssec_key_free(key);
+ free(keyid);
+ return knot_error_from_libdnssec(ret);
+}
+
+static int import_key(kdnssec_ctx_t *ctx, unsigned backend, const char *param,
+ int argc, char *argv[])
+{
+ if (ctx == NULL || param == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ // parse params
+ knot_time_t now = knot_time();
+ knot_kasp_key_timing_t timing = { .publish = now, .active = now };
+ kdnssec_generate_flags_t flags = 0;
+ uint16_t keysize = 0;
+ if (!genkeyargs(argc, argv, false, &flags, &ctx->policy->algorithm,
+ &keysize, &timing, NULL)) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = check_timers(&timing);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ normalize_generate_flags(&flags);
+
+ dnssec_key_t *key = NULL;
+ char *keyid = NULL;
+
+ if (backend == KEYSTORE_BACKEND_PEM) {
+ // open file
+ int fd = open(param, O_RDONLY, 0);
+ if (fd == -1) {
+ return knot_map_errno();
+ }
+
+ // determine size
+ off_t fsize = lseek(fd, 0, SEEK_END);
+ if (fsize == -1) {
+ close(fd);
+ return knot_map_errno();
+ }
+ if (lseek(fd, 0, SEEK_SET) == -1) {
+ close(fd);
+ return knot_map_errno();
+ }
+
+ // alloc memory
+ dnssec_binary_t pem = { 0 };
+ ret = dnssec_binary_alloc(&pem, fsize);
+ if (ret != DNSSEC_EOK) {
+ close(fd);
+ goto fail;
+ }
+
+ // read pem
+ ssize_t read_count = read(fd, pem.data, pem.size);
+ close(fd);
+ if (read_count == -1) {
+ dnssec_binary_free(&pem);
+ ret = knot_map_errno();
+ goto fail;
+ }
+
+ // put pem to kesytore
+ ret = dnssec_keystore_import(ctx->keystore, &pem, &keyid);
+ dnssec_binary_free(&pem);
+ if (ret != DNSSEC_EOK) {
+ goto fail;
+ }
+ } else {
+ assert(backend == KEYSTORE_BACKEND_PKCS11);
+ keyid = strdup(param);
+ }
+
+ // create dnssec key
+ ret = dnssec_key_new(&key);
+ if (ret != DNSSEC_EOK) {
+ goto fail;
+ }
+ ret = dnssec_key_set_dname(key, ctx->zone->dname);
+ if (ret != DNSSEC_EOK) {
+ goto fail;
+ }
+ dnssec_key_set_flags(key, dnskey_flags(flags & DNSKEY_GENERATE_SEP_ON));
+ dnssec_key_set_algorithm(key, ctx->policy->algorithm);
+
+ // fill key structure from keystore (incl. pubkey from privkey computation)
+ ret = dnssec_key_import_keystore(key, ctx->keystore, keyid);
+ if (ret != DNSSEC_EOK) {
+ goto fail;
+ }
+
+ // allocate kasp key
+ knot_kasp_key_t *kkey = calloc(1, sizeof(*kkey));
+ if (kkey == NULL) {
+ ret = KNOT_ENOMEM;
+ goto fail;
+ }
+ kkey->id = keyid;
+ kkey->key = key;
+ kkey->timing = timing;
+ kkey->is_ksk = (flags & DNSKEY_GENERATE_KSK);
+ kkey->is_zsk = (flags & DNSKEY_GENERATE_ZSK);
+
+ // append to zone
+ ret = kasp_zone_append(ctx->zone, kkey);
+ free(kkey);
+ if (ret != KNOT_EOK) {
+ goto fail;
+ }
+ ret = kdnssec_ctx_commit(ctx);
+ if (ret == KNOT_EOK) {
+ printf("%s\n", keyid);
+ return KNOT_EOK;
+ }
+fail:
+ dnssec_key_free(key);
+ free(keyid);
+ return knot_error_from_libdnssec(ret);
+}
+
+int keymgr_import_pem(kdnssec_ctx_t *ctx, const char *import_file, int argc, char *argv[])
+{
+ return import_key(ctx, KEYSTORE_BACKEND_PEM, import_file, argc, argv);
+}
+
+int keymgr_import_pkcs11(kdnssec_ctx_t *ctx, const char *key_id, int argc, char *argv[])
+{
+ return import_key(ctx, KEYSTORE_BACKEND_PKCS11, key_id, argc, argv);
+}
+
+int keymgr_nsec3_salt_print(kdnssec_ctx_t *ctx)
+{
+ dnssec_binary_t salt_bin;
+ knot_time_t created;
+ int ret = kasp_db_load_nsec3salt(*ctx->kasp_db, ctx->zone->dname,
+ &salt_bin, &created);
+ switch (ret) {
+ case KNOT_EOK:
+ printf("Current salt: ");
+ if (salt_bin.size == 0) {
+ printf("-");
+ }
+ for (size_t i = 0; i < salt_bin.size; i++) {
+ printf("%02X", (unsigned)salt_bin.data[i]);
+ }
+ printf("\n");
+ free(salt_bin.data);
+ break;
+ case KNOT_ENOENT:
+ printf("-- no salt --\n");
+ ret = KNOT_EOK;
+ break;
+ }
+ return ret;
+}
+
+int keymgr_nsec3_salt_set(kdnssec_ctx_t *ctx, const char *new_salt)
+{
+ assert(new_salt);
+
+ dnssec_binary_t salt_bin = { 0 };
+ if (strcmp(new_salt, "-") != 0 &&
+ hex_to_bin(new_salt, &salt_bin) != DNSSEC_EOK) {
+ return KNOT_EMALF;
+ }
+ if (salt_bin.size != ctx->policy->nsec3_salt_length) {
+ printf("Warning: specified salt doesn't match configured "
+ "salt length (%d).\n",
+ (int)ctx->policy->nsec3_salt_length);
+ }
+ int ret = kasp_db_store_nsec3salt(*ctx->kasp_db, ctx->zone->dname,
+ &salt_bin, knot_time());
+ if (salt_bin.size > 0) {
+ free(salt_bin.data);
+ }
+ return ret;
+}
+
+static void print_tsig(dnssec_tsig_algorithm_t mac, const char *name,
+ const dnssec_binary_t *secret)
+{
+ assert(name);
+ assert(secret);
+
+ const char *mac_name = dnssec_tsig_algorithm_to_name(mac);
+ assert(mac_name);
+
+ // client format (as a comment)
+ printf("# %s:%s:%.*s\n", mac_name, name, (int)secret->size, secret->data);
+
+ // server format
+ printf("key:\n");
+ printf(" - id: %s\n", name);
+ printf(" algorithm: %s\n", mac_name);
+ printf(" secret: %.*s\n", (int)secret->size, secret->data);
+}
+
+int keymgr_generate_tsig(const char *tsig_name, const char *alg_name, int bits)
+{
+ dnssec_tsig_algorithm_t alg = dnssec_tsig_algorithm_from_name(alg_name);
+ if (alg == DNSSEC_TSIG_UNKNOWN) {
+ return KNOT_INVALID_KEY_ALGORITHM;
+ }
+
+ int optimal_bits = dnssec_tsig_optimal_key_size(alg);
+ if (bits == 0) {
+ bits = optimal_bits; // TODO review
+ }
+
+ // round up bits to bytes
+ bits = (bits + CHAR_BIT - 1) / CHAR_BIT * CHAR_BIT;
+
+ if (bits != optimal_bits) {
+ printf("Notice: Optimal key size for %s is %d bits.",
+ dnssec_tsig_algorithm_to_name(alg), optimal_bits);
+ }
+ assert(bits % CHAR_BIT == 0);
+
+ _cleanup_binary_ dnssec_binary_t key = { 0 };
+ int r = dnssec_binary_alloc(&key, bits / CHAR_BIT);
+ if (r != DNSSEC_EOK) {
+ printf("Failed to allocate memory.");
+ return knot_error_from_libdnssec(r);
+ }
+
+ r = gnutls_rnd(GNUTLS_RND_KEY, key.data, key.size);
+ if (r != 0) {
+ printf("Failed to generate secret the key.");
+ return knot_error_from_libdnssec(r);
+ }
+
+ _cleanup_binary_ dnssec_binary_t key_b64 = { 0 };
+ r = dnssec_binary_to_base64(&key, &key_b64);
+ if (r != DNSSEC_EOK) {
+ printf("Failed to convert the key to Base64.");
+ return knot_error_from_libdnssec(r);
+ }
+
+ print_tsig(alg, tsig_name, &key_b64);
+
+ return KNOT_EOK;
+}
+
+static long is_uint32(const char *string)
+{
+ if (*string == '\0') {
+ return -1;
+ }
+ for (const char *p = string; *p != '\0'; p++) {
+ if (!is_digit(*p)) {
+ return -1;
+ }
+ }
+ long res = atol(string);
+ return (res <= UINT32_MAX ? res : -1);
+}
+
+static bool is_hex(const char *string)
+{
+ for (const char *p = string; *p != '\0'; p++) {
+ if (!is_xdigit(*p)) {
+ return false;
+ }
+ }
+ return (*string != '\0');
+}
+
+int keymgr_get_key(kdnssec_ctx_t *ctx, const char *key_spec, knot_kasp_key_t **key)
+{
+ long spec_tag = is_uint32(key_spec), spec_len = strlen(key_spec);
+ if (spec_tag < 0 && !is_hex(key_spec)) {
+ printf("Error in key specification.\n");
+ return KNOT_EINVAL;
+ }
+
+ *key = NULL;
+ for (size_t i = 0; i < ctx->zone->num_keys; i++) {
+ knot_kasp_key_t *candidate = &ctx->zone->keys[i];
+ if ((spec_tag >= 0 && dnssec_key_get_keytag(candidate->key) == spec_tag) ||
+ (spec_tag < 0 && strncmp(candidate->id, key_spec, spec_len) == 0)) {
+ if (*key == NULL) {
+ *key = candidate;
+ }
+ else {
+ printf("Key is not specified uniquely.\n");
+ return KNOT_ELIMIT;
+ }
+ }
+ }
+ if (*key == NULL) {
+ printf("Key not found.\n");
+ return KNOT_ENOENT;
+ }
+ return KNOT_EOK;
+}
+
+int keymgr_foreign_key_id(char *argv[], knot_dname_t **key_zone, char **key_id)
+{
+ *key_zone = knot_dname_from_str_alloc(argv[0]);
+ if (*key_zone == NULL) {
+ return KNOT_ENOMEM;
+ }
+ knot_dname_to_lower(*key_zone);
+
+ kdnssec_ctx_t kctx = { 0 };
+ int ret = kdnssec_ctx_init(conf(), &kctx, *key_zone, NULL);
+ if (ret != KNOT_EOK) {
+ printf("Failed to initialize zone %s (%s)\n", argv[0], knot_strerror(ret));
+ free(*key_zone);
+ *key_zone = NULL;
+ return KNOT_ENOZONE;
+ }
+ knot_kasp_key_t *key;
+ ret = keymgr_get_key(&kctx, argv[2], &key);
+ if (ret == KNOT_EOK) {
+ *key_id = strdup(key->id);
+ if (*key_id == NULL) {
+ ret = KNOT_ENOMEM;
+ }
+ }
+ kdnssec_ctx_deinit(&kctx);
+ return ret;
+}
+
+int keymgr_set_timing(knot_kasp_key_t *key, int argc, char *argv[])
+{
+ knot_kasp_key_timing_t temp = key->timing;
+ kdnssec_generate_flags_t flags = ((key->is_ksk ? DNSKEY_GENERATE_KSK : 0) | (key->is_zsk ? DNSKEY_GENERATE_ZSK : 0));
+
+ if (genkeyargs(argc, argv, true, &flags, NULL, NULL, &temp, NULL)) {
+ int ret = check_timers(&temp);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ key->timing = temp;
+ key->is_ksk = (flags & DNSKEY_GENERATE_KSK);
+ key->is_zsk = (flags & DNSKEY_GENERATE_ZSK);
+ return KNOT_EOK;
+ }
+ return KNOT_EINVAL;
+}
+
+static void print_timer(const char *name, knot_time_t t, knot_time_print_t format,
+ char separator)
+{
+ static char buff[100];
+ if (knot_time_print(format, t, buff, sizeof(buff)) < 0) {
+ printf("%s=(error)%c", name, separator); // shall not happen
+ } else {
+ printf("%s=%s%c", name, buff, separator);
+ }
+}
+
+int keymgr_list_keys(kdnssec_ctx_t *ctx, knot_time_print_t format)
+{
+ for (size_t i = 0; i < ctx->zone->num_keys; i++) {
+ knot_kasp_key_t *key = &ctx->zone->keys[i];
+ printf("%s ksk=%s zsk=%s tag=%05d algorithm=%-2d size=%-4u public-only=%s ", key->id,
+ (key->is_ksk ? "yes" : "no "), (key->is_zsk ? "yes" : "no "),
+ dnssec_key_get_keytag(key->key), (int)dnssec_key_get_algorithm(key->key),
+ dnssec_key_get_size(key->key), (key->is_pub_only ? "yes" : "no "));
+ print_timer("created", key->timing.created, format, ' ');
+ print_timer("pre-active", key->timing.pre_active, format, ' ');
+ print_timer("publish", key->timing.publish, format, ' ');
+ print_timer("ready", key->timing.ready, format, ' ');
+ print_timer("active", key->timing.active, format, ' ');
+ print_timer("retire-active", key->timing.retire_active, format, ' ');
+ print_timer("retire", key->timing.retire, format, ' ');
+ print_timer("post-active", key->timing.post_active, format, ' ');
+ print_timer("remove", key->timing.remove, format, '\n');
+ }
+ return KNOT_EOK;
+}
+
+static int print_ds(const knot_dname_t *dname, const dnssec_binary_t *rdata)
+{
+ wire_ctx_t ctx = wire_ctx_init(rdata->data, rdata->size);
+ if (wire_ctx_available(&ctx) < 4) {
+ return KNOT_EMALF;
+ }
+
+ char *name = knot_dname_to_str_alloc(dname);
+ if (!name) {
+ return KNOT_ENOMEM;
+ }
+
+ uint16_t keytag = wire_ctx_read_u16(&ctx);
+ uint8_t algorithm = wire_ctx_read_u8(&ctx);
+ uint8_t digest_type = wire_ctx_read_u8(&ctx);
+
+ size_t digest_size = wire_ctx_available(&ctx);
+
+ printf("%s DS %d %d %d ", name, keytag, algorithm, digest_type);
+ for (size_t i = 0; i < digest_size; i++) {
+ printf("%02x", ctx.position[i]);
+ }
+ printf("\n");
+
+ free(name);
+ return KNOT_EOK;
+}
+
+static int create_and_print_ds(const knot_dname_t *zone_name,
+ const dnssec_key_t *key, dnssec_key_digest_t digest)
+{
+ _cleanup_binary_ dnssec_binary_t rdata = { 0 };
+ int r = dnssec_key_create_ds(key, digest, &rdata);
+ if (r != DNSSEC_EOK) {
+ return knot_error_from_libdnssec(r);
+ }
+
+ return print_ds(zone_name, &rdata);
+}
+
+int keymgr_generate_ds(const knot_dname_t *dname, const knot_kasp_key_t *key)
+{
+ static const dnssec_key_digest_t digests[] = {
+ DNSSEC_KEY_DIGEST_SHA1,
+ DNSSEC_KEY_DIGEST_SHA256,
+ DNSSEC_KEY_DIGEST_SHA384,
+ 0
+ };
+
+ int ret = KNOT_EOK;
+ for (int i = 0; digests[i] != 0 && ret == KNOT_EOK; i++) {
+ ret = create_and_print_ds(dname, key->key, digests[i]);
+ }
+
+ return ret;
+}
+
+int keymgr_generate_dnskey(const knot_dname_t *dname, const knot_kasp_key_t *key)
+{
+ const dnssec_key_t *dnskey = key->key;
+
+ char *name = knot_dname_to_str_alloc(dname);
+ if (!name) {
+ return KNOT_ENOMEM;
+ }
+
+ uint16_t flags = dnssec_key_get_flags(dnskey);
+ uint8_t algorithm = dnssec_key_get_algorithm(dnskey);
+
+ dnssec_binary_t pubkey = { 0 };
+ int ret = dnssec_key_get_pubkey(dnskey, &pubkey);
+ if (ret != DNSSEC_EOK) {
+ free(name);
+ return knot_error_from_libdnssec(ret);
+ }
+
+ uint8_t *base64_output = NULL;
+ int len = base64_encode_alloc(pubkey.data, pubkey.size, &base64_output);
+ if (len < 0) {
+ free(name);
+ return len;
+ }
+
+ printf("%s DNSKEY %u 3 %u %.*s\n", name, flags, algorithm, len, base64_output);
+
+ free(base64_output);
+ free(name);
+ return KNOT_EOK;
+}
diff --git a/src/utils/keymgr/functions.h b/src/utils/keymgr/functions.h
new file mode 100644
index 0000000..0dcf9cc
--- /dev/null
+++ b/src/utils/keymgr/functions.h
@@ -0,0 +1,45 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include "knot/dnssec/context.h"
+
+int keymgr_generate_key(kdnssec_ctx_t *ctx, int argc, char *argv[]);
+
+int keymgr_import_bind(kdnssec_ctx_t *ctx, const char *import_file, bool pub_only);
+
+int keymgr_import_pem(kdnssec_ctx_t *ctx, const char *import_file, int argc, char *argv[]);
+
+int keymgr_import_pkcs11(kdnssec_ctx_t *ctx, const char *key_id, int argc, char *argv[]);
+
+int keymgr_nsec3_salt_print(kdnssec_ctx_t *ctx);
+
+int keymgr_nsec3_salt_set(kdnssec_ctx_t *ctx, const char *new_salt);
+
+int keymgr_generate_tsig(const char *tsig_name, const char *alg_name, int bits);
+
+int keymgr_get_key(kdnssec_ctx_t *ctx, const char *key_spec, knot_kasp_key_t **key);
+
+int keymgr_foreign_key_id(char *argv[], knot_dname_t **key_zone, char **key_id);
+
+int keymgr_set_timing(knot_kasp_key_t *key, int argc, char *argv[]);
+
+int keymgr_list_keys(kdnssec_ctx_t *ctx, knot_time_print_t format);
+
+int keymgr_generate_ds(const knot_dname_t *dname, const knot_kasp_key_t *key);
+
+int keymgr_generate_dnskey(const knot_dname_t *dname, const knot_kasp_key_t *key);
diff --git a/src/utils/keymgr/main.c b/src/utils/keymgr/main.c
new file mode 100644
index 0000000..0ed388f
--- /dev/null
+++ b/src/utils/keymgr/main.c
@@ -0,0 +1,373 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <getopt.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "contrib/string.h"
+#include "knot/conf/conf.h"
+#include "knot/dnssec/zone-keys.h"
+#include "libknot/libknot.h"
+#include "utils/common/params.h"
+#include "utils/keymgr/functions.h"
+
+#define PROGRAM_NAME "keymgr"
+
+static void print_help(void)
+{
+ printf("Usage:\n"
+ " %s -h | -V\n"
+ " %s -t <tsig_name> [<algorithm>] [<bits>]\n"
+ " %s [-c | -C | -d <path>] <zone> <command> [<argument>...]\n"
+ "\n"
+ "Parameters:\n"
+ " -c, --config <file> Use a textual configuration file.\n"
+ " (default %s)\n"
+ " -C, --confdb <dir> Use a binary configuration database directory.\n"
+ " (default %s)\n"
+ " -d, --dir <path> Use specified KASP database path and default configuration.\n"
+ " -t, --tsig <name> [alg] Generate a TSIG key.\n"
+ " -h, --help Print the program help.\n"
+ " -V, --version Print the program version.\n"
+ "\n"
+ "Commands:\n"
+ " list List all zone's DNSSEC keys.\n"
+ " generate Generate new DNSSEC key.\n"
+ " (syntax: generate <attribute_name>=<value>...)\n"
+ " import-bind Import BIND-style key file pair (.key + .private).\n"
+ " (syntax: import-bind <key_file_name>)\n"
+ " import-pub Import public-only key to be published in the zone (in BIND .key format).\n"
+ " (syntax: import-pub <key_file_name>)\n"
+ " import-pem Import key in PEM format. Specify its parameters manually.\n"
+ " (syntax: import-pem <pem_file_path> <attribute_name>=<value>...)\n"
+ " import-pkcs11 Import key stored in PKCS11 storage. Specify its parameters manually.\n"
+ " (syntax: import-pkcs11 <key_id> <attribute_name>=<value>...)\n"
+ " nsec3-salt Print current NSEC3 salt. If parameter is specified, set new salt.\n"
+ " (syntax: nsec3salt [<new_salt>])\n"
+ " ds Generate DS record(s) for specified key.\n"
+ " (syntax: ds <key_spec>)\n"
+ " dnskey Generate DNSKEY record for specified key.\n"
+ " (syntax: dnskey <key_spec>)\n"
+ " share Share an existing key of another zone with the specified zone.\n"
+ " (syntax: share <full_key_ID>\n"
+ " delete Remove the specified key from zone.\n"
+ " (syntax: delete <key_spec>)\n"
+ " set Set existing key's timing attribute.\n"
+ " (syntax: set <key_spec> <attribute_name>=<value>...)\n"
+ "\n"
+ "Key specification:\n"
+ " either the key tag (number) or [a prefix of] key ID.\n"
+ "\n"
+ "Key attributes:\n"
+ " algorithm The key cryptographic algorithm: either name (e.g. RSASHA256) or\n"
+ " number.\n"
+ " size The key size in bits.\n"
+ " ksk Whether the generated/imported key shall be Key Signing Key.\n"
+ " created/publish/ready/active/retire/remove The timestamp of the key\n"
+ " lifetime event (e.g. published=+1d active=1499770874)\n",
+ PROGRAM_NAME, PROGRAM_NAME, PROGRAM_NAME, CONF_DEFAULT_FILE, CONF_DEFAULT_DBDIR);
+}
+
+static int key_command(int argc, char *argv[], int optind)
+{
+ if (argc < optind + 2) {
+ printf("Zone name and/or command not specified\n");
+ print_help();
+ return KNOT_EINVAL;
+ }
+ argc -= optind;
+ argv += optind;
+
+ knot_dname_t *zone_name = knot_dname_from_str_alloc(argv[0]);
+ if (zone_name == NULL) {
+ return KNOT_ENOMEM;
+ }
+ knot_dname_to_lower(zone_name);
+
+ kdnssec_ctx_t kctx = { 0 };
+
+ conf_val_t mapsize = conf_default_get(conf(), C_MAX_KASP_DB_SIZE);
+ char *kasp_dir = conf_kaspdir(conf());
+ int ret = kasp_db_init(kaspdb(), kasp_dir, conf_int(&mapsize));
+ free(kasp_dir);
+ if (ret != KNOT_EOK) {
+ printf("Failed to initialize KASP db (%s)\n", knot_strerror(ret));
+ goto main_end;
+ }
+
+ ret = kdnssec_ctx_init(conf(), &kctx, zone_name, NULL);
+ if (ret != KNOT_EOK) {
+ printf("Failed to initialize KASP (%s)\n", knot_strerror(ret));
+ goto main_end;
+ }
+
+#define CHECK_MISSING_ARG(msg) \
+ if (argc < 3) { \
+ printf("%s\n", (msg)); \
+ ret = KNOT_EINVAL; \
+ goto main_end; \
+ }
+
+ bool print_ok_on_succes = true;
+ if (strcmp(argv[1], "generate") == 0) {
+ ret = keymgr_generate_key(&kctx, argc - 2, argv + 2);
+ print_ok_on_succes = false;
+ } else if (strcmp(argv[1], "import-bind") == 0) {
+ CHECK_MISSING_ARG("BIND-style key to import not specified");
+ ret = keymgr_import_bind(&kctx, argv[2], false);
+ } else if (strcmp(argv[1], "import-pub") == 0) {
+ CHECK_MISSING_ARG("BIND-style key to import not specified");
+ ret = keymgr_import_bind(&kctx, argv[2], true);
+ } else if (strcmp(argv[1], "import-pem") == 0) {
+ CHECK_MISSING_ARG("PEM file to import not specified");
+ ret = keymgr_import_pem(&kctx, argv[2], argc - 3, argv + 3);
+ } else if (strcmp(argv[1], "import-pkcs11") == 0) {
+ CHECK_MISSING_ARG("Key ID to import not specified");
+ ret = keymgr_import_pkcs11(&kctx, argv[2], argc - 3, argv + 3);
+ } else if (strcmp(argv[1], "nsec3-salt") == 0) {
+ if (argc > 2) {
+ ret = keymgr_nsec3_salt_set(&kctx, argv[2]);
+ } else {
+ ret = keymgr_nsec3_salt_print(&kctx);
+ print_ok_on_succes = false;
+ }
+ } else if (strcmp(argv[1], "set") == 0) {
+ CHECK_MISSING_ARG("Key is not specified");
+ knot_kasp_key_t *key2set;
+ ret = keymgr_get_key(&kctx, argv[2], &key2set);
+ if (ret == KNOT_EOK) {
+ ret = keymgr_set_timing(key2set, argc - 3, argv + 3);
+ if (ret == KNOT_EOK) {
+ ret = kdnssec_ctx_commit(&kctx);
+ }
+ }
+ } else if (strcmp(argv[1], "list") == 0) {
+ knot_time_print_t format = TIME_PRINT_UNIX;
+ if (argc > 2 && strcmp(argv[2], "human") == 0) {
+ format = TIME_PRINT_HUMAN_MIXED;
+ } else if (argc > 2 && strcmp(argv[2], "iso") == 0) {
+ format = TIME_PRINT_ISO8601;
+ }
+ ret = keymgr_list_keys(&kctx, format);
+ print_ok_on_succes = false;
+ } else if (strcmp(argv[1], "ds") == 0 || strcmp(argv[1], "dnskey") == 0) {
+ int (*generate_rr)(const knot_dname_t *, const knot_kasp_key_t *) = keymgr_generate_dnskey;
+ if (strcmp(argv[1], "ds") == 0) {
+ generate_rr = keymgr_generate_ds;
+ }
+ if (argc < 3) {
+ for (int i = 0; i < kctx.zone->num_keys && ret == KNOT_EOK; i++) {
+ if (kctx.zone->keys[i].is_ksk) {
+ ret = generate_rr(zone_name, &kctx.zone->keys[i]);
+ }
+ }
+ } else {
+ knot_kasp_key_t *key2rr;
+ ret = keymgr_get_key(&kctx, argv[2], &key2rr);
+ if (ret == KNOT_EOK) {
+ ret = generate_rr(zone_name, key2rr);
+ }
+ }
+ print_ok_on_succes = false;
+ } else if (strcmp(argv[1], "share") == 0) {
+ CHECK_MISSING_ARG("Key to be shared is not specified");
+ knot_dname_t *other_zone = NULL;
+ char *key_to_share = NULL;
+ ret = keymgr_foreign_key_id(argv, &other_zone, &key_to_share);
+ if (ret == KNOT_EOK) {
+ ret = kasp_db_share_key(*kctx.kasp_db, other_zone, kctx.zone->dname, key_to_share);
+ }
+ free(other_zone);
+ free(key_to_share);
+ } else if (strcmp(argv[1], "delete") == 0) {
+ CHECK_MISSING_ARG("Key is not specified");
+ knot_kasp_key_t *key2del;
+ ret = keymgr_get_key(&kctx, argv[2], &key2del);
+ if (ret == KNOT_EOK) {
+ ret = kdnssec_delete_key(&kctx, key2del);
+ }
+ } else {
+ printf("Wrong zone-key command: %s\n", argv[1]);
+ goto main_end;
+ }
+
+#undef CHECK_MISSING_ARG
+
+ if (ret == KNOT_EOK) {
+ printf("%s", print_ok_on_succes ? "OK\n" : "");
+ } else {
+ printf("Error (%s)\n", knot_strerror(ret));
+ }
+
+main_end:
+ kdnssec_ctx_deinit(&kctx);
+ kasp_db_close(kaspdb());
+ free(zone_name);
+
+ return ret;
+}
+
+static bool init_conf(const char *confdb)
+{
+ size_t max_conf_size = (size_t)CONF_MAPSIZE * 1024 * 1024;
+
+ conf_flag_t flags = CONF_FNOHOSTNAME | CONF_FOPTMODULES;
+ if (confdb != NULL) {
+ flags |= CONF_FREADONLY;
+ }
+
+ conf_t *new_conf = NULL;
+ int ret = conf_new(&new_conf, conf_schema, confdb, max_conf_size, flags);
+ if (ret != KNOT_EOK) {
+ printf("Failed opening configuration database %s (%s)\n",
+ (confdb == NULL ? "" : confdb), knot_strerror(ret));
+ return false;
+ }
+ conf_update(new_conf, CONF_UPD_FNONE);
+ return true;
+}
+
+static bool init_confile(const char *confile)
+{
+ int ret = conf_import(conf(), confile, true);
+ if (ret != KNOT_EOK) {
+ printf("Failed opening configuration file %s (%s)\n",
+ confile, knot_strerror(ret));
+ return false;
+ }
+ return true;
+}
+
+static bool init_conf_blank(const char *kasp_dir)
+{
+ char *confstr = sprintf_alloc("template:\n"""
+ " - id: default\n"
+ " storage: .\n"
+ " kasp-db: %s\n", kasp_dir);
+ int ret = conf_import(conf(), confstr, false);
+ free(confstr);
+ if (ret != KNOT_EOK) {
+ printf("Failed creating fake configuration (%s)\n",
+ knot_strerror(ret));
+ return false;
+ }
+ return true;
+}
+
+static void update_privileges(void)
+{
+ int uid, gid;
+ if (conf_user(conf(), &uid, &gid) != KNOT_EOK) {
+ return;
+ }
+
+ // Just try to alter process privileges if different from configured.
+ int unused __attribute__((unused));
+ if ((gid_t)gid != getgid()) {
+ unused = setregid(gid, gid);
+ }
+ if ((uid_t)uid != getuid()) {
+ unused = setreuid(uid, uid);
+ }
+}
+
+static bool conf_initialized = false; // This is a singleton as well as conf() is.
+
+#define CHECK_CONF_UNINIT \
+ if ((conf_initialized = !conf_initialized) == false) { \
+ printf("Error: multiple arguments attempting configuration initializatioin.\n"); \
+ return EXIT_FAILURE; \
+ }
+
+int main(int argc, char *argv[])
+{
+ int ret;
+
+ struct option opts[] = {
+ { "config", required_argument, NULL, 'c' },
+ { "confdb", required_argument, NULL, 'C' },
+ { "dir", required_argument, NULL, 'd' },
+ { "tsig", required_argument, NULL, 't' },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'V' },
+ { NULL }
+ };
+
+ int opt = 0;
+ while ((opt = getopt_long(argc, argv, "hVd:c:C:t:", opts, NULL)) != -1) {
+ switch (opt) {
+ case 'h':
+ print_help();
+ return EXIT_SUCCESS;
+ case 'V':
+ print_version(PROGRAM_NAME);
+ return EXIT_SUCCESS;
+ case 'd':
+ CHECK_CONF_UNINIT
+ if (!init_conf(NULL) || !init_conf_blank(optarg)) {
+ return EXIT_FAILURE;
+ }
+ break;
+ case 'c':
+ CHECK_CONF_UNINIT
+ if (!init_conf(NULL) || !init_confile(optarg)) {
+ return EXIT_FAILURE;
+ }
+ break;
+ case 'C':
+ CHECK_CONF_UNINIT
+ if (!init_conf(argv[2])) {
+ return EXIT_FAILURE;
+ }
+ break;
+ case 't':
+ ret = keymgr_generate_tsig(optarg, (argc > optind ? argv[optind] : "hmac-sha256"),
+ (argc > optind + 1 ? atol(argv[optind + 1]) : 0));
+ if (ret != KNOT_EOK) {
+ printf("Failed to generate TSIG (%s)\n", knot_strerror(ret));
+ }
+ return (ret == KNOT_EOK ? EXIT_SUCCESS : EXIT_FAILURE);
+ default:
+ print_help();
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (!conf_initialized) {
+ struct stat st;
+ if (stat(CONF_DEFAULT_DBDIR, &st) == 0 && init_conf(CONF_DEFAULT_DBDIR)) {
+ // initialized conf from default DB location
+ } else if (stat(CONF_DEFAULT_FILE, &st) == 0 &&
+ init_conf(NULL) && init_confile(CONF_DEFAULT_FILE)) {
+ // initialized conf from default confile
+ } else {
+ printf("Couldn't initialize configuration, please provide -c, -C, or -d option\n");
+ return EXIT_FAILURE;
+ }
+ }
+
+ update_privileges();
+
+ ret = key_command(argc, argv, optind);
+
+ conf_free(conf());
+
+ return (ret == KNOT_EOK ? EXIT_SUCCESS : EXIT_FAILURE);
+}
diff --git a/src/utils/khost/khost_main.c b/src/utils/khost/khost_main.c
new file mode 100644
index 0000000..fc3fe17
--- /dev/null
+++ b/src/utils/khost/khost_main.c
@@ -0,0 +1,43 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdlib.h>
+
+#include "libdnssec/crypto.h"
+#include "utils/khost/khost_params.h"
+#include "utils/kdig/kdig_exec.h"
+#include "libknot/libknot.h"
+
+int main(int argc, char *argv[])
+{
+ int ret = EXIT_SUCCESS;
+
+ kdig_params_t params;
+ if (khost_parse(&params, argc, argv) == KNOT_EOK) {
+ if (!params.stop) {
+ dnssec_crypto_init();
+ if (kdig_exec(&params) != KNOT_EOK) {
+ ret = EXIT_FAILURE;
+ }
+ dnssec_crypto_cleanup();
+ }
+ } else {
+ ret = EXIT_FAILURE;
+ }
+
+ khost_clean(&params);
+ return ret;
+}
diff --git a/src/utils/khost/khost_params.c b/src/utils/khost/khost_params.c
new file mode 100644
index 0000000..bd5f095
--- /dev/null
+++ b/src/utils/khost/khost_params.c
@@ -0,0 +1,365 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <getopt.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "utils/khost/khost_params.h"
+#include "utils/kdig/kdig_params.h"
+#include "utils/common/msg.h"
+#include "utils/common/params.h"
+#include "utils/common/resolv.h"
+#include "libknot/libknot.h"
+#include "contrib/strtonum.h"
+#include "contrib/ucw/lists.h"
+
+#define PROGRAM_NAME "khost"
+
+#define DEFAULT_RETRIES_HOST 1
+#define DEFAULT_TIMEOUT_HOST 2
+
+static const style_t DEFAULT_STYLE_HOST = {
+ .format = FORMAT_HOST,
+ .style = {
+ .wrap = false,
+ .show_class = true,
+ .show_ttl = true,
+ .verbose = false,
+ .original_ttl = false,
+ .empty_ttl = false,
+ .human_ttl = false,
+ .human_tmstamp = true,
+ .generic = false,
+ .ascii_to_idn = name_to_idn
+ },
+ .show_query = false,
+ .show_header = false,
+ .show_edns = false,
+ .show_question = true,
+ .show_answer = true,
+ .show_authority = true,
+ .show_additional = true,
+ .show_tsig = false,
+ .show_footer = false
+};
+
+static int khost_init(kdig_params_t *params)
+{
+ // Initialize params with kdig defaults.
+ int ret = kdig_init(params);
+
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Set khost specific defaults.
+ free(params->config->port);
+ params->config->port = strdup(DEFAULT_DNS_PORT);
+ params->config->retries = DEFAULT_RETRIES_HOST;
+ params->config->wait = DEFAULT_TIMEOUT_HOST;
+ params->config->class_num = KNOT_CLASS_IN;
+ params->config->style = DEFAULT_STYLE_HOST;
+ params->config->idn = true;
+
+ // Check port.
+ if (params->config->port == NULL) {
+ query_free(params->config);
+ return KNOT_ENOMEM;
+ }
+
+ return KNOT_EOK;
+}
+
+void khost_clean(kdig_params_t *params)
+{
+ if (params == NULL) {
+ DBG_NULL;
+ return;
+ }
+
+ kdig_clean(params);
+}
+
+static int parse_server(const char *value, list_t *servers, const char *def_port)
+{
+ if (params_parse_server(value, servers, def_port) != KNOT_EOK) {
+ ERR("invalid server %s\n", value);
+ return KNOT_EINVAL;
+ }
+
+ return KNOT_EOK;
+}
+
+static int parse_name(const char *value, list_t *queries, const query_t *conf)
+{
+ char *reverse = get_reverse_name(value);
+ char *ascii_name = (char *)value;
+ query_t *query;
+
+ if (conf->idn) {
+ ascii_name = name_from_idn(value);
+ if (ascii_name == NULL) {
+ free(reverse);
+ return KNOT_EINVAL;
+ }
+ }
+
+ // If name is not FQDN, append trailing dot.
+ char *fqd_name = get_fqd_name(ascii_name);
+
+ if (conf->idn) {
+ free(ascii_name);
+ }
+
+ // RR type is known.
+ if (conf->type_num >= 0) {
+ if (conf->type_num == KNOT_RRTYPE_PTR) {
+ free(fqd_name);
+
+ // Check for correct address.
+ if (reverse == NULL) {
+ ERR("invalid IPv4/IPv6 address %s\n", value);
+ return KNOT_EINVAL;
+ }
+
+ // Add reverse query for address.
+ query = query_create(reverse, conf);
+ free(reverse);
+ if (query == NULL) {
+ return KNOT_ENOMEM;
+ }
+ add_tail(queries, (node_t *)query);
+ } else {
+ free(reverse);
+
+ // Add query for name and specified type.
+ query = query_create(fqd_name, conf);
+ free(fqd_name);
+ if (query == NULL) {
+ return KNOT_ENOMEM;
+ }
+ add_tail(queries, (node_t *)query);
+ }
+ // RR type is unknown, use defaults.
+ } else {
+ if (reverse == NULL) {
+ // Add query for name and type A.
+ query = query_create(fqd_name, conf);
+ if (query == NULL) {
+ free(fqd_name);
+ return KNOT_ENOMEM;
+ }
+ query->type_num = KNOT_RRTYPE_A;
+ add_tail(queries, (node_t *)query);
+
+ // Add query for name and type AAAA.
+ query = query_create(fqd_name, conf);
+ if (query == NULL) {
+ free(fqd_name);
+ return KNOT_ENOMEM;
+ }
+ query->type_num = KNOT_RRTYPE_AAAA;
+ query->style.hide_cname = true;
+ add_tail(queries, (node_t *)query);
+
+ // Add query for name and type MX.
+ query = query_create(fqd_name, conf);
+ if (query == NULL) {
+ free(fqd_name);
+ return KNOT_ENOMEM;
+ }
+ free(fqd_name);
+ query->type_num = KNOT_RRTYPE_MX;
+ query->style.hide_cname = true;
+ add_tail(queries, (node_t *)query);
+ } else {
+ free(fqd_name);
+
+ // Add reverse query for address.
+ query = query_create(reverse, conf);
+ free(reverse);
+ if (query == NULL) {
+ return KNOT_ENOMEM;
+ }
+ query->type_num = KNOT_RRTYPE_PTR;
+ add_tail(queries, (node_t *)query);
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+static void print_help(void)
+{
+ printf("Usage: %s [-4] [-6] [-adhrsTvVw] [-c class] [-t type]\n"
+ " [-R retries] [-W time] name [server]\n\n"
+ " -4 Use IPv4 protocol only.\n"
+ " -6 Use IPv6 protocol only.\n"
+ " -a Same as -t ANY -v.\n"
+ " -d Allow debug messages.\n"
+ " -h, --help Print the program help.\n"
+ " -r Disable recursion.\n"
+ " -T Use TCP protocol.\n"
+ " -v Verbose output.\n"
+ " -V, --version Print the program version.\n"
+ " -w Wait forever.\n"
+ " -c Set query class.\n"
+ " -t Set query type.\n"
+ " -R Set number of UDP retries.\n"
+ " -W Set wait interval.\n",
+ PROGRAM_NAME);
+}
+
+int khost_parse(kdig_params_t *params, int argc, char *argv[])
+{
+ if (params == NULL || argv == NULL) {
+ DBG_NULL;
+ return KNOT_EINVAL;
+ }
+
+ if (khost_init(params) != KNOT_EOK) {
+ return KNOT_ERROR;
+ }
+
+#ifdef LIBIDN
+ // Set up localization.
+ if (setlocale(LC_CTYPE, "") == NULL) {
+ params->config->idn = false;
+ }
+#endif
+
+ query_t *conf = params->config;
+ uint16_t rclass, rtype;
+ int64_t serial;
+ bool notify;
+
+ // Long options.
+ struct option opts[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'V' },
+ { NULL }
+ };
+
+ // Command line options processing.
+ int opt = 0;
+ while ((opt = getopt_long(argc, argv, "46adhrsTvVwc:t:R:W:", opts, NULL))
+ != -1) {
+ switch (opt) {
+ case '4':
+ conf->ip = IP_4;
+ break;
+ case '6':
+ conf->ip = IP_6;
+ break;
+ case 'a':
+ conf->type_num = KNOT_RRTYPE_ANY;
+ conf->style.format = FORMAT_FULL;
+ conf->style.show_header = true;
+ conf->style.show_edns = true;
+ conf->style.show_footer = true;
+ break;
+ case 'd':
+ msg_enable_debug(1);
+ break;
+ case 'h':
+ print_help();
+ params->stop = false;
+ return KNOT_EOK;
+ case 'r':
+ conf->flags.rd_flag = false;
+ break;
+ case 'T':
+ conf->protocol = PROTO_TCP;
+ break;
+ case 'v':
+ conf->style.format = FORMAT_FULL;
+ conf->style.show_header = true;
+ conf->style.show_edns = true;
+ conf->style.show_footer = true;
+ break;
+ case 'V':
+ print_version(PROGRAM_NAME);
+ params->stop = false;
+ return KNOT_EOK;
+ case 'w':
+ conf->wait = -1;
+ break;
+ case 'c':
+ if (params_parse_class(optarg, &rclass) != KNOT_EOK) {
+ ERR("invalid class '%s'\n", optarg);
+ return KNOT_EINVAL;
+ }
+ conf->class_num = rclass;
+ break;
+ case 't':
+ if (params_parse_type(optarg, &rtype, &serial, &notify)
+ != KNOT_EOK) {
+ ERR("invalid type '%s'\n", optarg);
+ return KNOT_EINVAL;
+ }
+ conf->type_num = rtype;
+ conf->serial = serial;
+ conf->notify = notify;
+
+ // If NOTIFY, reset default RD flag.
+ if (conf->notify) {
+ conf->flags.rd_flag = false;
+ }
+ break;
+ case 'R':
+ if (str_to_u32(optarg, &conf->retries) != KNOT_EOK) {
+ ERR("invalid retries '%s'\n", optarg);
+ return KNOT_EINVAL;
+ }
+ break;
+ case 'W':
+ if (params_parse_wait(optarg, &conf->wait) != KNOT_EOK) {
+ ERR("invalid wait '%s'\n", optarg);
+ return KNOT_EINVAL;
+ }
+ break;
+ default:
+ print_help();
+ return KNOT_ENOTSUP;
+ }
+ }
+
+ // Process non-option parameters.
+ switch (argc - optind) {
+ case 2:
+ if (parse_server(argv[optind + 1], &conf->servers, conf->port)
+ != KNOT_EOK) {
+ return KNOT_EINVAL;
+ }
+ case 1: // Fall through.
+ if (parse_name(argv[optind], &params->queries, conf)
+ != KNOT_EOK) {
+ return KNOT_EINVAL;
+ }
+ break;
+ default:
+ print_help();
+ return KNOT_ENOTSUP;
+ }
+
+ // Complete missing data in queries based on defaults.
+ complete_queries(&params->queries, params->config);
+
+ return KNOT_EOK;
+}
diff --git a/src/utils/khost/khost_params.h b/src/utils/khost/khost_params.h
new file mode 100644
index 0000000..7fbd1f5
--- /dev/null
+++ b/src/utils/khost/khost_params.h
@@ -0,0 +1,22 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "utils/kdig/kdig_params.h"
+
+int khost_parse(kdig_params_t *params, int argc, char *argv[]);
+void khost_clean(kdig_params_t *params);
diff --git a/src/utils/kjournalprint/main.c b/src/utils/kjournalprint/main.c
new file mode 100644
index 0000000..920782d
--- /dev/null
+++ b/src/utils/kjournalprint/main.c
@@ -0,0 +1,412 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdlib.h>
+#include <getopt.h>
+#include <sys/stat.h>
+
+#include "libknot/libknot.h"
+#include "knot/journal/journal.h"
+#include "knot/zone/zone-dump.h"
+#include "utils/common/exec.h"
+#include "contrib/dynarray.h"
+#include "contrib/strtonum.h"
+#include "contrib/string.h"
+
+#define PROGRAM_NAME "kjournalprint"
+
+#define RED "\x1B[31m"
+#define GRN "\x1B[32m"
+#define YLW "\x1B[93m"
+#define RESET "\x1B[0m"
+
+static void print_help(void)
+{
+ printf("Usage: %s [parameter] <journal_db> <zone_name>\n"
+ "\n"
+ "Parameters:\n"
+ " -l, --limit <num> Read only <num> newest changes.\n"
+ " -n, --no-color Get output without terminal coloring.\n"
+ " -z, --zone-list Instead of reading jurnal, display the list\n"
+ " of zones in the DB (<zone_name> not needed).\n"
+ " -d, --debug Debug mode output.\n"
+ " -h, --help Print the program help.\n"
+ " -V, --version Print the program version.\n",
+ PROGRAM_NAME);
+}
+
+// workaround: LMDB fails to detect proper mapsize
+static int reconfigure_mapsize(const char *journal_path, size_t *mapsize)
+{
+ char *data_mdb = sprintf_alloc("%s/data.mdb", journal_path);
+ if (data_mdb == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ struct stat st;
+ if (stat(data_mdb, &st) != 0 || st.st_size == 0) {
+ fprintf(stderr, "Journal does not exist: %s\n", journal_path);
+ free(data_mdb);
+ return KNOT_ENOENT;
+ }
+
+ *mapsize = st.st_size + st.st_size / 8; // 112.5% to allow opening when growing
+ free(data_mdb);
+ return KNOT_EOK;
+}
+
+static void print_changeset(const changeset_t *chs, bool color)
+{
+ printf(color ? YLW : "");
+ if (chs->soa_from == NULL) {
+ printf(";; Zone-in-journal, serial: %u\n",
+ knot_soa_serial(chs->soa_to->rrs.rdata));
+ } else {
+ printf(";; Changes between zone versions: %u -> %u\n",
+ knot_soa_serial(chs->soa_from->rrs.rdata),
+ knot_soa_serial(chs->soa_to->rrs.rdata));
+ }
+ changeset_print(chs, stdout, color);
+}
+
+dynarray_declare(rrtype, uint16_t, DYNARRAY_VISIBILITY_STATIC, 100)
+dynarray_define(rrtype, uint16_t, DYNARRAY_VISIBILITY_STATIC)
+
+typedef struct {
+ rrtype_dynarray_t *arr;
+ size_t *counter;
+} rrtypelist_ctx_t;
+
+static void rrtypelist_add(rrtype_dynarray_t *arr, uint16_t add_type)
+{
+ bool already_present = false;
+ dynarray_foreach(rrtype, uint16_t, i, *arr) {
+ if (*i == add_type) {
+ already_present = true;
+ break;
+ }
+ }
+ if (!already_present) {
+ rrtype_dynarray_add(arr, &add_type);
+ }
+}
+
+static int rrtypelist_callback(zone_node_t *node, void *data)
+{
+ rrtypelist_ctx_t *ctx = data;
+ for (int i = 0; i < node->rrset_count; i++) {
+ knot_rrset_t rrset = node_rrset_at(node, i);
+ rrtypelist_add(ctx->arr, rrset.type);
+ *ctx->counter += rrset.rrs.count;
+ }
+ return KNOT_EOK;
+}
+
+static void print_changeset_debugmode(const changeset_t *chs)
+{
+ // detect all types
+ rrtype_dynarray_t types = { 0 };
+ size_t count_minus = 1, count_plus = 1; // 1 for SOA which is always present but not iterated
+ rrtypelist_ctx_t ctx_minus = { &types, &count_minus }, ctx_plus = { &types, &count_plus };
+ (void)zone_contents_apply(chs->remove, rrtypelist_callback, &ctx_minus);
+ (void)zone_contents_nsec3_apply(chs->remove, rrtypelist_callback, &ctx_minus);
+ (void)zone_contents_apply(chs->add, rrtypelist_callback, &ctx_plus);
+ (void)zone_contents_nsec3_apply(chs->add, rrtypelist_callback, &ctx_plus);
+
+ if (chs->soa_from == NULL) {
+ printf("Zone-in-journal %u +++: %zu\t size: %zu\t", knot_soa_serial(chs->soa_to->rrs.rdata),
+ count_plus, changeset_serialized_size(chs));
+ } else {
+ printf("%u -> %u ---: %zu\t +++: %zu\t size: %zu\t", knot_soa_serial(chs->soa_from->rrs.rdata),
+ knot_soa_serial(chs->soa_to->rrs.rdata), count_minus, count_plus, changeset_serialized_size(chs));
+ }
+
+ char temp[100];
+ dynarray_foreach(rrtype, uint16_t, i, types) {
+ (void)knot_rrtype_to_string(*i, temp, sizeof(temp));
+ printf(" %s", temp);
+ }
+ printf("\n");
+}
+
+int print_journal(char *path, knot_dname_t *name, uint32_t limit, bool color, bool debugmode)
+{
+ list_t db;
+ init_list(&db);
+ int ret;
+ journal_db_t *jdb = NULL;
+
+ ret = journal_db_init(&jdb, path, 1, JOURNAL_MODE_ROBUST);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = reconfigure_mapsize(jdb->path, &jdb->fslimit);
+ if (ret != KNOT_EOK) {
+ journal_db_close(&jdb);
+ return ret;
+ }
+
+ ret = journal_open_db(&jdb);
+ if (ret != KNOT_EOK) {
+ journal_db_close(&jdb);
+ return ret;
+ }
+
+ if (!journal_exists(&jdb, name)) {
+ fprintf(stderr, "This zone does not exist in DB %s\n", path);
+ ret = KNOT_ENOENT;
+ }
+
+ journal_t *j = journal_new();
+
+ if (ret == KNOT_EOK) {
+ ret = journal_open(j, &jdb, name);
+ }
+ if (ret != KNOT_EOK) {
+ journal_free(&j);
+ journal_db_close(&jdb);
+ return ret;
+ }
+
+ bool has_bootstrap;
+ kserial_t merged_serial, serial_from, last_flushed, serial_to;
+ uint64_t occupied, occupied_all;
+ journal_metadata_info(j, &has_bootstrap, &merged_serial, &serial_from,
+ &last_flushed, &serial_to, &occupied, &occupied_all);
+
+ bool alternative_from = (has_bootstrap || merged_serial.valid);
+ bool is_empty = (!alternative_from && !serial_from.valid);
+ if (is_empty) {
+ ret = KNOT_ENOENT;
+ goto pj_finally;
+ }
+
+ if (has_bootstrap) {
+ ret = journal_load_bootstrap(j, &db);
+ } else if (merged_serial.valid) {
+ ret = journal_load_changesets(j, &db, merged_serial.serial);
+ } else {
+ ret = journal_load_changesets(j, &db, serial_from.serial);
+ }
+ if (ret != KNOT_EOK) {
+ goto pj_finally;
+ }
+
+ changeset_t *chs = NULL;
+
+ size_t db_remains = list_size(&db);
+
+ WALK_LIST(chs, db) {
+ if (--db_remains >= limit && limit > 0) {
+ continue;
+ }
+ if (debugmode) {
+ print_changeset_debugmode(chs);
+ } else {
+ print_changeset(chs, color);
+ }
+ }
+
+ changesets_free(&db);
+
+ if (debugmode) {
+ if ((alternative_from && serial_from.valid) ||
+ kserial_equal(serial_from, last_flushed)) {
+ init_list(&db);
+
+ ret = journal_load_changesets(j, &db, serial_from.serial);
+ switch (ret) {
+ case KNOT_EOK:
+ printf("---- Additional history ----\n");
+ break;
+ case KNOT_ENOENT:
+ printf("---- No additional history ----\n");
+ ret = KNOT_EOK;
+ break;
+ default:
+ goto pj_finally;
+ }
+ WALK_LIST(chs, db) {
+ print_changeset_debugmode(chs);
+ if (last_flushed.valid &&
+ serial_equal(knot_soa_serial(chs->soa_from->rrs.rdata), last_flushed.serial)) {
+ break;
+ }
+ }
+ changesets_free(&db);
+ } else {
+ printf("---- No additional history ----\n");
+ }
+ }
+
+ if (debugmode) {
+ printf("Occupied this zone (approx): %"PRIu64" KiB\n", occupied / 1024);
+ printf("Occupied all zones together: %"PRIu64" KiB\n", occupied_all / 1024);
+ }
+
+pj_finally:
+ journal_close(j);
+ journal_free(&j);
+ journal_db_close(&jdb);
+
+ return ret;
+}
+
+int list_zones(char *path)
+{
+ journal_db_t *jdb = NULL;
+ int ret = journal_db_init(&jdb, path, 1, JOURNAL_MODE_ROBUST);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = reconfigure_mapsize(jdb->path, &jdb->fslimit);
+ if (ret != KNOT_EOK) {
+ journal_db_close(&jdb);
+ return ret;
+ }
+
+ ret = journal_open_db(&jdb);
+ if (ret != KNOT_EOK) {
+ journal_db_close(&jdb);
+ return ret;
+ }
+
+ list_t zones;
+ init_list(&zones);
+ ret = journal_db_list_zones(&jdb, &zones);
+ if (ret == KNOT_EOK) {
+ ptrnode_t *zn;
+ char buff[KNOT_DNAME_TXT_MAXLEN + 1];
+ WALK_LIST(zn, zones) {
+ printf("%s\n", knot_dname_to_str(buff, (knot_dname_t *)zn->d, sizeof(buff)));
+ free(zn->d);
+ }
+ ptrlist_free(&zones, NULL);
+ }
+
+ journal_db_close(&jdb);
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ uint32_t limit = 0;
+ bool color = true, justlist = false, debugmode = false;
+
+ struct option opts[] = {
+ { "limit", required_argument, NULL, 'l' },
+ { "no-color", no_argument, NULL, 'n' },
+ { "zone-list", no_argument, NULL, 'z' },
+ { "debug", no_argument, NULL, 'd' },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'V' },
+ { NULL }
+ };
+
+ int opt = 0;
+ while ((opt = getopt_long(argc, argv, "l:nzdhV", opts, NULL)) != -1) {
+ switch (opt) {
+ case 'l':
+ if (str_to_u32(optarg, &limit) != KNOT_EOK) {
+ print_help();
+ return EXIT_FAILURE;
+ }
+ break;
+ case 'n':
+ color = false;
+ break;
+ case 'z':
+ justlist = true;
+ break;
+ case 'd':
+ debugmode = true;
+ break;
+ case 'h':
+ print_help();
+ return EXIT_SUCCESS;
+ case 'V':
+ print_version(PROGRAM_NAME);
+ return EXIT_SUCCESS;
+ default:
+ print_help();
+ return EXIT_FAILURE;
+ }
+ }
+
+ char *db = NULL;
+ knot_dname_t *name = NULL;
+
+ switch (argc - optind) {
+ case 2:
+ name = knot_dname_from_str_alloc(argv[optind + 1]);
+ knot_dname_to_lower(name);
+ // FALLTHROUGH
+ case 1:
+ db = argv[optind];
+ break;
+ default:
+ print_help();
+ return EXIT_FAILURE;
+ }
+
+ if (db == NULL) {
+ fprintf(stderr, "Journal DB path not specified\n");
+ return EXIT_FAILURE;
+ }
+
+ if (justlist) {
+ int ret = list_zones(db);
+ switch (ret) {
+ case KNOT_ENOENT:
+ printf("No zones in journal DB\n");
+ // FALLTHROUGH
+ case KNOT_EOK:
+ return EXIT_SUCCESS;
+ case KNOT_EMALF:
+ fprintf(stderr, "The journal DB is broken\n");
+ return EXIT_FAILURE;
+ default:
+ fprintf(stderr, "Failed to load zone list (%s)\n", knot_strerror(ret));
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (name == NULL) {
+ fprintf(stderr, "Zone not specified\n");
+ return EXIT_FAILURE;
+ }
+
+ int ret = print_journal(db, name, limit, color, debugmode);
+ free(name);
+
+ switch (ret) {
+ case KNOT_ENOENT:
+ printf("The journal is empty\n");
+ break;
+ case KNOT_EOUTOFZONE:
+ fprintf(stderr, "The specified journal DB does not contain the specified zone\n");
+ return EXIT_FAILURE;
+ case KNOT_EOK:
+ break;
+ default:
+ fprintf(stderr, "Failed to load changesets (%s)\n", knot_strerror(ret));
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/utils/knotc/commands.c b/src/utils/knotc/commands.c
new file mode 100644
index 0000000..ea73012
--- /dev/null
+++ b/src/utils/knotc/commands.c
@@ -0,0 +1,1168 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libknot/libknot.h"
+#include "knot/common/log.h"
+#include "knot/ctl/commands.h"
+#include "knot/conf/conf.h"
+#include "knot/conf/confdb.h"
+#include "knot/zone/zonefile.h"
+#include "knot/zone/zone-load.h"
+#include "contrib/macros.h"
+#include "contrib/string.h"
+#include "contrib/openbsd/strlcat.h"
+#include "utils/knotc/commands.h"
+#include "utils/knotc/estimator.h"
+
+#define CMD_EXIT "exit"
+
+#define CMD_STATUS "status"
+#define CMD_STOP "stop"
+#define CMD_RELOAD "reload"
+#define CMD_STATS "stats"
+
+#define CMD_ZONE_CHECK "zone-check"
+#define CMD_ZONE_MEMSTATS "zone-memstats"
+#define CMD_ZONE_STATUS "zone-status"
+#define CMD_ZONE_RELOAD "zone-reload"
+#define CMD_ZONE_REFRESH "zone-refresh"
+#define CMD_ZONE_RETRANSFER "zone-retransfer"
+#define CMD_ZONE_NOTIFY "zone-notify"
+#define CMD_ZONE_FLUSH "zone-flush"
+#define CMD_ZONE_SIGN "zone-sign"
+#define CMD_ZONE_KSK_SBM "zone-ksk-submitted"
+#define CMD_ZONE_FREEZE "zone-freeze"
+#define CMD_ZONE_THAW "zone-thaw"
+
+#define CMD_ZONE_READ "zone-read"
+#define CMD_ZONE_BEGIN "zone-begin"
+#define CMD_ZONE_COMMIT "zone-commit"
+#define CMD_ZONE_ABORT "zone-abort"
+#define CMD_ZONE_DIFF "zone-diff"
+#define CMD_ZONE_GET "zone-get"
+#define CMD_ZONE_SET "zone-set"
+#define CMD_ZONE_UNSET "zone-unset"
+#define CMD_ZONE_PURGE "zone-purge"
+#define CMD_ZONE_STATS "zone-stats"
+
+#define CMD_CONF_INIT "conf-init"
+#define CMD_CONF_CHECK "conf-check"
+#define CMD_CONF_IMPORT "conf-import"
+#define CMD_CONF_EXPORT "conf-export"
+#define CMD_CONF_LIST "conf-list"
+#define CMD_CONF_READ "conf-read"
+#define CMD_CONF_BEGIN "conf-begin"
+#define CMD_CONF_COMMIT "conf-commit"
+#define CMD_CONF_ABORT "conf-abort"
+#define CMD_CONF_DIFF "conf-diff"
+#define CMD_CONF_GET "conf-get"
+#define CMD_CONF_SET "conf-set"
+#define CMD_CONF_UNSET "conf-unset"
+
+#define CTL_LOG_STR "failed to control"
+
+#define CTL_SEND(type, data) \
+ ret = knot_ctl_send(args->ctl, (type), (data)); \
+ if (ret != KNOT_EOK) { \
+ log_error(CTL_LOG_STR" (%s)", knot_strerror(ret)); \
+ return ret; \
+ }
+
+#define CTL_SEND_DATA CTL_SEND(KNOT_CTL_TYPE_DATA, &data)
+#define CTL_SEND_BLOCK CTL_SEND(KNOT_CTL_TYPE_BLOCK, NULL)
+
+static int check_args(cmd_args_t *args, int min, int max)
+{
+ if (max == 0 && args->argc > 0) {
+ log_error("command doesn't take arguments");
+ return KNOT_EINVAL;
+ } else if (min == max && args->argc != min) {
+ log_error("command requires %i arguments", min);
+ return KNOT_EINVAL;
+ } else if (args->argc < min) {
+ log_error("command requires at least %i arguments", min);
+ return KNOT_EINVAL;
+ } else if (max > 0 && args->argc > max) {
+ log_error("command takes at most %i arguments", max);
+ return KNOT_EINVAL;
+ }
+
+ return KNOT_EOK;
+}
+
+static int check_conf_args(cmd_args_t *args)
+{
+ // Mask relevant flags.
+ cmd_flag_t flags = args->desc->flags;
+ flags &= CMD_FOPT_ITEM | CMD_FREQ_ITEM | CMD_FOPT_DATA;
+
+ switch (args->argc) {
+ case 0:
+ if (flags == CMD_FNONE || (flags & CMD_FOPT_ITEM)) {
+ return KNOT_EOK;
+ }
+ break;
+ case 1:
+ if (flags & (CMD_FOPT_ITEM | CMD_FREQ_ITEM)) {
+ return KNOT_EOK;
+ }
+ break;
+ default:
+ if (flags != CMD_FNONE) {
+ return KNOT_EOK;
+ }
+ break;
+ }
+
+ log_error("invalid number of arguments");
+
+ return KNOT_EINVAL;
+}
+
+static int get_conf_key(const char *key, knot_ctl_data_t *data)
+{
+ // Get key0.
+ const char *key0 = key;
+
+ // Check for id.
+ char *id = strchr(key, '[');
+ if (id != NULL) {
+ // Separate key0 and id.
+ *id++ = '\0';
+
+ // Check for id end.
+ char *id_end = id;
+ while ((id_end = strchr(id_end, ']')) != NULL) {
+ // Check for escaped character.
+ if (*(id_end - 1) != '\\') {
+ break;
+ }
+ id_end++;
+ }
+
+ // Check for unclosed id.
+ if (id_end == NULL) {
+ log_error("(missing bracket after identifier) %s", id);
+ return KNOT_EINVAL;
+ }
+
+ // Separate id and key1.
+ *id_end = '\0';
+
+ key = id_end + 1;
+
+ // Key1 or nothing must follow.
+ if (*key != '.' && *key != '\0') {
+ log_error("(unexpected token) %s", key);
+ return KNOT_EINVAL;
+ }
+ }
+
+ // Check for key1.
+ char *key1 = strchr(key, '.');
+ if (key1 != NULL) {
+ // Separate key0/id and key1.
+ *key1++ = '\0';
+
+ if (*key1 == '\0') {
+ log_error("(missing item specification)");
+ return KNOT_EINVAL;
+ }
+ }
+
+ (*data)[KNOT_CTL_IDX_SECTION] = key0;
+ (*data)[KNOT_CTL_IDX_ITEM] = key1;
+ (*data)[KNOT_CTL_IDX_ID] = id;
+
+ return KNOT_EOK;
+}
+
+static void format_data(ctl_cmd_t cmd, knot_ctl_type_t data_type,
+ knot_ctl_data_t *data, bool *empty)
+{
+ const char *error = (*data)[KNOT_CTL_IDX_ERROR];
+ const char *flags = (*data)[KNOT_CTL_IDX_FLAGS];
+ const char *key0 = (*data)[KNOT_CTL_IDX_SECTION];
+ const char *key1 = (*data)[KNOT_CTL_IDX_ITEM];
+ const char *id = (*data)[KNOT_CTL_IDX_ID];
+ const char *zone = (*data)[KNOT_CTL_IDX_ZONE];
+ const char *owner = (*data)[KNOT_CTL_IDX_OWNER];
+ const char *ttl = (*data)[KNOT_CTL_IDX_TTL];
+ const char *type = (*data)[KNOT_CTL_IDX_TYPE];
+ const char *value = (*data)[KNOT_CTL_IDX_DATA];
+
+ const char *sign = NULL;
+ if (ctl_has_flag(flags, CTL_FLAG_ADD)) {
+ sign = CTL_FLAG_ADD;
+ } else if (ctl_has_flag(flags, CTL_FLAG_REM)) {
+ sign = CTL_FLAG_REM;
+ }
+
+ switch (cmd) {
+ case CTL_STATUS:
+ if (error != NULL) {
+ printf("error: (%s)%s%s", error,
+ (type != NULL) ? " " : "",
+ (type != NULL) ? type : "");
+ } else if (value != NULL) {
+ printf("%s", value);
+ *empty = false;
+ }
+ break;
+ case CTL_STOP:
+ case CTL_RELOAD:
+ case CTL_CONF_BEGIN:
+ case CTL_CONF_ABORT:
+ // Only error message is expected here.
+ if (error != NULL) {
+ printf("error: (%s)", error);
+ }
+ break;
+ case CTL_ZONE_STATUS:
+ case CTL_ZONE_RELOAD:
+ case CTL_ZONE_REFRESH:
+ case CTL_ZONE_RETRANSFER:
+ case CTL_ZONE_NOTIFY:
+ case CTL_ZONE_FLUSH:
+ case CTL_ZONE_SIGN:
+ case CTL_ZONE_KSK_SBM:
+ case CTL_ZONE_BEGIN:
+ case CTL_ZONE_COMMIT:
+ case CTL_ZONE_ABORT:
+ case CTL_ZONE_PURGE:
+ if (data_type == KNOT_CTL_TYPE_DATA) {
+ printf("%s%s%s%s%s%s%s%s",
+ (!(*empty) ? "\n" : ""),
+ (error != NULL ? "error: " : ""),
+ (zone != NULL ? "[" : ""),
+ (zone != NULL ? zone : ""),
+ (zone != NULL ? "]" : ""),
+ (error != NULL ? " (" : ""),
+ (error != NULL ? error : ""),
+ (error != NULL ? ")" : ""));
+ *empty = false;
+ }
+ if (cmd == CTL_ZONE_STATUS && type != NULL) {
+ printf("%s %s: %s",
+ (data_type != KNOT_CTL_TYPE_DATA ? " |" : ""),
+ type, value);
+ }
+ break;
+ case CTL_CONF_COMMIT: // Can return a check error context.
+ case CTL_CONF_LIST:
+ case CTL_CONF_READ:
+ case CTL_CONF_DIFF:
+ case CTL_CONF_GET:
+ case CTL_CONF_SET:
+ case CTL_CONF_UNSET:
+ if (data_type == KNOT_CTL_TYPE_DATA) {
+ printf("%s%s%s%s%s%s%s%s%s%s%s%s",
+ (!(*empty) ? "\n" : ""),
+ (error != NULL ? "error: (" : ""),
+ (error != NULL ? error : ""),
+ (error != NULL ? ") " : ""),
+ (sign != NULL ? sign : ""),
+ (key0 != NULL ? key0 : ""),
+ (id != NULL ? "[" : ""),
+ (id != NULL ? id : ""),
+ (id != NULL ? "]" : ""),
+ (key1 != NULL ? "." : ""),
+ (key1 != NULL ? key1 : ""),
+ (value != NULL ? " =" : ""));
+ *empty = false;
+ }
+ if (value != NULL) {
+ printf(" %s", value);
+ }
+ break;
+ case CTL_ZONE_READ:
+ case CTL_ZONE_DIFF:
+ case CTL_ZONE_GET:
+ case CTL_ZONE_SET:
+ case CTL_ZONE_UNSET:
+ printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ (!(*empty) ? "\n" : ""),
+ (error != NULL ? "error: (" : ""),
+ (error != NULL ? error : ""),
+ (error != NULL ? ") " : ""),
+ (zone != NULL ? "[" : ""),
+ (zone != NULL ? zone : ""),
+ (zone != NULL ? "] " : ""),
+ (sign != NULL ? sign : ""),
+ (owner != NULL ? owner : ""),
+ (ttl != NULL ? " " : ""),
+ (ttl != NULL ? ttl : ""),
+ (type != NULL ? " " : ""),
+ (type != NULL ? type : ""),
+ (value != NULL ? " " : ""),
+ (value != NULL ? value : ""));
+ *empty = false;
+ break;
+ case CTL_STATS:
+ case CTL_ZONE_STATS:
+ printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ (!(*empty) ? "\n" : ""),
+ (error != NULL ? "error: (" : ""),
+ (error != NULL ? error : ""),
+ (error != NULL ? ") " : ""),
+ (zone != NULL ? "[" : ""),
+ (zone != NULL ? zone : ""),
+ (zone != NULL ? "] " : ""),
+ (key0 != NULL ? key0 : ""),
+ (key1 != NULL ? "." : ""),
+ (key1 != NULL ? key1 : ""),
+ (id != NULL ? "[" : ""),
+ (id != NULL ? id : ""),
+ (id != NULL ? "]" : ""),
+ (value != NULL ? " = " : ""),
+ (value != NULL ? value : ""));
+ *empty = false;
+ break;
+ default:
+ assert(0);
+ }
+}
+
+static void format_block(ctl_cmd_t cmd, bool failed, bool empty)
+{
+ switch (cmd) {
+ case CTL_STATUS:
+ printf("%s\n", (failed || !empty) ? "" : "Running");
+ break;
+ case CTL_STOP:
+ printf("%s\n", failed ? "" : "Stopped");
+ break;
+ case CTL_RELOAD:
+ printf("%s\n", failed ? "" : "Reloaded");
+ break;
+ case CTL_CONF_BEGIN:
+ case CTL_CONF_COMMIT:
+ case CTL_CONF_ABORT:
+ case CTL_CONF_SET:
+ case CTL_CONF_UNSET:
+ case CTL_ZONE_RELOAD:
+ case CTL_ZONE_REFRESH:
+ case CTL_ZONE_RETRANSFER:
+ case CTL_ZONE_NOTIFY:
+ case CTL_ZONE_FLUSH:
+ case CTL_ZONE_SIGN:
+ case CTL_ZONE_KSK_SBM:
+ case CTL_ZONE_FREEZE:
+ case CTL_ZONE_THAW:
+ case CTL_ZONE_BEGIN:
+ case CTL_ZONE_COMMIT:
+ case CTL_ZONE_ABORT:
+ case CTL_ZONE_SET:
+ case CTL_ZONE_UNSET:
+ case CTL_ZONE_PURGE:
+ printf("%s\n", failed ? "" : "OK");
+ break;
+ case CTL_ZONE_STATUS:
+ case CTL_ZONE_READ:
+ case CTL_ZONE_DIFF:
+ case CTL_ZONE_GET:
+ case CTL_CONF_LIST:
+ case CTL_CONF_READ:
+ case CTL_CONF_DIFF:
+ case CTL_CONF_GET:
+ case CTL_ZONE_STATS:
+ case CTL_STATS:
+ printf("%s", empty ? "" : "\n");
+ break;
+ default:
+ assert(0);
+ }
+}
+
+static int ctl_receive(cmd_args_t *args)
+{
+ bool failed = false;
+ bool empty = true;
+
+ while (true) {
+ knot_ctl_type_t type;
+ knot_ctl_data_t data;
+
+ int ret = knot_ctl_receive(args->ctl, &type, &data);
+ if (ret != KNOT_EOK) {
+ log_error(CTL_LOG_STR" (%s)", knot_strerror(ret));
+ return ret;
+ }
+
+ switch (type) {
+ case KNOT_CTL_TYPE_END:
+ log_error(CTL_LOG_STR" (%s)", knot_strerror(KNOT_EMALF));
+ return KNOT_EMALF;
+ case KNOT_CTL_TYPE_BLOCK:
+ format_block(args->desc->cmd, failed, empty);
+ return failed ? KNOT_ERROR : KNOT_EOK;
+ case KNOT_CTL_TYPE_DATA:
+ case KNOT_CTL_TYPE_EXTRA:
+ format_data(args->desc->cmd, type, &data, &empty);
+ break;
+ default:
+ assert(0);
+ return KNOT_EINVAL;
+ }
+
+ if (data[KNOT_CTL_IDX_ERROR] != NULL) {
+ failed = true;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+static int cmd_ctl(cmd_args_t *args)
+{
+ int ret = check_args(args, 0, (args->desc->cmd == CTL_STATUS ? 1 : 0));
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ knot_ctl_data_t data = {
+ [KNOT_CTL_IDX_CMD] = ctl_cmd_to_str(args->desc->cmd),
+ [KNOT_CTL_IDX_FLAGS] = args->force ? CTL_FLAG_FORCE : NULL,
+ [KNOT_CTL_IDX_TYPE] = args->argc > 0 ? args->argv[0] : NULL
+ };
+
+ CTL_SEND_DATA
+ CTL_SEND_BLOCK
+
+ return ctl_receive(args);
+}
+
+static int set_stats_items(cmd_args_t *args, knot_ctl_data_t *data)
+{
+ int min_args, max_args;
+ switch (args->desc->cmd) {
+ case CTL_STATS: min_args = 0; max_args = 1; break;
+ case CTL_ZONE_STATS: min_args = 1; max_args = 2; break;
+ default:
+ assert(0);
+ return KNOT_EINVAL;
+ }
+
+ // Check the number of arguments.
+ int ret = check_args(args, min_args, max_args);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ int idx = 0;
+
+ // Set ZONE name.
+ if (args->argc > idx && args->desc->cmd == CTL_ZONE_STATS) {
+ if (strcmp(args->argv[idx], "--") != 0) {
+ (*data)[KNOT_CTL_IDX_ZONE] = args->argv[idx];
+ }
+ idx++;
+ }
+
+ if (args->argc > idx) {
+ (*data)[KNOT_CTL_IDX_SECTION] = args->argv[idx];
+
+ char *item = strchr(args->argv[idx], '.');
+ if (item != NULL) {
+ // Separate section and item.
+ *item++ = '\0';
+ (*data)[KNOT_CTL_IDX_ITEM] = item;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+static int cmd_stats_ctl(cmd_args_t *args)
+{
+ knot_ctl_data_t data = {
+ [KNOT_CTL_IDX_CMD] = ctl_cmd_to_str(args->desc->cmd),
+ [KNOT_CTL_IDX_FLAGS] = args->force ? CTL_FLAG_FORCE : NULL
+ };
+
+ int ret = set_stats_items(args, &data);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ CTL_SEND_DATA
+ CTL_SEND_BLOCK
+
+ return ctl_receive(args);
+}
+
+static int zone_exec(cmd_args_t *args, int (*fcn)(const knot_dname_t *, void *),
+ void *data)
+{
+ bool failed = false;
+
+ // Process specified zones.
+ if (args->argc > 0) {
+ uint8_t id[KNOT_DNAME_MAXLEN];
+
+ for (int i = 0; i < args->argc; i++) {
+ if (knot_dname_from_str(id, args->argv[i], sizeof(id)) == NULL) {
+ log_zone_str_error(args->argv[i], "invalid name");
+ failed = true;
+ continue;
+ }
+ knot_dname_to_lower(id);
+
+ if (!conf_rawid_exists(conf(), C_ZONE, id, knot_dname_size(id))) {
+ log_zone_error(id, "%s", knot_strerror(KNOT_ENOZONE));
+ failed = true;
+ continue;
+ }
+
+ if (fcn(id, data) != KNOT_EOK) {
+ failed = true;
+ }
+ }
+ // Process all configured zones.
+ } else {
+ for (conf_iter_t iter = conf_iter(conf(), C_ZONE);
+ iter.code == KNOT_EOK; conf_iter_next(conf(), &iter)) {
+ conf_val_t val = conf_iter_id(conf(), &iter);
+ const knot_dname_t *id = conf_dname(&val);
+
+ if (fcn(id, data) != KNOT_EOK) {
+ failed = true;
+ }
+ }
+ }
+
+ return failed ? KNOT_ERROR : KNOT_EOK;
+}
+
+static int zone_check(const knot_dname_t *dname, void *data)
+{
+ UNUSED(data);
+
+ zone_contents_t *contents;
+ int ret = zone_load_contents(conf(), dname, &contents);
+ if (ret == KNOT_EOK) {
+ zone_contents_deep_free(contents);
+ }
+ return ret;
+}
+
+static int cmd_zone_check(cmd_args_t *args)
+{
+ return zone_exec(args, zone_check, NULL);
+}
+
+static int zone_memstats(const knot_dname_t *dname, void *data)
+{
+ // Init malloc wrapper for trie size estimation.
+ size_t malloc_size = 0;
+ knot_mm_t mem_ctx = {
+ .ctx = &malloc_size,
+ .alloc = estimator_malloc,
+ .free = estimator_free
+ };
+
+ // Init memory estimation context.
+ zone_estim_t est = {
+ .node_table = trie_create(&mem_ctx),
+ };
+
+ char buff[KNOT_DNAME_TXT_MAXLEN + 1];
+ char *zone_name = knot_dname_to_str(buff, dname, sizeof(buff));
+ char *zone_file = conf_zonefile(conf(), dname);
+ zs_scanner_t *zs = malloc(sizeof(zs_scanner_t));
+
+ if (est.node_table == NULL || zone_name == NULL || zone_file == NULL ||
+ zs == NULL) {
+ log_zone_error(dname, "%s", knot_strerror(KNOT_ENOMEM));
+ trie_free(est.node_table);
+ free(zone_file);
+ free(zs);
+ return KNOT_ENOMEM;
+ }
+
+ // Do a parser run, but do not actually create the zone.
+ if (zs_init(zs, zone_name, KNOT_CLASS_IN, 3600) != 0 ||
+ zs_set_processing(zs, estimator_rrset_memsize_wrap, NULL, &est) != 0 ||
+ zs_set_input_file(zs, zone_file) != 0 ||
+ zs_parse_all(zs) != 0) {
+ log_zone_error(dname, "failed to parse zone file '%s' (%s)",
+ zone_file, zs_errorname(zs->error.code));
+ trie_apply(est.node_table, estimator_free_trie_node, NULL);
+ trie_free(est.node_table);
+ free(zone_file);
+ zs_deinit(zs);
+ free(zs);
+ return KNOT_EPARSEFAIL;
+ }
+ free(zone_file);
+ zs_deinit(zs);
+ free(zs);
+
+ // Cleanup.
+ trie_apply(est.node_table, estimator_free_trie_node, NULL);
+ trie_free(est.node_table);
+
+ double zone_size = (est.rdata_size + est.node_size + est.dname_size +
+ malloc_size) / (1024.0 * 1024.0);
+
+ log_zone_info(dname, "%zu records, %.1f MiB memory",
+ est.record_count, zone_size);
+
+ double *total_size = (double *)data;
+ *total_size += zone_size;
+
+ return KNOT_EOK;
+}
+
+static int cmd_zone_memstats(cmd_args_t *args)
+{
+ double total_size = 0;
+
+ int ret = zone_exec(args, zone_memstats, &total_size);
+
+ if (args->argc != 1) {
+ log_info("Total %.1f MiB memory", total_size);
+ }
+
+ return ret;
+}
+
+static int cmd_zone_ctl(cmd_args_t *args)
+{
+ knot_ctl_data_t data = {
+ [KNOT_CTL_IDX_CMD] = ctl_cmd_to_str(args->desc->cmd),
+ [KNOT_CTL_IDX_FLAGS] = args->force ? CTL_FLAG_FORCE : NULL
+ };
+
+ // Check the number of arguments.
+ int ret = check_args(args, (args->desc->flags & CMD_FREQ_ZONE) ? 1 : 0, -1);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ if (args->desc->cmd == CTL_ZONE_PURGE && !args->force) {
+ log_error("force option required!");
+ return KNOT_EDENIED;
+ }
+
+ // Ignore all zones argument.
+ if (args->argc == 1 && strcmp(args->argv[0], "--") == 0) {
+ args->argc = 0;
+ }
+
+ if (args->argc == 0) {
+ CTL_SEND_DATA
+ }
+ for (int i = 0; i < args->argc; i++) {
+ data[KNOT_CTL_IDX_ZONE] = args->argv[i];
+
+ CTL_SEND_DATA
+ }
+
+ CTL_SEND_BLOCK
+
+ return ctl_receive(args);
+}
+
+#define MAX_FILTERS 7
+
+typedef struct {
+ const char *name;
+ char id;
+ bool with_data; // Only ONE filter of each filter_desc_t may have data!
+} filter_desc_t;
+
+const filter_desc_t zone_flush_filters[MAX_FILTERS] = {
+ { "+outdir", CTL_FILTER_FLUSH_OUTDIR, true },
+};
+
+const filter_desc_t zone_status_filters[MAX_FILTERS] = {
+ { "+role", CTL_FILTER_STATUS_ROLE },
+ { "+serial", CTL_FILTER_STATUS_SERIAL },
+ { "+transaction", CTL_FILTER_STATUS_TRANSACTION },
+ { "+freeze", CTL_FILTER_STATUS_FREEZE },
+ { "+events", CTL_FILTER_STATUS_EVENTS },
+};
+
+const filter_desc_t zone_purge_filters[MAX_FILTERS] = {
+ { "+expire", CTL_FILTER_PURGE_EXPIRE },
+ { "+timers", CTL_FILTER_PURGE_TIMERS },
+ { "+zonefile", CTL_FILTER_PURGE_ZONEFILE },
+ { "+journal", CTL_FILTER_PURGE_JOURNAL },
+ { "+kaspdb", CTL_FILTER_PURGE_KASPDB },
+ { "+orphan", CTL_FILTER_PURGE_ORPHAN },
+};
+
+const filter_desc_t null_filter = { 0 };
+
+static const filter_desc_t *get_filter(ctl_cmd_t cmd, const char *filter_name)
+{
+ const filter_desc_t *fd = NULL;
+ switch (cmd) {
+ case CTL_ZONE_FLUSH:
+ fd = zone_flush_filters;
+ break;
+ case CTL_ZONE_STATUS:
+ fd = zone_status_filters;
+ break;
+ case CTL_ZONE_PURGE:
+ fd = zone_purge_filters;
+ break;
+ default:
+ return &null_filter;
+ }
+ for (size_t i = 0; i < MAX_FILTERS && fd[i].name != NULL; i++) {
+ if (strcmp(fd[i].name, filter_name) == 0) {
+ return &fd[i];
+ }
+ }
+ return &null_filter;
+}
+
+static int cmd_zone_filter_ctl(cmd_args_t *args)
+{
+ knot_ctl_data_t data = {
+ [KNOT_CTL_IDX_CMD] = ctl_cmd_to_str(args->desc->cmd),
+ [KNOT_CTL_IDX_FLAGS] = args->force ? CTL_FLAG_FORCE : NULL
+ };
+
+ if (args->desc->cmd == CTL_ZONE_PURGE && !args->force) {
+ log_error("force option required!");
+ return KNOT_EDENIED;
+ }
+
+ char filter_buff[MAX_FILTERS + 1] = { 0 };
+
+ // First, process the filters.
+ for (int i = 0; i < args->argc; i++) {
+ if (args->argv[i][0] == '+') {
+ if (data[KNOT_CTL_IDX_FILTER] == NULL) {
+ data[KNOT_CTL_IDX_FILTER] = filter_buff;
+ }
+ char filter_id[2] = { get_filter(args->desc->cmd, args->argv[i])->id, 0 };
+ if (filter_id[0] == '\0') {
+ log_error("unknown filter: %s", args->argv[i]);
+ return KNOT_EINVAL;
+ }
+ if (strchr(filter_buff, filter_id[0]) == NULL) {
+ assert(strlen(filter_buff) < MAX_FILTERS);
+ strlcat(filter_buff, filter_id, sizeof(filter_buff));
+ }
+ if (get_filter(args->desc->cmd, args->argv[i])->with_data) {
+ data[KNOT_CTL_IDX_DATA] = args->argv[++i];
+ }
+ }
+ }
+
+ // Second, process zones.
+ int ret;
+ int sentzones = 0;
+ bool twodash = false;
+ for (int i = 0; i < args->argc; i++) {
+ // Skip filters.
+ if (args->argv[i][0] == '+') {
+ if (get_filter(args->desc->cmd, args->argv[i])->with_data) {
+ i++;
+ }
+ continue;
+ }
+
+ if (strcmp(args->argv[i], "--") != 0) {
+ data[KNOT_CTL_IDX_ZONE] = args->argv[i];
+ CTL_SEND_DATA
+ sentzones++;
+ } else {
+ twodash = true;
+ }
+ }
+
+ if ((args->desc->flags & CMD_FREQ_ZONE) && sentzones == 0 && !twodash) {
+ log_error("zone must be specified (or -- for all zones)");
+ return KNOT_EDENIED;
+ }
+
+ if (sentzones == 0) {
+ CTL_SEND_DATA
+ }
+ CTL_SEND_BLOCK
+
+ return ctl_receive(args);
+}
+
+static int set_rdata(cmd_args_t *args, int pos, char *rdata, size_t rdata_len)
+{
+ rdata[0] = '\0';
+
+ for (int i = pos; i < args->argc; i++) {
+ if (i > pos && strlcat(rdata, " ", rdata_len) >= rdata_len) {
+ return KNOT_ESPACE;
+ }
+ if (strlcat(rdata, args->argv[i], rdata_len) >= rdata_len) {
+ return KNOT_ESPACE;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+static int set_node_items(cmd_args_t *args, knot_ctl_data_t *data, char *rdata,
+ size_t rdata_len)
+{
+ int min_args, max_args;
+ switch (args->desc->cmd) {
+ case CTL_ZONE_READ:
+ case CTL_ZONE_GET: min_args = 1; max_args = 3; break;
+ case CTL_ZONE_DIFF: min_args = 1; max_args = 1; break;
+ case CTL_ZONE_SET: min_args = 3; max_args = -1; break;
+ case CTL_ZONE_UNSET: min_args = 2; max_args = -1; break;
+ default:
+ assert(0);
+ return KNOT_EINVAL;
+ }
+
+ // Check the number of arguments.
+ int ret = check_args(args, min_args, max_args);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ int idx = 0;
+
+ // Set ZONE name.
+ assert(args->argc > idx);
+ if (strcmp(args->argv[idx], "--") != 0) {
+ (*data)[KNOT_CTL_IDX_ZONE] = args->argv[idx];
+ }
+ idx++;
+
+ // Set OWNER name if specified.
+ if (args->argc > idx) {
+ (*data)[KNOT_CTL_IDX_OWNER] = args->argv[idx];
+ idx++;
+ }
+
+ // Set TTL only with an editing operation.
+ if (args->argc > idx) {
+ uint16_t type;
+ if (knot_rrtype_from_string(args->argv[idx], &type) != 0) {
+ switch (args->desc->cmd) {
+ case CTL_ZONE_SET:
+ case CTL_ZONE_UNSET:
+ (*data)[KNOT_CTL_IDX_TTL] = args->argv[idx];
+ idx++;
+ break;
+ default:
+ return KNOT_EINVAL;
+ }
+ }
+ }
+
+ // Set record TYPE if specified.
+ if (args->argc > idx) {
+ (*data)[KNOT_CTL_IDX_TYPE] = args->argv[idx];
+ idx++;
+ }
+
+ // Set record DATA if specified.
+ if (args->argc > idx) {
+ ret = set_rdata(args, idx, rdata, rdata_len);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ (*data)[KNOT_CTL_IDX_DATA] = rdata;
+ }
+
+ return KNOT_EOK;
+}
+
+static int cmd_zone_node_ctl(cmd_args_t *args)
+{
+ knot_ctl_data_t data = {
+ [KNOT_CTL_IDX_CMD] = ctl_cmd_to_str(args->desc->cmd),
+ [KNOT_CTL_IDX_FLAGS] = args->force ? CTL_FLAG_FORCE : NULL
+ };
+
+ char rdata[65536]; // Maximum item size in libknot control interface.
+
+ int ret = set_node_items(args, &data, rdata, sizeof(rdata));
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ CTL_SEND_DATA
+ CTL_SEND_BLOCK
+
+ return ctl_receive(args);
+}
+
+static int cmd_conf_init(cmd_args_t *args)
+{
+ int ret = check_args(args, 0, 0);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = conf_db_check(conf(), &conf()->read_txn);
+ if ((ret >= KNOT_EOK || ret == KNOT_CONF_EVERSION)) {
+ if (ret != KNOT_EOK && !args->force) {
+ log_error("use force option to overwrite the existing "
+ "destination and ensure the server is not running!");
+ return KNOT_EDENIED;
+ }
+
+ ret = conf_import(conf(), "", false);
+ }
+
+ if (ret == KNOT_EOK) {
+ log_info("OK");
+ } else {
+ log_error("init (%s)", knot_strerror(ret));
+ }
+
+ return ret;
+}
+
+static int cmd_conf_check(cmd_args_t *args)
+{
+ int ret = check_args(args, 0, 0);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ log_info("Configuration is valid");
+
+ return 0;
+}
+
+static int cmd_conf_import(cmd_args_t *args)
+{
+ int ret = check_args(args, 1, 1);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = conf_db_check(conf(), &conf()->read_txn);
+ if ((ret >= KNOT_EOK || ret == KNOT_CONF_EVERSION)) {
+ if (ret != KNOT_EOK && !args->force) {
+ log_error("use force option to overwrite the existing "
+ "destination and ensure the server is not running!");
+ return KNOT_EDENIED;
+ }
+
+ log_debug("importing confdb from file '%s'", args->argv[0]);
+
+ ret = conf_import(conf(), args->argv[0], true);
+ }
+
+ if (ret == KNOT_EOK) {
+ log_info("OK");
+ } else {
+ log_error("import (%s)", knot_strerror(ret));
+ }
+
+ return ret;
+}
+
+static int cmd_conf_export(cmd_args_t *args)
+{
+ int ret = check_args(args, 0, 1);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Stdout is the default output file.
+ const char *file_name = NULL;
+ if (args->argc > 0) {
+ file_name = args->argv[0];
+ log_debug("exporting confdb into file '%s'", file_name);
+ }
+
+ ret = conf_export(conf(), file_name, YP_SNONE);
+
+ if (ret == KNOT_EOK) {
+ if (args->argc > 0) {
+ log_info("OK");
+ }
+ } else {
+ log_error("export (%s)", knot_strerror(ret));
+ }
+
+ return ret;
+}
+
+static int cmd_conf_ctl(cmd_args_t *args)
+{
+ // Check the number of arguments.
+ int ret = check_conf_args(args);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ knot_ctl_data_t data = {
+ [KNOT_CTL_IDX_CMD] = ctl_cmd_to_str(args->desc->cmd),
+ [KNOT_CTL_IDX_FLAGS] = args->force ? CTL_FLAG_FORCE : NULL
+ };
+
+ // Send the command without parameters.
+ if (args->argc == 0) {
+ CTL_SEND_DATA
+ // Set the first item argument.
+ } else {
+ ret = get_conf_key(args->argv[0], &data);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Send if only one argument or item without values.
+ if (args->argc == 1 || !(args->desc->flags & CMD_FOPT_DATA)) {
+ CTL_SEND_DATA
+ }
+ }
+
+ // Send the item values or the other items.
+ for (int i = 1; i < args->argc; i++) {
+ if (args->desc->flags & CMD_FOPT_DATA) {
+ data[KNOT_CTL_IDX_DATA] = args->argv[i];
+ } else {
+ ret = get_conf_key(args->argv[i], &data);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ CTL_SEND_DATA
+ }
+
+ CTL_SEND_BLOCK
+
+ return ctl_receive(args);
+}
+
+const cmd_desc_t cmd_table[] = {
+ { CMD_EXIT, NULL, CTL_NONE },
+
+ { CMD_STATUS, cmd_ctl, CTL_STATUS, CMD_FOPT_DATA},
+ { CMD_STOP, cmd_ctl, CTL_STOP },
+ { CMD_RELOAD, cmd_ctl, CTL_RELOAD },
+ { CMD_STATS, cmd_stats_ctl, CTL_STATS },
+
+ { CMD_ZONE_CHECK, cmd_zone_check, CTL_NONE, CMD_FOPT_ZONE | CMD_FREAD },
+ { CMD_ZONE_MEMSTATS, cmd_zone_memstats, CTL_NONE, CMD_FOPT_ZONE | CMD_FREAD },
+ { CMD_ZONE_STATUS, cmd_zone_filter_ctl, CTL_ZONE_STATUS, CMD_FOPT_ZONE },
+ { CMD_ZONE_RELOAD, cmd_zone_ctl, CTL_ZONE_RELOAD, CMD_FOPT_ZONE },
+ { CMD_ZONE_REFRESH, cmd_zone_ctl, CTL_ZONE_REFRESH, CMD_FOPT_ZONE },
+ { CMD_ZONE_RETRANSFER, cmd_zone_ctl, CTL_ZONE_RETRANSFER, CMD_FOPT_ZONE },
+ { CMD_ZONE_NOTIFY, cmd_zone_ctl, CTL_ZONE_NOTIFY, CMD_FOPT_ZONE },
+ { CMD_ZONE_FLUSH, cmd_zone_filter_ctl, CTL_ZONE_FLUSH, CMD_FOPT_ZONE },
+ { CMD_ZONE_SIGN, cmd_zone_ctl, CTL_ZONE_SIGN, CMD_FOPT_ZONE },
+ { CMD_ZONE_KSK_SBM, cmd_zone_ctl, CTL_ZONE_KSK_SBM, CMD_FREQ_ZONE | CMD_FOPT_ZONE },
+ { CMD_ZONE_FREEZE, cmd_zone_ctl, CTL_ZONE_FREEZE, CMD_FOPT_ZONE },
+ { CMD_ZONE_THAW, cmd_zone_ctl, CTL_ZONE_THAW, CMD_FOPT_ZONE },
+
+ { CMD_ZONE_READ, cmd_zone_node_ctl, CTL_ZONE_READ, CMD_FREQ_ZONE },
+ { CMD_ZONE_BEGIN, cmd_zone_ctl, CTL_ZONE_BEGIN, CMD_FREQ_ZONE | CMD_FOPT_ZONE },
+ { CMD_ZONE_COMMIT, cmd_zone_ctl, CTL_ZONE_COMMIT, CMD_FREQ_ZONE | CMD_FOPT_ZONE },
+ { CMD_ZONE_ABORT, cmd_zone_ctl, CTL_ZONE_ABORT, CMD_FREQ_ZONE | CMD_FOPT_ZONE },
+ { CMD_ZONE_DIFF, cmd_zone_node_ctl, CTL_ZONE_DIFF, CMD_FREQ_ZONE },
+ { CMD_ZONE_GET, cmd_zone_node_ctl, CTL_ZONE_GET, CMD_FREQ_ZONE },
+ { CMD_ZONE_SET, cmd_zone_node_ctl, CTL_ZONE_SET, CMD_FREQ_ZONE },
+ { CMD_ZONE_UNSET, cmd_zone_node_ctl, CTL_ZONE_UNSET, CMD_FREQ_ZONE },
+ { CMD_ZONE_PURGE, cmd_zone_filter_ctl, CTL_ZONE_PURGE, CMD_FREQ_ZONE },
+ { CMD_ZONE_STATS, cmd_stats_ctl, CTL_ZONE_STATS, CMD_FREQ_ZONE },
+
+ { CMD_CONF_INIT, cmd_conf_init, CTL_NONE, CMD_FWRITE },
+ { CMD_CONF_CHECK, cmd_conf_check, CTL_NONE, CMD_FREAD | CMD_FREQ_MOD },
+ { CMD_CONF_IMPORT, cmd_conf_import, CTL_NONE, CMD_FWRITE | CMD_FOPT_MOD },
+ { CMD_CONF_EXPORT, cmd_conf_export, CTL_NONE, CMD_FREAD | CMD_FOPT_MOD },
+ { CMD_CONF_LIST, cmd_conf_ctl, CTL_CONF_LIST, CMD_FOPT_ITEM },
+ { CMD_CONF_READ, cmd_conf_ctl, CTL_CONF_READ, CMD_FOPT_ITEM },
+ { CMD_CONF_BEGIN, cmd_conf_ctl, CTL_CONF_BEGIN },
+ { CMD_CONF_COMMIT, cmd_conf_ctl, CTL_CONF_COMMIT },
+ { CMD_CONF_ABORT, cmd_conf_ctl, CTL_CONF_ABORT },
+ { CMD_CONF_DIFF, cmd_conf_ctl, CTL_CONF_DIFF, CMD_FOPT_ITEM | CMD_FREQ_TXN },
+ { CMD_CONF_GET, cmd_conf_ctl, CTL_CONF_GET, CMD_FOPT_ITEM | CMD_FREQ_TXN },
+ { CMD_CONF_SET, cmd_conf_ctl, CTL_CONF_SET, CMD_FREQ_ITEM | CMD_FOPT_DATA | CMD_FREQ_TXN },
+ { CMD_CONF_UNSET, cmd_conf_ctl, CTL_CONF_UNSET, CMD_FOPT_ITEM | CMD_FOPT_DATA | CMD_FREQ_TXN },
+ { NULL }
+};
+
+static const cmd_help_t cmd_help_table[] = {
+ { CMD_EXIT, "", "Exit interactive mode." },
+ { "", "", "" },
+ { CMD_STATUS, "[<detail>]", "Check if the server is running." },
+ { CMD_STOP, "", "Stop the server if running." },
+ { CMD_RELOAD, "", "Reload the server configuration and modified zones." },
+ { CMD_STATS, "[<module>[.<counter>]]", "Show global statistics counter(s)." },
+ { "", "", "" },
+ { CMD_ZONE_CHECK, "[<zone>...]", "Check if the zone can be loaded. (*)" },
+ { CMD_ZONE_MEMSTATS, "[<zone>...]", "Estimate memory use for the zone. (*)" },
+ { CMD_ZONE_RELOAD, "[<zone>...]", "Reload a zone from a disk." },
+ { CMD_ZONE_REFRESH, "[<zone>...]", "Force slave zone refresh." },
+ { CMD_ZONE_NOTIFY, "[<zone>...]", "Send a NOTIFY message to all configured remotes." },
+ { CMD_ZONE_RETRANSFER, "[<zone>...]", "Force slave zone retransfer (no serial check)." },
+ { CMD_ZONE_FLUSH, "[<zone>...] [<filter>...]", "Flush zone journal into the zone file." },
+ { CMD_ZONE_SIGN, "[<zone>...]", "Re-sign the automatically signed zone." },
+ { CMD_ZONE_KSK_SBM, "<zone>...", "When KSK submission, confirm parent's DS presence." },
+ { CMD_ZONE_FREEZE, "[<zone>...]", "Temporarily postpone automatic zone-changing events." },
+ { CMD_ZONE_THAW, "[<zone>...]", "Dismiss zone freeze." },
+ { "", "", "" },
+ { CMD_ZONE_READ, "<zone> [<owner> [<type>]]", "Get zone data that are currently being presented." },
+ { CMD_ZONE_BEGIN, "<zone>...", "Begin a zone transaction." },
+ { CMD_ZONE_COMMIT, "<zone>...", "Commit the zone transaction." },
+ { CMD_ZONE_ABORT, "<zone>...", "Abort the zone transaction." },
+ { CMD_ZONE_DIFF, "<zone>", "Get zone changes within the transaction." },
+ { CMD_ZONE_GET, "<zone> [<owner> [<type>]]", "Get zone data within the transaction." },
+ { CMD_ZONE_SET, "<zone> <owner> [<ttl>] <type> <rdata>", "Add zone record within the transaction." },
+ { CMD_ZONE_UNSET, "<zone> <owner> [<type> [<rdata>]]", "Remove zone data within the transaction." },
+ { CMD_ZONE_PURGE, "<zone>... [<filter>...]", "Purge zone data, zone file, journal, timers, and KASP data." },
+ { CMD_ZONE_STATS, "<zone> [<module>[.<counter>]]", "Show zone statistics counter(s)."},
+ { CMD_ZONE_STATUS, "<zone> [<filter>...]", "Show the zone status." },
+ { "", "", "" },
+ { CMD_CONF_INIT, "", "Initialize the confdb. (*)" },
+ { CMD_CONF_CHECK, "", "Check the server configuration. (*)" },
+ { CMD_CONF_IMPORT, "<filename>", "Import a config file into the confdb. (*)" },
+ { CMD_CONF_EXPORT, "[<filename>]", "Export the confdb into a config file or stdout. (*)" },
+ { CMD_CONF_LIST, "[<item>...]", "List the confdb sections or section items." },
+ { CMD_CONF_READ, "[<item>...]", "Get the item from the active confdb." },
+ { CMD_CONF_BEGIN, "", "Begin a writing confdb transaction." },
+ { CMD_CONF_COMMIT, "", "Commit the confdb transaction." },
+ { CMD_CONF_ABORT, "", "Rollback the confdb transaction." },
+ { CMD_CONF_DIFF, "[<item>...]", "Get the item difference within the transaction." },
+ { CMD_CONF_GET, "[<item>...]", "Get the item data within the transaction." },
+ { CMD_CONF_SET, " <item> [<data>...]", "Set the item data within the transaction." },
+ { CMD_CONF_UNSET, "[<item>] [<data>...]", "Unset the item data within the transaction." },
+ { NULL }
+};
+
+void print_commands(void)
+{
+ printf("\nActions:\n");
+
+ for (const cmd_help_t *cmd = cmd_help_table; cmd->name != NULL; cmd++) {
+ printf(" %-18s %-38s %s\n", cmd->name, cmd->params, cmd->desc);
+ }
+
+ printf("\n"
+ "Note:\n"
+ " Use @ owner to denote the zone name.\n"
+ " Empty or '--' <zone> parameter means all zones or all zones with a transaction.\n"
+ " Type <item> parameter in the form of <section>[<identifier>].<name>.\n"
+ " (*) indicates a local operation which requires a configuration.\n");
+}
diff --git a/src/utils/knotc/commands.h b/src/utils/knotc/commands.h
new file mode 100644
index 0000000..5cabaf1
--- /dev/null
+++ b/src/utils/knotc/commands.h
@@ -0,0 +1,68 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include "libknot/control/control.h"
+#include "knot/ctl/commands.h"
+
+/*! \brief Command condition flags. */
+typedef enum {
+ CMD_FNONE = 0, /*!< Empty flag. */
+ CMD_FREAD = 1 << 0, /*!< Required read access to config or confdb. */
+ CMD_FWRITE = 1 << 1, /*!< Required write access to confdb. */
+ CMD_FOPT_ITEM = 1 << 2, /*!< Optional item argument. */
+ CMD_FREQ_ITEM = 1 << 3, /*!< Required item argument. */
+ CMD_FOPT_DATA = 1 << 4, /*!< Optional item data argument. */
+ CMD_FOPT_ZONE = 1 << 5, /*!< Optional zone name argument. */
+ CMD_FREQ_ZONE = 1 << 6, /*!< Required zone name argument. */
+ CMD_FREQ_TXN = 1 << 7, /*!< Required open confdb transaction. */
+ CMD_FOPT_MOD = 1 << 8, /*!< Optional configured modules dependency. */
+ CMD_FREQ_MOD = 1 << 9, /*!< Required configured modules dependency. */
+} cmd_flag_t;
+
+struct cmd_desc;
+typedef struct cmd_desc cmd_desc_t;
+
+/*! \brief Command callback arguments. */
+typedef struct {
+ const cmd_desc_t *desc;
+ knot_ctl_t *ctl;
+ int argc;
+ const char **argv;
+ bool force;
+} cmd_args_t;
+
+/*! \brief Command callback description. */
+struct cmd_desc {
+ const char *name;
+ int (*fcn)(cmd_args_t *);
+ ctl_cmd_t cmd;
+ cmd_flag_t flags;
+};
+
+/*! \brief Command description. */
+typedef struct {
+ const char *name;
+ const char *params;
+ const char *desc;
+} cmd_help_t;
+
+/*! \brief Table of commands. */
+extern const cmd_desc_t cmd_table[];
+
+/*! \brief Prints commands help. */
+void print_commands(void);
diff --git a/src/utils/knotc/estimator.c b/src/utils/knotc/estimator.c
new file mode 100644
index 0000000..f1fa1a7
--- /dev/null
+++ b/src/utils/knotc/estimator.c
@@ -0,0 +1,147 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+
+#include "utils/knotc/estimator.h"
+#include "knot/zone/node.h"
+#include "libknot/libknot.h"
+#include "contrib/macros.h"
+#include "contrib/string.h"
+#include "contrib/ucw/lists.h"
+
+// Addition constants used for tweaking, mostly malloc overhead
+enum estim_consts {
+ MALLOC_OVERHEAD = sizeof(size_t), // set according to malloc.c
+ MALLOC_MIN = MALLOC_OVERHEAD * 3 // minimum size of malloc'd chunk
+};
+
+typedef struct {
+ node_t n;
+ uint16_t type;
+} type_list_item_t;
+
+static size_t add_overhead(size_t size)
+{
+ return MALLOC_OVERHEAD + size + size % MALLOC_MIN;
+}
+
+// return: 0 not present, 1 - present
+static int find_in_list(list_t *node_list, uint16_t type)
+{
+ node_t *n = NULL;
+ WALK_LIST(n, *node_list) {
+ type_list_item_t *l_entr = (type_list_item_t *)n;
+ assert(l_entr);
+ if (l_entr->type == type) {
+ return 1;
+ }
+ }
+
+ type_list_item_t *new_entry = malloc(sizeof(type_list_item_t));
+ assert(new_entry != NULL);
+ new_entry->type = type;
+
+ add_head(node_list, (node_t *)new_entry);
+ return 0;
+}
+
+// return: 0 not present (added), 1 - present
+static int dummy_node_add_type(list_t *l, uint16_t t)
+{
+ return find_in_list(l, t);
+}
+
+// return: 0 - unique, 1 - duplicate
+static int insert_dname_into_table(trie_t *table, const knot_dname_t *d,
+ list_t **dummy_node)
+{
+ size_t d_size = knot_dname_size(d);
+
+ trie_val_t *val = trie_get_try(table, (char *)d, d_size);
+ if (val == NULL) {
+ // Create new dummy node to use for this dname
+ *dummy_node = malloc(sizeof(list_t));
+ assert(dummy_node != NULL);
+ init_list(*dummy_node);
+ *trie_get_ins(table, (char *)d, d_size) = *dummy_node;
+ return 0;
+ } else {
+ // Return previously found dummy node
+ *dummy_node = (list_t *)(*val);
+ return 1;
+ }
+}
+
+static void rrset_memsize(zone_estim_t *est, const zs_scanner_t *scanner)
+{
+ // Handle RRSet's owner
+ list_t *dummy_node = NULL;
+ if (insert_dname_into_table(est->node_table, scanner->r_owner, &dummy_node) == 0) {
+ // First time we see this name == new node
+ est->node_size += add_overhead(sizeof(zone_node_t));
+ // Also, node has an owner.
+ est->dname_size += add_overhead(knot_dname_size(scanner->r_owner));
+ // Trie's nodes handled at the end of computation
+ }
+ assert(dummy_node);
+
+ // Add RDATA + size
+ size_t rdlen = knot_rdata_size(scanner->r_data_length);
+ est->rdata_size += add_overhead(rdlen);
+ est->record_count++;
+
+ /*
+ * RDATA size done, now add static part of RRSet to size.
+ * Do not add for RRs that would be merged.
+ * All possible duplicates will be added to total size.
+ */
+ if (dummy_node_add_type(dummy_node, scanner->r_type) == 0) {
+ /*
+ * New RR type, add actual rr_data struct's size. No way to
+ * guess the actual overhead taken up by the array, so we add
+ * it each time.
+ */
+ est->node_size += add_overhead(sizeof(struct rr_data));
+ }
+}
+
+void *estimator_malloc(void *ctx, size_t len)
+{
+ size_t *count = (size_t *)ctx;
+ *count += add_overhead(len);
+ return malloc(len);
+}
+
+void estimator_free(void *p)
+{
+ free(p);
+}
+
+void estimator_rrset_memsize_wrap(zs_scanner_t *scanner)
+{
+ rrset_memsize(scanner->process.data, scanner);
+}
+
+int estimator_free_trie_node(trie_val_t *val, void *data)
+{
+ UNUSED(data);
+ list_t *trie_n = (list_t *)(*val);
+ WALK_LIST_FREE(*trie_n);
+ free(trie_n);
+
+ return KNOT_EOK;
+}
diff --git a/src/utils/knotc/estimator.h b/src/utils/knotc/estimator.h
new file mode 100644
index 0000000..ee05d5f
--- /dev/null
+++ b/src/utils/knotc/estimator.h
@@ -0,0 +1,64 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include "contrib/qp-trie/trie.h"
+#include "libzscanner/scanner.h"
+
+/*!
+ * \brief Memory estimation context.
+ */
+typedef struct {
+ trie_t *node_table; /*!< Same trie is in actual zone. */
+ size_t rdata_size; /*!< Estimated RDATA size. */
+ size_t dname_size; /*!< Estimated DNAME size. */
+ size_t node_size; /*!< Estimated node size. */
+ size_t record_count; /*!< Total record count for zone. */
+} zone_estim_t;
+
+/*!
+ * \brief Size counting malloc wrapper.
+ *
+ * \param ctx Data for malloc wrapper.
+ * \param len Size to allocate.
+ *
+ * \retval Alloc'd data on succes.
+ * \retval NULL on error.
+ */
+void *estimator_malloc(void *ctx, size_t len);
+
+/*!
+ * \brief Size counting free wrapper.
+ *
+ * \param p Data to free.
+ */
+void estimator_free(void *p);
+
+/*!
+ * \brief For use with scanner - counts memsize of RRSets.
+ *
+ * \param scanner Scanner context.
+ */
+void estimator_rrset_memsize_wrap(zs_scanner_t *scanner);
+
+/*!
+ * \brief Cleanup function for use with trie.
+ *
+ * \param val Data to free.
+ * \param data Unused variable.
+ */
+int estimator_free_trie_node(trie_val_t *val, void *data);
diff --git a/src/utils/knotc/interactive.c b/src/utils/knotc/interactive.c
new file mode 100644
index 0000000..ad14104
--- /dev/null
+++ b/src/utils/knotc/interactive.c
@@ -0,0 +1,433 @@
+/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdio.h>
+#include <histedit.h>
+
+#include "knot/common/log.h"
+#include "utils/common/lookup.h"
+#include "utils/knotc/interactive.h"
+#include "utils/knotc/commands.h"
+#include "contrib/string.h"
+
+#define PROGRAM_NAME "knotc"
+#define HISTORY_FILE ".knotc_history"
+
+extern params_t params;
+
+static void cmds_lookup(EditLine *el, const char *str, size_t str_len)
+{
+ lookup_t lookup;
+ int ret = lookup_init(&lookup);
+ if (ret != KNOT_EOK) {
+ return;
+ }
+
+ // Fill the lookup with command names.
+ for (const cmd_desc_t *desc = cmd_table; desc->name != NULL; desc++) {
+ ret = lookup_insert(&lookup, desc->name, NULL);
+ if (ret != KNOT_EOK) {
+ goto cmds_lookup_finish;
+ }
+ }
+
+ lookup_complete(&lookup, str, str_len, el, true);
+
+cmds_lookup_finish:
+ lookup_deinit(&lookup);
+}
+
+static void local_zones_lookup(EditLine *el, const char *str, size_t str_len)
+{
+ lookup_t lookup;
+ int ret = lookup_init(&lookup);
+ if (ret != KNOT_EOK) {
+ return;
+ }
+
+ char buff[KNOT_DNAME_TXT_MAXLEN + 1];
+
+ // Fill the lookup with local zone names.
+ for (conf_iter_t iter = conf_iter(conf(), C_ZONE);
+ iter.code == KNOT_EOK; conf_iter_next(conf(), &iter)) {
+ conf_val_t val = conf_iter_id(conf(), &iter);
+ char *name = knot_dname_to_str(buff, conf_dname(&val), sizeof(buff));
+
+ ret = lookup_insert(&lookup, name, NULL);
+ if (ret != KNOT_EOK) {
+ conf_iter_finish(conf(), &iter);
+ goto local_zones_lookup_finish;
+ }
+ }
+
+ lookup_complete(&lookup, str, str_len, el, true);
+
+local_zones_lookup_finish:
+ lookup_deinit(&lookup);
+}
+
+static char *get_id_name(const char *section)
+{
+ const cmd_desc_t *desc = cmd_table;
+ while (desc->name != NULL && desc->cmd != CTL_CONF_LIST) {
+ desc++;
+ }
+ assert(desc->name != NULL);
+
+ knot_ctl_data_t query = {
+ [KNOT_CTL_IDX_CMD] = ctl_cmd_to_str(desc->cmd),
+ [KNOT_CTL_IDX_SECTION] = section
+ };
+
+ knot_ctl_t *ctl = NULL;
+ knot_ctl_type_t type;
+ knot_ctl_data_t reply;
+
+ // Try to get the first group item (possible id).
+ if (set_ctl(&ctl, desc, &params) != KNOT_EOK ||
+ knot_ctl_send(ctl, KNOT_CTL_TYPE_DATA, &query) != KNOT_EOK ||
+ knot_ctl_send(ctl, KNOT_CTL_TYPE_BLOCK, NULL) != KNOT_EOK ||
+ knot_ctl_receive(ctl, &type, &reply) != KNOT_EOK ||
+ type != KNOT_CTL_TYPE_DATA || reply[KNOT_CTL_IDX_ERROR] != NULL) {
+ unset_ctl(ctl);
+ return NULL;
+ }
+
+ char *id_name = strdup(reply[KNOT_CTL_IDX_ITEM]);
+
+ unset_ctl(ctl);
+
+ return id_name;
+}
+
+static void id_lookup(EditLine *el, const char *str, size_t str_len,
+ const cmd_desc_t *cmd_desc, const char *section, bool add_space)
+{
+ // Decide which confdb transaction to ask.
+ unsigned ctl_code = (cmd_desc->flags & CMD_FREQ_TXN) ?
+ CTL_CONF_GET : CTL_CONF_READ;
+
+ const cmd_desc_t *desc = cmd_table;
+ while (desc->name != NULL && desc->cmd != ctl_code) {
+ desc++;
+ }
+ assert(desc->name != NULL);
+
+ char *id_name = get_id_name(section);
+ if (id_name == NULL) {
+ return;
+ }
+
+ knot_ctl_data_t query = {
+ [KNOT_CTL_IDX_CMD] = ctl_cmd_to_str(desc->cmd),
+ [KNOT_CTL_IDX_SECTION] = section,
+ [KNOT_CTL_IDX_ITEM] = id_name
+ };
+
+ lookup_t lookup;
+ knot_ctl_t *ctl = NULL;
+
+ if (set_ctl(&ctl, desc, &params) != KNOT_EOK ||
+ knot_ctl_send(ctl, KNOT_CTL_TYPE_DATA, &query) != KNOT_EOK ||
+ knot_ctl_send(ctl, KNOT_CTL_TYPE_BLOCK, NULL) != KNOT_EOK ||
+ lookup_init(&lookup) != KNOT_EOK) {
+ unset_ctl(ctl);
+ free(id_name);
+ return;
+ }
+
+ free(id_name);
+
+ while (true) {
+ knot_ctl_type_t type;
+ knot_ctl_data_t reply;
+
+ // Receive one section id.
+ if (knot_ctl_receive(ctl, &type, &reply) != KNOT_EOK) {
+ goto id_lookup_finish;
+ }
+
+ // Stop if finished transfer.
+ if (type != KNOT_CTL_TYPE_DATA) {
+ break;
+ }
+
+ // Insert the id into the lookup.
+ if (reply[KNOT_CTL_IDX_ERROR] != NULL ||
+ lookup_insert(&lookup, reply[KNOT_CTL_IDX_DATA], NULL) != KNOT_EOK) {
+ goto id_lookup_finish;
+ }
+ }
+
+ lookup_complete(&lookup, str, str_len, el, add_space);
+
+id_lookup_finish:
+ lookup_deinit(&lookup);
+ unset_ctl(ctl);
+}
+
+static void list_lookup(EditLine *el, const char *section, const char *item)
+{
+ const cmd_desc_t *desc = cmd_table;
+ while (desc->name != NULL && desc->cmd != CTL_CONF_LIST) {
+ desc++;
+ }
+ assert(desc->name != NULL);
+
+ knot_ctl_data_t query = {
+ [KNOT_CTL_IDX_CMD] = ctl_cmd_to_str(desc->cmd),
+ [KNOT_CTL_IDX_SECTION] = section
+ };
+
+ lookup_t lookup;
+ knot_ctl_t *ctl = NULL;
+
+ if (set_ctl(&ctl, desc, &params) != KNOT_EOK ||
+ knot_ctl_send(ctl, KNOT_CTL_TYPE_DATA, &query) != KNOT_EOK ||
+ knot_ctl_send(ctl, KNOT_CTL_TYPE_BLOCK, NULL) != KNOT_EOK ||
+ lookup_init(&lookup) != KNOT_EOK) {
+ unset_ctl(ctl);
+ return;
+ }
+
+ while (true) {
+ knot_ctl_type_t type;
+ knot_ctl_data_t reply;
+
+ // Receive one section/item name.
+ if (knot_ctl_receive(ctl, &type, &reply) != KNOT_EOK) {
+ goto list_lookup_finish;
+ }
+
+ // Stop if finished transfer.
+ if (type != KNOT_CTL_TYPE_DATA) {
+ break;
+ }
+
+ const char *str = (section == NULL) ? reply[KNOT_CTL_IDX_SECTION] :
+ reply[KNOT_CTL_IDX_ITEM];
+
+ // Insert the name into the lookup.
+ if (reply[KNOT_CTL_IDX_ERROR] != NULL ||
+ lookup_insert(&lookup, str, NULL) != KNOT_EOK) {
+ goto list_lookup_finish;
+ }
+ }
+
+ lookup_complete(&lookup, item, strlen(item), el, section != NULL);
+
+list_lookup_finish:
+ lookup_deinit(&lookup);
+ unset_ctl(ctl);
+}
+
+static void item_lookup(EditLine *el, const char *str, const cmd_desc_t *cmd_desc)
+{
+ // List all sections.
+ if (str == NULL) {
+ list_lookup(el, NULL, "");
+ return;
+ }
+
+ // Check for id specification.
+ char *id = (strchr(str, '['));
+ if (id != NULL) {
+ char *section = strndup(str, id - str);
+
+ // Check for completed id specification.
+ char *id_stop = (strchr(id, ']'));
+ if (id_stop != NULL) {
+ // Complete the item name.
+ if (*(id_stop + 1) == '.') {
+ list_lookup(el, section, id_stop + 2);
+ }
+ } else {
+ // Complete the section id.
+ id_lookup(el, id + 1, strlen(id + 1), cmd_desc, section, false);
+ }
+
+ free(section);
+ } else {
+ // Check for item specification.
+ char *dot = (strchr(str, '.'));
+ if (dot != NULL) {
+ // Complete the item name.
+ char *section = strndup(str, dot - str);
+ list_lookup(el, section, dot + 1);
+ free(section);
+ } else {
+ // Complete the section name.
+ list_lookup(el, NULL, str);
+ }
+ }
+}
+
+static unsigned char complete(EditLine *el, int ch)
+{
+ int argc, token, pos;
+ const char **argv;
+
+ const LineInfo *li = el_line(el);
+ Tokenizer *tok = tok_init(NULL);
+
+ // Parse the line.
+ int ret = tok_line(tok, li, &argc, &argv, &token, &pos);
+ if (ret != 0) {
+ goto complete_exit;
+ }
+
+ // Show possible commands.
+ if (argc == 0) {
+ print_commands();
+ goto complete_exit;
+ }
+
+ // Complete the command name.
+ if (token == 0) {
+ cmds_lookup(el, argv[0], pos);
+ goto complete_exit;
+ }
+
+ // Find the command descriptor.
+ const cmd_desc_t *desc = cmd_table;
+ while (desc->name != NULL && strcmp(desc->name, argv[0]) != 0) {
+ desc++;
+ }
+ if (desc->name == NULL) {
+ goto complete_exit;
+ }
+
+ // Finish if a command with no or unsupported arguments.
+ if (desc->flags == CMD_FNONE || desc->flags == CMD_FREAD ||
+ desc->flags == CMD_FWRITE) {
+ goto complete_exit;
+ }
+
+ ret = set_config(desc, &params);
+ if (ret != KNOT_EOK) {
+ goto complete_exit;
+ }
+
+ // Complete the zone name.
+ if (desc->flags & (CMD_FREQ_ZONE | CMD_FOPT_ZONE)) {
+ if (token > 1 && !(desc->flags & CMD_FOPT_ZONE)) {
+ goto complete_exit;
+ }
+
+ if (desc->flags & CMD_FREAD) {
+ local_zones_lookup(el, argv[token], pos);
+ } else {
+ id_lookup(el, argv[token], pos, desc, "zone", true);
+ }
+ goto complete_exit;
+ // Complete the section/id/item name.
+ } else if (desc->flags & (CMD_FOPT_ITEM | CMD_FREQ_ITEM)) {
+ if (token == 1) {
+ item_lookup(el, argv[1], desc);
+ }
+ goto complete_exit;
+ }
+
+complete_exit:
+ conf_update(NULL, CONF_UPD_FNONE);
+ tok_reset(tok);
+ tok_end(tok);
+
+ return CC_REDISPLAY;
+}
+
+static char *prompt(EditLine *el)
+{
+ return PROGRAM_NAME"> ";
+}
+
+int interactive_loop(params_t *params)
+{
+ char *hist_file = NULL;
+ const char *home = getenv("HOME");
+ if (home != NULL) {
+ hist_file = sprintf_alloc("%s/%s", home, HISTORY_FILE);
+ }
+ if (hist_file == NULL) {
+ log_notice("failed to get home directory");
+ }
+
+ EditLine *el = el_init(PROGRAM_NAME, stdin, stdout, stderr);
+ if (el == NULL) {
+ log_error("interactive mode not available");
+ free(hist_file);
+ return KNOT_ERROR;
+ }
+
+ History *hist = history_init();
+ if (hist == NULL) {
+ log_error("interactive mode not available");
+ el_end(el);
+ free(hist_file);
+ return KNOT_ERROR;
+ }
+
+ HistEvent hev = { 0 };
+ history(hist, &hev, H_SETSIZE, 100);
+ el_set(el, EL_HIST, history, hist);
+ history(hist, &hev, H_LOAD, hist_file);
+
+ el_set(el, EL_TERMINAL, NULL);
+ el_set(el, EL_EDITOR, "emacs");
+ el_set(el, EL_PROMPT, prompt);
+ el_set(el, EL_SIGNAL, 1);
+ el_source(el, NULL);
+
+ el_set(el, EL_ADDFN, PROGRAM_NAME"-complete",
+ "Perform "PROGRAM_NAME" completion.", complete);
+ el_set(el, EL_BIND, "^I", PROGRAM_NAME"-complete", NULL);
+
+ int count;
+ const char *line;
+ while ((line = el_gets(el, &count)) != NULL && count > 0) {
+ history(hist, &hev, H_ENTER, line);
+
+ Tokenizer *tok = tok_init(NULL);
+
+ // Tokenize the current line.
+ int argc;
+ const char **argv;
+ const LineInfo *li = el_line(el);
+ int ret = tok_line(tok, li, &argc, &argv, NULL, NULL);
+ if (ret != 0) {
+ continue;
+ }
+
+ // Process the command.
+ ret = process_cmd(argc, argv, params);
+
+ history(hist, &hev, H_SAVE, hist_file);
+ tok_reset(tok);
+ tok_end(tok);
+
+ // Check for the exit command.
+ if (ret == KNOT_CTL_ESTOP) {
+ break;
+ }
+ }
+
+ history_end(hist);
+ free(hist_file);
+
+ el_end(el);
+
+ return KNOT_EOK;
+}
diff --git a/src/utils/knotc/interactive.h b/src/utils/knotc/interactive.h
new file mode 100644
index 0000000..6c7b3be
--- /dev/null
+++ b/src/utils/knotc/interactive.h
@@ -0,0 +1,26 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include "utils/knotc/process.h"
+
+/*!
+ * Executes an interactive processing loop.
+ *
+ * \param[in] params Utility parameters.
+ */
+int interactive_loop(params_t *params);
diff --git a/src/utils/knotc/main.c b/src/utils/knotc/main.c
new file mode 100644
index 0000000..826c7bf
--- /dev/null
+++ b/src/utils/knotc/main.c
@@ -0,0 +1,145 @@
+/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <getopt.h>
+#include <stdio.h>
+
+#include "contrib/strtonum.h"
+#include "knot/common/log.h"
+#include "utils/common/params.h"
+#include "utils/knotc/commands.h"
+#include "utils/knotc/interactive.h"
+#include "utils/knotc/process.h"
+
+#define PROGRAM_NAME "knotc"
+#define SPACE " "
+#define DEFAULT_CTL_TIMEOUT 10
+
+static void print_help(void)
+{
+ printf("Usage: %s [parameters] <action> [action_args]\n"
+ "\n"
+ "Parameters:\n"
+ " -c, --config <file> "SPACE"Use a textual configuration file.\n"
+ " "SPACE" (default %s)\n"
+ " -C, --confdb <dir> "SPACE"Use a binary configuration database directory.\n"
+ " "SPACE" (default %s)\n"
+ " -m, --max-conf-size <MiB>"SPACE"Set maximum configuration size (max 10000 MiB).\n"
+ " "SPACE" (default %d MiB)\n"
+ " -s, --socket <path> "SPACE"Use a control UNIX socket path.\n"
+ " "SPACE" (default %s)\n"
+ " -t, --timeout <sec> "SPACE"Use a control socket timeout (max 7200 seconds).\n"
+ " "SPACE" (default %u seconds)\n"
+ " -f, --force "SPACE"Forced operation. Overrides some checks.\n"
+ " -v, --verbose "SPACE"Enable debug output.\n"
+ " -h, --help "SPACE"Print the program help.\n"
+ " -V, --version "SPACE"Print the program version.\n",
+ PROGRAM_NAME, CONF_DEFAULT_FILE, CONF_DEFAULT_DBDIR,
+ CONF_MAPSIZE, RUN_DIR "/knot.sock", DEFAULT_CTL_TIMEOUT);
+
+ print_commands();
+}
+
+params_t params = {
+ .max_conf_size = (size_t)CONF_MAPSIZE * 1024 * 1024,
+ .timeout = DEFAULT_CTL_TIMEOUT * 1000
+};
+
+int main(int argc, char **argv)
+{
+ /* Long options. */
+ struct option opts[] = {
+ { "config", required_argument, NULL, 'c' },
+ { "confdb", required_argument, NULL, 'C' },
+ { "max-conf-size", required_argument, NULL, 'm' },
+ { "socket", required_argument, NULL, 's' },
+ { "timeout", required_argument, NULL, 't' },
+ { "force", no_argument, NULL, 'f' },
+ { "verbose", no_argument, NULL, 'v' },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'V' },
+ { NULL }
+ };
+
+ /* Parse command line arguments */
+ int opt = 0;
+ while ((opt = getopt_long(argc, argv, "+c:C:m:s:t:fvhV", opts, NULL)) != -1) {
+ switch (opt) {
+ case 'c':
+ params.config = optarg;
+ break;
+ case 'C':
+ params.confdb = optarg;
+ break;
+ case 'm':
+ if (str_to_size(optarg, &params.max_conf_size, 1, 10000) != KNOT_EOK) {
+ print_help();
+ return EXIT_FAILURE;
+ }
+ /* Convert to bytes. */
+ params.max_conf_size *= 1024 * 1024;
+ break;
+ case 's':
+ params.socket = optarg;
+ break;
+ case 't':
+ if (str_to_int(optarg, &params.timeout, 0, 7200) != KNOT_EOK) {
+ print_help();
+ return EXIT_FAILURE;
+ }
+ /* Convert to milliseconds. */
+ params.timeout *= 1000;
+ break;
+ case 'f':
+ params.force = true;
+ break;
+ case 'v':
+ params.verbose = true;
+ break;
+ case 'h':
+ print_help();
+ return EXIT_SUCCESS;
+ case 'V':
+ print_version(PROGRAM_NAME);
+ return EXIT_SUCCESS;
+ default:
+ print_help();
+ return EXIT_FAILURE;
+ }
+ }
+
+ /* Set up simplified logging just to stdout/stderr. */
+ log_init();
+ log_levels_set(LOG_TARGET_STDOUT, LOG_SOURCE_ANY,
+ LOG_MASK(LOG_INFO) | LOG_MASK(LOG_NOTICE));
+ log_levels_set(LOG_TARGET_STDERR, LOG_SOURCE_ANY, LOG_UPTO(LOG_WARNING));
+ log_levels_set(LOG_TARGET_SYSLOG, LOG_SOURCE_ANY, 0);
+ log_flag_set(LOG_FLAG_NOTIMESTAMP | LOG_FLAG_NOINFO);
+ if (params.verbose) {
+ log_levels_add(LOG_TARGET_STDOUT, LOG_SOURCE_ANY, LOG_MASK(LOG_DEBUG));
+ }
+
+ int ret;
+ if (argc - optind < 1) {
+ ret = interactive_loop(&params);
+ } else {
+ ret = process_cmd(argc - optind, (const char **)argv + optind, &params);
+ }
+
+ log_close();
+
+ return (ret == KNOT_EOK) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/src/utils/knotc/process.c b/src/utils/knotc/process.c
new file mode 100644
index 0000000..7f0502f
--- /dev/null
+++ b/src/utils/knotc/process.c
@@ -0,0 +1,238 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <sys/stat.h>
+
+#include "knot/conf/conf.h"
+#include "knot/common/log.h"
+#include "utils/knotc/commands.h"
+#include "utils/knotc/process.h"
+
+static const cmd_desc_t *get_cmd_desc(const char *command)
+{
+ /* Find requested command. */
+ const cmd_desc_t *desc = cmd_table;
+ while (desc->name != NULL) {
+ if (strcmp(desc->name, command) == 0) {
+ break;
+ }
+ desc++;
+ }
+ if (desc->name == NULL) {
+ log_error("invalid command '%s'", command);
+ return NULL;
+ }
+
+ return desc;
+}
+
+int set_config(const cmd_desc_t *desc, params_t *params)
+{
+ if (params->config != NULL && params->confdb != NULL) {
+ log_error("ambiguous configuration source");
+ return KNOT_EINVAL;
+ }
+
+ /* Mask relevant flags. */
+ cmd_flag_t flags = desc->flags & (CMD_FREAD | CMD_FWRITE);
+ cmd_flag_t mod_flags = desc->flags & (CMD_FOPT_MOD | CMD_FREQ_MOD);
+
+ /* Choose the optimal config source. */
+ struct stat st;
+ bool import = false;
+ if (flags == CMD_FNONE && params->socket != NULL) {
+ /* Control operation, known socket, skip configuration. */
+ return KNOT_EOK;
+ } else if (params->confdb != NULL) {
+ import = false;
+ } else if (flags == CMD_FWRITE) {
+ import = false;
+ params->confdb = CONF_DEFAULT_DBDIR;
+ } else if (params->config != NULL){
+ import = true;
+ } else if (stat(CONF_DEFAULT_DBDIR, &st) == 0) {
+ import = false;
+ params->confdb = CONF_DEFAULT_DBDIR;
+ } else if (stat(CONF_DEFAULT_FILE, &st) == 0) {
+ import = true;
+ params->config = CONF_DEFAULT_FILE;
+ } else if (flags != CMD_FNONE) {
+ log_error("no configuration source available");
+ return KNOT_EINVAL;
+ }
+
+ const char *src = import ? params->config : params->confdb;
+ log_debug("%s '%s'", import ? "config" : "confdb",
+ (src != NULL) ? src : "empty");
+
+ /* Prepare config flags. */
+ conf_flag_t conf_flags = CONF_FNOHOSTNAME;
+ if (params->confdb != NULL && !(flags & CMD_FWRITE)) {
+ conf_flags |= CONF_FREADONLY;
+ }
+ if (import || mod_flags & CMD_FOPT_MOD) {
+ conf_flags |= CONF_FOPTMODULES;
+ } else if (mod_flags & CMD_FREQ_MOD) {
+ conf_flags |= CONF_FREQMODULES;
+ }
+
+ /* Open confdb. */
+ conf_t *new_conf = NULL;
+ int ret = conf_new(&new_conf, conf_schema, params->confdb,
+ params->max_conf_size, conf_flags);
+ if (ret != KNOT_EOK) {
+ log_error("failed to open configuration database '%s' (%s)",
+ (params->confdb != NULL) ? params->confdb : "",
+ knot_strerror(ret));
+ return ret;
+ }
+
+ /* Import the config file. */
+ if (import) {
+ ret = conf_import(new_conf, params->config, true);
+ if (ret != KNOT_EOK) {
+ log_error("failed to load configuration file '%s' (%s)",
+ params->config, knot_strerror(ret));
+ conf_free(new_conf);
+ return ret;
+ }
+ }
+
+ /* Update to the new config. */
+ conf_update(new_conf, CONF_UPD_FNONE);
+
+ return KNOT_EOK;
+}
+
+int set_ctl(knot_ctl_t **ctl, const cmd_desc_t *desc, params_t *params)
+{
+ if (desc == NULL) {
+ *ctl = NULL;
+ return KNOT_EINVAL;
+ }
+
+ /* Mask relevant flags. */
+ cmd_flag_t flags = desc->flags & (CMD_FREAD | CMD_FWRITE);
+
+ /* Check if control socket is required. */
+ if (flags != CMD_FNONE) {
+ *ctl = NULL;
+ return KNOT_EOK;
+ }
+
+ /* Get control socket path. */
+ char *path = NULL;
+ if (params->socket != NULL) {
+ path = strdup(params->socket);
+ } else {
+ conf_val_t listen_val = conf_get(conf(), C_CTL, C_LISTEN);
+ conf_val_t rundir_val = conf_get(conf(), C_SRV, C_RUNDIR);
+ char *rundir = conf_abs_path(&rundir_val, NULL);
+ path = conf_abs_path(&listen_val, rundir);
+ free(rundir);
+ }
+ if (path == NULL) {
+ log_error("empty control socket path");
+ return KNOT_EINVAL;
+ }
+
+ log_debug("socket '%s'", path);
+
+ *ctl = knot_ctl_alloc();
+ if (*ctl == NULL) {
+ free(path);
+ return KNOT_ENOMEM;
+ }
+
+ knot_ctl_set_timeout(*ctl, params->timeout);
+
+ int ret = knot_ctl_connect(*ctl, path);
+ if (ret != KNOT_EOK) {
+ knot_ctl_free(*ctl);
+ *ctl = NULL;
+ log_error("failed to connect to socket '%s' (%s)", path,
+ knot_strerror(ret));
+ free(path);
+ return ret;
+ }
+
+ free(path);
+
+ return KNOT_EOK;
+}
+
+void unset_ctl(knot_ctl_t *ctl)
+{
+ if (ctl == NULL) {
+ return;
+ }
+
+ int ret = knot_ctl_send(ctl, KNOT_CTL_TYPE_END, NULL);
+ if (ret != KNOT_EOK && ret != KNOT_ECONN) {
+ log_error("failed to finish control (%s)", knot_strerror(ret));
+ }
+
+ knot_ctl_close(ctl);
+ knot_ctl_free(ctl);
+}
+
+int process_cmd(int argc, const char **argv, params_t *params)
+{
+ if (argc == 0) {
+ return KNOT_ENOTSUP;
+ }
+
+ /* Check the command name. */
+ const cmd_desc_t *desc = get_cmd_desc(argv[0]);
+ if (desc == NULL) {
+ return KNOT_ENOENT;
+ }
+
+ /* Check for exit. */
+ if (desc->fcn == NULL) {
+ return KNOT_CTL_ESTOP;
+ }
+
+ /* Set up the configuration. */
+ int ret = set_config(desc, params);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ /* Prepare command parameters. */
+ cmd_args_t args = {
+ .desc = desc,
+ .argc = argc - 1,
+ .argv = argv + 1,
+ .force = params->force
+ };
+
+ /* Set control interface if necessary. */
+ ret = set_ctl(&args.ctl, desc, params);
+ if (ret != KNOT_EOK) {
+ conf_update(NULL, CONF_UPD_FNONE);
+ return ret;
+ }
+
+ /* Execute the command. */
+ ret = desc->fcn(&args);
+
+ /* Cleanup */
+ unset_ctl(args.ctl);
+ conf_update(NULL, CONF_UPD_FNONE);
+
+ return ret;
+}
diff --git a/src/utils/knotc/process.h b/src/utils/knotc/process.h
new file mode 100644
index 0000000..20b5357
--- /dev/null
+++ b/src/utils/knotc/process.h
@@ -0,0 +1,69 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include "utils/knotc/commands.h"
+
+/*! Utility command line parameters. */
+typedef struct {
+ const char *config;
+ const char *confdb;
+ size_t max_conf_size;
+ const char *socket;
+ bool verbose;
+ bool force;
+ int timeout;
+} params_t;
+
+/*!
+ * Prepares a proper configuration according to the specified command.
+ *
+ * \param[in] desc Utility command descriptor.
+ * \param[in] params Utility parameters.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int set_config(const cmd_desc_t *desc, params_t *params);
+
+/*!
+ * Estabilishes a control interface if necessary.
+ *
+ * \param[in] ctl Control context.
+ * \param[in] desc Utility command descriptor.
+ * \param[in] params Utility parameters.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int set_ctl(knot_ctl_t **ctl, const cmd_desc_t *desc, params_t *params);
+
+/*!
+ * Cleans up the control context.
+ *
+ * \param[in] ctl Control context.
+ */
+void unset_ctl(knot_ctl_t *ctl);
+
+/*!
+ * Processes the given utility command.
+ *
+ * \param[in] argc Number of command arguments.
+ * \param[in] argv Command arguments.
+ * \param[in] params Utility parameters.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int process_cmd(int argc, const char **argv, params_t *params);
diff --git a/src/utils/knotd/main.c b/src/utils/knotd/main.c
new file mode 100644
index 0000000..b2bcc83
--- /dev/null
+++ b/src/utils/knotd/main.c
@@ -0,0 +1,620 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/stat.h>
+#include <urcu.h>
+
+#ifdef ENABLE_CAP_NG
+#include <cap-ng.h>
+#endif
+
+#ifdef ENABLE_SYSTEMD
+#include <systemd/sd-daemon.h>
+#endif
+
+#include "libdnssec/crypto.h"
+#include "libknot/libknot.h"
+#include "contrib/strtonum.h"
+#include "knot/ctl/process.h"
+#include "knot/conf/conf.h"
+#include "knot/conf/migration.h"
+#include "knot/conf/module.h"
+#include "knot/common/log.h"
+#include "knot/common/process.h"
+#include "knot/common/stats.h"
+#include "knot/server/server.h"
+#include "knot/server/tcp-handler.h"
+#include "knot/zone/timers.h"
+
+#define PROGRAM_NAME "knotd"
+
+/* Signal flags. */
+static volatile bool sig_req_stop = false;
+static volatile bool sig_req_reload = false;
+
+/* \brief Signal started state to the init system. */
+static void init_signal_started(void)
+{
+#ifdef ENABLE_SYSTEMD
+ sd_notify(0, "READY=1");
+#endif
+}
+
+static int make_daemon(int nochdir, int noclose)
+{
+ int fd, ret;
+
+ switch (fork()) {
+ case -1:
+ /* Error */
+ return -1;
+ case 0:
+ /* Forked */
+ break;
+ default:
+ /* Exit the main process */
+ _exit(0);
+ }
+
+ if (setsid() == -1) {
+ return -1;
+ }
+
+ if (!nochdir) {
+ ret = chdir("/");
+ if (ret == -1)
+ return errno;
+ }
+
+ if (!noclose) {
+ ret = close(STDIN_FILENO);
+ ret += close(STDOUT_FILENO);
+ ret += close(STDERR_FILENO);
+ if (ret < 0) {
+ return errno;
+ }
+
+ fd = open("/dev/null", O_RDWR);
+ if (fd == -1) {
+ return errno;
+ }
+
+ if (dup2(fd, STDIN_FILENO) < 0) {
+ close(fd);
+ return errno;
+ }
+ if (dup2(fd, STDOUT_FILENO) < 0) {
+ close(fd);
+ return errno;
+ }
+ if (dup2(fd, STDERR_FILENO) < 0) {
+ close(fd);
+ return errno;
+ }
+ }
+
+ return 0;
+}
+
+struct signal {
+ int signum;
+ bool handle;
+};
+
+/*! \brief Signals used by the server. */
+static const struct signal SIGNALS[] = {
+ { SIGHUP, true }, /* Reload server. */
+ { SIGINT, true }, /* Terminate server .*/
+ { SIGTERM, true },
+ { SIGALRM, false }, /* Internal thread synchronization. */
+ { SIGPIPE, false }, /* Ignored. Some I/O errors. */
+ { 0 }
+};
+
+/*! \brief Server signal handler. */
+static void handle_signal(int signum)
+{
+ switch (signum) {
+ case SIGHUP:
+ sig_req_reload = true;
+ break;
+ case SIGINT:
+ case SIGTERM:
+ if (sig_req_stop) {
+ exit(EXIT_FAILURE);
+ }
+ sig_req_stop = true;
+ break;
+ default:
+ /* ignore */
+ break;
+ }
+}
+
+/*! \brief Setup signal handlers and blocking mask. */
+static void setup_signals(void)
+{
+ /* Block all signals. */
+ static sigset_t all;
+ sigfillset(&all);
+ sigdelset(&all, SIGPROF);
+ pthread_sigmask(SIG_SETMASK, &all, NULL);
+
+ /* Setup handlers. */
+ struct sigaction action = { .sa_handler = handle_signal };
+ for (const struct signal *s = SIGNALS; s->signum > 0; s++) {
+ sigaction(s->signum, &action, NULL);
+ }
+}
+
+/*! \brief Unblock server control signals. */
+static void enable_signals(void)
+{
+ sigset_t mask;
+ sigemptyset(&mask);
+
+ for (const struct signal *s = SIGNALS; s->signum > 0; s++) {
+ if (s->handle) {
+ sigaddset(&mask, s->signum);
+ }
+ }
+
+ pthread_sigmask(SIG_UNBLOCK, &mask, NULL);
+}
+
+/*! \brief Drop POSIX 1003.1e capabilities. */
+static void drop_capabilities(void)
+{
+#ifdef ENABLE_CAP_NG
+ /* Drop all capabilities. */
+ if (capng_have_capability(CAPNG_EFFECTIVE, CAP_SETPCAP)) {
+ capng_clear(CAPNG_SELECT_BOTH);
+
+ /* Apply. */
+ if (capng_apply(CAPNG_SELECT_BOTH) < 0) {
+ log_error("failed to set process capabilities (%s)",
+ strerror(errno));
+ }
+ } else {
+ log_info("process not allowed to set capabilities, skipping");
+ }
+#endif /* ENABLE_CAP_NG */
+}
+
+/*! \brief Event loop listening for signals and remote commands. */
+static void event_loop(server_t *server, const char *socket)
+{
+ knot_ctl_t *ctl = knot_ctl_alloc();
+ if (ctl == NULL) {
+ log_fatal("control, failed to initialize (%s)",
+ knot_strerror(KNOT_ENOMEM));
+ return;
+ }
+
+ // Set control timeout.
+ knot_ctl_set_timeout(ctl, conf()->cache.ctl_timeout);
+
+ /* Get control socket configuration. */
+ char *listen;
+ if (socket == NULL) {
+ conf_val_t listen_val = conf_get(conf(), C_CTL, C_LISTEN);
+ conf_val_t rundir_val = conf_get(conf(), C_SRV, C_RUNDIR);
+ char *rundir = conf_abs_path(&rundir_val, NULL);
+ listen = conf_abs_path(&listen_val, rundir);
+ free(rundir);
+ } else {
+ listen = strdup(socket);
+ }
+ if (listen == NULL) {
+ knot_ctl_free(ctl);
+ log_fatal("control, empty socket path");
+ return;
+ }
+
+ log_info("control, binding to '%s'", listen);
+
+ /* Bind the control socket. */
+ int ret = knot_ctl_bind(ctl, listen);
+ if (ret != KNOT_EOK) {
+ knot_ctl_free(ctl);
+ log_fatal("control, failed to bind socket '%s' (%s)",
+ listen, knot_strerror(ret));
+ free(listen);
+ return;
+ }
+ free(listen);
+
+ enable_signals();
+
+ /* Run event loop. */
+ for (;;) {
+ /* Interrupts. */
+ if (sig_req_stop) {
+ break;
+ }
+ if (sig_req_reload) {
+ sig_req_reload = false;
+ server_reload(server);
+ }
+
+ // Update control timeout.
+ knot_ctl_set_timeout(ctl, conf()->cache.ctl_timeout);
+
+ ret = knot_ctl_accept(ctl);
+ if (ret != KNOT_EOK) {
+ continue;
+ }
+
+ ret = ctl_process(ctl, server);
+ knot_ctl_close(ctl);
+ if (ret == KNOT_CTL_ESTOP) {
+ break;
+ }
+ }
+
+ /* Unbind the control socket. */
+ knot_ctl_unbind(ctl);
+ knot_ctl_free(ctl);
+}
+
+static void print_help(void)
+{
+ printf("Usage: %s [parameters]\n"
+ "\n"
+ "Parameters:\n"
+ " -c, --config <file> Use a textual configuration file.\n"
+ " (default %s)\n"
+ " -C, --confdb <dir> Use a binary configuration database directory.\n"
+ " (default %s)\n"
+ " -m, --max-conf-size <MiB> Set maximum configuration size (max 10000 MiB).\n"
+ " (default %d MiB)\n"
+ " -s, --socket <path> Use a remote control UNIX socket path.\n"
+ " (default %s)\n"
+ " -d, --daemonize=[dir] Run the server as a daemon (with new root directory).\n"
+ " -v, --verbose Enable debug output.\n"
+ " -h, --help Print the program help.\n"
+ " -V, --version Print the program version.\n",
+ PROGRAM_NAME, CONF_DEFAULT_FILE, CONF_DEFAULT_DBDIR,
+ CONF_MAPSIZE, RUN_DIR "/knot.sock");
+}
+
+static void print_version(void)
+{
+ printf("%s (Knot DNS), version %s\n", PROGRAM_NAME, PACKAGE_VERSION);
+}
+
+static int set_config(const char *confdb, const char *config, size_t max_conf_size)
+{
+ if (config != NULL && confdb != NULL) {
+ log_fatal("ambiguous configuration source");
+ return KNOT_EINVAL;
+ }
+
+ /* Choose the optimal config source. */
+ struct stat st;
+ bool import = false;
+ if (confdb != NULL) {
+ import = false;
+ } else if (config != NULL){
+ import = true;
+ } else if (stat(CONF_DEFAULT_DBDIR, &st) == 0) {
+ import = false;
+ confdb = CONF_DEFAULT_DBDIR;
+ } else {
+ import = true;
+ config = CONF_DEFAULT_FILE;
+ }
+
+ const char *src = import ? config : confdb;
+ log_debug("%s '%s'", import ? "config" : "confdb",
+ (src != NULL) ? src : "empty");
+
+ /* Open confdb. */
+ conf_t *new_conf = NULL;
+ int ret = conf_new(&new_conf, conf_schema, confdb, max_conf_size, CONF_FREQMODULES);
+ if (ret != KNOT_EOK) {
+ log_fatal("failed to open configuration database '%s' (%s)",
+ (confdb != NULL) ? confdb : "", knot_strerror(ret));
+ return ret;
+ }
+
+ /* Import the config file. */
+ if (import) {
+ ret = conf_import(new_conf, config, true);
+ if (ret != KNOT_EOK) {
+ log_fatal("failed to load configuration file '%s' (%s)",
+ config, knot_strerror(ret));
+ conf_free(new_conf);
+ return ret;
+ }
+ }
+
+ // Migrate from old schema.
+ ret = conf_migrate(new_conf);
+ if (ret != KNOT_EOK) {
+ log_error("failed to migrate configuration (%s)", knot_strerror(ret));
+ }
+
+ /* Update to the new config. */
+ conf_update(new_conf, CONF_UPD_FNONE);
+
+ return KNOT_EOK;
+}
+
+static void write_timers(const zone_t *zone, knot_db_txn_t *txn, int *ret)
+{
+ if (*ret == KNOT_EOK) {
+ *ret = zone_timers_write(NULL, zone->name, &zone->timers, txn);
+ }
+}
+
+static void update_timerdb(server_t *server)
+{
+ if (server->timers_db == NULL) {
+ return;
+ }
+
+ log_info("updating persistent timer DB");
+
+ knot_db_txn_t txn;
+ int ret = zone_timers_write_begin(server->timers_db, &txn);
+ if (ret == KNOT_EOK) {
+ knot_zonedb_foreach(server->zone_db, write_timers, &txn, &ret);
+ }
+ if (ret == KNOT_EOK) {
+ ret = zone_timers_write_end(&txn);
+ }
+ if (ret != KNOT_EOK) {
+ log_warning("failed to update persistent timer DB (%s)",
+ knot_strerror(ret));
+ }
+}
+
+int main(int argc, char **argv)
+{
+ bool daemonize = false;
+ const char *config = NULL;
+ const char *confdb = NULL;
+ size_t max_conf_size = (size_t)CONF_MAPSIZE * 1024 * 1024;
+ const char *daemon_root = "/";
+ char *socket = NULL;
+ bool verbose = false;
+
+ /* Long options. */
+ struct option opts[] = {
+ { "config", required_argument, NULL, 'c' },
+ { "confdb", required_argument, NULL, 'C' },
+ { "max-conf-size", required_argument, NULL, 'm' },
+ { "socket", required_argument, NULL, 's' },
+ { "daemonize", optional_argument, NULL, 'd' },
+ { "verbose", no_argument, NULL, 'v' },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'V' },
+ { NULL }
+ };
+
+ /* Parse command line arguments. */
+ int opt = 0;
+ while ((opt = getopt_long(argc, argv, "c:C:m:s:dvhV", opts, NULL)) != -1) {
+ switch (opt) {
+ case 'c':
+ config = optarg;
+ break;
+ case 'C':
+ confdb = optarg;
+ break;
+ case 'm':
+ if (str_to_size(optarg, &max_conf_size, 1, 10000) != KNOT_EOK) {
+ print_help();
+ return EXIT_FAILURE;
+ }
+ /* Convert to bytes. */
+ max_conf_size *= 1024 * 1024;
+ break;
+ case 's':
+ socket = optarg;
+ break;
+ case 'd':
+ daemonize = true;
+ if (optarg) {
+ daemon_root = optarg;
+ }
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ case 'h':
+ print_help();
+ return EXIT_SUCCESS;
+ case 'V':
+ print_version();
+ return EXIT_SUCCESS;
+ default:
+ print_help();
+ return EXIT_FAILURE;
+ }
+ }
+
+ /* Check for non-option parameters. */
+ if (argc - optind > 0) {
+ print_help();
+ return EXIT_FAILURE;
+ }
+
+ /* Set file creation mask to remove all permissions for others. */
+ umask(S_IROTH|S_IWOTH|S_IXOTH);
+
+ /* Now check if we want to daemonize. */
+ if (daemonize) {
+ if (make_daemon(1, 0) != 0) {
+ fprintf(stderr, "Daemonization failed, shutting down...\n");
+ return EXIT_FAILURE;
+ }
+ }
+
+ /* Setup base signal handling. */
+ setup_signals();
+
+ /* Initialize cryptographic backend. */
+ dnssec_crypto_init();
+ atexit(dnssec_crypto_cleanup);
+
+ /* Initialize pseudorandom number generator. */
+ srand(time(NULL));
+
+ /* Initialize logging subsystem. */
+ log_init();
+ if (verbose) {
+ log_levels_add(LOG_TARGET_STDOUT, LOG_SOURCE_ANY, LOG_MASK(LOG_DEBUG));
+ }
+
+ /* Set up the configuration */
+ int ret = set_config(confdb, config, max_conf_size);
+ if (ret != KNOT_EOK) {
+ log_close();
+ return EXIT_FAILURE;
+ }
+
+ /* Reconfigure logging. */
+ log_reconfigure(conf());
+
+ /* Initialize server. */
+ server_t server;
+ ret = server_init(&server, conf_bg_threads(conf()));
+ if (ret != KNOT_EOK) {
+ log_fatal("failed to initialize server (%s)", knot_strerror(ret));
+ conf_free(conf());
+ log_close();
+ return EXIT_FAILURE;
+ }
+
+ /* Reconfigure server interfaces.
+ * @note This MUST be done before we drop privileges. */
+ server_reconfigure(conf(), &server);
+
+ /* Alter privileges. */
+ int uid, gid;
+ if (conf_user(conf(), &uid, &gid) != KNOT_EOK ||
+ log_update_privileges(uid, gid) != KNOT_EOK ||
+ proc_update_privileges(uid, gid) != KNOT_EOK) {
+ log_fatal("failed to drop privileges");
+ server_wait(&server);
+ server_deinit(&server);
+ conf_free(conf());
+ log_close();
+ return EXIT_FAILURE;
+ }
+
+ /* Drop POSIX capabilities. */
+ drop_capabilities();
+
+ /* Activate global query modules. */
+ conf_activate_modules(conf(), NULL, conf()->query_modules,
+ &conf()->query_plan);
+
+ /* Check and create PID file. */
+ long pid = (long)getpid();
+ if (daemonize) {
+ char *pidfile = pid_check_and_create();
+ if (pidfile == NULL) {
+ server_wait(&server);
+ server_deinit(&server);
+ conf_free(conf());
+ log_close();
+ return EXIT_FAILURE;
+ }
+
+ log_info("PID stored in '%s'", pidfile);
+ free(pidfile);
+ if (chdir(daemon_root) != 0) {
+ log_warning("failed to change working directory to %s",
+ daemon_root);
+ } else {
+ log_info("changed directory to %s", daemon_root);
+ }
+ }
+
+ /* Now we're going multithreaded. */
+ rcu_register_thread();
+
+ /* Populate zone database. */
+ log_info("loading %zu zones", conf_id_count(conf(), C_ZONE));
+ server_update_zones(conf(), &server);
+
+ /* Check number of loaded zones. */
+ if (knot_zonedb_size(server.zone_db) == 0) {
+ log_warning("no zones loaded");
+ }
+
+ stats_reconfigure(conf(), &server);
+
+ /* Start it up. */
+ log_info("starting server");
+ conf_val_t async_val = conf_get(conf(), C_SRV, C_ASYNC_START);
+ ret = server_start(&server, conf_bool(&async_val));
+ if (ret != KNOT_EOK) {
+ log_fatal("failed to start server (%s)", knot_strerror(ret));
+ server_wait(&server);
+ stats_deinit();
+ server_deinit(&server);
+ rcu_unregister_thread();
+ pid_cleanup();
+ log_close();
+ conf_free(conf());
+ return EXIT_FAILURE;
+ }
+
+ if (daemonize) {
+ log_info("server started as a daemon, PID %ld", pid);
+ } else {
+ log_info("server started in the foreground, PID %ld", pid);
+ init_signal_started();
+ }
+
+ /* Start the event loop. */
+ event_loop(&server, socket);
+
+ /* Teardown server. */
+ server_stop(&server);
+ server_wait(&server);
+ stats_deinit();
+
+ /* Update timers database. */
+ update_timerdb(&server);
+
+ /* Cleanup PID file. */
+ pid_cleanup();
+
+ /* Free server and configuration. */
+ server_deinit(&server);
+ conf_free(conf());
+
+ /* Unhook from RCU. */
+ rcu_unregister_thread();
+
+ log_info("shutting down");
+ log_close();
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/utils/knsec3hash/knsec3hash.c b/src/utils/knsec3hash/knsec3hash.c
new file mode 100644
index 0000000..b901676
--- /dev/null
+++ b/src/utils/knsec3hash/knsec3hash.c
@@ -0,0 +1,184 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "contrib/base32hex.h"
+#include "contrib/strtonum.h"
+#include "libdnssec/error.h"
+#include "libdnssec/nsec.h"
+#include "libdnssec/shared/dname.h"
+#include "libdnssec/shared/hex.h"
+#include "libknot/libknot.h"
+
+#define PROGRAM_NAME "knsec3hash"
+#define error(fmt, ...) fprintf(stderr, fmt "\n", ##__VA_ARGS__)
+
+/*!
+ * \brief Print program help (and example).
+ */
+static void print_help(void)
+{
+ printf("Usage: " PROGRAM_NAME " <salt> <algorithm> <iterations> <domain-name>\n");
+ printf("Example: " PROGRAM_NAME " c01dcafe 1 10 knot-dns.cz\n");
+}
+
+/*!
+ * \brief Print program version.
+ */
+static void print_version(void)
+{
+ printf("%s (Knot DNS), version %s\n", PROGRAM_NAME, PACKAGE_VERSION);
+}
+
+/*!
+ * \brief Parse NSEC3 salt.
+ */
+static int str_to_salt(const char *str, dnssec_binary_t *salt)
+{
+ if (strcmp(str, "-") == 0) {
+ salt->size = 0;
+ return DNSSEC_EOK;
+ } else {
+ return hex_to_bin(str, salt);
+ }
+}
+
+/*!
+ * \brief Parse NSEC3 parameters and fill structure with NSEC3 parameters.
+ */
+static bool parse_nsec3_params(dnssec_nsec3_params_t *params, const char *salt_str,
+ const char *algorithm_str, const char *iterations_str)
+{
+ uint8_t algorithm = 0;
+ int r = str_to_u8(algorithm_str, &algorithm);
+ if (r != KNOT_EOK) {
+ error("Invalid algorithm number.");
+ return false;
+ }
+
+ uint16_t iterations = 0;
+ r = str_to_u16(iterations_str, &iterations);
+ if (r != KNOT_EOK) {
+ error("Invalid iteration count.");
+ return false;
+ }
+
+ dnssec_binary_t salt = { 0 };
+ r = str_to_salt(salt_str, &salt);
+ if (r != DNSSEC_EOK) {
+ error("Invalid salt, %s.", knot_strerror(r));
+ return false;
+ }
+
+ if (salt.size > UINT8_MAX) {
+ error("Invalid salt, maximum length is %d bytes.", UINT8_MAX);
+ dnssec_binary_free(&salt);
+ return false;
+ }
+
+ params->algorithm = algorithm;
+ params->iterations = iterations;
+ params->salt = salt;
+ params->flags = 0;
+
+ return true;
+}
+
+/*!
+ * \brief Entry point of 'knsec3hash'.
+ */
+int main(int argc, char *argv[])
+{
+ struct option options[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'V' },
+ { NULL }
+ };
+
+ int opt = 0;
+ while ((opt = getopt_long(argc, argv, "hV", options, NULL)) != -1) {
+ switch(opt) {
+ case 'h':
+ print_help();
+ return 0;
+ case 'V':
+ print_version();
+ return 0;
+ default:
+ print_help();
+ return 1;
+ }
+ }
+
+ // knsec3hash <salt> <algorithm> <iterations> <domain>
+ if (argc != 5) {
+ print_help();
+ return 1;
+ }
+
+ int exit_code = 1;
+ dnssec_nsec3_params_t nsec3_params = { 0 };
+
+ dnssec_binary_t dname = { 0 };
+ dnssec_binary_t digest = { 0 };
+ dnssec_binary_t digest_print = { 0 };
+
+ if (!parse_nsec3_params(&nsec3_params, argv[1], argv[2], argv[3])) {
+ goto fail;
+ }
+
+ dname.data = knot_dname_from_str_alloc(argv[4]);
+ if (dname.data == NULL) {
+ error("Cannot parse domain name.");
+ goto fail;
+ }
+ dname.size = dname_length(dname.data);
+
+ dname_normalize(dname.data);
+
+ int r = dnssec_nsec3_hash(&dname, &nsec3_params, &digest);
+ if (r != DNSSEC_EOK) {
+ error("Cannot compute NSEC3 hash, %s.", knot_strerror(r));
+ goto fail;
+ }
+
+ r = base32hex_encode_alloc(digest.data, digest.size, &digest_print.data);
+ if (r < 0) {
+ error("Cannot encode computed hash, %s.", knot_strerror(r));
+ goto fail;
+ }
+ digest_print.size = r;
+
+ exit_code = 0;
+
+ printf("%.*s (salt=%s, hash=%d, iterations=%d)\n", (int)digest_print.size,
+ digest_print.data, argv[1], nsec3_params.algorithm,
+ nsec3_params.iterations);
+
+fail:
+ dnssec_nsec3_params_free(&nsec3_params);
+ dnssec_binary_free(&dname);
+ dnssec_binary_free(&digest);
+ dnssec_binary_free(&digest_print);
+
+ return exit_code;
+}
diff --git a/src/utils/knsupdate/knsupdate_exec.c b/src/utils/knsupdate/knsupdate_exec.c
new file mode 100644
index 0000000..a92de88
--- /dev/null
+++ b/src/utils/knsupdate/knsupdate_exec.c
@@ -0,0 +1,1058 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "libdnssec/random.h"
+#include "utils/knsupdate/knsupdate_exec.h"
+#include "utils/common/exec.h"
+#include "utils/common/msg.h"
+#include "utils/common/netio.h"
+#include "utils/common/params.h"
+#include "utils/common/sign.h"
+#include "utils/common/token.h"
+#include "libknot/libknot.h"
+#include "contrib/ctype.h"
+#include "contrib/getline.h"
+#include "contrib/macros.h"
+#include "contrib/string.h"
+#include "contrib/strtonum.h"
+#include "contrib/openbsd/strlcpy.h"
+
+/* Declarations of cmd parse functions. */
+typedef int (*cmd_handle_f)(const char *lp, knsupdate_params_t *params);
+int cmd_add(const char* lp, knsupdate_params_t *params);
+int cmd_answer(const char* lp, knsupdate_params_t *params);
+int cmd_class(const char* lp, knsupdate_params_t *params);
+int cmd_debug(const char* lp, knsupdate_params_t *params);
+int cmd_del(const char* lp, knsupdate_params_t *params);
+int cmd_gsstsig(const char* lp, knsupdate_params_t *params);
+int cmd_key(const char* lp, knsupdate_params_t *params);
+int cmd_local(const char* lp, knsupdate_params_t *params);
+int cmd_nxdomain(const char *lp, knsupdate_params_t *params);
+int cmd_nxrrset(const char *lp, knsupdate_params_t *params);
+int cmd_oldgsstsig(const char* lp, knsupdate_params_t *params);
+int cmd_origin(const char* lp, knsupdate_params_t *params);
+int cmd_prereq(const char* lp, knsupdate_params_t *params);
+int cmd_quit(const char* lp, knsupdate_params_t *params);
+int cmd_realm(const char* lp, knsupdate_params_t *params);
+int cmd_send(const char* lp, knsupdate_params_t *params);
+int cmd_server(const char* lp, knsupdate_params_t *params);
+int cmd_show(const char* lp, knsupdate_params_t *params);
+int cmd_ttl(const char* lp, knsupdate_params_t *params);
+int cmd_update(const char* lp, knsupdate_params_t *params);
+int cmd_yxdomain(const char *lp, knsupdate_params_t *params);
+int cmd_yxrrset(const char *lp, knsupdate_params_t *params);
+int cmd_zone(const char* lp, knsupdate_params_t *params);
+
+/* Sorted list of commands.
+ * This way we could identify command byte-per-byte and
+ * cancel early if the next is lexicographically greater.
+ */
+const char* cmd_array[] = {
+ "\x3" "add",
+ "\x6" "answer",
+ "\x5" "class", /* {classname} */
+ "\x5" "debug",
+ "\x3" "del",
+ "\x6" "delete",
+ "\x7" "gsstsig",
+ "\x3" "key", /* {[alg:]name} {secret} */
+ "\x5" "local", /* {address} [port] */
+ "\x8" "nxdomain",
+ "\x7" "nxrrset",
+ "\xa" "oldgsstsig",
+ "\x6" "origin", /* {name} */
+ "\x6" "prereq", /* (nx|yx)(domain|rrset) {domain-name} ... */
+ "\x4" "quit",
+ "\x5" "realm", /* {[realm_name]} */
+ "\x4" "send",
+ "\x6" "server", /* {servername} [port] */
+ "\x4" "show",
+ "\x3" "ttl", /* {seconds} */
+ "\x6" "update", /* (add|delete) {domain-name} ... */
+ "\x8" "yxdomain",
+ "\x7" "yxrrset",
+ "\x4" "zone", /* {zonename} */
+ NULL
+};
+
+cmd_handle_f cmd_handle[] = {
+ cmd_add,
+ cmd_answer,
+ cmd_class,
+ cmd_debug,
+ cmd_del,
+ cmd_del, /* delete/del synonyms */
+ cmd_gsstsig,
+ cmd_key,
+ cmd_local,
+ cmd_nxdomain,
+ cmd_nxrrset,
+ cmd_oldgsstsig,
+ cmd_origin,
+ cmd_prereq,
+ cmd_quit,
+ cmd_realm,
+ cmd_send,
+ cmd_server,
+ cmd_show,
+ cmd_ttl,
+ cmd_update,
+ cmd_yxdomain,
+ cmd_yxrrset,
+ cmd_zone,
+};
+
+/* {prereq} command table. */
+const char* pq_array[] = {
+ "\x8" "nxdomain",
+ "\x7" "nxrrset",
+ "\x8" "yxdomain",
+ "\x7" "yxrrset",
+ NULL
+};
+
+enum {
+ PQ_NXDOMAIN = 0,
+ PQ_NXRRSET,
+ PQ_YXDOMAIN,
+ PQ_YXRRSET
+};
+
+/* RR parser flags */
+enum {
+ PARSE_NODEFAULT = 1 << 0, /* Do not fill defaults. */
+ PARSE_NAMEONLY = 1 << 1, /* Parse only name. */
+ PARSE_NOTTL = 1 << 2 /* Ignore TTL item. */
+};
+
+static bool dname_isvalid(const char *lp)
+{
+ knot_dname_t *dn = knot_dname_from_str_alloc(lp);
+ if (dn == NULL) {
+ return false;
+ }
+ knot_dname_free(dn, NULL);
+ return true;
+}
+
+/* This is probably redundant, but should be a bit faster so let's keep it. */
+static int parse_full_rr(zs_scanner_t *s, const char* lp)
+{
+ if (zs_set_input_string(s, lp, strlen(lp)) != 0 ||
+ zs_parse_all(s) != 0) {
+ ERR("invalid record (%s)\n", zs_strerror(s->error.code));
+ return KNOT_EPARSEFAIL;
+ }
+
+ /* Class must not differ from specified. */
+ if (s->r_class != s->default_class) {
+ char cls_s[16] = {0};
+ knot_rrclass_to_string(s->default_class, cls_s, sizeof(cls_s));
+ ERR("class mismatch '%s'\n", cls_s);
+ return KNOT_EPARSEFAIL;
+ }
+
+ return KNOT_EOK;
+}
+
+static int parse_partial_rr(zs_scanner_t *s, const char *lp, unsigned flags)
+{
+ /* Extract owner. */
+ size_t len = strcspn(lp, SEP_CHARS);
+ char *owner_str = calloc(1, len + 2); // 2 ~ ('.' + '\0')
+ memcpy(owner_str, lp, len);
+
+ /* Make dname FQDN if it isn't. */
+ bool fqdn = true;
+ if (owner_str[len - 1] != '.') {
+ owner_str[len] = '.';
+ fqdn = false;
+ }
+
+ knot_dname_t *owner = knot_dname_from_str_alloc(owner_str);
+ free(owner_str);
+ if (owner == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ s->r_owner_length = knot_dname_size(owner);
+ memcpy(s->r_owner, owner, s->r_owner_length);
+ knot_dname_free(owner, NULL);
+
+ /* Append origin if not FQDN. */
+ if (!fqdn) {
+ s->r_owner_length--;
+ memcpy(s->r_owner + s->r_owner_length, s->zone_origin,
+ s->zone_origin_length);
+ s->r_owner_length += s->zone_origin_length;
+ }
+
+ lp = tok_skipspace(lp + len);
+
+ /* Initialize */
+ s->r_type = KNOT_RRTYPE_ANY;
+ s->r_class = s->default_class;
+ s->r_data_length = 0;
+ if (flags & PARSE_NODEFAULT) {
+ s->r_ttl = 0;
+ } else {
+ s->r_ttl = s->default_ttl;
+ }
+
+ /* Parse only name? */
+ if (flags & PARSE_NAMEONLY) {
+ if (*lp != '\0') {
+ WARN("ignoring input data '%s'\n", lp);
+ }
+ return KNOT_EOK;
+ }
+
+ /* Now there could be [ttl] [class] [type [data...]]. */
+ char *np = NULL;
+ long ttl = strtol(lp, &np, 10);
+ if (ttl >= 0 && np && (*np == '\0' || is_space(*np))) {
+ DBG("%s: parsed ttl=%lu\n", __func__, ttl);
+ if (flags & PARSE_NOTTL) {
+ WARN("ignoring TTL value '%ld'\n", ttl);
+ } else {
+ s->r_ttl = ttl;
+ }
+ lp = tok_skipspace(np);
+ }
+
+ uint16_t num;
+ char *buff = NULL;
+ char *cls = NULL;
+ char *type = NULL;
+
+ /* Try to find class. */
+ len = strcspn(lp, SEP_CHARS);
+ if (len > 0) {
+ buff = strndup(lp, len);
+ }
+
+ if (knot_rrclass_from_string(buff, &num) == 0) {
+ /* Class must not differ from specified. */
+ if (num != s->default_class) {
+ ERR("class mismatch '%s'\n", buff);
+ free(buff);
+ return KNOT_EPARSEFAIL;
+ }
+ cls = buff;
+ buff = NULL;
+ s->r_class = num;
+ DBG("%s: parsed class=%u '%s'\n", __func__, s->r_class, cls);
+ lp = tok_skipspace(lp + len);
+ }
+
+ /* Try to parser type. */
+ if (cls != NULL) {
+ len = strcspn(lp, SEP_CHARS);
+ if (len > 0) {
+ buff = strndup(lp, len);
+ }
+ }
+ if (knot_rrtype_from_string(buff, &num) == 0) {
+ type = buff;
+ buff = NULL;
+ s->r_type = num;
+ DBG("%s: parsed type=%u '%s'\n", __func__, s->r_type, type);
+ lp = tok_skipspace(lp + len);
+ }
+
+ free(buff);
+
+ /* Remainder */
+ if (*lp == '\0') {
+ free(cls);
+ free(type);
+ return KNOT_EOK;
+ }
+
+ /* Need to parse rdata, synthetize input. */
+ char *rr = sprintf_alloc(" %u IN %s %s\n", s->r_ttl, type, lp);
+ free(cls);
+ free(type);
+ if (rr == NULL) {
+ return KNOT_ENOMEM;
+ }
+ if (zs_set_input_string(s, rr, strlen(rr)) != 0 ||
+ zs_parse_all(s) != 0) {
+ ERR("invalid rdata (%s)\n", zs_strerror(s->error.code));
+ return KNOT_EPARSEFAIL;
+ }
+ free(rr);
+
+ return KNOT_EOK;
+}
+
+static srv_info_t *parse_host(const char *lp, const char* default_port)
+{
+ /* Extract server address. */
+ srv_info_t *srv = NULL;
+ size_t len = strcspn(lp, SEP_CHARS);
+ char *addr = strndup(lp, len);
+ if (!addr) return NULL;
+ DBG("%s: parsed addr: %s\n", __func__, addr);
+
+ /* Store port/service if present. */
+ lp = tok_skipspace(lp + len);
+ if (*lp == '\0') {
+ srv = srv_info_create(addr, default_port);
+ free(addr);
+ return srv;
+ }
+
+ len = strcspn(lp, SEP_CHARS);
+ char *port = strndup(lp, len);
+ if (!port) {
+ free(addr);
+ return NULL;
+ }
+ DBG("%s: parsed port: %s\n", __func__, port);
+
+ /* Create server struct. */
+ srv = srv_info_create(addr, port);
+ free(addr);
+ free(port);
+ return srv;
+}
+
+/* Append parsed RRSet to list. */
+static int rr_list_append(zs_scanner_t *s, list_t *target_list, knot_mm_t *mm)
+{
+ knot_rrset_t *rr = knot_rrset_new(s->r_owner, s->r_type, s->r_class,
+ s->r_ttl, NULL);
+ if (!rr) {
+ DBG("%s: failed to create rrset\n", __func__);
+ return KNOT_ENOMEM;
+ }
+
+ /* Create RDATA. */
+ int ret = knot_rrset_add_rdata(rr, s->r_data, s->r_data_length, NULL);
+ if (ret != KNOT_EOK) {
+ DBG("%s: failed to set rrset from wire (%s)\n",
+ __func__, knot_strerror(ret));
+ knot_rrset_free(rr, NULL);
+ return ret;
+ }
+
+ if (ptrlist_add(target_list, rr, mm) == NULL) {
+ knot_rrset_free(rr, NULL);
+ return KNOT_ENOMEM;
+ }
+
+ return KNOT_EOK;
+}
+
+/*! \brief Write RRSet list to packet section. */
+static int rr_list_to_packet(knot_pkt_t *dst, list_t *list)
+{
+ assert(dst != NULL);
+ assert(list != NULL);
+
+ ptrnode_t *node = NULL;
+ WALK_LIST(node, *list) {
+ int ret = knot_pkt_put(dst, KNOT_COMPR_HINT_NONE,
+ (knot_rrset_t *)node->d, 0);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+/*! \brief Build UPDATE query. */
+static int build_query(knsupdate_params_t *params)
+{
+ /* Clear old query. */
+ knot_pkt_t *query = params->query;
+ knot_pkt_clear(query);
+
+ /* Write question. */
+ knot_wire_set_id(query->wire, dnssec_random_uint16_t());
+ knot_wire_set_opcode(query->wire, KNOT_OPCODE_UPDATE);
+ knot_dname_t *qname = knot_dname_from_str_alloc(params->zone);
+ int ret = knot_pkt_put_question(query, qname, params->class_num,
+ params->type_num);
+ knot_dname_free(qname, NULL);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ /* Now, PREREQ => ANSWER section. */
+ ret = knot_pkt_begin(query, KNOT_ANSWER);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ /* Write PREREQ. */
+ ret = rr_list_to_packet(query, &params->prereq_list);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ /* Now, UPDATE data => AUTHORITY section. */
+ ret = knot_pkt_begin(query, KNOT_AUTHORITY);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ /* Write UPDATE data. */
+ return rr_list_to_packet(query, &params->update_list);
+}
+
+static int pkt_sendrecv(knsupdate_params_t *params)
+{
+ net_t net;
+ int ret;
+
+ ret = net_init(params->srcif,
+ params->server,
+ get_iptype(params->ip),
+ get_socktype(params->protocol, KNOT_RRTYPE_SOA),
+ params->wait,
+ NET_FLAGS_NONE,
+ NULL,
+ &net);
+ if (ret != KNOT_EOK) {
+ return -1;
+ }
+
+ ret = net_connect(&net);
+ DBG("%s: send_msg = %d\n", __func__, net.sockfd);
+ if (ret != KNOT_EOK) {
+ net_clean(&net);
+ return -1;
+ }
+
+ ret = net_send(&net, params->query->wire, params->query->size);
+ if (ret != KNOT_EOK) {
+ net_close(&net);
+ net_clean(&net);
+ return -1;
+ }
+
+ /* Clear response buffer. */
+ knot_pkt_clear(params->answer);
+
+ /* Wait for reception. */
+ int rb = net_receive(&net, params->answer->wire, params->answer->max_size);
+ DBG("%s: receive_msg = %d\n", __func__, rb);
+ if (rb <= 0) {
+ net_close(&net);
+ net_clean(&net);
+ return -1;
+ } else {
+ params->answer->size = rb;
+ }
+
+ net_close(&net);
+ net_clean(&net);
+
+ return rb;
+}
+
+static int process_line(char *lp, void *arg)
+{
+ knsupdate_params_t *params = (knsupdate_params_t *)arg;
+
+ /* Check for empty line or comment. */
+ if (lp[0] == '\0' || lp[0] == ';') {
+ return KNOT_EOK;
+ }
+
+ int ret = tok_find(lp, cmd_array);
+ if (ret < 0) {
+ return ret; /* Syntax error - do nothing. */
+ }
+
+ const char *cmd = cmd_array[ret];
+ const char *val = tok_skipspace(lp + TOK_L(cmd));
+ ret = cmd_handle[ret](val, params);
+ if (ret != KNOT_EOK) {
+ DBG("operation '%s' failed (%s) on line '%s'\n",
+ TOK_S(cmd), knot_strerror(ret), lp);
+ }
+
+ return ret;
+}
+
+static bool is_terminal(FILE *file)
+{
+ int fd = fileno(file);
+ assert(fd >= 0);
+ return isatty(fd);
+}
+
+static int process_lines(knsupdate_params_t *params, FILE *input)
+{
+ char *buf = NULL;
+ size_t buflen = 0;
+ bool interactive = is_terminal(input);
+ int ret = KNOT_EOK;
+
+ /* Print first program prompt if interactive. */
+ if (interactive) {
+ fprintf(stderr, "> ");
+ }
+
+ /* Process lines. */
+ while (!params->stop && knot_getline(&buf, &buflen, input) != -1) {
+ /* Remove leading and trailing white space. */
+ char *line = strstrip(buf);
+ int call_ret = process_line(line, params);
+ memset(line, 0, strlen(line));
+ free(line);
+ if (call_ret != KNOT_EOK) {
+ /* Return the first error. */
+ if (ret == KNOT_EOK) {
+ ret = call_ret;
+ }
+
+ /* Exit if error and not interactive. */
+ if (!interactive) {
+ break;
+ }
+ }
+
+ /* Print program prompt if interactive. */
+ if (interactive && !params->stop) {
+ fprintf(stderr, "> ");
+ }
+ }
+
+ if (interactive && feof(input)) {
+ /* Terminate line after empty prompt. */
+ fprintf(stderr, "\n");
+ }
+
+ if (buf != NULL) {
+ memset(buf, 0, buflen);
+ free(buf);
+ }
+
+ return ret;
+}
+
+int knsupdate_exec(knsupdate_params_t *params)
+{
+ if (!params) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = KNOT_EOK;
+
+ /* If no file specified, use stdin. */
+ if (EMPTY_LIST(params->qfiles)) {
+ ret = process_lines(params, stdin);
+ }
+
+ /* Read from each specified file. */
+ ptrnode_t *n = NULL;
+ WALK_LIST(n, params->qfiles) {
+ const char *filename = (const char*)n->d;
+ if (strcmp(filename, "-") == 0) {
+ ret = process_lines(params, stdin);
+ if (ret != KNOT_EOK) {
+ break;
+ }
+ continue;
+ }
+
+ FILE *fp = fopen(filename, "r");
+ if (!fp) {
+ ERR("failed to open '%s' (%s)\n",
+ filename, strerror(errno));
+ ret = KNOT_EFILE;
+ break;
+ }
+ ret = process_lines(params, fp);
+ fclose(fp);
+ if (ret != KNOT_EOK) {
+ break;
+ }
+ }
+
+ return ret;
+}
+
+int cmd_update(const char* lp, knsupdate_params_t *params)
+{
+ DBG("%s: lp='%s'\n", __func__, lp);
+
+ /* update is optional token, next add|del|delete */
+ int bp = tok_find(lp, cmd_array);
+ if (bp < 0) return bp; /* Syntax error. */
+
+ /* allow only specific tokens */
+ cmd_handle_f *h = cmd_handle;
+ if (h[bp] != cmd_add && h[bp] != cmd_del) {
+ ERR("unexpected token '%s' after 'update', allowed: '%s'\n",
+ lp, "{add|del|delete}");
+ return KNOT_EPARSEFAIL;
+ }
+
+ return h[bp](tok_skipspace(lp + TOK_L(cmd_array[bp])), params);
+}
+
+int cmd_add(const char* lp, knsupdate_params_t *params)
+{
+ DBG("%s: lp='%s'\n", __func__, lp);
+
+ if (parse_full_rr(&params->parser, lp) != KNOT_EOK) {
+ return KNOT_EPARSEFAIL;
+ }
+
+ return rr_list_append(&params->parser, &params->update_list, &params->mm);
+}
+
+int cmd_del(const char* lp, knsupdate_params_t *params)
+{
+ DBG("%s: lp='%s'\n", __func__, lp);
+
+ zs_scanner_t *rrp = &params->parser;
+ int ret = parse_partial_rr(rrp, lp, PARSE_NODEFAULT);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ /* Check owner name. */
+ if (rrp->r_owner_length == 0) {
+ ERR("failed to parse owner name '%s'\n", lp);
+ return KNOT_EPARSEFAIL;
+ }
+
+ rrp->r_ttl = 0; /* Set TTL = 0 when deleting. */
+
+ /* When deleting whole RRSet, use ANY class */
+ if (rrp->r_data_length == 0) {
+ rrp->r_class = KNOT_CLASS_ANY;
+ } else {
+ rrp->r_class = KNOT_CLASS_NONE;
+ }
+
+ return rr_list_append(rrp, &params->update_list, &params->mm);
+}
+
+int cmd_class(const char* lp, knsupdate_params_t *params)
+{
+ DBG("%s: lp='%s'\n", __func__, lp);
+
+ uint16_t cls;
+
+ if (knot_rrclass_from_string(lp, &cls) != 0) {
+ ERR("failed to parse class '%s'\n", lp);
+ return KNOT_EPARSEFAIL;
+ }
+
+ params->class_num = cls;
+ params->parser.default_class = params->class_num;
+
+ return KNOT_EOK;
+}
+
+int cmd_ttl(const char* lp, knsupdate_params_t *params)
+{
+ DBG("%s: lp='%s'\n", __func__, lp);
+
+ uint32_t ttl = 0;
+
+ if (str_to_u32(lp, &ttl) != KNOT_EOK) {
+ ERR("failed to parse ttl '%s'\n", lp);
+ return KNOT_EPARSEFAIL;
+ }
+
+ return knsupdate_set_ttl(params, ttl);
+}
+
+int cmd_debug(const char* lp, knsupdate_params_t *params)
+{
+ UNUSED(params);
+ DBG("%s: lp='%s'\n", __func__, lp);
+
+ msg_enable_debug(1);
+
+ return KNOT_EOK;
+}
+
+int cmd_nxdomain(const char *lp, knsupdate_params_t *params)
+{
+ DBG("%s: lp='%s'\n", __func__, lp);
+
+ zs_scanner_t *s = &params->parser;
+ int ret = parse_partial_rr(s, lp, PARSE_NODEFAULT | PARSE_NAMEONLY);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ s->r_ttl = 0;
+ s->r_class = KNOT_CLASS_NONE;
+
+ return rr_list_append(s, &params->prereq_list, &params->mm);
+}
+
+int cmd_yxdomain(const char *lp, knsupdate_params_t *params)
+{
+ DBG("%s: lp='%s'\n", __func__, lp);
+
+ zs_scanner_t *s = &params->parser;
+ int ret = parse_partial_rr(s, lp, PARSE_NODEFAULT | PARSE_NAMEONLY);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ s->r_ttl = 0;
+ s->r_class = KNOT_CLASS_ANY;
+
+ return rr_list_append(s, &params->prereq_list, &params->mm);
+}
+
+int cmd_nxrrset(const char *lp, knsupdate_params_t *params)
+{
+ DBG("%s: lp='%s'\n", __func__, lp);
+
+ zs_scanner_t *s = &params->parser;
+ int ret = parse_partial_rr(s, lp, PARSE_NOTTL);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ /* Check owner name. */
+ if (s->r_owner_length == 0) {
+ ERR("failed to parse prereq owner name '%s'\n", lp);
+ return KNOT_EPARSEFAIL;
+ }
+
+ s->r_ttl = 0;
+ s->r_class = KNOT_CLASS_NONE;
+
+ return rr_list_append(s, &params->prereq_list, &params->mm);
+}
+
+int cmd_yxrrset(const char *lp, knsupdate_params_t *params)
+{
+ DBG("%s: lp='%s'\n", __func__, lp);
+
+ zs_scanner_t *s = &params->parser;
+ int ret = parse_partial_rr(s, lp, PARSE_NOTTL);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ /* Check owner name. */
+ if (s->r_owner_length == 0) {
+ ERR("failed to parse prereq owner name '%s'\n", lp);
+ return KNOT_EPARSEFAIL;
+ }
+
+ s->r_ttl = 0;
+ if (s->r_data_length > 0) {
+ s->r_class = KNOT_CLASS_IN;
+ } else {
+ s->r_class = KNOT_CLASS_ANY;
+ }
+
+ return rr_list_append(s, &params->prereq_list, &params->mm);
+}
+
+int cmd_prereq(const char* lp, knsupdate_params_t *params)
+{
+ DBG("%s: lp='%s'\n", __func__, lp);
+
+ /* Scan prereq specifier ([ny]xrrset|[ny]xdomain) */
+ int prereq_type = tok_find(lp, pq_array);
+ if (prereq_type < 0) {
+ return prereq_type;
+ }
+
+ const char *tok = pq_array[prereq_type];
+ DBG("%s: type %s\n", __func__, TOK_S(tok));
+ lp = tok_skipspace(lp + TOK_L(tok));
+
+ int ret = KNOT_EOK;
+ switch(prereq_type) {
+ case PQ_NXDOMAIN:
+ ret = cmd_nxdomain(lp, params);
+ break;
+ case PQ_YXDOMAIN:
+ ret = cmd_yxdomain(lp, params);
+ break;
+ case PQ_NXRRSET:
+ ret = cmd_nxrrset(lp, params);
+ break;
+ case PQ_YXRRSET:
+ ret = cmd_yxrrset(lp, params);
+ break;
+ default:
+ ret = KNOT_ERROR;
+ }
+
+ return ret;
+}
+
+int cmd_quit(const char* lp, knsupdate_params_t *params)
+{
+ DBG("%s: lp='%s'\n", __func__, lp);
+
+ params->stop = true;
+
+ return KNOT_EOK;
+}
+
+int cmd_send(const char* lp, knsupdate_params_t *params)
+{
+ DBG("%s: lp='%s'\n", __func__, lp);
+ DBG("sending packet\n");
+
+ /* Build query packet. */
+ int ret = build_query(params);
+ if (ret != KNOT_EOK) {
+ ERR("failed to build UPDATE message (%s)\n", knot_strerror(ret));
+ return ret;
+ }
+
+ /* Sign if key specified. */
+ sign_context_t sign_ctx = { 0 };
+ if (params->tsig_key.name) {
+ ret = sign_context_init_tsig(&sign_ctx, &params->tsig_key);
+ if (ret != KNOT_EOK) {
+ ERR("failed to initialize signing context (%s)\n",
+ knot_strerror(ret));
+ return ret;
+ }
+
+ ret = sign_packet(params->query, &sign_ctx);
+ if (ret != KNOT_EOK) {
+ ERR("failed to sign UPDATE message (%s)\n",
+ knot_strerror(ret));
+ sign_context_deinit(&sign_ctx);
+ return ret;
+ }
+ }
+
+ int rb = 0;
+ /* Send/recv message (1 try + N retries). */
+ int tries = 1 + params->retries;
+ for (; tries > 0; --tries) {
+ rb = pkt_sendrecv(params);
+ if (rb > 0) {
+ break;
+ }
+ }
+
+ /* Check Send/recv result. */
+ if (rb <= 0) {
+ sign_context_deinit(&sign_ctx);
+ return KNOT_ECONNREFUSED;
+ }
+
+ /* Parse response. */
+ ret = knot_pkt_parse(params->answer, 0);
+ if (ret != KNOT_EOK) {
+ ERR("failed to parse response (%s)\n", knot_strerror(ret));
+ sign_context_deinit(&sign_ctx);
+ return ret;
+ }
+
+ /* Check signature if expected. */
+ if (params->tsig_key.name) {
+ ret = verify_packet(params->answer, &sign_ctx);
+ sign_context_deinit(&sign_ctx);
+ if (ret != KNOT_EOK) {
+ print_packet(params->answer, NULL, 0, -1, 0, true,
+ &params->style);
+ ERR("reply verification (%s)\n", knot_strerror(ret));
+ return ret;
+ }
+ }
+
+ /* Free RRSet lists. */
+ knsupdate_reset(params);
+
+ /* Check return code. */
+ if (knot_pkt_ext_rcode(params->answer) != KNOT_RCODE_NOERROR) {
+ print_packet(params->answer, NULL, 0, -1, 0, true, &params->style);
+ ERR("update failed with error '%s'\n",
+ knot_pkt_ext_rcode_name(params->answer));
+ ret = KNOT_ERROR;
+ } else {
+ DBG("update success\n");
+ }
+
+ return ret;
+}
+
+int cmd_zone(const char* lp, knsupdate_params_t *params)
+{
+ DBG("%s: lp='%s'\n", __func__, lp);
+
+ /* Check zone name. */
+ if (!dname_isvalid(lp)) {
+ ERR("failed to parse zone '%s'\n", lp);
+ return KNOT_EPARSEFAIL;
+ }
+
+ free(params->zone);
+ params->zone = strdup(lp);
+
+ return KNOT_EOK;
+}
+
+int cmd_server(const char* lp, knsupdate_params_t *params)
+{
+ DBG("%s: lp='%s'\n", __func__, lp);
+
+ /* Parse host. */
+ srv_info_t *srv = parse_host(lp, params->server->service);
+ if (!srv) {
+ ERR("failed to parse server '%s'\n", lp);
+ return KNOT_ENOMEM;
+ }
+
+ srv_info_free(params->server);
+ params->server = srv;
+
+ return KNOT_EOK;
+}
+
+int cmd_local(const char* lp, knsupdate_params_t *params)
+{
+ DBG("%s: lp='%s'\n", __func__, lp);
+
+ /* Parse host. */
+ srv_info_t *srv = parse_host(lp, "0");
+ if (!srv) {
+ ERR("failed to parse local '%s'\n", lp);
+ return KNOT_ENOMEM;
+ }
+
+ srv_info_free(params->srcif);
+ params->srcif = srv;
+
+ return KNOT_EOK;
+}
+
+int cmd_show(const char* lp, knsupdate_params_t *params)
+{
+ DBG("%s: lp='%s'\n", __func__, lp);
+
+ if (!params->query) {
+ return KNOT_EOK;
+ }
+
+ printf("Update query:\n");
+ build_query(params);
+ print_packet(params->query, NULL, 0, -1, 0, false, &params->style);
+ printf("\n");
+
+ return KNOT_EOK;
+}
+
+int cmd_answer(const char* lp, knsupdate_params_t *params)
+{
+ DBG("%s: lp='%s'\n", __func__, lp);
+
+ if (!params->answer) {
+ return KNOT_EOK;
+ }
+
+ printf("\nAnswer:\n");
+ print_packet(params->answer, NULL, 0, -1, 0, true, &params->style);
+
+ return KNOT_EOK;
+}
+
+int cmd_key(const char* lp, knsupdate_params_t *params)
+{
+ DBG("%s: lp='%s'\n", __func__, lp);
+
+ /* Convert to default format. */
+ char *kstr = strdup(lp);
+ if (!kstr) {
+ return KNOT_ENOMEM;
+ }
+
+ int ret = KNOT_EOK;
+
+ /* Search for the name secret separation. Allow also alg:name:key form. */
+ char *sep = strchr(kstr, ' ');
+ if (sep != NULL) {
+ /* Replace ' ' with ':'. More spaces are ignored in base64. */
+ *sep = ':';
+ }
+
+ /* Override existing key. */
+ knot_tsig_key_deinit(&params->tsig_key);
+
+ ret = knot_tsig_key_init_str(&params->tsig_key, kstr);
+ if (ret != KNOT_EOK) {
+ ERR("invalid key specification\n");
+ }
+
+ free(kstr);
+
+ return ret;
+}
+
+int cmd_origin(const char* lp, knsupdate_params_t *params)
+{
+ DBG("%s: lp='%s'\n", __func__, lp);
+
+ /* Check zone name. */
+ if (!dname_isvalid(lp)) {
+ ERR("failed to parse zone '%s'\n", lp);
+ return KNOT_EPARSEFAIL;
+ }
+
+ return knsupdate_set_origin(params, lp);
+}
+
+/*
+ * Not implemented.
+ */
+
+int cmd_gsstsig(const char* lp, knsupdate_params_t *params)
+{
+ UNUSED(params);
+ DBG("%s: lp='%s'\n", __func__, lp);
+
+ return KNOT_ENOTSUP;
+}
+
+int cmd_oldgsstsig(const char* lp, knsupdate_params_t *params)
+{
+ UNUSED(params);
+ DBG("%s: lp='%s'\n", __func__, lp);
+
+ return KNOT_ENOTSUP;
+}
+
+int cmd_realm(const char* lp, knsupdate_params_t *params)
+{
+ UNUSED(params);
+ DBG("%s: lp='%s'\n", __func__, lp);
+
+ return KNOT_ENOTSUP;
+}
diff --git a/src/utils/knsupdate/knsupdate_exec.h b/src/utils/knsupdate/knsupdate_exec.h
new file mode 100644
index 0000000..182c141
--- /dev/null
+++ b/src/utils/knsupdate/knsupdate_exec.h
@@ -0,0 +1,21 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include "utils/knsupdate/knsupdate_params.h"
+
+int knsupdate_exec(knsupdate_params_t *params);
diff --git a/src/utils/knsupdate/knsupdate_main.c b/src/utils/knsupdate/knsupdate_main.c
new file mode 100644
index 0000000..69d471f
--- /dev/null
+++ b/src/utils/knsupdate/knsupdate_main.c
@@ -0,0 +1,44 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdlib.h>
+
+#include "libdnssec/crypto.h"
+#include "utils/knsupdate/knsupdate_exec.h"
+#include "utils/knsupdate/knsupdate_params.h"
+#include "libknot/libknot.h"
+
+int main(int argc, char *argv[])
+{
+
+ int ret = EXIT_SUCCESS;
+
+ knsupdate_params_t params;
+ if (knsupdate_parse(&params, argc, argv) == KNOT_EOK) {
+ if (!params.stop) {
+ dnssec_crypto_init();
+ if (knsupdate_exec(&params) != KNOT_EOK) {
+ ret = EXIT_FAILURE;
+ }
+ dnssec_crypto_cleanup();
+ }
+ } else {
+ ret = EXIT_FAILURE;
+ }
+
+ knsupdate_clean(&params);
+ return ret;
+}
diff --git a/src/utils/knsupdate/knsupdate_params.c b/src/utils/knsupdate/knsupdate_params.c
new file mode 100644
index 0000000..f2eee91
--- /dev/null
+++ b/src/utils/knsupdate/knsupdate_params.c
@@ -0,0 +1,314 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "utils/knsupdate/knsupdate_params.h"
+#include "utils/common/msg.h"
+#include "utils/common/netio.h"
+#include "libknot/libknot.h"
+#include "libknot/tsig.h"
+#include "contrib/mempattern.h"
+#include "contrib/strtonum.h"
+#include "contrib/ucw/mempool.h"
+
+#define PROGRAM_NAME "knsupdate"
+
+#define DEFAULT_RETRIES_NSUPDATE 3
+#define DEFAULT_TIMEOUT_NSUPDATE 12
+
+static const style_t DEFAULT_STYLE_NSUPDATE = {
+ .format = FORMAT_NSUPDATE,
+ .style = {
+ .wrap = false,
+ .show_class = true,
+ .show_ttl = true,
+ .verbose = false,
+ .original_ttl = false,
+ .empty_ttl = false,
+ .human_ttl = false,
+ .human_tmstamp = true,
+ .generic = false,
+ .ascii_to_idn = NULL
+ },
+ .show_query = false,
+ .show_header = true,
+ .show_edns = false,
+ .show_question = true,
+ .show_answer = true,
+ .show_authority = true,
+ .show_additional = true,
+ .show_tsig = true,
+ .show_footer = false
+};
+
+static void parse_err(zs_scanner_t *s) {
+ ERR("failed to parse RR: %s\n", zs_strerror(s->error.code));
+}
+
+static int parser_set_default(zs_scanner_t *s, const char *fmt, ...)
+{
+ /* Format string. */
+ char buf[512]; /* Must suffice for domain name and TTL. */
+ va_list ap;
+ va_start(ap, fmt);
+ int n = vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+
+ if (n < 0 || (size_t)n >= sizeof(buf)) {
+ return KNOT_ESPACE;
+ }
+
+ /* Buffer must contain newline */
+ if (zs_set_input_string(s, buf, n) != 0 ||
+ zs_parse_all(s) != 0) {
+ return KNOT_EPARSEFAIL;
+ }
+
+ return KNOT_EOK;
+}
+
+static int knsupdate_init(knsupdate_params_t *params)
+{
+ memset(params, 0, sizeof(knsupdate_params_t));
+
+ /* Initialize lists. */
+ init_list(&params->qfiles);
+ init_list(&params->update_list);
+ init_list(&params->prereq_list);
+
+ /* Initialize memory context. */
+ mm_ctx_mempool(&params->mm, MM_DEFAULT_BLKSIZE);
+
+ /* Default server. */
+ params->server = srv_info_create(DEFAULT_IPV4_NAME, DEFAULT_DNS_PORT);
+ if (!params->server)
+ return KNOT_ENOMEM;
+
+ /* Default settings. */
+ params->ip = IP_ALL;
+ params->protocol = PROTO_ALL;
+ params->class_num = KNOT_CLASS_IN;
+ params->type_num = KNOT_RRTYPE_SOA;
+ params->ttl = 0;
+ params->retries = DEFAULT_RETRIES_NSUPDATE;
+ params->wait = DEFAULT_TIMEOUT_NSUPDATE;
+ params->zone = strdup(".");
+
+ /* Initialize RR parser. */
+ if (zs_init(&params->parser, ".", params->class_num, 0) != 0 ||
+ zs_set_processing(&params->parser, NULL, parse_err, NULL) != 0) {
+ zs_deinit(&params->parser);
+ return KNOT_ENOMEM;
+ }
+
+ /* Default style. */
+ params->style = DEFAULT_STYLE_NSUPDATE;
+
+ /* Create query/answer packets. */
+ params->query = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, &params->mm);
+ params->answer = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, &params->mm);
+
+ return KNOT_EOK;
+}
+
+void knsupdate_clean(knsupdate_params_t *params)
+{
+ if (params == NULL) {
+ return;
+ }
+
+ /* Clear current query. */
+ knsupdate_reset(params);
+
+ /* Free qfiles. */
+ ptrlist_free(&params->qfiles, &params->mm);
+
+ srv_info_free(params->server);
+ srv_info_free(params->srcif);
+ free(params->zone);
+ zs_deinit(&params->parser);
+ knot_pkt_free(params->query);
+ knot_pkt_free(params->answer);
+ knot_tsig_key_deinit(&params->tsig_key);
+
+ /* Clean up the structure. */
+ mp_delete(params->mm.ctx);
+ memset(params, 0, sizeof(*params));
+}
+
+/*! \brief Free RRSet list. */
+static void rr_list_free(list_t *list, knot_mm_t *mm)
+{
+ assert(list != NULL);
+ assert(mm != NULL);
+
+ ptrnode_t *node = NULL;
+ WALK_LIST(node, *list) {
+ knot_rrset_t *rrset = (knot_rrset_t *)node->d;
+ knot_rrset_free(rrset, NULL);
+ }
+ ptrlist_free(list, mm);
+}
+
+void knsupdate_reset(knsupdate_params_t *params)
+{
+ /* Free ADD/REMOVE RRSets. */
+ rr_list_free(&params->update_list, &params->mm);
+
+ /* Free PREREQ RRSets. */
+ rr_list_free(&params->prereq_list, &params->mm);
+}
+
+static void print_help(void)
+{
+ printf("Usage: %s [-d] [-v] [-k keyfile | -y [hmac:]name:key]\n"
+ " [-p port] [-t timeout] [-r retries] [filename]\n",
+ PROGRAM_NAME);
+}
+
+int knsupdate_parse(knsupdate_params_t *params, int argc, char *argv[])
+{
+ if (params == NULL || argv == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ int ret = knsupdate_init(params);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Long options.
+ struct option opts[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'V' },
+ { NULL }
+ };
+
+ /* Command line options processing. */
+ int opt = 0;
+ while ((opt = getopt_long(argc, argv, "dhDvVp:t:r:y:k:", opts, NULL))
+ != -1) {
+ switch (opt) {
+ case 'd':
+ case 'D': /* Extra debugging. */
+ msg_enable_debug(1);
+ break;
+ case 'h':
+ print_help();
+ params->stop = true;
+ return KNOT_EOK;
+ case 'v':
+ params->protocol = PROTO_TCP;
+ break;
+ case 'V':
+ print_version(PROGRAM_NAME);
+ params->stop = true;
+ return KNOT_EOK;
+ case 'p':
+ free(params->server->service);
+ params->server->service = strdup(optarg);
+ if (!params->server->service) {
+ ERR("failed to set default port '%s'\n", optarg);
+ return KNOT_ENOMEM;
+ }
+ break;
+ case 'r':
+ ret = str_to_u32(optarg, &params->retries);
+ if (ret != KNOT_EOK) {
+ ERR("invalid retries '%s'\n", optarg);
+ return ret;
+ }
+ break;
+ case 't':
+ ret = params_parse_wait(optarg, &params->wait);
+ if (ret != KNOT_EOK) {
+ ERR("invalid timeout '%s'\n", optarg);
+ return ret;
+ }
+ break;
+ case 'y':
+ knot_tsig_key_deinit(&params->tsig_key);
+ ret = knot_tsig_key_init_str(&params->tsig_key, optarg);
+ if (ret != KNOT_EOK) {
+ ERR("failed to parse key '%s'\n", optarg);
+ return ret;
+ }
+ break;
+ case 'k':
+ knot_tsig_key_deinit(&params->tsig_key);
+ ret = knot_tsig_key_init_file(&params->tsig_key, optarg);
+ if (ret != KNOT_EOK) {
+ ERR("failed to parse keyfile '%s'\n", optarg);
+ return ret;
+ }
+ break;
+ default:
+ print_help();
+ return KNOT_ENOTSUP;
+ }
+ }
+
+ /* No retries for TCP. */
+ if (params->protocol == PROTO_TCP) {
+ params->retries = 0;
+ } else {
+ /* If wait/tries < 1 s, set 1 second for each try. */
+ if (params->wait > 0 &&
+ (uint32_t)params->wait < ( 1 + params->retries)) {
+ params->wait = 1;
+ } else {
+ params->wait /= (1 + params->retries);
+ }
+ }
+
+ /* Process non-option parameters. */
+ for (; optind < argc; ++optind) {
+ ptrlist_add(&params->qfiles, argv[optind], &params->mm);
+ }
+
+ return ret;
+}
+
+int knsupdate_set_ttl(knsupdate_params_t *params, const uint32_t ttl)
+{
+ int ret = parser_set_default(&params->parser, "$TTL %u\n", ttl);
+ if (ret == KNOT_EOK) {
+ params->ttl = ttl;
+ } else {
+ ERR("failed to set default TTL, %s\n", knot_strerror(ret));
+ }
+ return ret;
+}
+
+int knsupdate_set_origin(knsupdate_params_t *params, const char *origin)
+{
+ char *fqdn = get_fqd_name(origin);
+
+ int ret = parser_set_default(&params->parser, "$ORIGIN %s\n", fqdn);
+
+ free(fqdn);
+
+ if (ret != KNOT_EOK) {
+ ERR("failed to set default origin, %s\n", knot_strerror(ret));
+ }
+ return ret;
+}
diff --git a/src/utils/knsupdate/knsupdate_params.h b/src/utils/knsupdate/knsupdate_params.h
new file mode 100644
index 0000000..2c0c391
--- /dev/null
+++ b/src/utils/knsupdate/knsupdate_params.h
@@ -0,0 +1,74 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#include "utils/common/netio.h"
+#include "utils/common/params.h"
+#include "utils/common/sign.h"
+#include "libknot/libknot.h"
+#include "libzscanner/scanner.h"
+#include "contrib/ucw/lists.h"
+
+/*! \brief knsupdate-specific params data. */
+typedef struct {
+ /*!< Stop processing - just print help, version,... */
+ bool stop;
+ /*!< List of files with query data. */
+ list_t qfiles;
+ /*!< List of nameservers to query to. */
+ srv_info_t *server;
+ /*!< Local interface (optional). */
+ srv_info_t *srcif;
+ /*!< Version of ip protocol to use. */
+ ip_t ip;
+ /*!< Type (TCP, UDP) protocol to use. */
+ protocol_t protocol;
+ /*!< Default class number. */
+ uint16_t class_num;
+ /*!< Default type number. */
+ uint16_t type_num;
+ /*!< Default TTL. */
+ uint32_t ttl;
+ /*!< Number of UDP retries. */
+ uint32_t retries;
+ /*!< Wait for network response in seconds (-1 means forever). */
+ int32_t wait;
+ /*!< Current zone. */
+ char *zone;
+ /*!< RR parser. */
+ zs_scanner_t parser;
+ /*!< Current packet. */
+ knot_pkt_t *query;
+ /*!< Current response. */
+ knot_pkt_t *answer;
+ /*< Lists of RRSets. */
+ list_t update_list, prereq_list;
+ /*!< Transaction signature context. */
+ knot_tsig_key_t tsig_key;
+ /*!< Default output settings. */
+ style_t style;
+ /*!< Memory context. */
+ knot_mm_t mm;
+} knsupdate_params_t;
+
+int knsupdate_parse(knsupdate_params_t *params, int argc, char *argv[]);
+int knsupdate_set_ttl(knsupdate_params_t *params, const uint32_t ttl);
+int knsupdate_set_origin(knsupdate_params_t *params, const char *origin);
+void knsupdate_clean(knsupdate_params_t *params);
+void knsupdate_reset(knsupdate_params_t *params);
diff --git a/src/utils/kzonecheck/main.c b/src/utils/kzonecheck/main.c
new file mode 100644
index 0000000..2e8ce71
--- /dev/null
+++ b/src/utils/kzonecheck/main.c
@@ -0,0 +1,148 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <getopt.h>
+#include <libgen.h>
+#include <stdio.h>
+
+#include "contrib/time.h"
+#include "libknot/libknot.h"
+#include "knot/common/log.h"
+#include "utils/common/params.h"
+#include "utils/kzonecheck/zone_check.h"
+
+#define PROGRAM_NAME "kzonecheck"
+
+static void print_help(void)
+{
+ printf("Usage: %s [parameters] <filename>\n"
+ "\n"
+ "Parameters:\n"
+ " -o, --origin <zone_origin> Zone name.\n"
+ " (default filename without .zone)\n"
+ " -t, --time <timestamp> Current time specification.\n"
+ " (default current UNIX time)\n"
+ " -v, --verbose Enable debug output.\n"
+ " -h, --help Print the program help.\n"
+ " -V, --version Print the program version.\n"
+ "\n",
+ PROGRAM_NAME);
+}
+
+int main(int argc, char *argv[])
+{
+ const char *origin = NULL;
+ bool verbose = false;
+ knot_time_t check_time = (knot_time_t)time(NULL);
+
+ /* Long options. */
+ struct option opts[] = {
+ { "origin", required_argument, NULL, 'o' },
+ { "time", required_argument, NULL, 't' },
+ { "verbose", no_argument, NULL, 'v' },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'V' },
+ { NULL }
+ };
+
+ /* Parse command line arguments */
+ int opt = 0;
+ while ((opt = getopt_long(argc, argv, "o:t:vVh", opts, NULL)) != -1) {
+ switch (opt) {
+ case 'o':
+ origin = optarg;
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ case 'h':
+ print_help();
+ return EXIT_SUCCESS;
+ case 'V':
+ print_version(PROGRAM_NAME);
+ return EXIT_SUCCESS;
+ case 't':
+ if (knot_time_parse("YMDhms|#|+-#U|+-#",
+ optarg, &check_time) != KNOT_EOK) {
+ fprintf(stderr, "Unknown time format\n");
+ return EXIT_FAILURE;
+ }
+ break;
+ default:
+ print_help();
+ return EXIT_FAILURE;
+ }
+ }
+
+ /* Check if there's at least one remaining non-option. */
+ if (optind >= argc) {
+ fprintf(stderr, "Expected zone file name\n");
+ print_help();
+ return EXIT_FAILURE;
+ }
+
+ char *filename = argv[optind];
+
+ char *zonename;
+ if (origin == NULL) {
+ /* Get zone name from file name. */
+ const char *ext = ".zone";
+ zonename = basename(filename);
+ if (strcmp(zonename + strlen(zonename) - strlen(ext), ext) == 0) {
+ zonename = strndup(zonename, strlen(zonename) - strlen(ext));
+ } else {
+ zonename = strdup(zonename);
+ }
+ } else {
+ zonename = strdup(origin);
+ }
+
+ log_init();
+ log_levels_set(LOG_TARGET_STDOUT, LOG_SOURCE_ANY, 0);
+ log_levels_set(LOG_TARGET_STDERR, LOG_SOURCE_ANY, 0);
+ log_levels_set(LOG_TARGET_SYSLOG, LOG_SOURCE_ANY, 0);
+ log_flag_set(LOG_FLAG_NOTIMESTAMP | LOG_FLAG_NOINFO);
+ if (verbose) {
+ log_levels_add(LOG_TARGET_STDOUT, LOG_SOURCE_ANY, LOG_UPTO(LOG_DEBUG));
+ }
+
+ knot_dname_t *dname = knot_dname_from_str_alloc(zonename);
+ free(zonename);
+ int ret = zone_check(filename, dname, stdout, (time_t)check_time);
+ knot_dname_free(dname, NULL);
+
+ log_close();
+
+ switch (ret) {
+ case KNOT_EOK:
+ if (verbose) {
+ fprintf(stdout, "No semantic error found\n");
+ }
+ return EXIT_SUCCESS;
+ case KNOT_EZONEINVAL:
+ fprintf(stdout, "Serious semantic error detected\n");
+ // FALLTHROUGH
+ case KNOT_ESEMCHECK:
+ return EXIT_FAILURE;
+ case KNOT_EACCES:
+ case KNOT_EFILE:
+ fprintf(stderr, "Failed to load the zone file\n");
+ return EXIT_FAILURE;
+ default:
+ fprintf(stderr, "Failed to run semantic checks (%s)\n", knot_strerror(ret));
+ return EXIT_FAILURE;
+ }
+}
diff --git a/src/utils/kzonecheck/zone_check.c b/src/utils/kzonecheck/zone_check.c
new file mode 100644
index 0000000..5ddc7d0
--- /dev/null
+++ b/src/utils/kzonecheck/zone_check.c
@@ -0,0 +1,91 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "knot/zone/contents.h"
+#include "knot/zone/zonefile.h"
+#include "utils/kzonecheck/zone_check.h"
+
+typedef struct {
+ sem_handler_t handler;
+ FILE *outfile;
+ unsigned errors[SEM_ERR_UNKNOWN + 1]; /*!< Counting errors by type. */
+ unsigned error_count; /*!< Total error count. */
+} err_handler_stats_t;
+
+static void err_callback(sem_handler_t *handler, const zone_contents_t *zone,
+ const zone_node_t *node, sem_error_t error, const char *data)
+{
+ assert(handler != NULL);
+ assert(zone != NULL);
+ err_handler_stats_t *stats = (err_handler_stats_t *)handler;
+
+ char buff[KNOT_DNAME_TXT_MAXLEN + 1] = "";
+ (void)knot_dname_to_str(buff, (node != NULL ? node->owner : zone->apex->owner),
+ sizeof(buff));
+
+ fprintf(stats->outfile, "[%s] %s%s%s\n",
+ buff, sem_error_msg(error),
+ (data != NULL ? " " : ""),
+ (data != NULL ? data : ""));
+
+ stats->errors[error]++;
+ stats->error_count++;
+}
+
+static void print_statistics(err_handler_stats_t *stats)
+{
+ fprintf(stats->outfile, "\nError summary:\n");
+ for (sem_error_t i = 0; i <= SEM_ERR_UNKNOWN; ++i) {
+ if (stats->errors[i] > 0) {
+ fprintf(stats->outfile, "%4u\t%s\n", stats->errors[i],
+ sem_error_msg(i));
+ }
+ }
+}
+
+int zone_check(const char *zone_file, const knot_dname_t *zone_name,
+ FILE *outfile, time_t time)
+{
+ err_handler_stats_t stats = {
+ .handler = { .cb = err_callback },
+ .outfile = outfile
+ };
+
+ zloader_t zl;
+ int ret = zonefile_open(&zl, zone_file, zone_name, true, time);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ zl.err_handler = (sem_handler_t *)&stats;
+ zl.creator->master = true;
+
+ zone_contents_t *contents = zonefile_load(&zl);
+ zonefile_close(&zl);
+ if (contents == NULL && !stats.handler.fatal_error) {
+ return KNOT_ERROR;
+ }
+ zone_contents_deep_free(contents);
+
+ if (stats.error_count > 0) {
+ print_statistics(&stats);
+ return stats.handler.fatal_error ? KNOT_EZONEINVAL : KNOT_ESEMCHECK;
+ } else {
+ return KNOT_EOK;
+ }
+}
diff --git a/src/utils/kzonecheck/zone_check.h b/src/utils/kzonecheck/zone_check.h
new file mode 100644
index 0000000..67b0f5e
--- /dev/null
+++ b/src/utils/kzonecheck/zone_check.h
@@ -0,0 +1,22 @@
+/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include "libknot/libknot.h"
+
+int zone_check(const char *zone_file, const knot_dname_t *zone_name,
+ FILE *outfile, time_t time);