Serge Bazanski | d4438d6 | 2021-05-23 13:37:30 +0200 | [diff] [blame] | 1 | package ident |
| 2 | |
| 3 | import ( |
| 4 | "fmt" |
Serge Bazanski | ce2737f | 2021-05-23 17:15:29 +0200 | [diff] [blame] | 5 | "net" |
| 6 | "regexp" |
| 7 | "strconv" |
Serge Bazanski | d4438d6 | 2021-05-23 13:37:30 +0200 | [diff] [blame] | 8 | ) |
| 9 | |
| 10 | // Request is an ident protocol request, as seen by the client or server. |
| 11 | type 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 Bazanski | ce2737f | 2021-05-23 17:15:29 +0200 | [diff] [blame] | 18 | |
| 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 Bazanski | d4438d6 | 2021-05-23 13:37:30 +0200 | [diff] [blame] | 26 | } |
| 27 | |
| 28 | // encode encodes ths Request as per RFC1413, including the terminating \r\n. |
| 29 | func (r *Request) encode() []byte { |
| 30 | return []byte(fmt.Sprintf("%d,%d\r\n", r.ServerPort, r.ClientPort)) |
| 31 | } |
Serge Bazanski | ce2737f | 2021-05-23 17:15:29 +0200 | [diff] [blame] | 32 | |
| 33 | var ( |
| 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. |
| 41 | func 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 | } |