blob: 9c94e759430772f3086bb039ad5b1b619bb44874 [file] [log] [blame]
Serge Bazanskid4438d62021-05-23 13:37:30 +02001package ident
2
3import (
4 "fmt"
Serge Bazanskice2737f2021-05-23 17:15:29 +02005 "net"
6 "regexp"
7 "strconv"
Serge Bazanskid4438d62021-05-23 13:37:30 +02008)
9
10// Request is an ident protocol request, as seen by the client or server.
11type Request struct {
12 // ClientPort is the port number on the client side of the indent protocol,
13 // ie. the port local to the ident client.
14 ClientPort uint16
15 // ServerPort is the port number on the server side of the ident protocol,
16 // ie. the port local to the ident server.
17 ServerPort uint16
Serge Bazanskice2737f2021-05-23 17:15:29 +020018
19 // ClientAddress is the address of the ident protocol client. This is set
20 // by the ident Server before invoking handlers, and is ignored by the
21 // ident protocol Client.
22 // In handlers this can be used to ensure that responses are only returned
23 // to clients who are running on the remote side of the connection that
24 // they are querying about.
25 ClientAddress net.Addr
Serge Bazanskid4438d62021-05-23 13:37:30 +020026}
27
28// encode encodes ths Request as per RFC1413, including the terminating \r\n.
29func (r *Request) encode() []byte {
30 return []byte(fmt.Sprintf("%d,%d\r\n", r.ServerPort, r.ClientPort))
31}
Serge Bazanskice2737f2021-05-23 17:15:29 +020032
33var (
34 // reRequest matches request from RFC1413, but allows extra whitespace
35 // between significant tokens.
36 reRequest = regexp.MustCompile(`^\s*(\d{1,5})\s*,\s*(\d{1,5})\s*$`)
37)
38
39// decodeRequest parses the given bytes as an ident request. The data must be
40// stripped of the trailing \r\n.
41func decodeRequest(data []byte) (*Request, error) {
42 match := reRequest.FindStringSubmatch(string(data))
43 if match == nil {
44 return nil, fmt.Errorf("unparseable request")
45 }
46 serverPort, err := strconv.ParseUint(match[1], 10, 16)
47 if err != nil {
48 return nil, fmt.Errorf("invalid server port: %w", err)
49 }
50 clientPort, err := strconv.ParseUint(match[2], 10, 16)
51 if err != nil {
52 return nil, fmt.Errorf("invalid client port: %w", err)
53 }
54 return &Request{
55 ClientPort: uint16(clientPort),
56 ServerPort: uint16(serverPort),
57 }, nil
58}