mirror of
https://github.com/coredns/coredns.git
synced 2026-04-08 04:55:40 -04:00
plugin/tsig: add require_opcode directive for opcode-based TSIG (#7828)
Extend the tsig plugin to require TSIG signatures based on DNS opcodes,
similar to the existing qtype-based requirement.
The new require_opcode directive accepts opcode names (QUERY, IQUERY,
STATUS, NOTIFY, UPDATE) or the special values "all" and "none".
This is useful for requiring TSIG on dynamic update (UPDATE) or zone
transfer notification (NOTIFY) requests while allowing unsigned queries.
Example:
```
tsig {
secret key. NoTCJU+DMqFWywaPyxSijrDEA/eC3nK0xi3AMEZuPVk=
require_opcode UPDATE NOTIFY
}
```
Signed-off-by: Seena Fallah <seenafallah@gmail.com>
This commit is contained in:
@@ -32,49 +32,85 @@ key "name2.key." {
|
||||
defer cleanup()
|
||||
|
||||
tests := []struct {
|
||||
input string
|
||||
shouldErr bool
|
||||
expectedZones []string
|
||||
expectedQTypes qTypes
|
||||
expectedSecrets map[string]string
|
||||
expectedAll bool
|
||||
input string
|
||||
shouldErr bool
|
||||
expectedZones []string
|
||||
expectedQTypes qTypes
|
||||
expectedOpCodes opCodes
|
||||
expectedSecrets map[string]string
|
||||
expectedAllTypes bool
|
||||
expectedAllOpcodes bool
|
||||
}{
|
||||
{
|
||||
input: "tsig {\n " + secretConfig + "}",
|
||||
expectedZones: []string{"."},
|
||||
expectedQTypes: defaultQTypes,
|
||||
expectedOpCodes: defaultOpCodes,
|
||||
expectedSecrets: secrets,
|
||||
},
|
||||
{
|
||||
input: "tsig {\n secrets " + secretsFile + "\n}",
|
||||
expectedZones: []string{"."},
|
||||
expectedQTypes: defaultQTypes,
|
||||
expectedOpCodes: defaultOpCodes,
|
||||
expectedSecrets: secrets,
|
||||
},
|
||||
{
|
||||
input: "tsig example.com {\n " + secretConfig + "}",
|
||||
expectedZones: []string{"example.com."},
|
||||
expectedQTypes: defaultQTypes,
|
||||
expectedOpCodes: defaultOpCodes,
|
||||
expectedSecrets: secrets,
|
||||
},
|
||||
{
|
||||
input: "tsig {\n " + secretConfig + " require all \n}",
|
||||
expectedZones: []string{"."},
|
||||
expectedQTypes: qTypes{},
|
||||
expectedAll: true,
|
||||
expectedSecrets: secrets,
|
||||
input: "tsig {\n " + secretConfig + " require all \n}",
|
||||
expectedZones: []string{"."},
|
||||
expectedQTypes: qTypes{},
|
||||
expectedOpCodes: defaultOpCodes,
|
||||
expectedAllTypes: true,
|
||||
expectedSecrets: secrets,
|
||||
},
|
||||
{
|
||||
input: "tsig {\n " + secretConfig + " require none \n}",
|
||||
expectedZones: []string{"."},
|
||||
expectedQTypes: qTypes{},
|
||||
expectedAll: false,
|
||||
expectedOpCodes: defaultOpCodes,
|
||||
expectedSecrets: secrets,
|
||||
},
|
||||
{
|
||||
input: "tsig {\n " + secretConfig + " \n require A AAAA \n}",
|
||||
expectedZones: []string{"."},
|
||||
expectedQTypes: qTypes{dns.TypeA: {}, dns.TypeAAAA: {}},
|
||||
expectedOpCodes: defaultOpCodes,
|
||||
expectedSecrets: secrets,
|
||||
},
|
||||
{
|
||||
input: "tsig {\n " + secretConfig + " \n require_opcode UPDATE NOTIFY \n}",
|
||||
expectedZones: []string{"."},
|
||||
expectedQTypes: defaultQTypes,
|
||||
expectedOpCodes: opCodes{dns.OpcodeUpdate: {}, dns.OpcodeNotify: {}},
|
||||
expectedSecrets: secrets,
|
||||
},
|
||||
{
|
||||
input: "tsig {\n " + secretConfig + " \n require_opcode all \n}",
|
||||
expectedZones: []string{"."},
|
||||
expectedQTypes: defaultQTypes,
|
||||
expectedOpCodes: opCodes{},
|
||||
expectedAllOpcodes: true,
|
||||
expectedSecrets: secrets,
|
||||
},
|
||||
{
|
||||
input: "tsig {\n " + secretConfig + " \n require_opcode none \n}",
|
||||
expectedZones: []string{"."},
|
||||
expectedQTypes: defaultQTypes,
|
||||
expectedOpCodes: opCodes{},
|
||||
expectedSecrets: secrets,
|
||||
},
|
||||
{
|
||||
input: "tsig {\n " + secretConfig + " \n require AXFR \n require_opcode UPDATE \n}",
|
||||
expectedZones: []string{"."},
|
||||
expectedQTypes: qTypes{dns.TypeAXFR: {}},
|
||||
expectedOpCodes: opCodes{dns.OpcodeUpdate: {}},
|
||||
expectedSecrets: secrets,
|
||||
},
|
||||
{
|
||||
@@ -93,6 +129,14 @@ key "name2.key." {
|
||||
input: "tsig {\n require invalid-qtype \n}",
|
||||
shouldErr: true,
|
||||
},
|
||||
{
|
||||
input: "tsig {\n require_opcode \n}",
|
||||
shouldErr: true,
|
||||
},
|
||||
{
|
||||
input: "tsig {\n require_opcode INVALID \n}",
|
||||
shouldErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
serverBlockKeys := []string{"."}
|
||||
@@ -121,8 +165,12 @@ key "name2.key." {
|
||||
}
|
||||
}
|
||||
|
||||
if test.expectedAll != ts.all {
|
||||
t.Errorf("Test %d expected require all to be '%v', but got '%v'.", i, test.expectedAll, ts.all)
|
||||
if test.expectedAllTypes != ts.allTypes {
|
||||
t.Errorf("Test %d expected require all types to be '%v', but got '%v'.", i, test.expectedAllTypes, ts.allTypes)
|
||||
}
|
||||
|
||||
if test.expectedAllOpcodes != ts.allOpcodes {
|
||||
t.Errorf("Test %d expected require all opcodes to be '%v', but got '%v'.", i, test.expectedAllOpcodes, ts.allOpcodes)
|
||||
}
|
||||
|
||||
if len(test.expectedQTypes) != len(ts.types) {
|
||||
@@ -135,6 +183,16 @@ key "name2.key." {
|
||||
}
|
||||
}
|
||||
|
||||
if len(test.expectedOpCodes) != len(ts.opcodes) {
|
||||
t.Fatalf("Test %d expected required opcodes '%v', but got '%v'.", i, test.expectedOpCodes, ts.opcodes)
|
||||
}
|
||||
for op := range test.expectedOpCodes {
|
||||
if _, ok := ts.opcodes[op]; !ok {
|
||||
t.Errorf("Test %d required opcodes '%v', but got '%v'.", i, test.expectedOpCodes, ts.opcodes)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if len(test.expectedSecrets) != len(ts.secrets) {
|
||||
t.Fatalf("Test %d expected secrets '%v', but got '%v'.", i, test.expectedSecrets, ts.secrets)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user