packed.go 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894
  1. /*
  2. * Copyright (c) 2023, Psiphon Inc.
  3. * All rights reserved.
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. */
  19. package protocol
  20. import (
  21. "encoding"
  22. "encoding/base64"
  23. "encoding/hex"
  24. "encoding/json"
  25. "fmt"
  26. "strconv"
  27. "strings"
  28. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
  29. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/accesscontrol"
  30. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
  31. "github.com/fxamacker/cbor/v2"
  32. )
  33. // PackedAPIParameters is a compacted representation of common.APIParameters
  34. // using integer keys in place of string keys, and with some values
  35. // represented in compacted form, such as byte slices in place of hex or
  36. // base64 strings.
  37. //
  38. // The PackedAPIParameters representation is intended to be used to create
  39. // compacted, CBOR encodings of API parameters.
  40. type PackedAPIParameters map[int]interface{}
  41. // EncodePackedAPIParameters converts common.APIParameters to
  42. // PackedAPIParameters.
  43. func EncodePackedAPIParameters(params common.APIParameters) (PackedAPIParameters, error) {
  44. packedParams := PackedAPIParameters{}
  45. for name, value := range params {
  46. spec, ok := packedAPIParametersNameToSpec[name]
  47. if !ok {
  48. // The API parameter to be packed is not in
  49. // packedAPIParametersNameToSpec. This will occur if
  50. // packedAPIParametersNameToSpec is not updated when new API
  51. // parameters are added. Fail the operation and, ultimately, the
  52. // dial rather than proceeding without the parameter.
  53. return nil, errors.Tracef("unknown parameter name: %s", name)
  54. }
  55. if spec.converter != nil {
  56. var err error
  57. value, err = spec.converter.pack(value)
  58. if err != nil {
  59. return nil, errors.Tracef(
  60. "pack %s (%T) failed: %v", name, params[name], err)
  61. }
  62. }
  63. if _, ok := packedParams[spec.key]; ok {
  64. // This is a sanity check and shouldn't happen unless
  65. // packedAPIParametersNameToSpec is misconfigured.
  66. return nil, errors.TraceNew("duplicate parameter")
  67. }
  68. packedParams[spec.key] = value
  69. }
  70. return packedParams, nil
  71. }
  72. // DecodePackedAPIParameters converts PackedAPIParameters to
  73. // common.APIParameters
  74. func DecodePackedAPIParameters(packedParams PackedAPIParameters) (common.APIParameters, error) {
  75. params := common.APIParameters{}
  76. for key, value := range packedParams {
  77. spec, ok := packedAPIParametersKeyToSpec[key]
  78. if !ok {
  79. // The API parameter received is not in
  80. // packedAPIParametersNameToInt. Skip logging it and proceed.
  81. // This allows for production psiphond/broker instances to handle
  82. // experimental clients which ship new parameters, and matches
  83. // the legacy JSON-encoded API parameters behavior.
  84. continue
  85. }
  86. if spec.converter != nil {
  87. var err error
  88. value, err = spec.converter.unpack(value)
  89. if err != nil {
  90. return nil, errors.Tracef(
  91. "unpack %s (%T) failed: %v", spec.name, packedParams[key], err)
  92. }
  93. }
  94. if _, ok := params[spec.name]; ok {
  95. // This is a sanity check and shouldn't happen unless
  96. // packedAPIParametersKeyToSpec is misconfigured.
  97. return nil, errors.TraceNew("duplicate parameter")
  98. }
  99. params[spec.name] = value
  100. }
  101. return params, nil
  102. }
  103. // GetNetworkType returns the "network_type" API parameter value, if present.
  104. func (p PackedAPIParameters) GetNetworkType() (string, bool) {
  105. spec, ok := packedAPIParametersNameToSpec["network_type"]
  106. if !ok {
  107. return "", false
  108. }
  109. value, ok := p[spec.key]
  110. if !ok {
  111. return "", false
  112. }
  113. networkType, ok := value.(string)
  114. if !ok {
  115. return "", false
  116. }
  117. return networkType, true
  118. }
  119. // MakePackedAPIParametersRequestPayload converts common.APIParameters to
  120. // PackedAPIParameters and encodes the packed parameters as CBOR data.
  121. func MakePackedAPIParametersRequestPayload(
  122. params common.APIParameters) ([]byte, error) {
  123. packedParams, err := EncodePackedAPIParameters(params)
  124. if err != nil {
  125. return nil, errors.Trace(err)
  126. }
  127. payload, err := CBOREncoding.Marshal(packedParams)
  128. if err != nil {
  129. return nil, errors.Trace(err)
  130. }
  131. payload = addPackedAPIParametersPreamble(payload)
  132. return payload, nil
  133. }
  134. // GetPackedAPIParametersRequestPayload decodes the CBOR payload and converts
  135. // the PackedAPIParameters to common.APIParameters.
  136. //
  137. // GetPackedAPIParametersRequestPayload returns false and a nil error if the
  138. // input payload is not CBOR data, which is the case for legacy JSON
  139. // payloads.
  140. func GetPackedAPIParametersRequestPayload(
  141. payload []byte) (common.APIParameters, bool, error) {
  142. payload, ok := isPackedAPIParameters(payload)
  143. if !ok {
  144. return nil, false, nil
  145. }
  146. var packedParams PackedAPIParameters
  147. err := cbor.Unmarshal(payload, &packedParams)
  148. if err != nil {
  149. return nil, false, errors.Trace(err)
  150. }
  151. params, err := DecodePackedAPIParameters(packedParams)
  152. if err != nil {
  153. return nil, false, errors.Trace(err)
  154. }
  155. return params, true, nil
  156. }
  157. const (
  158. packedAPIParametersDistinguisher = byte(0)
  159. packedAPIParametersVersion = byte(1)
  160. )
  161. func addPackedAPIParametersPreamble(payload []byte) []byte {
  162. var preamble [2]byte
  163. // Use a simple 0 byte to distinguish payloads from JSON.
  164. preamble[0] = packedAPIParametersDistinguisher
  165. // Add a version tag, for future protocol changes.
  166. preamble[1] = packedAPIParametersVersion
  167. // Attempt to use the input buffer, which will avoid an allocation if it
  168. // has sufficient capacity.
  169. payload = append(payload, preamble[:]...)
  170. copy(payload[2:], payload[:len(payload)-2])
  171. copy(payload[0:2], preamble[:])
  172. return payload
  173. }
  174. func isPackedAPIParameters(payload []byte) ([]byte, bool) {
  175. if len(payload) < 2 {
  176. return nil, false
  177. }
  178. if payload[0] != packedAPIParametersDistinguisher {
  179. return nil, false
  180. }
  181. if payload[1] != packedAPIParametersVersion {
  182. return nil, false
  183. }
  184. return payload[2:], true
  185. }
  186. // PackedServerEntryFields is a compacted representation of ServerEntryFields
  187. // using integer keys in place of string keys, and with some values
  188. // represented in compacted form, such as byte slices in place of hex or
  189. // base64 strings.
  190. //
  191. // The PackedServerEntryFields representation is intended to be used in
  192. // CBOR-encoded messages, including in-proxy broker requests.
  193. //
  194. // To support older clients encoding signed server entries with new,
  195. // unrecognized fields, the encoded structure includes a list of packed
  196. // fields, Fields, and a list of raw, unpacked fields, UnrecognizedFields.
  197. type PackedServerEntryFields struct {
  198. Fields map[int]interface{} `cbor:"1,keyasint,omitempty"`
  199. UnrecognizedFields map[string]interface{} `cbor:"2,keyasint,omitempty"`
  200. }
  201. // EncodePackedServerEntryFields converts serverEntryFields to
  202. // PackedServerEntryFields.
  203. func EncodePackedServerEntryFields(
  204. serverEntryFields ServerEntryFields) (PackedServerEntryFields, error) {
  205. // An allocated but empty UnrecognizedFields should be omitted from any
  206. // CBOR encoding, taking no space.
  207. packedServerEntry := PackedServerEntryFields{
  208. Fields: make(map[int]interface{}),
  209. UnrecognizedFields: make(map[string]interface{}),
  210. }
  211. for name, value := range serverEntryFields {
  212. spec, ok := packedServerEntryFieldsNameToSpec[name]
  213. if !ok {
  214. // Add unrecognized fields to the unpacked UnrecognizedFields set.
  215. if _, ok := packedServerEntry.UnrecognizedFields[name]; ok {
  216. // This is a sanity check and shouldn't happen.
  217. return PackedServerEntryFields{}, errors.TraceNew("duplicate field")
  218. }
  219. packedServerEntry.UnrecognizedFields[name] = value
  220. continue
  221. }
  222. if spec.converter != nil {
  223. var err error
  224. value, err = spec.converter.pack(value)
  225. if err != nil {
  226. return PackedServerEntryFields{}, errors.Tracef(
  227. "pack %s (%T) failed: %v", name, serverEntryFields[name], err)
  228. }
  229. }
  230. if _, ok := packedServerEntry.Fields[spec.key]; ok {
  231. // This is a sanity check and shouldn't happen unless
  232. // packedServerEntryFieldsNameToSpec is misconfigured.
  233. return PackedServerEntryFields{}, errors.TraceNew("duplicate field")
  234. }
  235. packedServerEntry.Fields[spec.key] = value
  236. }
  237. return packedServerEntry, nil
  238. }
  239. // DecodePackedServerEntryFields converts PackedServerEntryFields to
  240. // ServerEntryFields.
  241. func DecodePackedServerEntryFields(
  242. packedServerEntryFields PackedServerEntryFields) (ServerEntryFields, error) {
  243. serverEntryFields := ServerEntryFields{}
  244. for key, value := range packedServerEntryFields.Fields {
  245. spec, ok := packedServerEntryFieldsKeyToSpec[key]
  246. if !ok {
  247. // Unlike DecodePackedAPIParameters, unknown fields cannot be
  248. // ignored as they may be part of the server entry digital
  249. // signature. Production psiphond/broker instances must be
  250. // updated to handle new server entry fields.
  251. return nil, errors.Tracef("unknown field key: %d", key)
  252. }
  253. if spec.converter != nil {
  254. var err error
  255. value, err = spec.converter.unpack(value)
  256. if err != nil {
  257. return nil, errors.Tracef(
  258. "unpack %s (%T) failed: %v",
  259. spec.name, packedServerEntryFields.Fields[key], err)
  260. }
  261. }
  262. if _, ok := serverEntryFields[spec.name]; ok {
  263. // This is a sanity check and shouldn't happen unless
  264. // packedServerEntryFieldsKeyToSpec is misconfigured.
  265. return nil, errors.TraceNew("duplicate field")
  266. }
  267. serverEntryFields[spec.name] = value
  268. }
  269. for name, value := range packedServerEntryFields.UnrecognizedFields {
  270. if _, ok := serverEntryFields[name]; ok {
  271. // This is a sanity check and shouldn't happen.
  272. return nil, errors.TraceNew("duplicate field")
  273. }
  274. serverEntryFields[name] = value
  275. }
  276. return serverEntryFields, nil
  277. }
  278. type packSpec struct {
  279. key int
  280. name string
  281. converter *packConverter
  282. }
  283. // packConverter defines an optional pack/unpack transformation to further
  284. // reduce encoding overhead. For example, fields that are expected to be hex
  285. // strings may be converted to byte slices, and then back again; integer
  286. // strings are converted to actual integers; etc..
  287. type packConverter struct {
  288. pack func(interface{}) (interface{}, error)
  289. unpack func(interface{}) (interface{}, error)
  290. }
  291. func packInt(v interface{}) (interface{}, error) {
  292. switch value := v.(type) {
  293. case string:
  294. i, err := strconv.Atoi(value)
  295. if err != nil {
  296. return nil, errors.Trace(err)
  297. }
  298. return i, nil
  299. case float64:
  300. // Decoding server entry JSON from the local datastore may produce
  301. // float64 field types.
  302. return int(value), nil
  303. default:
  304. return nil, errors.TraceNew(
  305. "expected string or float type")
  306. }
  307. }
  308. func unpackInt(v interface{}) (interface{}, error) {
  309. switch i := v.(type) {
  310. case int:
  311. return strconv.FormatInt(int64(i), 10), nil
  312. case int64:
  313. return strconv.FormatInt(i, 10), nil
  314. case uint64:
  315. return strconv.FormatUint(i, 10), nil
  316. default:
  317. return nil, errors.TraceNew(
  318. "expected int, int64, or uint64 type")
  319. }
  320. }
  321. func packFloat(v interface{}) (interface{}, error) {
  322. switch value := v.(type) {
  323. case string:
  324. i, err := strconv.ParseFloat(value, 64)
  325. if err != nil {
  326. return nil, errors.Trace(err)
  327. }
  328. return i, nil
  329. case float64:
  330. return value, nil
  331. default:
  332. return nil, errors.TraceNew(
  333. "expected string or float type")
  334. }
  335. }
  336. func unpackFloat(v interface{}) (interface{}, error) {
  337. f, ok := v.(float64)
  338. if !ok {
  339. return nil, errors.TraceNew("expected int type")
  340. }
  341. return fmt.Sprintf("%f", f), nil
  342. }
  343. func packHex(v interface{}) (interface{}, error) {
  344. // Accept a type that is either a string, or implements MarshalText
  345. // returning a string. The resulting string must be hex encoded.
  346. s, err := stringOrTextMarshal(v)
  347. if err != nil {
  348. return nil, errors.Trace(err)
  349. }
  350. b, err := hex.DecodeString(s)
  351. if err != nil {
  352. return nil, errors.Trace(err)
  353. }
  354. return b, nil
  355. }
  356. func unpackHexLower(v interface{}) (interface{}, error) {
  357. b, ok := v.([]byte)
  358. if !ok {
  359. return nil, errors.TraceNew("expected []byte type")
  360. }
  361. return hex.EncodeToString(b), nil
  362. }
  363. func unpackHexUpper(v interface{}) (interface{}, error) {
  364. s, err := unpackHexLower(v)
  365. if err != nil {
  366. return nil, errors.Trace(err)
  367. }
  368. return strings.ToUpper(s.(string)), nil
  369. }
  370. func packBase64(v interface{}) (interface{}, error) {
  371. // Accept a type that is either a string, or implements MarshalText
  372. // returning a string. The resulting string must be base64 encoded.
  373. s, err := stringOrTextMarshal(v)
  374. if err != nil {
  375. return nil, errors.Trace(err)
  376. }
  377. b, err := base64.StdEncoding.DecodeString(s)
  378. if err != nil {
  379. return nil, errors.Trace(err)
  380. }
  381. return b, nil
  382. }
  383. func unpackBase64(v interface{}) (interface{}, error) {
  384. b, ok := v.([]byte)
  385. if !ok {
  386. return nil, errors.TraceNew("expected []byte type")
  387. }
  388. return base64.StdEncoding.EncodeToString(b), nil
  389. }
  390. func packUnpaddedBase64(v interface{}) (interface{}, error) {
  391. // Accept a type that is either a string, or implements MarshalText
  392. // returning a string. The resulting string must be base64 encoded
  393. // (unpadded).
  394. s, err := stringOrTextMarshal(v)
  395. if err != nil {
  396. return nil, errors.Trace(err)
  397. }
  398. b, err := base64.RawStdEncoding.DecodeString(s)
  399. if err != nil {
  400. return nil, errors.Trace(err)
  401. }
  402. return b, nil
  403. }
  404. func unpackUnpaddedBase64(v interface{}) (interface{}, error) {
  405. b, ok := v.([]byte)
  406. if !ok {
  407. return nil, errors.TraceNew("expected []byte type")
  408. }
  409. return base64.RawStdEncoding.EncodeToString(b), nil
  410. }
  411. func packAuthorizations(v interface{}) (interface{}, error) {
  412. auths, ok := v.([]string)
  413. if !ok {
  414. return nil, errors.TraceNew("expected []string type")
  415. }
  416. packedAuths, err := accesscontrol.PackAuthorizations(auths, CBOREncoding)
  417. if err != nil {
  418. return nil, errors.Trace(err)
  419. }
  420. return packedAuths, nil
  421. }
  422. func unpackAuthorizations(v interface{}) (interface{}, error) {
  423. packedAuths, ok := v.([]byte)
  424. if !ok {
  425. return nil, errors.TraceNew("expected []byte type")
  426. }
  427. auths, err := accesscontrol.UnpackAuthorizations(packedAuths)
  428. if err != nil {
  429. return nil, errors.Trace(err)
  430. }
  431. return auths, nil
  432. }
  433. func packNoop(v interface{}) (interface{}, error) {
  434. return v, nil
  435. }
  436. func unpackRawJSON(v interface{}) (interface{}, error) {
  437. // For compatibility with the legacy JSON encoding as used in the status
  438. // API request payload, where the input is pre-JSON-marshaling
  439. // json.RawMessage (so use packNoop) and the output is expected to be an
  440. // unmarshaled JSON decoded object; e.g., map[string]interface{}.
  441. packedRawJSON, ok := v.([]byte)
  442. if !ok {
  443. return nil, errors.TraceNew("expected []byte type")
  444. }
  445. var unmarshaledJSON map[string]interface{}
  446. err := json.Unmarshal(packedRawJSON, &unmarshaledJSON)
  447. if err != nil {
  448. return nil, errors.Trace(err)
  449. }
  450. return unmarshaledJSON, nil
  451. }
  452. func unpackSliceOfJSONCompatibleMaps(v interface{}) (interface{}, error) {
  453. // For compatibility with the legacy JSON encoding as used for tactics
  454. // speed test sample parameters. This converts CBOR maps of type map
  455. // [interface{}]interface{} to JSON-compatible maps of type map
  456. // [string]interface{}.
  457. if v == nil {
  458. return nil, nil
  459. }
  460. packedEntries, ok := v.([]interface{})
  461. if !ok {
  462. return nil, errors.TraceNew("expected []interface{} type")
  463. }
  464. entries := make([]map[string]interface{}, len(packedEntries))
  465. for i, packedEntry := range packedEntries {
  466. entry, ok := packedEntry.(map[interface{}]interface{})
  467. if !ok {
  468. return nil, errors.TraceNew("expected map[interface{}]interface{} type")
  469. }
  470. entries[i] = make(map[string]interface{})
  471. for key, value := range entry {
  472. strKey, ok := key.(string)
  473. if !ok {
  474. return nil, errors.TraceNew("expected string type")
  475. }
  476. entries[i][strKey] = value
  477. }
  478. }
  479. return entries, nil
  480. }
  481. func stringOrTextMarshal(v interface{}) (string, error) {
  482. switch value := v.(type) {
  483. case string:
  484. return value, nil
  485. case encoding.TextMarshaler:
  486. bytes, err := value.MarshalText()
  487. if err != nil {
  488. return "", errors.Trace(err)
  489. }
  490. return string(bytes), nil
  491. default:
  492. return "", errors.TraceNew(
  493. "expected string or TextMarshaler type")
  494. }
  495. }
  496. var (
  497. // All of the following variables should be read-only after
  498. // initialization, due to concurrent access.
  499. packedAPIParametersNameToSpec = make(map[string]packSpec)
  500. packedAPIParametersKeyToSpec = make(map[int]packSpec)
  501. packedServerEntryFieldsNameToSpec = make(map[string]packSpec)
  502. packedServerEntryFieldsKeyToSpec = make(map[int]packSpec)
  503. intConverter = &packConverter{packInt, unpackInt}
  504. floatConverter = &packConverter{packFloat, unpackFloat}
  505. lowerHexConverter = &packConverter{packHex, unpackHexLower}
  506. upperHexConverter = &packConverter{packHex, unpackHexUpper}
  507. base64Converter = &packConverter{packBase64, unpackBase64}
  508. unpaddedBase64Converter = &packConverter{packUnpaddedBase64, unpackUnpaddedBase64}
  509. authorizationsConverter = &packConverter{packAuthorizations, unpackAuthorizations}
  510. rawJSONConverter = &packConverter{packNoop, unpackRawJSON}
  511. compatibleJSONMapConverter = &packConverter{packNoop, unpackSliceOfJSONCompatibleMaps}
  512. )
  513. func init() {
  514. // Packed API parameters
  515. //
  516. // - must be appended to when server entry fields are added; existing key
  517. // values cannot be reordered or reused.
  518. //
  519. // - limitation: use of converters means secrets/passwords/IDs are locked
  520. // in as upper or lower hex with even digits, etc.
  521. //
  522. // - while not currently the case, if different API requests have the same
  523. // input field name with different types, the nil converter must be used.
  524. packedAPIParameterSpecs := []packSpec{
  525. // Specs: protocol.PSIPHON_API_HANDSHAKE_AUTHORIZATIONS
  526. {1, "authorizations", authorizationsConverter},
  527. // Specs:
  528. // tactics.SPEED_TEST_SAMPLES_PARAMETER_NAME
  529. // tactics.APPLIED_TACTICS_TAG_PARAMETER_NAME
  530. // tactics.STORED_TACTICS_TAG_PARAMETER_NAME
  531. {2, "stored_tactics_tag", lowerHexConverter},
  532. {3, "speed_test_samples", compatibleJSONMapConverter},
  533. {4, "applied_tactics_tag", lowerHexConverter},
  534. // Specs: server.baseParams
  535. //
  536. // - client_build_rev does not use a hex converter since some values
  537. // are a non-even length prefix of a commit hash hex.
  538. {5, "client_session_id", lowerHexConverter},
  539. {6, "propagation_channel_id", upperHexConverter},
  540. {7, "sponsor_id", upperHexConverter},
  541. {8, "client_version", intConverter},
  542. {9, "client_platform", nil},
  543. {10, "client_features", nil},
  544. {11, "client_build_rev", nil},
  545. {12, "device_region", nil},
  546. {13, "device_location", nil},
  547. // Specs: server.baseSessionParams
  548. {14, "session_id", lowerHexConverter},
  549. // Specs: server.baseDialParams
  550. //
  551. // - intConverter is used for boolean fields as those are "0"/"1"
  552. // string values by legacy convention.
  553. //
  554. // - the `padding` field is not packed since it is intended to pad the
  555. // encoded message to its existing size.
  556. {15, "relay_protocol", nil},
  557. {16, "ssh_client_version", nil},
  558. {17, "upstream_proxy_type", nil},
  559. {18, "upstream_proxy_custom_header_names", nil},
  560. {19, "fronting_provider_id", upperHexConverter},
  561. {20, "meek_dial_address", nil},
  562. {21, "meek_resolved_ip_address", nil},
  563. {22, "meek_sni_server_name", nil},
  564. {23, "meek_host_header", nil},
  565. {24, "meek_transformed_host_name", intConverter},
  566. {25, "user_agent", nil},
  567. {26, "tls_profile", nil},
  568. {27, "tls_version", nil},
  569. {28, "server_entry_region", nil},
  570. {29, "server_entry_source", nil},
  571. {30, "server_entry_timestamp", nil},
  572. {31, "dial_port_number", intConverter},
  573. {32, "quic_version", nil},
  574. {33, "quic_dial_sni_address", nil},
  575. {34, "quic_disable_client_path_mtu_discovery", intConverter},
  576. {35, "upstream_bytes_fragmented", intConverter},
  577. {36, "upstream_min_bytes_written", intConverter},
  578. {37, "upstream_max_bytes_written", intConverter},
  579. {38, "upstream_min_delayed", intConverter},
  580. {39, "upstream_max_delayed", intConverter},
  581. {40, "padding", nil},
  582. {41, "pad_response", intConverter},
  583. {42, "is_replay", intConverter},
  584. {43, "egress_region", nil},
  585. {44, "dial_duration", intConverter},
  586. {45, "candidate_number", intConverter},
  587. {46, "established_tunnels_count", intConverter},
  588. {47, "upstream_ossh_padding", intConverter},
  589. {48, "meek_cookie_size", intConverter},
  590. {49, "meek_limit_request", intConverter},
  591. {50, "meek_redial_probability", floatConverter},
  592. {51, "meek_tls_padding", intConverter},
  593. {52, "network_latency_multiplier", floatConverter},
  594. {53, "client_bpf", nil},
  595. {54, "network_type", nil},
  596. {55, "conjure_cached", nil},
  597. {56, "conjure_delay", nil},
  598. {57, "conjure_transport", nil},
  599. {58, "conjure_prefix", nil},
  600. {59, "conjure_stun", nil},
  601. {60, "conjure_empty_packet", intConverter},
  602. {61, "conjure_network", nil},
  603. {62, "conjure_port_number", intConverter},
  604. {63, "split_tunnel", nil},
  605. {64, "split_tunnel_regions", nil},
  606. {65, "dns_preresolved", nil},
  607. {66, "dns_preferred", nil},
  608. {67, "dns_transform", nil},
  609. {68, "dns_attempt", intConverter},
  610. {69, "http_transform", nil},
  611. {70, "seed_transform", nil},
  612. {71, "ossh_prefix", nil},
  613. {72, "tls_fragmented", intConverter},
  614. {73, "tls_padding", intConverter},
  615. {74, "tls_ossh_sni_server_name", nil},
  616. {75, "tls_ossh_transformed_host_name", intConverter},
  617. // Specs: server.inproxyDialParams
  618. {76, "inproxy_connection_id", unpaddedBase64Converter},
  619. {77, "inproxy_relay_packet", unpaddedBase64Converter},
  620. {78, "inproxy_broker_is_replay", intConverter},
  621. {79, "inproxy_broker_transport", nil},
  622. {80, "inproxy_broker_fronting_provider_id", upperHexConverter},
  623. {81, "inproxy_broker_dial_address", nil},
  624. {82, "inproxy_broker_resolved_ip_address", nil},
  625. {83, "inproxy_broker_sni_server_name", nil},
  626. {84, "inproxy_broker_host_header", nil},
  627. {85, "inproxy_broker_transformed_host_name", intConverter},
  628. {86, "inproxy_broker_user_agent", nil},
  629. {87, "inproxy_broker_tls_profile", nil},
  630. {88, "inproxy_broker_tls_version", nil},
  631. {89, "inproxy_broker_tls_fragmented", intConverter},
  632. {90, "inproxy_broker_tls_padding", intConverter},
  633. {91, "inproxy_broker_client_bpf", nil},
  634. {92, "inproxy_broker_upstream_bytes_fragmented", intConverter},
  635. {93, "inproxy_broker_upstream_min_bytes_written", intConverter},
  636. {94, "inproxy_broker_upstream_max_bytes_written", intConverter},
  637. {95, "inproxy_broker_upstream_min_delayed", intConverter},
  638. {96, "inproxy_broker_upstream_max_delayed", intConverter},
  639. {97, "inproxy_broker_http_transform", nil},
  640. {98, "inproxy_broker_dns_preresolved", nil},
  641. {99, "inproxy_broker_dns_preferred", nil},
  642. {100, "inproxy_broker_dns_transform", nil},
  643. {101, "inproxy_broker_dns_attempt", intConverter},
  644. {102, "inproxy_webrtc_dns_preresolved", nil},
  645. {103, "inproxy_webrtc_dns_preferred", nil},
  646. {104, "inproxy_webrtc_dns_transform", nil},
  647. {105, "inproxy_webrtc_dns_attempt", intConverter},
  648. {106, "inproxy_webrtc_stun_server", nil},
  649. {107, "inproxy_webrtc_stun_server_resolved_ip_address", nil},
  650. {108, "inproxy_webrtc_stun_server_RFC5780", nil},
  651. {109, "inproxy_webrtc_stun_server_RFC5780_resolved_ip_address", nil},
  652. {110, "inproxy_webrtc_randomize_dtls", intConverter},
  653. {111, "inproxy_webrtc_padded_messages_sent", intConverter},
  654. {112, "inproxy_webrtc_padded_messages_received", intConverter},
  655. {113, "inproxy_webrtc_decoy_messages_sent", intConverter},
  656. {114, "inproxy_webrtc_decoy_messages_received", intConverter},
  657. {115, "inproxy_webrtc_local_ice_candidate_type", nil},
  658. {116, "inproxy_webrtc_local_ice_candidate_is_initiator", intConverter},
  659. {117, "inproxy_webrtc_local_ice_candidate_is_IPv6", intConverter},
  660. {118, "inproxy_webrtc_local_ice_candidate_port", intConverter},
  661. {119, "inproxy_webrtc_remote_ice_candidate_type", nil},
  662. {120, "inproxy_webrtc_remote_ice_candidate_is_IPv6", intConverter},
  663. {121, "inproxy_webrtc_remote_ice_candidate_port", intConverter},
  664. // Specs: server.handshakeRequestParams
  665. {122, "missing_server_entry_signature", base64Converter},
  666. {123, "missing_server_entry_provider_id", base64Converter},
  667. // Specs: server.uniqueUserParams
  668. //
  669. // - future enhancement: add a timestamp converter from RFC3339 to and
  670. // from 64-bit Unix time?
  671. {124, "last_connected", nil},
  672. // Specs: server.connectedRequestParams
  673. {125, "establishment_duration", intConverter},
  674. // Specs: server.remoteServerListStatParams
  675. {126, "client_download_timestamp", nil},
  676. {127, "tunneled", intConverter},
  677. {128, "url", nil},
  678. {129, "etag", nil},
  679. {130, "bytes", intConverter},
  680. {131, "duration", intConverter},
  681. // Specs: server.failedTunnelStatParams
  682. //
  683. // - given CBOR integer encoding, int key values greater than 128 may
  684. // be a byte longer; this means some failed_tunnel required field
  685. // key encodings may be longer than some optional handshake field
  686. // key encodings; however, we prioritize reducing the handshake
  687. // size, since it comes earlier in the tunnel flow.
  688. {132, "server_entry_tag", base64Converter},
  689. {133, "client_failed_timestamp", nil},
  690. {134, "record_probability", floatConverter},
  691. {135, "liveness_test_upstream_bytes", intConverter},
  692. {136, "liveness_test_sent_upstream_bytes", intConverter},
  693. {137, "liveness_test_downstream_bytes", intConverter},
  694. {138, "liveness_test_received_downstream_bytes", intConverter},
  695. {139, "bytes_up", intConverter},
  696. {140, "bytes_down", intConverter},
  697. {141, "tunnel_error", nil},
  698. // Specs: status request payload
  699. //
  700. // - future enhancement: pack the statusData payload, which is
  701. // currently sent as unpacked JSON.
  702. {142, "statusData", rawJSONConverter},
  703. {143, "inproxy_webrtc_local_ice_candidate_is_private_IP", intConverter},
  704. {144, "inproxy_webrtc_remote_ice_candidate_is_private_IP", intConverter},
  705. // Next key value = 145
  706. }
  707. for _, spec := range packedAPIParameterSpecs {
  708. if _, ok := packedAPIParametersNameToSpec[spec.name]; ok {
  709. panic("duplicate parameter name")
  710. }
  711. packedAPIParametersNameToSpec[spec.name] = spec
  712. if _, ok := packedAPIParametersKeyToSpec[spec.key]; ok {
  713. panic("duplicate parameter key")
  714. }
  715. packedAPIParametersKeyToSpec[spec.key] = spec
  716. }
  717. // Packed server entry fields
  718. //
  719. // - must be appended to when server entry fields are added; existing key
  720. // values cannot be reordered or reused.
  721. //
  722. // - limitation: use of converters means secrets/passwords/IDs are locked
  723. // in as upper or lower hex with even digits, etc.
  724. //
  725. // - since webServerCertificate is omitted in non-legacy server entries,
  726. // no PEM-encoding packer is implemented.
  727. //
  728. // - unlike API integer parameters and certain server entry fields, most
  729. // port values are already int types and so not converted.
  730. //
  731. // - local-only fields are also packed, to allow for future use of packed
  732. // encodings in the local datastore.
  733. packedServerEntryFieldSpecs := []packSpec{
  734. {1, "tag", base64Converter},
  735. {2, "ipAddress", nil},
  736. {3, "webServerPort", intConverter},
  737. {4, "webServerSecret", lowerHexConverter},
  738. {5, "webServerCertificate", nil},
  739. {6, "sshPort", nil},
  740. {7, "sshUsername", nil},
  741. {8, "sshPassword", lowerHexConverter},
  742. {9, "sshHostKey", unpaddedBase64Converter},
  743. {10, "sshObfuscatedPort", nil},
  744. {11, "sshObfuscatedQUICPort", nil},
  745. {12, "limitQUICVersions", nil},
  746. {13, "sshObfuscatedTapdancePort", nil},
  747. {14, "sshObfuscatedConjurePort", nil},
  748. {15, "sshObfuscatedKey", lowerHexConverter},
  749. {16, "capabilities", nil},
  750. {17, "region", nil},
  751. {18, "providerID", upperHexConverter},
  752. {19, "frontingProviderID", upperHexConverter},
  753. {20, "tlsOSSHPort", nil},
  754. {21, "meekServerPort", nil},
  755. {22, "meekCookieEncryptionPublicKey", base64Converter},
  756. {23, "meekObfuscatedKey", lowerHexConverter},
  757. {24, "meekFrontingHost", nil},
  758. {25, "meekFrontingHosts", nil},
  759. {26, "meekFrontingDomain", nil},
  760. {27, "meekFrontingAddresses", nil},
  761. {28, "meekFrontingAddressesRegex", nil},
  762. {29, "meekFrontingDisableSNI", nil},
  763. {30, "tacticsRequestPublicKey", base64Converter},
  764. {31, "tacticsRequestObfuscatedKey", base64Converter},
  765. {32, "configurationVersion", nil},
  766. {33, "signature", base64Converter},
  767. {34, "disableHTTPTransforms", nil},
  768. {35, "disableObfuscatedQUICTransforms", nil},
  769. {36, "disableOSSHTransforms", nil},
  770. {37, "disableOSSHPrefix", nil},
  771. {38, "inproxySessionPublicKey", unpaddedBase64Converter},
  772. {39, "inproxySessionRootObfuscationSecret", unpaddedBase64Converter},
  773. {40, "inproxySSHPort", nil},
  774. {41, "inproxyOSSHPort", nil},
  775. {42, "inproxyQUICPort", nil},
  776. {43, "inproxyMeekPort", nil},
  777. {44, "inproxyTlsOSSHPort", nil},
  778. {45, "localSource", nil},
  779. {46, "localTimestamp", nil},
  780. {47, "isLocalDerivedTag", nil},
  781. }
  782. for _, spec := range packedServerEntryFieldSpecs {
  783. if _, ok := packedServerEntryFieldsNameToSpec[spec.name]; ok {
  784. panic("duplicate field name")
  785. }
  786. packedServerEntryFieldsNameToSpec[spec.name] = spec
  787. if _, ok := packedServerEntryFieldsKeyToSpec[spec.key]; ok {
  788. panic("duplicate field key")
  789. }
  790. packedServerEntryFieldsKeyToSpec[spec.key] = spec
  791. }
  792. }