GNUnet P2P protocol specification
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

398 lines
12 KiB

  1. package gns
  2. import (
  3. "encoding/hex"
  4. "fmt"
  5. "gnunet/enums"
  6. "gnunet/message"
  7. "github.com/bfix/gospel/crypto/ed25519"
  8. "github.com/bfix/gospel/logger"
  9. )
  10. // HdlrInst is the type for functions that instanciate custom block handlers.
  11. type HdlrInst func(*message.GNSResourceRecord, []string) (BlockHandler, error)
  12. // Error codes
  13. var (
  14. ErrInvalidRecordMix = fmt.Errorf("Invalid mix of RR types in block")
  15. ErrBlockHandler = fmt.Errorf("Internal block handler failure")
  16. )
  17. // Mapping of RR types to BlockHandler instanciation functions
  18. var (
  19. customHandler = map[int]HdlrInst{
  20. enums.GNS_TYPE_PKEY: NewPkeyHandler,
  21. enums.GNS_TYPE_GNS2DNS: NewGns2DnsHandler,
  22. enums.GNS_TYPE_BOX: NewBoxHandler,
  23. enums.GNS_TYPE_LEHO: NewLehoHandler,
  24. }
  25. )
  26. //======================================================================
  27. // GNS blocks that contain special records (PKEY, GNS2DNS, BOX, LEHO...)
  28. // require special treatment with respect to other resource records with
  29. // different types in the same block. Usually only certain other types
  30. // (or none at all) are allowed.
  31. //======================================================================
  32. // BlockHandler interface.
  33. type BlockHandler interface {
  34. // AddRecord inserts a RR into the BlockHandler for (later) processing.
  35. // The handler can inspect the remaining labels in a path if required.
  36. // It returns an error if a record is not accepted by the block handler.
  37. AddRecord(rr *message.GNSResourceRecord, labels []string) error
  38. // TypeAction returns a flag indicating how a resource record of a
  39. // given type is to be treated by a custom block handler:
  40. // = -1: Record is not allowed
  41. // = 0: Record is allowed but will be ignored
  42. // = 1: Record is allowed and will be processed
  43. TypeAction(t int) int
  44. // Records returns a list of RR of the given types associated with
  45. // the custom handler
  46. Records(kind RRTypeList) *GNSRecordSet
  47. }
  48. //----------------------------------------------------------------------
  49. // Manage list of block handlers
  50. // Under normal circumstances there is only one (or none) block handler
  51. // per block, but future constructs may allow multiple block handlers
  52. // to be present. The block handler list implements the BlockHandler
  53. // interface.
  54. // The BlockHandlerList maintains a map of actually instantiated handlers
  55. // (indexed by record type) and a list of record types (with occurrence
  56. // count) in the block.
  57. //----------------------------------------------------------------------
  58. // BlockHandlerList is a list of block handlers instantiated.
  59. type BlockHandlerList struct {
  60. list map[int]BlockHandler // list of handler instances
  61. }
  62. // NewBlockHandlerList instantiates an a list of active block handlers
  63. // for a given set of records (GNS block).
  64. func NewBlockHandlerList(records []*message.GNSResourceRecord, labels []string) (*BlockHandlerList, error) {
  65. // initialize block handler list
  66. hl := &BlockHandlerList{
  67. list: make(map[int]BlockHandler),
  68. }
  69. // build a list of record types that are handled by a custom handler.
  70. rrList := NewRRTypeList(
  71. enums.GNS_TYPE_PKEY,
  72. enums.GNS_TYPE_GNS2DNS,
  73. enums.GNS_TYPE_BOX,
  74. enums.GNS_TYPE_LEHO)
  75. // Traverse record list and build list of handler instances
  76. for _, rec := range records {
  77. // check for custom handler type
  78. rrType := int(rec.Type)
  79. if rrList.HasType(rrType) {
  80. // check if a handler for given type already exists
  81. var (
  82. hdlr BlockHandler
  83. ok bool
  84. err error
  85. )
  86. if hdlr, ok = hl.list[rrType]; ok {
  87. // add record to existing handler
  88. if err = hdlr.AddRecord(rec, labels); err != nil {
  89. return nil, err
  90. }
  91. continue
  92. }
  93. // create a new handler instance
  94. switch rrType {
  95. case enums.GNS_TYPE_PKEY:
  96. hdlr, err = NewPkeyHandler(rec, labels)
  97. case enums.GNS_TYPE_GNS2DNS:
  98. hdlr, err = NewGns2DnsHandler(rec, labels)
  99. case enums.GNS_TYPE_BOX:
  100. hdlr, err = NewBoxHandler(rec, labels)
  101. case enums.GNS_TYPE_LEHO:
  102. hdlr, err = NewLehoHandler(rec, labels)
  103. }
  104. if err != nil {
  105. return nil, err
  106. }
  107. // store handler in list
  108. hl.list[rrType] = hdlr
  109. }
  110. }
  111. return hl, nil
  112. }
  113. // GetHandler returns a BlockHandler for the given key. If no block handler exists
  114. // under the given name, a new one is created and stored in the list. The type of
  115. // the new block handler is derived from the key value.
  116. func (hl *BlockHandlerList) GetHandler(t int) BlockHandler {
  117. // return handler for given key if it exists
  118. if hdlr, ok := hl.list[t]; ok {
  119. return hdlr
  120. }
  121. return nil
  122. }
  123. //----------------------------------------------------------------------
  124. // PKEY handler: Only one PKEY as sole record in a block
  125. //----------------------------------------------------------------------
  126. // PkeyHandler implementing the BlockHandler interface
  127. type PkeyHandler struct {
  128. pkey *ed25519.PublicKey // Zone key
  129. rec *message.GNSResourceRecord // associated recource record
  130. }
  131. // NewPkeyHandler returns a new BlockHandler instance
  132. func NewPkeyHandler(rec *message.GNSResourceRecord, labels []string) (BlockHandler, error) {
  133. if int(rec.Type) != enums.GNS_TYPE_PKEY {
  134. return nil, ErrInvalidRecordType
  135. }
  136. h := &PkeyHandler{
  137. pkey: nil,
  138. }
  139. if err := h.AddRecord(rec, labels); err != nil {
  140. return nil, err
  141. }
  142. return h, nil
  143. }
  144. // AddRecord inserts a PKEY record into the handler.
  145. func (h *PkeyHandler) AddRecord(rec *message.GNSResourceRecord, labels []string) error {
  146. if int(rec.Type) != enums.GNS_TYPE_PKEY {
  147. return ErrInvalidRecordType
  148. }
  149. // check for sole PKEY record in block
  150. if h.pkey != nil {
  151. return ErrInvalidPKEY
  152. }
  153. // check for sane key data
  154. if len(rec.Data) != 32 {
  155. return ErrInvalidPKEY
  156. }
  157. // set a PKEY handler
  158. h.pkey = ed25519.NewPublicKeyFromBytes(rec.Data)
  159. h.rec = rec
  160. return nil
  161. }
  162. // TypeAction return a flag indicating how a resource record of a given type
  163. // is to be treated (see BlockHandler interface)
  164. func (h *PkeyHandler) TypeAction(t int) int {
  165. // no other resource record type is not allowed
  166. if t == enums.GNS_TYPE_PKEY {
  167. return 1
  168. }
  169. return -1
  170. }
  171. // Records returns a list of RR of the given type associated with this handler
  172. func (h *PkeyHandler) Records(kind RRTypeList) *GNSRecordSet {
  173. rs := NewGNSRecordSet()
  174. if kind.HasType(enums.GNS_TYPE_PKEY) {
  175. rs.AddRecord(h.rec)
  176. }
  177. return rs
  178. }
  179. //----------------------------------------------------------------------
  180. // GNS2DNS handler
  181. //----------------------------------------------------------------------
  182. // Gns2DnsHandler implementing the BlockHandler interface
  183. type Gns2DnsHandler struct {
  184. Name string // DNS query name
  185. Servers []string // DNS servers to ask
  186. recs []*message.GNSResourceRecord // list of rersource records
  187. }
  188. // NewGns2DnsHandler returns a new BlockHandler instance
  189. func NewGns2DnsHandler(rec *message.GNSResourceRecord, labels []string) (BlockHandler, error) {
  190. if int(rec.Type) != enums.GNS_TYPE_GNS2DNS {
  191. return nil, ErrInvalidRecordType
  192. }
  193. h := &Gns2DnsHandler{
  194. Name: "",
  195. Servers: make([]string, 0),
  196. recs: make([]*message.GNSResourceRecord, 0),
  197. }
  198. if err := h.AddRecord(rec, labels); err != nil {
  199. return nil, err
  200. }
  201. return h, nil
  202. }
  203. // AddRecord inserts a GNS2DNS record into the handler.
  204. func (h *Gns2DnsHandler) AddRecord(rec *message.GNSResourceRecord, labels []string) error {
  205. if int(rec.Type) != enums.GNS_TYPE_GNS2DNS {
  206. return ErrInvalidRecordType
  207. }
  208. logger.Printf(logger.DBG, "[gns] GNS2DNS data: %s\n", hex.EncodeToString(rec.Data))
  209. // extract list of names in DATA block:
  210. next, dnsQuery := DNSNameFromBytes(rec.Data, 0)
  211. dnsServer := string(rec.Data[next : len(rec.Data)-1])
  212. logger.Printf(logger.DBG, "[gns] GNS2DNS query '%s'@'%s'\n", dnsQuery, dnsServer)
  213. if len(dnsServer) == 0 || len(dnsQuery) == 0 {
  214. return ErrInvalidRecordBody
  215. }
  216. // check if all GNS2DNS records refer to the same query name
  217. if len(h.Servers) == 0 {
  218. h.Name = dnsQuery
  219. }
  220. if dnsQuery != h.Name {
  221. return ErrInvalidRecordBody
  222. }
  223. h.Servers = append(h.Servers, dnsServer)
  224. h.recs = append(h.recs, rec)
  225. return nil
  226. }
  227. // TypeAction return a flag indicating how a resource record of a given type
  228. // is to be treated (see BlockHandler interface)
  229. func (h *Gns2DnsHandler) TypeAction(t int) int {
  230. // anything goes...
  231. return 1
  232. }
  233. // Records returns a list of RR of the given type associated with this handler
  234. func (h *Gns2DnsHandler) Records(kind RRTypeList) *GNSRecordSet {
  235. rs := NewGNSRecordSet()
  236. if kind.HasType(enums.GNS_TYPE_GNS2DNS) {
  237. for _, rec := range h.recs {
  238. rs.AddRecord(rec)
  239. }
  240. }
  241. return rs
  242. }
  243. //----------------------------------------------------------------------
  244. // BOX handler
  245. //----------------------------------------------------------------------
  246. // BoxHandler implementing the BlockHandler interface
  247. type BoxHandler struct {
  248. boxes map[string]*Box // map of found boxes
  249. }
  250. // NewBoxHandler returns a new BlockHandler instance
  251. func NewBoxHandler(rec *message.GNSResourceRecord, labels []string) (BlockHandler, error) {
  252. if int(rec.Type) != enums.GNS_TYPE_BOX {
  253. return nil, ErrInvalidRecordType
  254. }
  255. h := &BoxHandler{
  256. boxes: make(map[string]*Box),
  257. }
  258. if err := h.AddRecord(rec, labels); err != nil {
  259. return nil, err
  260. }
  261. return h, nil
  262. }
  263. // AddRecord inserts a BOX record into the handler.
  264. func (h *BoxHandler) AddRecord(rec *message.GNSResourceRecord, labels []string) error {
  265. if int(rec.Type) != enums.GNS_TYPE_BOX {
  266. return ErrInvalidRecordType
  267. }
  268. logger.Printf(logger.DBG, "[box-rr] for labels %v\n", labels)
  269. // check if we need to process the BOX record:
  270. // (1) only two remaining labels
  271. if len(labels) != 2 {
  272. return nil
  273. }
  274. // (2) remaining labels must start with '_'
  275. if labels[0][0] != '_' || labels[1][0] != '_' {
  276. return nil
  277. }
  278. // (3) check of "svc" and "proto" match values in the BOX
  279. box := NewBox(rec)
  280. if box.Matches(labels) {
  281. logger.Println(logger.DBG, "[box-rr] MATCH -- adding record")
  282. h.boxes[box.key] = box
  283. }
  284. return nil
  285. }
  286. // TypeAction return a flag indicating how a resource record of a given type
  287. // is to be treated (see BlockHandler interface)
  288. func (h *BoxHandler) TypeAction(t int) int {
  289. // anything goes...
  290. return 1
  291. }
  292. // Records returns a list of RR of the given type associated with this handler
  293. func (h *BoxHandler) Records(kind RRTypeList) *GNSRecordSet {
  294. rs := NewGNSRecordSet()
  295. for _, box := range h.boxes {
  296. if kind.HasType(int(box.Type)) {
  297. // valid box found: assemble new resource record.
  298. rr := new(message.GNSResourceRecord)
  299. rr.Expires = box.rec.Expires
  300. rr.Flags = box.rec.Flags
  301. rr.Type = box.Type
  302. rr.Size = uint32(len(box.RR))
  303. rr.Data = box.RR
  304. rs.AddRecord(rr)
  305. }
  306. }
  307. return rs
  308. }
  309. //----------------------------------------------------------------------
  310. // LEHO handler
  311. //----------------------------------------------------------------------
  312. // LehoHandler implementing the BlockHandler interface
  313. type LehoHandler struct {
  314. name string
  315. rec *message.GNSResourceRecord
  316. }
  317. // NewLehoHandler returns a new BlockHandler instance
  318. func NewLehoHandler(rec *message.GNSResourceRecord, labels []string) (BlockHandler, error) {
  319. if int(rec.Type) != enums.GNS_TYPE_LEHO {
  320. return nil, ErrInvalidRecordType
  321. }
  322. h := &LehoHandler{
  323. name: "",
  324. }
  325. if err := h.AddRecord(rec, labels); err != nil {
  326. return nil, err
  327. }
  328. return h, nil
  329. }
  330. // AddRecord inserts a LEHO record into the handler.
  331. func (h *LehoHandler) AddRecord(rec *message.GNSResourceRecord, labels []string) error {
  332. if int(rec.Type) != enums.GNS_TYPE_LEHO {
  333. return ErrInvalidRecordType
  334. }
  335. h.name = string(rec.Data)
  336. h.rec = rec
  337. return nil
  338. }
  339. // TypeAction return a flag indicating how a resource record of a given type
  340. // is to be treated (see BlockHandler interface)
  341. func (h *LehoHandler) TypeAction(t int) int {
  342. // only A and AAAA records allowed beside LEHO
  343. switch t {
  344. case enums.GNS_TYPE_LEHO, enums.GNS_TYPE_DNS_A, enums.GNS_TYPE_DNS_AAAA:
  345. return 1
  346. default:
  347. return -1
  348. }
  349. }
  350. // Records returns a list of RR of the given type associated with this handler
  351. func (h *LehoHandler) Records(kind RRTypeList) *GNSRecordSet {
  352. rs := NewGNSRecordSet()
  353. if kind.HasType(enums.GNS_TYPE_LEHO) {
  354. rs.AddRecord(h.rec)
  355. }
  356. return rs
  357. }