-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix the recursor unix sock messaging
Honor the status messages requirements and message length preamble.
- Loading branch information
Showing
5 changed files
with
165 additions
and
74 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
//go:build armbe || arm64be || mips || mips64 || mips64p32 || ppc || ppc64 || s390 || s390x || sparc || sparc64 | ||
|
||
package main | ||
|
||
import "encoding/binary" | ||
|
||
var HostEndianness = binary.BigEndian |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
//go:build 386 || amd64 || amd64p32 || arm || arm64 || loong64 || mipsle || mips64le || mips64p32le || ppc64le || riscv || riscv64 || wasm | ||
|
||
package main | ||
|
||
import "encoding/binary" | ||
|
||
var HostEndianness = binary.LittleEndian |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package main | ||
|
||
// derived from https://raw.githubusercontent.com/OrfeasZ/telegraf/b8a4e6cb7aef4134bd506cb873c8040c084a2406/plugins/inputs/powerdns_recursor/protocol_commons.go | ||
// license: MIT | ||
|
||
import ( | ||
"fmt" | ||
"net" | ||
"strconv" | ||
) | ||
|
||
// This below is generally unsafe but necessary in this case | ||
// since the powerdns protocol encoding is host dependent. | ||
// The C implementation uses size_t as the size type for the | ||
// command length. The size and endianness of size_t change | ||
// depending on the platform the program is being run on. | ||
// Using the target architecture endianness and the known | ||
// integer size, we can "recreate" the corresponding C | ||
// behavior in an effort to maintain compatibility. Of course | ||
// in cases where one program is compiled for i386 and the | ||
// other for amd64 (and similar), this method will fail. | ||
|
||
const uintSizeInBytes = strconv.IntSize / 8 | ||
|
||
func writeNativeUIntToConn(conn net.Conn, value uint) error { | ||
intData := make([]byte, uintSizeInBytes) | ||
|
||
switch uintSizeInBytes { | ||
case 4: | ||
HostEndianness.PutUint32(intData, uint32(value)) | ||
case 8: | ||
HostEndianness.PutUint64(intData, uint64(value)) | ||
default: | ||
return fmt.Errorf("unsupported system configuration") | ||
} | ||
|
||
_, err := conn.Write(intData) | ||
return err | ||
} | ||
|
||
func readNativeUIntFromConn(conn net.Conn) (uint, error) { | ||
intData := make([]byte, uintSizeInBytes) | ||
|
||
n, err := conn.Read(intData) | ||
|
||
if err != nil { | ||
return 0, err | ||
} | ||
|
||
if n != uintSizeInBytes { | ||
return 0, fmt.Errorf("did not read enough data for native uint: read '%v' bytes, expected '%v'", n, uintSizeInBytes) | ||
} | ||
|
||
switch uintSizeInBytes { | ||
case 4: | ||
return uint(HostEndianness.Uint32(intData)), nil | ||
case 8: | ||
return uint(HostEndianness.Uint64(intData)), nil | ||
default: | ||
return 0, fmt.Errorf("unsupported system configuration") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
package main | ||
|
||
// derived from https://raw.githubusercontent.com/OrfeasZ/telegraf/b8a4e6cb7aef4134bd506cb873c8040c084a2406/plugins/inputs/powerdns_recursor/protocol_v3.go | ||
// license: MIT | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"net" | ||
"time" | ||
) | ||
|
||
// V3 (4.6.0+) Protocol: | ||
// Standard unix stream socket | ||
// Synchronous request / response | ||
// Data structure: | ||
// status: uint32 | ||
// dataLength: size_t | ||
// data: byte[dataLength] | ||
func wipe(name string) error { | ||
conn, err := net.Dial("unix", pdnsSock) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
defer conn.Close() | ||
|
||
if err := conn.SetDeadline(time.Now().Add(evHandlingTimeout)); err != nil { | ||
return err | ||
} | ||
|
||
// Write 4-byte response code. | ||
if _, err = conn.Write([]byte{0, 0, 0, 0}); err != nil { | ||
return err | ||
} | ||
|
||
command := []byte("wipe-cache " + name + "\n") | ||
log.Printf(">>> %s", command) | ||
|
||
if err = writeNativeUIntToConn(conn, uint(len(command))); err != nil { | ||
return err | ||
} | ||
|
||
if _, err = conn.Write(command); err != nil { | ||
return err | ||
} | ||
|
||
// Now read the response. | ||
status := make([]byte, 4) | ||
n, err := conn.Read(status) | ||
if err != nil { | ||
return err | ||
} | ||
if n == 0 { | ||
return fmt.Errorf("no status code received") | ||
} | ||
|
||
responseLength, err := readNativeUIntFromConn(conn) | ||
if err != nil { | ||
return err | ||
} | ||
if responseLength == 0 { | ||
return fmt.Errorf("received data length was '0'") | ||
} | ||
|
||
// Don't allow more than 64kb of data to prevent DOS / issues | ||
// with architecture mismatch. V2 protocol allowed for up to | ||
// 16kb, so 64kb should give us a pretty good margin for anything | ||
// that has been added since. | ||
if responseLength > 64*1024 { | ||
return fmt.Errorf("received data length was '%d', we only allow up to '%d'", responseLength, 64*1024) | ||
} | ||
|
||
data := make([]byte, responseLength) | ||
n, err = conn.Read(data) | ||
if err != nil { | ||
return err | ||
} | ||
if uint(n) != responseLength { | ||
return fmt.Errorf("no data received, expected '%v' bytes but got '%v'", responseLength, n) | ||
} | ||
|
||
// Process data | ||
log.Print(string(data)) | ||
|
||
return nil | ||
} |